diff --git a/.github/workflows/tests-misc.yml b/.github/workflows/tests-misc.yml index 846a7e5aeb87..c2148a60d676 100644 --- a/.github/workflows/tests-misc.yml +++ b/.github/workflows/tests-misc.yml @@ -370,6 +370,17 @@ jobs: components: cargo, clippy, rust-docs, rust-src, rustfmt, rustc, rust-std - name: Install protobuf run: brew install protobuf + - name: install solc + run: brew install solidity + - name: Install resolc + run: | + VERSION="0.3.0" + ASSET_URL="https://github.com/paritytech/revive/releases/download/v$VERSION/resolc-universal-apple-darwin" + echo "Downloading resolc v$VERSION from $ASSET_URL" + curl -Lsf --show-error -o $HOME/.cargo/bin/resolc "$ASSET_URL" + chmod +x $HOME/.cargo/bin/resolc + xattr -c $HOME/.cargo/bin/resolc + resolc --version - name: cargo info run: | echo "######## rustup show ########" @@ -406,3 +417,4 @@ jobs: else echo '### Good job! All the required jobs passed 🚀' >> $GITHUB_STEP_SUMMARY fi + diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 13fb11e8cf61..744d4d6b7d42 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1182,6 +1182,10 @@ impl pallet_revive::Config for Runtime { type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>; type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>; type UnsafeUnstableInterface = ConstBool; + #[cfg(feature = "runtime-benchmarks")] + type AllowEVMBytecode = ConstBool; + #[cfg(not(feature = "runtime-benchmarks"))] + type AllowEVMBytecode = ConstBool; type UploadOrigin = EnsureSigned; type InstantiateOrigin = EnsureSigned; type RuntimeHoldReason = RuntimeHoldReason; @@ -1199,7 +1203,10 @@ parameter_types! { impl pallet_migrations::Config for Runtime { type RuntimeEvent = RuntimeEvent; #[cfg(not(feature = "runtime-benchmarks"))] - type Migrations = pallet_revive::migrations::v1::Migration; + type Migrations = ( + pallet_revive::migrations::v1::Migration, + pallet_revive::migrations::v2::Migration, + ); // Benchmarks need mocked migrations to guarantee that they succeed. #[cfg(feature = "runtime-benchmarks")] type Migrations = pallet_migrations::mock_helpers::MockedMigrations; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 3d65d3b16829..52bb4a74cdb6 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -1664,11 +1664,14 @@ fn weight_of_message_increases_when_dealing_with_erc20s() { fn withdraw_and_deposit_erc20s() { let sender: AccountId = ALICE.into(); let beneficiary: AccountId = BOB.into(); + let revive_account = pallet_revive::Pallet::::account_id(); let checking_account = asset_hub_westend_runtime::xcm_config::ERC20TransfersCheckingAccount::get(); let initial_wnd_amount = 10_000_000_000_000u128; ExtBuilder::::default().build().execute_with(|| { + // Bring the revive account to life. + assert_ok!(Balances::mint_into(&revive_account, initial_wnd_amount)); // We need to give enough funds for every account involved so they // can call `Revive::map_account`. assert_ok!(Balances::mint_into(&sender, initial_wnd_amount)); @@ -1729,6 +1732,7 @@ fn withdraw_and_deposit_erc20s() { fn non_existent_erc20_will_error() { let sender: AccountId = ALICE.into(); let beneficiary: AccountId = BOB.into(); + let revive_account = pallet_revive::Pallet::::account_id(); let checking_account = asset_hub_westend_runtime::xcm_config::ERC20TransfersCheckingAccount::get(); let initial_wnd_amount = 10_000_000_000_000u128; @@ -1736,6 +1740,8 @@ fn non_existent_erc20_will_error() { let non_existent_contract_address = [1u8; 20]; ExtBuilder::::default().build().execute_with(|| { + // Bring the revive account to life. + assert_ok!(Balances::mint_into(&revive_account, initial_wnd_amount)); // We need to give enough funds for every account involved so they // can call `Revive::map_account`. assert_ok!(Balances::mint_into(&sender, initial_wnd_amount)); @@ -1772,11 +1778,15 @@ fn non_existent_erc20_will_error() { fn smart_contract_not_erc20_will_error() { let sender: AccountId = ALICE.into(); let beneficiary: AccountId = BOB.into(); + let revive_account = pallet_revive::Pallet::::account_id(); let checking_account = asset_hub_westend_runtime::xcm_config::ERC20TransfersCheckingAccount::get(); let initial_wnd_amount = 10_000_000_000_000u128; ExtBuilder::::default().build().execute_with(|| { + // Bring the revive account to life. + assert_ok!(Balances::mint_into(&revive_account, initial_wnd_amount)); + // We need to give enough funds for every account involved so they // can call `Revive::map_account`. assert_ok!(Balances::mint_into(&sender, initial_wnd_amount)); @@ -1822,11 +1832,15 @@ fn smart_contract_not_erc20_will_error() { fn smart_contract_does_not_return_bool_fails() { let sender: AccountId = ALICE.into(); let beneficiary: AccountId = BOB.into(); + let revive_account = pallet_revive::Pallet::::account_id(); let checking_account = asset_hub_westend_runtime::xcm_config::ERC20TransfersCheckingAccount::get(); let initial_wnd_amount = 10_000_000_000_000u128; ExtBuilder::::default().build().execute_with(|| { + // Bring the revive account to life. + assert_ok!(Balances::mint_into(&revive_account, initial_wnd_amount)); + // We need to give enough funds for every account involved so they // can call `Revive::map_account`. assert_ok!(Balances::mint_into(&sender, initial_wnd_amount)); @@ -1875,11 +1889,15 @@ fn smart_contract_does_not_return_bool_fails() { fn expensive_erc20_runs_out_of_gas() { let sender: AccountId = ALICE.into(); let beneficiary: AccountId = BOB.into(); + let revive_account = pallet_revive::Pallet::::account_id(); let checking_account = asset_hub_westend_runtime::xcm_config::ERC20TransfersCheckingAccount::get(); let initial_wnd_amount = 10_000_000_000_000u128; ExtBuilder::::default().build().execute_with(|| { + // Bring the revive account to life. + assert_ok!(Balances::mint_into(&revive_account, initial_wnd_amount)); + // We need to give enough funds for every account involved so they // can call `Revive::map_account`. assert_ok!(Balances::mint_into(&sender, initial_wnd_amount)); diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index ff2f538bb361..ce485a96ba2d 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -853,6 +853,7 @@ impl pallet_revive::Config for Runtime { type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>; type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>; type UnsafeUnstableInterface = ConstBool; + type AllowEVMBytecode = ConstBool; type UploadOrigin = EnsureSigned; type InstantiateOrigin = EnsureSigned; type RuntimeHoldReason = RuntimeHoldReason; diff --git a/prdoc/pr_9285.prdoc b/prdoc/pr_9285.prdoc new file mode 100644 index 000000000000..8e0b4f8cf7b6 --- /dev/null +++ b/prdoc/pr_9285.prdoc @@ -0,0 +1,17 @@ +title: '[revive] revm backend' +doc: +- audience: Runtime Dev + description: | + Initial EVM support for pallet-revive via the REVM crate to create a dual-VM system that can execute both PolkaVM and EVM + - Added AllowEVMBytecode: Get to the config to enable/disable EVM call and instantiation + - The basic flow of uploading an EVM contract and running it should work + - instructions are copied and adapted from REVM they should be ignored in this PR and reviewed in follow-up PR +crates: +- name: pallet-revive + bump: major +- name: pallet-revive-fixtures + bump: patch +- name: asset-hub-westend-runtime + bump: patch +- name: penpal-runtime + bump: patch diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 4ea04b736c02..f03eebeeecc3 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -1490,6 +1490,7 @@ impl pallet_revive::Config for Runtime { type NativeToEthRatio = ConstU32<1_000_000>; // 10^(18 - 12) Eth is 10^18, Native is 10^12. type EthGasEncoder = (); type FindAuthor = ::FindAuthor; + type AllowEVMBytecode = ConstBool; } impl pallet_sudo::Config for Runtime { diff --git a/substrate/frame/revive/fixtures/build.rs b/substrate/frame/revive/fixtures/build.rs index a3030a66afad..f26ca85f5e30 100644 --- a/substrate/frame/revive/fixtures/build.rs +++ b/substrate/frame/revive/fixtures/build.rs @@ -463,7 +463,7 @@ fn generate_fixture_location(temp_dir: &Path, out_dir: &Path, entries: &[Entry]) // Generate sol! macros for Solidity contracts for entry in entries.iter().filter(|e| matches!(e.contract_type, ContractType::Solidity)) { let relative_path = format!("contracts/{}", entry.path().split('/').last().unwrap()); - writeln!(file, r#"alloy_core::sol!("{}");"#, relative_path) + writeln!(file, r#"#[cfg(feature = "std")] alloy_core::sol!("{}");"#, relative_path) .context("Failed to write sol! macro to fixture_location.rs")?; } diff --git a/substrate/frame/revive/fixtures/contracts/Fibonacci.sol b/substrate/frame/revive/fixtures/contracts/Fibonacci.sol new file mode 100644 index 000000000000..edd852e00142 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/Fibonacci.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract Fibonacci { + function fib(uint n) public pure returns (uint) { + if (n <= 1) { + return n; + } + return fib(n - 1) + fib(n - 2); + } +} diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index 8d7fd221ec6c..d07dd0c46043 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -84,6 +84,14 @@ macro_rules! build_runtime( }; ); +/// Get the pallet account and whitelist it for benchmarking. +/// The account is warmed up `on_initialize` so read should not impact the PoV. +fn whitelisted_pallet_account() -> T::AccountId { + let pallet_account = Pallet::::account_id(); + whitelist_account!(pallet_account); + pallet_account +} + #[benchmarks( where BalanceOf: Into + TryFrom, @@ -122,7 +130,7 @@ mod benchmarks { // This benchmarks the overhead of loading a code of size `c` byte from storage and into // the execution engine. // - // `call_with_code_per_byte(c) - call_with_code_per_byte(0)` + // `call_with_pvm_code_per_byte(c) - call_with_pvm_code_per_byte(0)` // // This does **not** include the actual execution for which the gas meter // is responsible. The code used here will just return on call. @@ -131,7 +139,7 @@ mod benchmarks { // is not in the first basic block is never read. We are primarily interested in the // `proof_size` result of this benchmark. #[benchmark(pov_mode = Measured)] - fn call_with_code_per_byte(c: Linear<0, { 100 * 1024 }>) -> Result<(), BenchmarkError> { + fn call_with_pvm_code_per_byte(c: Linear<0, { 100 * 1024 }>) -> Result<(), BenchmarkError> { let instance = Contract::::with_caller(whitelisted_caller(), VmBinaryModule::sized(c), vec![])?; let value = Pallet::::min_balance(); @@ -150,6 +158,29 @@ mod benchmarks { Ok(()) } + // This benchmarks the overhead of loading a code of size `c` byte from storage and into + // the execution engine. + /// This is similar to `call_with_pvm_code_per_byte` but for EVM bytecode. + #[benchmark(pov_mode = Measured)] + fn call_with_evm_code_per_byte(c: Linear<1, { 10 * 1024 }>) -> Result<(), BenchmarkError> { + let instance = + Contract::::with_caller(whitelisted_caller(), VmBinaryModule::evm_sized(c), vec![])?; + let value = Pallet::::min_balance(); + let storage_deposit = default_deposit_limit::(); + + #[extrinsic_call] + call( + RawOrigin::Signed(instance.caller.clone()), + instance.address, + value, + Weight::MAX, + storage_deposit, + vec![], + ); + + Ok(()) + } + // Measure the amount of time it takes to compile a single basic block. // // (basic_block_compilation(1) - basic_block_compilation(0)).ref_time() @@ -159,7 +190,7 @@ mod benchmarks { // we will always charge one max sized block per contract call. // // We ignore the proof size component when using this benchmark as this is already accounted - // for in `call_with_code_per_byte`. + // for in `call_with_pvm_code_per_byte`. #[benchmark(pov_mode = Measured)] fn basic_block_compilation(b: Linear<0, 1>) -> Result<(), BenchmarkError> { let instance = Contract::::with_caller( @@ -192,6 +223,7 @@ mod benchmarks { c: Linear<0, { 100 * 1024 }>, i: Linear<0, { limits::CALLDATA_BYTES }>, ) { + let pallet_account = whitelisted_pallet_account::(); let input = vec![42u8; i as usize]; let salt = [42u8; 32]; let value = Pallet::::min_balance(); @@ -209,9 +241,11 @@ mod benchmarks { let deposit = T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account_id); - // uploading the code reserves some balance in the callers account - let code_deposit = - T::Currency::balance_on_hold(&HoldReason::CodeUploadDepositReserve.into(), &caller); + // uploading the code reserves some balance in the pallet's account + let code_deposit = T::Currency::balance_on_hold( + &HoldReason::CodeUploadDepositReserve.into(), + &pallet_account, + ); let mapping_deposit = T::Currency::balance_on_hold(&HoldReason::AddressMapping.into(), &caller); assert_eq!( @@ -234,6 +268,7 @@ mod benchmarks { i: Linear<0, { limits::CALLDATA_BYTES }>, d: Linear<0, 1>, ) { + let pallet_account = whitelisted_pallet_account::(); let input = vec![42u8; i as usize]; let value = Pallet::::min_balance(); @@ -259,9 +294,11 @@ mod benchmarks { let deposit = T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account_id); - // uploading the code reserves some balance in the callers account - let code_deposit = - T::Currency::balance_on_hold(&HoldReason::CodeUploadDepositReserve.into(), &caller); + // uploading the code reserves some balance in the pallet account + let code_deposit = T::Currency::balance_on_hold( + &HoldReason::CodeUploadDepositReserve.into(), + &pallet_account, + ); let mapping_deposit = T::Currency::balance_on_hold(&HoldReason::AddressMapping.into(), &caller); @@ -284,6 +321,7 @@ mod benchmarks { // `s`: Size of e salt in bytes. #[benchmark(pov_mode = Measured)] fn instantiate(i: Linear<0, { limits::CALLDATA_BYTES }>) -> Result<(), BenchmarkError> { + let pallet_account = whitelisted_pallet_account::(); let input = vec![42u8; i as usize]; let salt = [42u8; 32]; let value = Pallet::::min_balance(); @@ -304,8 +342,10 @@ mod benchmarks { let deposit = T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account_id); - let code_deposit = - T::Currency::balance_on_hold(&HoldReason::CodeUploadDepositReserve.into(), &account_id); + let code_deposit = T::Currency::balance_on_hold( + &HoldReason::CodeUploadDepositReserve.into(), + &pallet_account, + ); let mapping_deposit = T::Currency::balance_on_hold(&HoldReason::AddressMapping.into(), &account_id); // value was removed from the caller @@ -328,9 +368,10 @@ mod benchmarks { // The dummy contract used here does not do this. The costs for the data copy is billed as // part of `seal_call_data_copy`. The costs for invoking a contract of a specific size are not // part of this benchmark because we cannot know the size of the contract when issuing a call - // transaction. See `call_with_code_per_byte` for this. + // transaction. See `call_with_pvm_code_per_byte` for this. #[benchmark(pov_mode = Measured)] fn call() -> Result<(), BenchmarkError> { + let pallet_account = whitelisted_pallet_account::(); let data = vec![42u8; 1024]; let instance = Contract::::with_caller(whitelisted_caller(), VmBinaryModule::dummy(), vec![])?; @@ -346,7 +387,7 @@ mod benchmarks { ); let code_deposit = T::Currency::balance_on_hold( &HoldReason::CodeUploadDepositReserve.into(), - &instance.caller, + &pallet_account, ); let mapping_deposit = T::Currency::balance_on_hold(&HoldReason::AddressMapping.into(), &instance.caller); @@ -369,6 +410,7 @@ mod benchmarks { // `d`: with or without dust value to transfer #[benchmark(pov_mode = Measured)] fn eth_call(d: Linear<0, 1>) -> Result<(), BenchmarkError> { + let pallet_account = whitelisted_pallet_account::(); let data = vec![42u8; 1024]; let instance = Contract::::with_caller(whitelisted_caller(), VmBinaryModule::dummy(), vec![])?; @@ -390,7 +432,7 @@ mod benchmarks { ); let code_deposit = T::Currency::balance_on_hold( &HoldReason::CodeUploadDepositReserve.into(), - &instance.caller, + &pallet_account, ); let mapping_deposit = T::Currency::balance_on_hold(&HoldReason::AddressMapping.into(), &instance.caller); @@ -420,14 +462,15 @@ mod benchmarks { #[benchmark(pov_mode = Measured)] fn upload_code(c: Linear<0, { 100 * 1024 }>) { let caller = whitelisted_caller(); + let pallet_account = whitelisted_pallet_account::(); T::Currency::set_balance(&caller, caller_funding::()); let VmBinaryModule { code, hash, .. } = VmBinaryModule::sized(c); let origin = RawOrigin::Signed(caller.clone()); let storage_deposit = default_deposit_limit::(); #[extrinsic_call] _(origin, code, storage_deposit); - // uploading the code reserves some balance in the callers account - assert!(T::Currency::total_balance_on_hold(&caller) > 0u32.into()); + // uploading the code reserves some balance in the pallet's account + assert!(T::Currency::total_balance_on_hold(&pallet_account) > 0u32.into()); assert!(>::code_exists(&hash)); } @@ -437,6 +480,7 @@ mod benchmarks { #[benchmark(pov_mode = Measured)] fn remove_code() -> Result<(), BenchmarkError> { let caller = whitelisted_caller(); + let pallet_account = whitelisted_pallet_account::(); T::Currency::set_balance(&caller, caller_funding::()); let VmBinaryModule { code, hash, .. } = VmBinaryModule::dummy(); let origin = RawOrigin::Signed(caller.clone()); @@ -444,12 +488,12 @@ mod benchmarks { let uploaded = >::bare_upload_code(origin.clone().into(), code, storage_deposit)?; assert_eq!(uploaded.code_hash, hash); - assert_eq!(uploaded.deposit, T::Currency::total_balance_on_hold(&caller)); + assert_eq!(uploaded.deposit, T::Currency::total_balance_on_hold(&pallet_account)); assert!(>::code_exists(&hash)); #[extrinsic_call] _(origin, hash); // removing the code should have unreserved the deposit - assert_eq!(T::Currency::total_balance_on_hold(&caller), 0u32.into()); + assert_eq!(T::Currency::total_balance_on_hold(&pallet_account), 0u32.into()); assert!(>::code_removed(&hash)); Ok(()) } @@ -1079,11 +1123,21 @@ mod benchmarks { )); } + /// Benchmark the ocst of terminating a contract. + /// + /// `r`: whether the old code will be removed as a result of this operation. (1: yes, 0: no) #[benchmark(pov_mode = Measured)] - fn seal_terminate() -> Result<(), BenchmarkError> { + fn seal_terminate(r: Linear<0, 1>) -> Result<(), BenchmarkError> { + let delete_code = r == 1; let beneficiary = account::("beneficiary", 0, 0); - build_runtime!(runtime, memory: [beneficiary.encode(),]); + build_runtime!(runtime, instance, memory: [beneficiary.encode(),]); + let code_hash = instance.info()?.code_hash; + + // Increment the refcount of the code hash so that it does not get deleted + if !delete_code { + >::increment_refcount(code_hash).unwrap(); + } let result; #[block] @@ -1092,6 +1146,7 @@ mod benchmarks { } assert!(matches!(result, Err(crate::vm::pvm::TrapReason::Termination))); + assert_eq!(PristineCode::::get(code_hash).is_none(), delete_code); Ok(()) } @@ -2208,12 +2263,23 @@ mod benchmarks { assert_eq!(&memory[..20], runtime.ext().ecdsa_to_eth_address(&pub_key_bytes).unwrap()); } + /// Benchmark the cost of setting the code hash of a contract. + /// + /// `r`: whether the old code will be removed as a result of this operation. (1: yes, 0: no) #[benchmark(pov_mode = Measured)] - fn seal_set_code_hash() -> Result<(), BenchmarkError> { - let code_hash = - Contract::::with_index(1, VmBinaryModule::dummy(), vec![])?.info()?.code_hash; + fn seal_set_code_hash(r: Linear<0, 1>) -> Result<(), BenchmarkError> { + let delete_old_code = r == 1; + let code_hash = Contract::::with_index(1, VmBinaryModule::sized(42), vec![])? + .info()? + .code_hash; + + build_runtime!(runtime, instance, memory: [ code_hash.encode(),]); + let old_code_hash = instance.info()?.code_hash; - build_runtime!(runtime, memory: [ code_hash.encode(),]); + // Increment the refcount of the code hash so that it does not get deleted + if !delete_old_code { + >::increment_refcount(old_code_hash).unwrap(); + } let result; #[block] @@ -2222,6 +2288,30 @@ mod benchmarks { } assert_ok!(result); + assert_eq!(PristineCode::::get(old_code_hash).is_none(), delete_old_code); + Ok(()) + } + + /// Benchmark the cost of executing `r` noop (JUMPDEST) instructions. + #[benchmark(pov_mode = Measured)] + fn evm_opcode(r: Linear<0, 10_000>) -> Result<(), BenchmarkError> { + use crate::vm::evm; + use revm::bytecode::Bytecode; + + let module = VmBinaryModule::evm_noop(r); + let inputs = evm::EVMInputs::new(vec![]); + + let code = Bytecode::new_raw(revm::primitives::Bytes::from(module.code.clone())); + let mut setup = CallSetup::::new(module); + let (mut ext, _) = setup.ext(); + + let result; + #[block] + { + result = evm::call(code, &mut ext, inputs); + } + + assert!(result.is_ok()); Ok(()) } @@ -2330,6 +2420,31 @@ mod benchmarks { assert_eq!(meter.consumed(), ::WeightInfo::v1_migration_step() * 2); } + #[benchmark] + fn v2_migration_step() { + use crate::migrations::v2; + let code_hash = H256::from([0; 32]); + let old_code_info = v2::Migration::::create_old_code_info( + whitelisted_caller(), + 1000u32.into(), + 1, + 100, + 0, + ); + v2::Migration::::insert_old_code_info(code_hash, old_code_info.clone()); + let mut meter = WeightMeter::new(); + + #[block] + { + v2::Migration::::step(None, &mut meter).unwrap(); + } + + v2::Migration::::assert_migrated_code_info(code_hash, &old_code_info); + + // uses twice the weight once for migration and then for checking if there is another key. + assert_eq!(meter.consumed(), ::WeightInfo::v2_migration_step() * 2); + } + impl_benchmark_test_suite!( Contracts, crate::tests::ExtBuilder::default().build(), diff --git a/substrate/frame/revive/src/call_builder.rs b/substrate/frame/revive/src/call_builder.rs index 1213dc874d4e..6d6ca9348fdf 100644 --- a/substrate/frame/revive/src/call_builder.rs +++ b/substrate/frame/revive/src/call_builder.rs @@ -416,6 +416,13 @@ impl VmBinaryModule { Self::with_num_instructions(size / 3) } + // Same as [`Self::sized`] but using EVM bytecode. + pub fn evm_sized(size: u32) -> Self { + use revm::bytecode::opcode::STOP; + let code = vec![STOP; size as usize]; + Self::new(code) + } + /// A contract code of specified number of instructions that uses all its bytes for instructions /// but will return immediately. /// @@ -477,4 +484,12 @@ impl VmBinaryModule { let code = polkavm_common::assembler::assemble(&text).unwrap(); Self::new(code) } + + /// An evm contract that executes `size` JUMPDEST instructions. + pub fn evm_noop(size: u32) -> Self { + use revm::bytecode::opcode::JUMPDEST; + + let code = vec![JUMPDEST; size as usize]; + Self::new(code) + } } diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 5aed60859485..f75c1f599e0d 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -20,6 +20,7 @@ use crate::{ api::{GenericTransaction, TransactionSigned}, GasEncoder, }, + vm::pvm::extract_code_and_data, AccountIdOf, AddressMapper, BalanceOf, Config, MomentOf, OnChargeTransactionBalanceOf, Pallet, LOG_TARGET, RUNTIME_PALLETS_ADDR, }; @@ -367,23 +368,22 @@ pub trait EthExtra { .into() } } else { - let blob = match polkavm::ProgramBlob::blob_length(&data) { - Some(blob_len) => - blob_len.try_into().ok().and_then(|blob_len| (data.split_at_checked(blob_len))), - _ => None, - }; - - let Some((code, data)) = blob else { - log::debug!(target: LOG_TARGET, "Failed to extract polkavm code & data"); - return Err(InvalidTransaction::Call); + let (code, data) = if data.starts_with(&polkavm_common::program::BLOB_MAGIC) { + let Some((code, data)) = extract_code_and_data(&data) else { + log::debug!(target: LOG_TARGET, "Failed to extract polkavm code & data"); + return Err(InvalidTransaction::Call); + }; + (code, data) + } else { + (data, Default::default()) }; crate::Call::eth_instantiate_with_code:: { value, gas_limit, storage_deposit_limit, - code: code.to_vec(), - data: data.to_vec(), + code, + data, } .into() }; @@ -678,13 +678,17 @@ mod test { #[test] fn check_instantiate_data() { - let code = b"invalid code".to_vec(); + let code: Vec = polkavm_common::program::BLOB_MAGIC + .into_iter() + .chain(b"invalid code".iter().cloned()) + .collect(); let data = vec![1]; + let builder = UncheckedExtrinsicBuilder::instantiate_with(code.clone(), data.clone()); // Fail because the tx input fail to get the blob length assert_eq!( - builder.mutate_estimate_and_check(Box::new(|tx| tx.input = vec![1, 2, 3].into())), + builder.check(), Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) ); } diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 4cd9c6d93dca..41fe73aee209 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -25,9 +25,9 @@ use crate::{ storage::{self, meter::Diff, AccountIdOrAddress, WriteOutcome}, tracing::if_tracing, transient_storage::TransientStorage, - AccountInfo, AccountInfoOf, BalanceOf, BalanceWithDust, CodeInfo, CodeInfoOf, Config, - ContractInfo, Error, Event, ImmutableData, ImmutableDataOf, Pallet as Contracts, RuntimeCosts, - LOG_TARGET, + AccountInfo, AccountInfoOf, BalanceOf, BalanceWithDust, CodeInfo, CodeInfoOf, CodeRemoved, + Config, ContractInfo, Error, Event, ImmutableData, ImmutableDataOf, Pallet as Contracts, + RuntimeCosts, LOG_TARGET, }; use alloc::vec::Vec; use core::{fmt::Debug, marker::PhantomData, mem}; @@ -203,13 +203,14 @@ pub trait Ext: PrecompileWithInfoExt { /// /// This function will fail if the same contract is present on the contract /// call stack. - fn terminate(&mut self, beneficiary: &H160) -> DispatchResult; + fn terminate(&mut self, beneficiary: &H160) -> Result; /// Returns the code hash of the contract being executed. fn own_code_hash(&mut self) -> &H256; /// Sets new code hash and immutable data for an existing contract. - fn set_code_hash(&mut self, hash: H256) -> DispatchResult; + /// Returns whether the old code was removed as a result of this operation. + fn set_code_hash(&mut self, hash: H256) -> Result; /// Get the length of the immutable data. /// @@ -477,11 +478,6 @@ pub trait Executable: Sized { /// The code hash of the executable. fn code_hash(&self) -> &H256; - - /// Returns true if the executable is a PVM blob. - fn is_pvm(&self) -> bool { - self.code().starts_with(&polkavm_common::program::BLOB_MAGIC) - } } /// The complete call stack of a contract execution. @@ -577,7 +573,7 @@ impl, Env> ExecutableOrPrecompile { fn is_pvm(&self) -> bool { match self { - Self::Executable(e) => e.is_pvm(), + Self::Executable(e) => e.code_info().is_pvm(), _ => false, } } @@ -1132,6 +1128,7 @@ where let do_transaction = || -> ExecResult { let caller = self.caller(); + let skip_transfer = self.skip_transfer; let frame = top_frame_mut!(self); let account_id = &frame.account_id.clone(); @@ -1215,12 +1212,12 @@ where } } - let code_deposit = executable + let mut code_deposit = executable .as_executable() .map(|exec| exec.code_info().deposit()) .unwrap_or_default(); - let output = match executable { + let mut output = match executable { ExecutableOrPrecompile::Executable(executable) => executable.execute(self, entry_point, input_data), ExecutableOrPrecompile::Precompile { instance, .. } => @@ -1248,6 +1245,27 @@ where // Hence we need to delay charging the base deposit after execution. if entry_point == ExportedFunction::Constructor { let contract_info = frame.contract_info(); + // if we are dealing with EVM bytecode + // We upload the new runtime code, and update the code + if !is_pvm { + // Only keep return data for tracing + let data = if crate::tracing::if_tracing(|_| {}).is_none() { + core::mem::replace(&mut output.data, Default::default()) + } else { + output.data.clone() + }; + + let mut module = crate::ContractBlob::::from_evm_runtime_code( + data, + caller.account_id()?.clone(), + )?; + module.store_code(skip_transfer)?; + code_deposit = module.code_info().deposit(); + contract_info.code_hash = *module.code_hash(); + + >::increment_refcount(contract_info.code_hash)?; + } + let deposit = contract_info.update_base_deposit(code_deposit); frame .nested_storage @@ -1645,7 +1663,7 @@ where } } - fn terminate(&mut self, beneficiary: &H160) -> DispatchResult { + fn terminate(&mut self, beneficiary: &H160) -> Result { if self.is_recursive() { return Err(Error::::TerminatedWhileReentrant.into()); } @@ -1661,9 +1679,9 @@ where let account_address = T::AddressMapper::to_address(&frame.account_id); AccountInfoOf::::remove(&account_address); ImmutableDataOf::::remove(&account_address); - >::decrement_refcount(info.code_hash)?; + let removed = >::decrement_refcount(info.code_hash)?; - Ok(()) + Ok(removed) } fn own_code_hash(&mut self) -> &H256 { @@ -1685,7 +1703,7 @@ where /// `self.immutable_data` at the address of the (reverted) contract instantiation. /// /// The `set_code_hash` contract API stays disabled until this change is implemented. - fn set_code_hash(&mut self, hash: H256) -> DispatchResult { + fn set_code_hash(&mut self, hash: H256) -> Result { let frame = top_frame_mut!(self); let info = frame.contract_info(); @@ -1703,8 +1721,8 @@ where frame.nested_storage.charge_deposit(frame.account_id.clone(), deposit); >::increment_refcount(hash)?; - >::decrement_refcount(prev_hash)?; - Ok(()) + let removed = >::decrement_refcount(prev_hash)?; + Ok(removed) } fn immutable_data_len(&mut self) -> u32 { diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index 63b10c60eedd..28505b7815e6 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -23,11 +23,11 @@ use crate::{ precompiles::Diff, storage::{ContractInfo, WriteOutcome}, transient_storage::TransientStorage, - Config, ExecReturnValue, ImmutableData, + CodeRemoved, Config, ExecReturnValue, ImmutableData, }; use alloc::vec::Vec; use core::marker::PhantomData; -use frame_support::{dispatch::DispatchResult, weights::Weight}; +use frame_support::weights::Weight; use sp_core::{H160, H256, U256}; use sp_runtime::DispatchError; @@ -37,6 +37,12 @@ pub struct MockExt { _phantom: PhantomData, } +impl MockExt { + pub fn new() -> Self { + Self { gas_meter: GasMeter::new(Weight::MAX), _phantom: PhantomData } + } +} + impl PrecompileExt for MockExt { type T = T; @@ -233,7 +239,7 @@ impl Ext for MockExt { panic!("MockExt::delegate_call") } - fn terminate(&mut self, _beneficiary: &H160) -> DispatchResult { + fn terminate(&mut self, _beneficiary: &H160) -> Result { panic!("MockExt::terminate") } @@ -241,7 +247,7 @@ impl Ext for MockExt { panic!("MockExt::own_code_hash") } - fn set_code_hash(&mut self, _hash: H256) -> DispatchResult { + fn set_code_hash(&mut self, _hash: H256) -> Result { panic!("MockExt::set_code_hash") } diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index 9b1995e2db7e..9dfb213cbf52 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -176,10 +176,6 @@ impl Executable for MockExecutable { self.code_hash.as_ref() } - fn is_pvm(&self) -> bool { - true - } - fn code_hash(&self) -> &H256 { &self.code_hash } @@ -1276,7 +1272,7 @@ fn instantiation_traps() { #[test] fn termination_from_instantiate_fails() { let terminate_ch = MockLoader::insert(Constructor, |ctx, _| { - ctx.ext.terminate(&ALICE_ADDR)?; + let _ = ctx.ext.terminate(&ALICE_ADDR)?; exec_success() }); diff --git a/substrate/frame/revive/src/gas.rs b/substrate/frame/revive/src/gas.rs index b310dd4a46a1..7f791c7eb567 100644 --- a/substrate/frame/revive/src/gas.rs +++ b/substrate/frame/revive/src/gas.rs @@ -219,6 +219,18 @@ impl GasMeter { Ok(ChargedAmount(amount)) } + /// Charge the specified amount of EVM gas. + /// This is used for basic opcodes (e.g arithmetic, bitwise, ...) that don't have a dedicated + /// benchmark + pub fn charge_evm_gas(&mut self, gas: u64) -> Result<(), DispatchError> { + let base_cost = T::WeightInfo::evm_opcode(1).saturating_sub(T::WeightInfo::evm_opcode(0)); + self.gas_left = self + .gas_left + .checked_sub(&base_cost.saturating_mul(gas)) + .ok_or_else(|| Error::::OutOfGas)?; + Ok(()) + } + /// Adjust a previously charged amount down to its actual amount. /// /// This is when a maximum a priori amount was charged and then should be partially diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 11c69bfdfe9e..192cc7ffcb99 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -54,7 +54,7 @@ use crate::{ meter::Meter as StorageMeter, AccountInfo, AccountType, ContractInfo, DeletionQueueManager, }, tracing::if_tracing, - vm::{CodeInfo, ContractBlob, RuntimeCosts}, + vm::{pvm::extract_code_and_data, CodeInfo, ContractBlob, RuntimeCosts}, }; use alloc::{boxed::Box, format, vec}; use codec::{Codec, Decode, Encode}; @@ -81,7 +81,7 @@ use frame_system::{ use pallet_transaction_payment::OnChargeTransaction; use scale_info::TypeInfo; use sp_runtime::{ - traits::{BadOrigin, Bounded, Convert, Dispatchable, Saturating}, + traits::{Bounded, Convert, Dispatchable, Saturating}, AccountId32, DispatchError, }; @@ -107,7 +107,6 @@ pub use crate::vm::pvm::SyscallDoc; pub type BalanceOf = <::Currency as Inspect<::AccountId>>::Balance; type TrieId = BoundedVec>; -type CodeVec = BoundedVec>; type ImmutableData = BoundedVec>; pub(crate) type OnChargeTransactionBalanceOf = <::OnChargeTransaction as OnChargeTransaction>::Balance; @@ -226,6 +225,10 @@ pub mod pallet { #[pallet::constant] type UnsafeUnstableInterface: Get; + /// Allow EVM bytecode to be uploaded and instantiated. + #[pallet::constant] + type AllowEVMBytecode: Get; + /// Origin allowed to upload code. /// /// By default, it is safe to set this to `EnsureSigned`, allowing anyone to upload contract @@ -337,6 +340,7 @@ pub mod pallet { type DepositPerItem = DepositPerItem; type Time = Self; type UnsafeUnstableInterface = ConstBool; + type AllowEVMBytecode = ConstBool; type UploadOrigin = EnsureSigned; type InstantiateOrigin = EnsureSigned; type WeightInfo = (); @@ -491,8 +495,11 @@ pub mod pallet { } /// A mapping from a contract's code hash to its code. + /// The code's size is bounded by [`crate::limits::BLOB_BYTES`] for PVM and + /// [`revm::primitives::eip170::MAX_CODE_SIZE`] for EVM bytecode. #[pallet::storage] - pub(crate) type PristineCode = StorageMap<_, Identity, H256, CodeVec>; + #[pallet::unbounded] + pub(crate) type PristineCode = StorageMap<_, Identity, H256, Vec>; /// A mapping from a contract's code hash to its code info. #[pallet::storage] @@ -538,6 +545,13 @@ pub mod pallet { #[pallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { fn build(&self) { + if !System::::account_exists(&Pallet::::account_id()) { + let _ = T::Currency::mint_into( + &Pallet::::account_id(), + T::Currency::minimum_balance(), + ); + } + for id in &self.mapped_accounts { if let Err(err) = T::AddressMapper::map(id) { log::error!(target: LOG_TARGET, "Failed to map account {id:?}: {err:?}"); @@ -548,6 +562,11 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { + fn on_initialize(_block: BlockNumberFor) -> Weight { + // Warm up the pallet account. + System::::account_exists(&Pallet::::account_id()); + return T::DbWeight::get().reads(1) + } fn on_idle(_block: BlockNumberFor, limit: Weight) -> Weight { let mut meter = WeightMeter::with_limit(limit); ContractInfo::::process_deletion_queue_batch(&mut meter); @@ -916,8 +935,7 @@ pub mod pallet { /// Upload new `code` without instantiating a contract from it. /// /// If the code does not already exist a deposit is reserved from the caller - /// and unreserved only when [`Self::remove_code`] is called. The size of the reserve - /// depends on the size of the supplied `code`. + /// The size of the reserve depends on the size of the supplied `code`. /// /// # Note /// @@ -925,6 +943,9 @@ pub mod pallet { /// To avoid this situation a constructor could employ access control so that it can /// only be instantiated by permissioned entities. The same is true when uploading /// through [`Self::instantiate_with_code`]. + /// + /// If the refcount of the code reaches zero after terminating the last contract that + /// references this code, the code will be removed automatically. #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::upload_code(code.len() as u32))] pub fn upload_code( @@ -979,7 +1000,7 @@ pub mod pallet { }; >::increment_refcount(code_hash)?; - >::decrement_refcount(contract.code_hash)?; + let _ = >::decrement_refcount(contract.code_hash)?; contract.code_hash = code_hash; Ok(()) @@ -1146,7 +1167,14 @@ where storage_deposit_limit.saturating_reduce(upload_deposit); (executable, upload_deposit) }, - Code::Upload(_code) => return Err(>::CodeRejected.into()), + Code::Upload(code) => + if T::AllowEVMBytecode::get() { + let origin = T::UploadOrigin::ensure_origin(origin)?; + let executable = ContractBlob::from_evm_init_code(code, origin)?; + (executable, Default::default()) + } else { + return Err(>::CodeRejected.into()) + }, Code::Existing(code_hash) => (ContractBlob::from_storage(code_hash, &mut gas_meter)?, Default::default()), }; @@ -1333,19 +1361,9 @@ where None => { // Extract code and data from the input. let (code, data) = if input.starts_with(&polkavm_common::program::BLOB_MAGIC) { - match polkavm::ProgramBlob::blob_length(&input) { - Some(blob_len) => blob_len - .try_into() - .ok() - .and_then(|blob_len| (input.split_at_checked(blob_len))) - .unwrap_or_else(|| (&input[..], &[][..])), - _ => { - log::debug!(target: LOG_TARGET, "Failed to extract polkavm blob length"); - (&input[..], &[][..]) - }, - } + extract_code_and_data(&input).unwrap_or_else(|| (input, Default::default())) } else { - return Err(EthTransactError::Message("Invalid transaction".into())); + (input, vec![]) }; // Dry run the call. @@ -1354,8 +1372,8 @@ where value, gas_limit, storage_deposit_limit, - Code::Upload(code.to_vec()), - data.to_vec(), + Code::Upload(code.clone()), + data.clone(), None, BumpNonce::No, ); @@ -1390,8 +1408,8 @@ where value, gas_limit, storage_deposit_limit, - code: code.to_vec(), - data: data.to_vec(), + code, + data, } .into(); (result, dispatch_call) @@ -1576,6 +1594,13 @@ where } impl Pallet { + /// Pallet account, used to hold funds for contracts upload deposit. + pub fn account_id() -> T::AccountId { + use frame_support::PalletId; + use sp_runtime::traits::AccountIdConversion; + PalletId(*b"py/reviv").into_account_truncating() + } + /// Returns true if the evm value carries dust. fn has_dust(value: U256) -> bool { value % U256::from(::NativeToEthRatio::get()) != U256::zero() diff --git a/substrate/frame/revive/src/limits.rs b/substrate/frame/revive/src/limits.rs index 1a88f73749f1..8fb426446aba 100644 --- a/substrate/frame/revive/src/limits.rs +++ b/substrate/frame/revive/src/limits.rs @@ -82,7 +82,7 @@ pub const IMMUTABLE_BYTES: u32 = 4 * 1024; /// will not be affected by those limits. pub mod code { use super::PAGE_SIZE; - use crate::{CodeVec, Config, Error, LOG_TARGET}; + use crate::{Config, Error, LOG_TARGET}; use alloc::vec::Vec; use sp_runtime::DispatchError; @@ -115,25 +115,25 @@ pub mod code { /// Make sure that the various program parts are within the defined limits. pub fn enforce( - blob: Vec, + pvm_blob: Vec, available_syscalls: &[&[u8]], - ) -> Result { + ) -> Result, DispatchError> { use polkavm::program::ISA64_V1 as ISA; use polkavm_common::program::EstimateInterpreterMemoryUsageArgs; - let len: u64 = blob.len() as u64; - let blob: CodeVec = blob.try_into().map_err(|_| { - log::debug!(target: LOG_TARGET, "contract blob too large: {len} limit: {}", BLOB_BYTES); - >::BlobTooLarge - })?; + let len: u64 = pvm_blob.len() as u64; + if len > crate::limits::code::BLOB_BYTES.into() { + log::debug!(target: LOG_TARGET, "contract blob too large: {len} limit: {BLOB_BYTES}"); + return Err(>::BlobTooLarge.into()) + } #[cfg(feature = "std")] if std::env::var_os("REVIVE_SKIP_VALIDATION").is_some() { log::warn!(target: LOG_TARGET, "Skipping validation because env var REVIVE_SKIP_VALIDATION is set"); - return Ok(blob) + return Ok(pvm_blob) } - let program = polkavm::ProgramBlob::parse(blob.as_slice().into()).map_err(|err| { + let program = polkavm::ProgramBlob::parse(pvm_blob.as_slice().into()).map_err(|err| { log::debug!(target: LOG_TARGET, "failed to parse polkavm blob: {err:?}"); Error::::CodeRejected })?; @@ -242,7 +242,7 @@ pub mod code { return Err(Error::::StaticMemoryTooLarge.into()) } - Ok(blob) + Ok(pvm_blob) } } diff --git a/substrate/frame/revive/src/migrations.rs b/substrate/frame/revive/src/migrations.rs index 694ecfd75d2f..f2c702a3e900 100644 --- a/substrate/frame/revive/src/migrations.rs +++ b/substrate/frame/revive/src/migrations.rs @@ -20,5 +20,8 @@ /// Migrations from the old `ContractInfoOf` to the new `AccountInfoOf` storage pub mod v1; +/// Migrations from the old `CodeInfoOf` to the new `CodeInfoOf` storage +pub mod v2; + /// A unique identifier across all pallets. const PALLET_MIGRATIONS_ID: &[u8; 17] = b"pallet-revive-mbm"; diff --git a/substrate/frame/revive/src/migrations/v2.rs b/substrate/frame/revive/src/migrations/v2.rs new file mode 100644 index 000000000000..803283c6ab34 --- /dev/null +++ b/substrate/frame/revive/src/migrations/v2.rs @@ -0,0 +1,297 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Multi-Block Migration v2 +//! +//! - migrate the old `CodeInfoOf` storage to the new `CodeInfoOf` which add the new `code_type` +//! field. +//! - Unhold the deposit on the owner and transfer it to the pallet account. + +extern crate alloc; +use super::PALLET_MIGRATIONS_ID; +use crate::{vm::BytecodeType, weights::WeightInfo, Config, Pallet, H256, LOG_TARGET}; +use frame_support::{ + migrations::{MigrationId, SteppedMigration, SteppedMigrationError}, + pallet_prelude::PhantomData, + traits::{ + fungible::{Inspect, Mutate, MutateHold}, + tokens::{Fortitude, Precision, Restriction}, + }, + weights::WeightMeter, +}; + +#[cfg(feature = "try-runtime")] +use alloc::{collections::btree_map::BTreeMap, vec::Vec}; + +#[cfg(feature = "try-runtime")] +use frame_support::{sp_runtime::TryRuntimeError, traits::fungible::InspectHold}; + +/// Module containing the old storage items. +mod old { + use super::Config; + use crate::{pallet::Pallet, AccountIdOf, BalanceOf, H256}; + use codec::{Decode, Encode}; + use frame_support::{storage_alias, Identity}; + + #[derive(Clone, Encode, Decode)] + pub struct CodeInfo { + pub owner: AccountIdOf, + #[codec(compact)] + pub deposit: BalanceOf, + #[codec(compact)] + pub refcount: u64, + pub code_len: u32, + pub behaviour_version: u32, + } + + #[storage_alias] + /// The storage item that is being migrated from. + pub type CodeInfoOf = StorageMap, Identity, H256, CodeInfo>; +} + +mod new { + use super::{BytecodeType, Config}; + use crate::{pallet::Pallet, AccountIdOf, BalanceOf, H256}; + use codec::{Decode, Encode}; + use frame_support::{storage_alias, DebugNoBound, Identity}; + + #[derive(PartialEq, Eq, DebugNoBound, Encode, Decode)] + pub struct CodeInfo { + pub owner: AccountIdOf, + #[codec(compact)] + pub deposit: BalanceOf, + #[codec(compact)] + pub refcount: u64, + pub code_len: u32, + pub code_type: BytecodeType, + pub behaviour_version: u32, + } + + #[storage_alias] + /// The storage item that is being migrated to. + pub type CodeInfoOf = StorageMap, Identity, H256, CodeInfo>; +} + +/// Migrates the items of the [`old::CodeInfoOf`] map into [`crate::CodeInfoOf`] by adding the +/// `code_type` field. +pub struct Migration(PhantomData); + +impl SteppedMigration for Migration { + type Cursor = H256; + type Identifier = MigrationId<17>; + + fn id() -> Self::Identifier { + MigrationId { pallet_id: *PALLET_MIGRATIONS_ID, version_from: 1, version_to: 2 } + } + + fn step( + mut cursor: Option, + meter: &mut WeightMeter, + ) -> Result, SteppedMigrationError> { + let required = ::WeightInfo::v2_migration_step(); + if meter.remaining().any_lt(required) { + return Err(SteppedMigrationError::InsufficientWeight { required }); + } + + if !frame_system::Pallet::::account_exists(&Pallet::::account_id()) { + let _ = + T::Currency::mint_into(&Pallet::::account_id(), T::Currency::minimum_balance()); + } + + loop { + if meter.try_consume(required).is_err() { + break; + } + + let mut iter = if let Some(last_key) = cursor { + old::CodeInfoOf::::iter_from(old::CodeInfoOf::::hashed_key_for(last_key)) + } else { + old::CodeInfoOf::::iter() + }; + + if let Some((last_key, value)) = iter.next() { + if let Err(err) = T::Currency::transfer_on_hold( + &crate::HoldReason::CodeUploadDepositReserve.into(), + &value.owner, + &Pallet::::account_id(), + value.deposit, + Precision::Exact, + Restriction::OnHold, + Fortitude::Polite, + ) { + log::error!( + target: LOG_TARGET, + "Failed to unhold the deposit for code hash {last_key:?} and owner {:?}: {err:?}", + value.owner, + ); + } + + new::CodeInfoOf::::insert( + last_key, + new::CodeInfo { + owner: value.owner, + deposit: value.deposit, + refcount: value.refcount, + code_len: value.code_len, + code_type: BytecodeType::Pvm, + behaviour_version: value.behaviour_version, + }, + ); + cursor = Some(last_key) + } else { + cursor = None; + break + } + } + Ok(cursor) + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + use codec::Encode; + + // Return the state of the storage before the migration. + Ok(old::CodeInfoOf::::iter().collect::>().encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(prev: Vec) -> Result<(), TryRuntimeError> { + use codec::Decode; + use sp_runtime::{traits::Zero, Saturating}; + + // Check the state of the storage after the migration. + let prev_map = BTreeMap::>::decode(&mut &prev[..]) + .expect("Failed to decode the previous storage state"); + + // Check the len of prev and post are the same. + assert_eq!( + crate::CodeInfoOf::::iter().count(), + prev_map.len(), + "Migration failed: the number of items in the storage after the migration is not the same as before" + ); + + let deposit_sum: crate::BalanceOf = Zero::zero(); + + for (code_hash, old_code_info) in prev_map { + deposit_sum.saturating_add(old_code_info.deposit); + Self::assert_migrated_code_info(code_hash, &old_code_info); + } + + assert_eq!( + ::Currency::balance_on_hold( + &crate::HoldReason::CodeUploadDepositReserve.into(), + &Pallet::::account_id(), + ), + deposit_sum, + ); + + Ok(()) + } +} + +#[cfg(any(feature = "runtime-benchmarks", feature = "try-runtime", test))] +impl Migration { + /// Insert an old CodeInfo for benchmarking purposes. + pub fn insert_old_code_info(code_hash: H256, code_info: old::CodeInfo) { + old::CodeInfoOf::::insert(code_hash, code_info); + } + + /// Create an old CodeInfo struct for benchmarking. + pub fn create_old_code_info( + owner: crate::AccountIdOf, + deposit: crate::BalanceOf, + refcount: u64, + code_len: u32, + behaviour_version: u32, + ) -> old::CodeInfo { + use frame_support::traits::fungible::Mutate; + T::Currency::mint_into(&owner, Pallet::::min_balance() + deposit) + .expect("Failed to mint into owner account"); + T::Currency::hold(&crate::HoldReason::CodeUploadDepositReserve.into(), &owner, deposit) + .expect("Failed to hold the deposit on the owner account"); + + old::CodeInfo { owner, deposit, refcount, code_len, behaviour_version } + } + + /// Assert that the migrated CodeInfo matches the expected values from the old CodeInfo. + pub fn assert_migrated_code_info(code_hash: H256, old_code_info: &old::CodeInfo) { + use frame_support::traits::fungible::InspectHold; + use sp_runtime::traits::Zero; + let migrated = + new::CodeInfoOf::::get(code_hash).expect("Failed to get migrated CodeInfo"); + + assert!(::Currency::balance_on_hold( + &crate::HoldReason::CodeUploadDepositReserve.into(), + &old_code_info.owner + ) + .is_zero()); + + assert_eq!( + migrated, + new::CodeInfo { + owner: old_code_info.owner.clone(), + deposit: old_code_info.deposit, + refcount: old_code_info.refcount, + code_len: old_code_info.code_len, + behaviour_version: old_code_info.behaviour_version, + code_type: BytecodeType::Pvm, + }, + "Migration failed: deposit mismatch for key {code_hash:?}", + ); + } +} + +#[test] +fn migrate_to_v2() { + use crate::{ + tests::{ExtBuilder, Test}, + AccountIdOf, + }; + use alloc::collections::BTreeMap; + + ExtBuilder::default().genesis_config(None).build().execute_with(|| { + // Store the original values to verify against later + let mut original_values = BTreeMap::new(); + + for i in 0..10u8 { + let code_hash = H256::from([i; 32]); + let old_info = Migration::::create_old_code_info( + AccountIdOf::::from([i; 32]), + (1000u32 + i as u32).into(), + 1 + i as u64, + 100 + i as u32, + i as u32, + ); + + Migration::::insert_old_code_info(code_hash, old_info.clone()); + original_values.insert(code_hash, old_info); + } + + let mut cursor = None; + let mut weight_meter = WeightMeter::new(); + while let Some(new_cursor) = Migration::::step(cursor, &mut weight_meter).unwrap() { + cursor = Some(new_cursor); + } + + assert_eq!(crate::CodeInfoOf::::iter().count(), 10); + + // Verify all values match between old and new with code_type set to PVM + for (code_hash, old_value) in original_values { + Migration::::assert_migrated_code_info(code_hash, &old_value); + } + }) +} diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs index 5bebe36b444e..4690e79d4144 100644 --- a/substrate/frame/revive/src/primitives.rs +++ b/substrate/frame/revive/src/primitives.rs @@ -357,3 +357,12 @@ pub enum BumpNonce { /// Increment the nonce after contract instantiation Yes, } + +/// Indicates whether the code was removed after the last refcount was decremented. +#[must_use = "You must handle whether the code was removed or not."] +pub enum CodeRemoved { + /// The code was not removed. (refcount > 0) + No, + /// The code was removed. (refcount == 0) + Yes, +} diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 9b3a3c10a932..2a3e3e218069 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -18,6 +18,7 @@ mod pallet_dummy; mod precompiles; mod pvm; +mod sol; use crate::{ self as pallet_revive, test_utils::*, AccountId32Mapper, BalanceOf, BalanceWithDust, @@ -212,6 +213,10 @@ impl Test { pub fn set_unstable_interface(unstable_interface: bool) { UNSTABLE_INTERFACE.with(|v| *v.borrow_mut() = unstable_interface); } + + pub fn set_allow_evm_bytecode(allow_evm_bytecode: bool) { + ALLOW_EVM_BYTECODE.with(|v| *v.borrow_mut() = allow_evm_bytecode); + } } parameter_types! { @@ -320,6 +325,7 @@ where } parameter_types! { pub static UnstableInterface: bool = true; + pub static AllowEvmBytecode: bool = true; pub CheckingAccount: AccountId32 = BOB.clone(); } @@ -340,6 +346,7 @@ impl Config for Test { type DepositPerByte = DepositPerByte; type DepositPerItem = DepositPerItem; type UnsafeUnstableInterface = UnstableInterface; + type AllowEVMBytecode = AllowEvmBytecode; type UploadOrigin = EnsureAccount; type InstantiateOrigin = EnsureAccount; type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent; @@ -363,6 +370,7 @@ pub struct ExtBuilder { existential_deposit: u64, storage_version: Option, code_hashes: Vec, + genesis_config: Option>, } impl Default for ExtBuilder { @@ -371,11 +379,17 @@ impl Default for ExtBuilder { existential_deposit: ExistentialDeposit::get(), storage_version: None, code_hashes: vec![], + genesis_config: Some(crate::GenesisConfig::::default()), } } } impl ExtBuilder { + /// The pallet genesis config to use, or None if you don't want to include it. + pub fn genesis_config(mut self, config: Option>) -> Self { + self.genesis_config = config; + self + } pub fn existential_deposit(mut self, existential_deposit: u64) -> Self { self.existential_deposit = existential_deposit; self @@ -400,7 +414,9 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); - crate::GenesisConfig::::default().assimilate_storage(&mut t).unwrap(); + if let Some(genesis_config) = self.genesis_config { + genesis_config.assimilate_storage(&mut t).unwrap(); + } let mut ext = sp_io::TestExternalities::new(t); ext.register_extension(KeystoreExt::new(MemoryKeystore::new())); ext.execute_with(|| { diff --git a/substrate/frame/revive/src/tests/pvm.rs b/substrate/frame/revive/src/tests/pvm.rs index 81aab74f72f2..c21dfe3ad02a 100644 --- a/substrate/frame/revive/src/tests/pvm.rs +++ b/substrate/frame/revive/src/tests/pvm.rs @@ -46,7 +46,7 @@ use frame_support::{ assert_err, assert_err_ignore_postinfo, assert_noop, assert_ok, storage::child, traits::{ - fungible::{BalancedHold, Inspect, Mutate, MutateHold}, + fungible::{BalancedHold, Inspect, Mutate}, tokens::Preservation, OnIdle, OnInitialize, }, @@ -490,8 +490,12 @@ fn instantiate_unique_trie_id() { ExtBuilder::default().existential_deposit(500).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); - Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, deposit_limit::()) - .unwrap(); + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + binary.clone(), + deposit_limit::(), + ) + .unwrap(); // Instantiate the contract and store its trie id for later comparison. let Contract { addr, .. } = @@ -508,6 +512,8 @@ fn instantiate_unique_trie_id() { assert_ok!(builder::call(addr).build()); // Re-Instantiate after termination. + Contracts::upload_code(RuntimeOrigin::signed(ALICE), binary, deposit_limit::()) + .unwrap(); assert_ok!(builder::instantiate(code_hash).build()); // Trie ids shouldn't match or we might have a collision @@ -722,7 +728,7 @@ fn deploy_and_call_other_contract() { ), source: ALICE, dest: callee_account.clone(), - transferred: 555, + transferred: 556, }), topics: vec![], }, @@ -1000,6 +1006,7 @@ fn self_destruct_works() { .build_and_unwrap_contract(); let hold_balance = contract_base_deposit(&contract.addr); + let upload_deposit = get_code_deposit(&code_hash); // Check that the BOB contract has been instantiated. let _ = get_contract(&contract.addr); @@ -1010,8 +1017,8 @@ fn self_destruct_works() { // Call BOB without input data which triggers termination. assert_matches!(builder::call(contract.addr).build(), Ok(_)); - // Check that code is still there but refcount dropped to zero. - assert_refcount!(&code_hash, 0); + // Check that the code is gone + assert!(PristineCode::::get(&code_hash).is_none()); // Check that account is gone assert!(get_contract_checked(&contract.addr).is_none()); @@ -1033,6 +1040,18 @@ fn self_destruct_works() { pretty_assertions::assert_eq!( System::events(), vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::TransferOnHold { + reason: ::RuntimeHoldReason::Contracts( + HoldReason::CodeUploadDepositReserve, + ), + source: Pallet::::account_id(), + dest: ALICE, + amount: upload_deposit, + }), + topics: vec![], + }, EventRecord { phase: Phase::Initialization, event: RuntimeEvent::Balances(pallet_balances::Event::TransferOnHold { @@ -1711,10 +1730,7 @@ fn refcounter() { // remove the last contract assert_ok!(builder::call(addr2).build()); - assert_refcount!(code_hash, 0); - - // refcount is `0` but code should still exists because it needs to be removed manually - assert!(crate::PristineCode::::contains_key(&code_hash)); + assert!(PristineCode::::get(&code_hash).is_none()); }); } @@ -1951,7 +1967,6 @@ fn remove_code_works() { assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash)); }); } - #[test] fn remove_code_wrong_origin() { let (binary, code_hash) = compile_module("dummy").unwrap(); @@ -2042,12 +2057,13 @@ fn instantiate_with_zero_balance_works() { vec![ EventRecord { phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Held { + event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { + source: ALICE, + dest: Pallet::::account_id(), + transferred: 777, reason: ::RuntimeHoldReason::Contracts( HoldReason::CodeUploadDepositReserve, ), - who: ALICE, - amount: 776, }), topics: vec![], }, @@ -2091,7 +2107,7 @@ fn instantiate_with_zero_balance_works() { ), source: ALICE, dest: account_id, - transferred: 336, + transferred: 337, }), topics: vec![], }, @@ -2130,12 +2146,13 @@ fn instantiate_with_below_existential_deposit_works() { vec![ EventRecord { phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Held { + event: RuntimeEvent::Balances(pallet_balances::Event::TransferAndHold { + source: ALICE, + dest: Pallet::::account_id(), + transferred: 777, reason: ::RuntimeHoldReason::Contracts( HoldReason::CodeUploadDepositReserve, ), - who: ALICE, - amount: 776, }), topics: vec![], }, @@ -2188,7 +2205,7 @@ fn instantiate_with_below_existential_deposit_works() { ), source: ALICE, dest: account_id.clone(), - transferred: 336, + transferred: 337, }), topics: vec![], }, @@ -2367,7 +2384,7 @@ fn set_code_extrinsic() { // successful call assert_ok!(Contracts::set_code(RuntimeOrigin::root(), addr, new_code_hash)); assert_eq!(get_contract(&addr).code_hash, new_code_hash); - assert_refcount!(&code_hash, 0); + assert!(PristineCode::::get(&code_hash).is_none()); assert_refcount!(&new_code_hash, 1); }); } @@ -2770,10 +2787,9 @@ fn deposit_limit_in_nested_instantiate() { fn deposit_limit_honors_liquidity_restrictions() { let (binary, _code_hash) = compile_module("store_call").unwrap(); ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let bobs_balance = 1_000; - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let _ = ::Currency::set_balance(&BOB, bobs_balance); let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let _ = ::Currency::set_balance(&BOB, min_balance); // Instantiate the BOB contract. let Contract { addr, account_id } = @@ -2787,13 +2803,6 @@ fn deposit_limit_honors_liquidity_restrictions() { info_deposit + min_balance ); - // check that the hold is honored - ::Currency::hold( - &HoldReason::CodeUploadDepositReserve.into(), - &BOB, - bobs_balance - min_balance, - ) - .unwrap(); assert_err_ignore_postinfo!( builder::call(addr) .origin(RuntimeOrigin::signed(BOB)) @@ -2802,7 +2811,6 @@ fn deposit_limit_honors_liquidity_restrictions() { .build(), >::StorageDepositNotEnoughFunds, ); - assert_eq!(::Currency::free_balance(&BOB), min_balance); }); } @@ -2893,7 +2901,7 @@ fn native_dependency_deposit_works() { .build_and_unwrap_result(); // Check updated storage_deposit due to code size changes - let deposit_diff = lockup_deposit_percent.mul_ceil(get_code_deposit(&code_hash)) - + let deposit_diff = lockup_deposit_percent.mul_ceil(upload_deposit) - lockup_deposit_percent.mul_ceil(get_code_deposit(&dummy_code_hash)); let new_base_deposit = contract_base_deposit(&addr); assert_ne!(deposit_diff, 0); diff --git a/substrate/frame/revive/src/tests/sol.rs b/substrate/frame/revive/src/tests/sol.rs new file mode 100644 index 000000000000..5fe1f578fdf3 --- /dev/null +++ b/substrate/frame/revive/src/tests/sol.rs @@ -0,0 +1,131 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{ + assert_refcount, + test_utils::{builder::Contract, ALICE}, + tests::{ + builder, + test_utils::{contract_base_deposit, ensure_stored, get_contract}, + ExtBuilder, Test, + }, + Code, Config, PristineCode, +}; +use alloy_core::{primitives::U256, sol_types::SolInterface}; +use frame_support::traits::fungible::Mutate; +use pallet_revive_fixtures::{compile_module_with_type, Fibonacci, FixtureType}; +use pretty_assertions::assert_eq; + +#[test] +fn basic_evm_flow_works() { + let (code, init_hash) = compile_module_with_type("Fibonacci", FixtureType::Solc).unwrap(); + + ExtBuilder::default().build().execute_with(|| { + for i in 1u8..=2 { + let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code.clone())) + .salt(Some([i; 32])) + .build_and_unwrap_contract(); + + // check the code exists + let contract = get_contract(&addr); + ensure_stored(contract.code_hash); + let deposit = contract_base_deposit(&addr); + assert_eq!(contract.total_deposit(), deposit); + assert_refcount!(contract.code_hash, i as u64); + + let result = builder::bare_call(addr) + .data( + Fibonacci::FibonacciCalls::fib(Fibonacci::fibCall { n: U256::from(10u64) }) + .abi_encode(), + ) + .build_and_unwrap_result(); + assert_eq!( + U256::from(55u32), + U256::from_be_bytes::<32>(result.data.try_into().unwrap()) + ); + } + + // init code is not stored + assert!(!PristineCode::::contains_key(init_hash)); + }); +} + +#[test] +fn basic_evm_flow_tracing_works() { + use crate::{ + evm::{CallTrace, CallTracer, CallType}, + test_utils::ALICE_ADDR, + tracing::trace, + }; + let (code, _) = compile_module_with_type("Fibonacci", FixtureType::Solc).unwrap(); + + ExtBuilder::default().build().execute_with(|| { + let mut tracer = CallTracer::new(Default::default(), |_| crate::U256::zero()); + let _ = ::Currency::set_balance(&ALICE, 100_000_000_000); + + let Contract { addr, .. } = trace(&mut tracer, || { + builder::bare_instantiate(Code::Upload(code.clone())).build_and_unwrap_contract() + }); + + let contract = get_contract(&addr); + let runtime_code = PristineCode::::get(contract.code_hash).unwrap(); + + assert_eq!( + tracer.collect_trace().unwrap(), + CallTrace { + from: ALICE_ADDR, + call_type: CallType::Create2, + to: addr, + input: code.into(), + output: runtime_code.into(), + value: Some(crate::U256::zero()), + ..Default::default() + } + ); + + let mut call_tracer = CallTracer::new(Default::default(), |_| crate::U256::zero()); + let result = trace(&mut call_tracer, || { + builder::bare_call(addr) + .data( + Fibonacci::FibonacciCalls::fib(Fibonacci::fibCall { n: U256::from(10u64) }) + .abi_encode(), + ) + .build_and_unwrap_result() + }); + + assert_eq!( + U256::from(55u32), + U256::from_be_bytes::<32>(result.data.clone().try_into().unwrap()) + ); + + assert_eq!( + call_tracer.collect_trace().unwrap(), + CallTrace { + call_type: CallType::Call, + from: ALICE_ADDR, + to: addr, + input: Fibonacci::FibonacciCalls::fib(Fibonacci::fibCall { n: U256::from(10u64) }) + .abi_encode() + .into(), + output: result.data.into(), + value: Some(crate::U256::zero()), + ..Default::default() + }, + ); + }); +} diff --git a/substrate/frame/revive/src/tracing.rs b/substrate/frame/revive/src/tracing.rs index 3be2717c8f45..1641ad1e33e6 100644 --- a/substrate/frame/revive/src/tracing.rs +++ b/substrate/frame/revive/src/tracing.rs @@ -36,8 +36,8 @@ pub fn trace R>(tracer: &mut (dyn Tracing + 'static), f: F) -> /// /// This is safe to be called from on-chain code as tracing will never be activated /// there. Hence the closure is not executed in this case. -pub(crate) fn if_tracing(f: F) { - tracer::with(f); +pub(crate) fn if_tracing R>(f: F) -> Option { + tracer::with(f) } /// Defines methods to trace contract interactions. diff --git a/substrate/frame/revive/src/vm/evm.rs b/substrate/frame/revive/src/vm/evm.rs new file mode 100644 index 000000000000..52ec7b296b2c --- /dev/null +++ b/substrate/frame/revive/src/vm/evm.rs @@ -0,0 +1,225 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod instructions; + +use crate::{ + vm::{BytecodeType, ExecResult, Ext}, + AccountIdOf, CodeInfo, Config, ContractBlob, DispatchError, Error, ExecReturnValue, H256, + LOG_TARGET, +}; +use alloc::vec::Vec; +use instructions::instruction_table; +use pallet_revive_uapi::ReturnFlags; +use revm::{ + bytecode::Bytecode, + interpreter::{ + host::DummyHost, + interpreter::{ExtBytecode, ReturnDataImpl, RuntimeFlags}, + interpreter_action::InterpreterAction, + interpreter_types::InputsTr, + CallInput, Gas, Interpreter, InterpreterResult, InterpreterTypes, SharedMemory, Stack, + }, + primitives::{self, hardfork::SpecId, Address, Bytes}, +}; + +impl ContractBlob { + /// Create a new contract from EVM init code. + pub fn from_evm_init_code(code: Vec, owner: AccountIdOf) -> Result { + if code.len() > revm::primitives::eip3860::MAX_INITCODE_SIZE { + return Err(>::BlobTooLarge.into()); + } + + let code_len = code.len() as u32; + let code_info = CodeInfo { + owner, + deposit: Default::default(), + refcount: 0, + code_len, + code_type: BytecodeType::Evm, + behaviour_version: Default::default(), + }; + + Bytecode::new_raw_checked(Bytes::from(code.to_vec())).map_err(|err| { + log::debug!(target: LOG_TARGET, "failed to create evm bytecode from init code: {err:?}" ); + >::CodeRejected + })?; + + // Code hash is not relevant for init code, since it is not stored on-chain. + let code_hash = H256::default(); + Ok(ContractBlob { code, code_info, code_hash }) + } + + /// Create a new contract from EVM runtime code. + pub fn from_evm_runtime_code( + code: Vec, + owner: AccountIdOf, + ) -> Result { + if code.len() > revm::primitives::eip170::MAX_CODE_SIZE { + return Err(>::BlobTooLarge.into()); + } + + let code_len = code.len() as u32; + let deposit = super::calculate_code_deposit::(code_len); + + let code_info = CodeInfo { + owner, + deposit, + refcount: 0, + code_len, + code_type: BytecodeType::Evm, + behaviour_version: Default::default(), + }; + + Bytecode::new_raw_checked(Bytes::from(code.to_vec())).map_err(|err| { + log::debug!(target: LOG_TARGET, "failed to create evm bytecode from code: {err:?}" ); + >::CodeRejected + })?; + + let code_hash = H256(sp_io::hashing::keccak_256(&code)); + Ok(ContractBlob { code, code_info, code_hash }) + } +} + +/// Calls the EVM interpreter with the provided bytecode and inputs. +pub fn call<'a, E: Ext>(bytecode: Bytecode, ext: &'a mut E, inputs: EVMInputs) -> ExecResult { + let mut interpreter: Interpreter> = Interpreter { + gas: Gas::default(), + bytecode: ExtBytecode::new(bytecode), + stack: Stack::new(), + return_data: Default::default(), + memory: SharedMemory::new(), + input: inputs, + runtime_flag: RuntimeFlags { is_static: false, spec_id: SpecId::default() }, + extend: ext, + }; + + let table = instruction_table::<'a, E>(); + let result = run(&mut interpreter, &table); + + if result.is_error() { + Err(Error::::ContractTrapped.into()) + } else { + Ok(ExecReturnValue { + flags: if result.is_revert() { ReturnFlags::REVERT } else { ReturnFlags::empty() }, + data: result.output.to_vec(), + }) + } +} + +/// Runs the EVM interpreter +fn run( + interpreter: &mut Interpreter, + table: &revm::interpreter::InstructionTable, +) -> InterpreterResult { + let host = &mut DummyHost {}; + let action = interpreter.run_plain(table, host); + match action { + InterpreterAction::Return(result) => return result, + InterpreterAction::NewFrame(_) => { + // TODO handle new frame + InterpreterResult::new( + revm::interpreter::InstructionResult::FatalExternalError, + Default::default(), + interpreter.gas, + ) + }, + } +} + +/// EVMInterpreter implements the `InterpreterTypes`. +/// +/// Note: +/// +/// Our implementation set the `InterpreterTypes::Extend` associated type, to the `Ext` trait, to +/// reuse all the host functions that are defined by this trait +pub struct EVMInterpreter<'a, E: Ext> { + _phantom: core::marker::PhantomData<&'a E>, +} + +impl<'a, E: Ext> InterpreterTypes for EVMInterpreter<'a, E> { + type Stack = Stack; + type Memory = SharedMemory; + type Bytecode = ExtBytecode; + type ReturnData = ReturnDataImpl; + type Input = EVMInputs; + type RuntimeFlag = RuntimeFlags; + type Extend = &'a mut E; + type Output = InterpreterAction; +} + +/// EVMInputs implements the `InputsTr` trait for EVM inputs, allowing the EVM interpreter to access +/// the call input data. +/// +/// Note: +/// +/// In our implementation of the instruction table, Everything except the call input data will be +/// accessed through the `InterpreterTypes::Extend` associated type, our implementation will panic +/// if any of those methods are called. +#[derive(Debug, Clone, Default)] +pub struct EVMInputs(CallInput); + +impl EVMInputs { + pub fn new(input: Vec) -> Self { + Self(CallInput::Bytes(input.into())) + } +} + +impl InputsTr for EVMInputs { + fn target_address(&self) -> Address { + panic!() + } + + fn caller_address(&self) -> Address { + panic!() + } + + fn bytecode_address(&self) -> Option<&Address> { + panic!() + } + + fn input(&self) -> &CallInput { + &self.0 + } + + fn call_value(&self) -> primitives::U256 { + // TODO replae by panic once instruction that use call_value are updated + primitives::U256::ZERO + } +} + +/// Blanket conversion trait between `sp_core::U256` and `revm::primitives::U256` +#[allow(dead_code)] +pub trait U256Converter { + /// Convert `self` into `revm::primitives::U256` + fn into_revm_u256(&self) -> revm::primitives::U256; + + /// Convert from `revm::primitives::U256` into `Self` + fn from_revm_u256(value: &revm::primitives::U256) -> Self; +} + +impl U256Converter for sp_core::U256 { + fn into_revm_u256(&self) -> revm::primitives::U256 { + let bytes = self.to_big_endian(); + revm::primitives::U256::from_be_bytes(bytes) + } + + fn from_revm_u256(value: &revm::primitives::U256) -> Self { + let bytes = value.to_be_bytes::<32>(); + sp_core::U256::from_big_endian(&bytes) + } +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/arithmetic.rs b/substrate/frame/revive/src/vm/evm/instructions/arithmetic.rs new file mode 100644 index 000000000000..6aa47e2bae86 --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/arithmetic.rs @@ -0,0 +1,156 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::{ + i256::{i256_div, i256_mod}, + Context, +}; +use crate::vm::Ext; +use revm::{ + interpreter::{ + gas as revm_gas, + interpreter_types::{RuntimeFlag, StackTr}, + }, + primitives::U256, +}; + +/// Implements the ADD instruction - adds two values from stack. +pub fn add<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + *op2 = op1.wrapping_add(*op2); +} + +/// Implements the MUL instruction - multiplies two values from stack. +pub fn mul<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::LOW); + popn_top!([op1], op2, context.interpreter); + *op2 = op1.wrapping_mul(*op2); +} + +/// Implements the SUB instruction - subtracts two values from stack. +pub fn sub<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + *op2 = op1.wrapping_sub(*op2); +} + +/// Implements the DIV instruction - divides two values from stack. +pub fn div<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::LOW); + popn_top!([op1], op2, context.interpreter); + if !op2.is_zero() { + *op2 = op1.wrapping_div(*op2); + } +} + +/// Implements the SDIV instruction. +/// +/// Performs signed division of two values from stack. +pub fn sdiv<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::LOW); + popn_top!([op1], op2, context.interpreter); + *op2 = i256_div(op1, *op2); +} + +/// Implements the MOD instruction. +/// +/// Pops two values from stack and pushes the remainder of their division. +pub fn rem<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::LOW); + popn_top!([op1], op2, context.interpreter); + if !op2.is_zero() { + *op2 = op1.wrapping_rem(*op2); + } +} + +/// Implements the SMOD instruction. +/// +/// Performs signed modulo of two values from stack. +pub fn smod<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::LOW); + popn_top!([op1], op2, context.interpreter); + *op2 = i256_mod(op1, *op2) +} + +/// Implements the ADDMOD instruction. +/// +/// Pops three values from stack and pushes (a + b) % n. +pub fn addmod<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::MID); + popn_top!([op1, op2], op3, context.interpreter); + *op3 = op1.add_mod(op2, *op3) +} + +/// Implements the MULMOD instruction. +/// +/// Pops three values from stack and pushes (a * b) % n. +pub fn mulmod<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::MID); + popn_top!([op1, op2], op3, context.interpreter); + *op3 = op1.mul_mod(op2, *op3) +} + +/// Implements the EXP instruction - exponentiates two values from stack. +pub fn exp<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + let spec_id = context.interpreter.runtime_flag.spec_id(); + popn_top!([op1], op2, context.interpreter); + gas_or_fail!(context.interpreter, revm_gas::exp_cost(spec_id, *op2)); + *op2 = op1.pow(*op2); +} + +/// Implements the `SIGNEXTEND` opcode as defined in the Ethereum Yellow Paper. +/// +/// In the yellow paper `SIGNEXTEND` is defined to take two inputs, we will call them +/// `x` and `y`, and produce one output. +/// +/// The first `t` bits of the output (numbering from the left, starting from 0) are +/// equal to the `t`-th bit of `y`, where `t` is equal to `256 - 8(x + 1)`. +/// +/// The remaining bits of the output are equal to the corresponding bits of `y`. +/// +/// **Note**: If `x >= 32` then the output is equal to `y` since `t <= 0`. +/// +/// To efficiently implement this algorithm in the case `x < 32` we do the following. +/// +/// Let `b` be equal to the `t`-th bit of `y` and let `s = 255 - t = 8x + 7` +/// (this is effectively the same index as `t`, but numbering the bits from the +/// right instead of the left). +/// +/// We can create a bit mask which is all zeros up to and including the `t`-th bit, +/// and all ones afterwards by computing the quantity `2^s - 1`. +/// +/// We can use this mask to compute the output depending on the value of `b`. +/// +/// If `b == 1` then the yellow paper says the output should be all ones up to +/// and including the `t`-th bit, followed by the remaining bits of `y`; this is equal to +/// `y | !mask` where `|` is the bitwise `OR` and `!` is bitwise negation. +/// +/// Similarly, if `b == 0` then the yellow paper says the output should start with all zeros, +/// then end with bits from `b`; this is equal to `y & mask` where `&` is bitwise `AND`. +pub fn signextend<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::LOW); + popn_top!([ext], x, context.interpreter); + // For 31 we also don't need to do anything. + if ext < U256::from(31) { + let ext = ext.as_limbs()[0]; + let bit_index = (8 * ext + 7) as usize; + let bit = x.bit(bit_index); + let mask = (U256::from(1) << bit_index) - U256::from(1); + *x = if bit { *x | !mask } else { *x & mask }; + } +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/bitwise.rs b/substrate/frame/revive/src/vm/evm/instructions/bitwise.rs new file mode 100644 index 000000000000..87a2ec4d4967 --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/bitwise.rs @@ -0,0 +1,572 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::{i256::i256_cmp, Context}; +use crate::vm::Ext; +use core::cmp::Ordering; +use revm::{ + interpreter::{ + gas as revm_gas, + interpreter_types::{RuntimeFlag, StackTr}, + }, + primitives::U256, +}; + +/// Implements the LT instruction - less than comparison. +pub fn lt<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + *op2 = U256::from(op1 < *op2); +} + +/// Implements the GT instruction - greater than comparison. +pub fn gt<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + + *op2 = U256::from(op1 > *op2); +} + +/// Implements the CLZ instruction - count leading zeros. +pub fn clz<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, OSAKA); + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([], op1, context.interpreter); + + let leading_zeros = op1.leading_zeros(); + *op1 = U256::from(leading_zeros); +} + +/// Implements the SLT instruction. +/// +/// Signed less than comparison of two values from stack. +pub fn slt<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + + *op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Less); +} + +/// Implements the SGT instruction. +/// +/// Signed greater than comparison of two values from stack. +pub fn sgt<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + + *op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Greater); +} + +/// Implements the EQ instruction. +/// +/// Equality comparison of two values from stack. +pub fn eq<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + + *op2 = U256::from(op1 == *op2); +} + +/// Implements the ISZERO instruction. +/// +/// Checks if the top stack value is zero. +pub fn iszero<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([], op1, context.interpreter); + *op1 = U256::from(op1.is_zero()); +} + +/// Implements the AND instruction. +/// +/// Bitwise AND of two values from stack. +pub fn bitand<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + *op2 = op1 & *op2; +} + +/// Implements the OR instruction. +/// +/// Bitwise OR of two values from stack. +pub fn bitor<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + + *op2 = op1 | *op2; +} + +/// Implements the XOR instruction. +/// +/// Bitwise XOR of two values from stack. +pub fn bitxor<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + + *op2 = op1 ^ *op2; +} + +/// Implements the NOT instruction. +/// +/// Bitwise NOT (negation) of the top stack value. +pub fn not<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([], op1, context.interpreter); + + *op1 = !*op1; +} + +/// Implements the BYTE instruction. +/// +/// Extracts a single byte from a word at a given index. +pub fn byte<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + + let o1 = as_usize_saturated!(op1); + *op2 = if o1 < 32 { + // `31 - o1` because `byte` returns LE, while we want BE + U256::from(op2.byte(31 - o1)) + } else { + U256::ZERO + }; +} + +/// EIP-145: Bitwise shifting instructions in EVM +pub fn shl<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, CONSTANTINOPLE); + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + + let shift = as_usize_saturated!(op1); + *op2 = if shift < 256 { *op2 << shift } else { U256::ZERO } +} + +/// EIP-145: Bitwise shifting instructions in EVM +pub fn shr<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, CONSTANTINOPLE); + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + + let shift = as_usize_saturated!(op1); + *op2 = if shift < 256 { *op2 >> shift } else { U256::ZERO } +} + +/// EIP-145: Bitwise shifting instructions in EVM +pub fn sar<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, CONSTANTINOPLE); + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([op1], op2, context.interpreter); + + let shift = as_usize_saturated!(op1); + *op2 = if shift < 256 { + op2.arithmetic_shr(shift) + } else if op2.bit(255) { + U256::MAX + } else { + U256::ZERO + }; +} + +#[cfg(test)] +mod tests { + use super::{byte, clz, sar, shl, shr}; + use revm::{ + interpreter::{host::DummyHost, InstructionContext}, + primitives::{hardfork::SpecId, uint, U256}, + }; + + pub fn test_interpreter() -> revm::interpreter::Interpreter< + crate::vm::evm::EVMInterpreter<'static, crate::exec::mock_ext::MockExt>, + > { + use crate::tests::Test; + use revm::{ + interpreter::{ + interpreter::{RuntimeFlags, SharedMemory}, + Interpreter, Stack, + }, + primitives::hardfork::SpecId, + }; + + let mock_ext = Box::leak(Box::new(crate::exec::mock_ext::MockExt::::new())); + + Interpreter { + gas: revm::interpreter::Gas::new(0), + bytecode: Default::default(), + stack: Stack::new(), + return_data: Default::default(), + memory: SharedMemory::new(), + input: crate::vm::evm::EVMInputs::default(), + runtime_flag: RuntimeFlags { is_static: false, spec_id: SpecId::default() }, + extend: mock_ext, + } + } + + #[test] + fn test_shift_left() { + let mut interpreter = test_interpreter(); + + struct TestCase { + value: U256, + shift: U256, + expected: U256, + } + + uint! { + let test_cases = [ + TestCase { + value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + shift: 0x00_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + }, + TestCase { + value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + shift: 0x01_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000002_U256, + }, + TestCase { + value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + shift: 0xff_U256, + expected: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + shift: 0x0100_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + shift: 0x0101_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0x00_U256, + expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0x01_U256, + expected: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe_U256, + }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0xff_U256, + expected: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0x0100_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + shift: 0x01_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0x01_U256, + expected: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe_U256, + }, + ]; + } + + for test in test_cases { + push!(interpreter, test.value); + push!(interpreter, test.shift); + let context = + InstructionContext { host: &mut DummyHost, interpreter: &mut interpreter }; + shl(context); + let res = interpreter.stack.pop().unwrap(); + assert_eq!(res, test.expected); + } + } + + #[test] + fn test_logical_shift_right() { + let mut interpreter = test_interpreter(); + + struct TestCase { + value: U256, + shift: U256, + expected: U256, + } + + uint! { + let test_cases = [ + TestCase { + value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + shift: 0x00_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + }, + TestCase { + value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + shift: 0x01_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, + shift: 0x01_U256, + expected: 0x4000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, + shift: 0xff_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + }, + TestCase { + value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, + shift: 0x0100_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, + shift: 0x0101_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0x00_U256, + expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0x01_U256, + expected: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0xff_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0x0100_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + shift: 0x01_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + }, + ]; + } + + for test in test_cases { + push!(interpreter, test.value); + push!(interpreter, test.shift); + let context = + InstructionContext { host: &mut DummyHost, interpreter: &mut interpreter }; + shr(context); + let res = interpreter.stack.pop().unwrap(); + assert_eq!(res, test.expected); + } + } + + #[test] + fn test_arithmetic_shift_right() { + let mut interpreter = test_interpreter(); + + struct TestCase { + value: U256, + shift: U256, + expected: U256, + } + + uint! { + let test_cases = [ + TestCase { + value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + shift: 0x00_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + }, + TestCase { + value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + shift: 0x01_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, + shift: 0x01_U256, + expected: 0xc000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, + shift: 0xff_U256, + expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + }, + TestCase { + value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, + shift: 0x0100_U256, + expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + }, + TestCase { + value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, + shift: 0x0101_U256, + expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0x00_U256, + expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0x01_U256, + expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0xff_U256, + expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0x0100_U256, + expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + }, + TestCase { + value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + shift: 0x01_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0x4000000000000000000000000000000000000000000000000000000000000000_U256, + shift: 0xfe_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + }, + TestCase { + value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0xf8_U256, + expected: 0x000000000000000000000000000000000000000000000000000000000000007f_U256, + }, + TestCase { + value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0xfe_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256, + }, + TestCase { + value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0xff_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + }, + TestCase { + value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + shift: 0x0100_U256, + expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256, + }, + ]; + } + + for test in test_cases { + push!(interpreter, test.value); + push!(interpreter, test.shift); + let context = + InstructionContext { host: &mut DummyHost, interpreter: &mut interpreter }; + sar(context); + let res = interpreter.stack.pop().unwrap(); + assert_eq!(res, test.expected); + } + } + + #[test] + fn test_byte() { + struct TestCase { + input: U256, + index: usize, + expected: U256, + } + + let mut interpreter = test_interpreter(); + + let input_value = U256::from(0x1234567890abcdef1234567890abcdef_u128); + let test_cases = (0..32) + .map(|i| { + let byte_pos = 31 - i; + + let shift_amount = U256::from(byte_pos * 8); + let byte_value = (input_value >> shift_amount) & U256::from(0xFF); + TestCase { input: input_value, index: i, expected: byte_value } + }) + .collect::>(); + + for test in test_cases.iter() { + push!(interpreter, test.input); + push!(interpreter, U256::from(test.index)); + let context = + InstructionContext { host: &mut DummyHost, interpreter: &mut interpreter }; + byte(context); + let res = interpreter.stack.pop().unwrap(); + assert_eq!(res, test.expected, "Failed at index: {}", test.index); + } + } + + #[test] + fn test_clz() { + let mut interpreter = test_interpreter(); + interpreter.runtime_flag.spec_id = SpecId::OSAKA; + + struct TestCase { + value: U256, + expected: U256, + } + + uint! { + let test_cases = [ + TestCase { value: 0x0_U256, expected: 256_U256 }, + TestCase { value: 0x1_U256, expected: 255_U256 }, + TestCase { value: 0x2_U256, expected: 254_U256 }, + TestCase { value: 0x3_U256, expected: 254_U256 }, + TestCase { value: 0x4_U256, expected: 253_U256 }, + TestCase { value: 0x7_U256, expected: 253_U256 }, + TestCase { value: 0x8_U256, expected: 252_U256 }, + TestCase { value: 0xff_U256, expected: 248_U256 }, + TestCase { value: 0x100_U256, expected: 247_U256 }, + TestCase { value: 0xffff_U256, expected: 240_U256 }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, // U256::MAX + expected: 0_U256, + }, + TestCase { + value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, // 1 << 255 + expected: 0_U256, + }, + TestCase { // Smallest value with 1 leading zero + value: 0x4000000000000000000000000000000000000000000000000000000000000000_U256, // 1 << 254 + expected: 1_U256, + }, + TestCase { // Value just below 1 << 255 + value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + expected: 1_U256, + }, + ]; + } + + for test in test_cases { + push!(interpreter, test.value); + let context = + InstructionContext { host: &mut DummyHost, interpreter: &mut interpreter }; + clz(context); + let res = interpreter.stack.pop().unwrap(); + assert_eq!( + res, test.expected, + "CLZ for value {:#x} failed. Expected: {}, Got: {}", + test.value, test.expected, res + ); + } + } +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/block_info.rs b/substrate/frame/revive/src/vm/evm/instructions/block_info.rs new file mode 100644 index 000000000000..375de2f6f9c2 --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/block_info.rs @@ -0,0 +1,90 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::Context; +use crate::{vm::Ext, RuntimeCosts}; +use revm::{ + interpreter::{gas as revm_gas, host::Host, interpreter_types::RuntimeFlag}, + primitives::{hardfork::SpecId::*, U256}, +}; + +/// EIP-1344: ChainID opcode +pub fn chainid<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, ISTANBUL); + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, context.host.chain_id()); +} + +/// Implements the COINBASE instruction. +/// +/// Pushes the current block's beneficiary address onto the stack. +pub fn coinbase<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, context.host.beneficiary().into_word().into()); +} + +/// Implements the TIMESTAMP instruction. +/// +/// Pushes the current block's timestamp onto the stack. +pub fn timestamp<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, context.host.timestamp()); +} + +/// Implements the NUMBER instruction. +/// +/// Pushes the current block number onto the stack. +pub fn block_number<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas!(context.interpreter, RuntimeCosts::BlockNumber); + let block_number = context.interpreter.extend.block_number(); + push!(context.interpreter, U256::from_limbs(block_number.0)); +} + +/// Implements the DIFFICULTY/PREVRANDAO instruction. +/// +/// Pushes the block difficulty (pre-merge) or prevrandao (post-merge) onto the stack. +pub fn difficulty<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + if context.interpreter.runtime_flag.spec_id().is_enabled_in(MERGE) { + // Unwrap is safe as this fields is checked in validation handler. + push!(context.interpreter, context.host.prevrandao().unwrap()); + } else { + push!(context.interpreter, context.host.difficulty()); + } +} + +/// Implements the GASLIMIT instruction. +/// +/// Pushes the current block's gas limit onto the stack. +pub fn gaslimit<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, context.host.gas_limit()); +} + +/// EIP-3198: BASEFEE opcode +pub fn basefee<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, LONDON); + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, context.host.basefee()); +} + +/// EIP-7516: BLOBBASEFEE opcode +pub fn blob_basefee<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, CANCUN); + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, context.host.blob_gasprice()); +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/contract.rs b/substrate/frame/revive/src/vm/evm/instructions/contract.rs new file mode 100644 index 000000000000..1cf67725db88 --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/contract.rs @@ -0,0 +1,297 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod call_helpers; + +pub use call_helpers::{calc_call_gas, get_memory_input_and_out_ranges}; + +use super::{utility::IntoAddress, Context}; +use crate::vm::Ext; +use alloc::boxed::Box; +use revm::{ + context_interface::CreateScheme, + interpreter::{ + gas as revm_gas, + host::Host, + interpreter_action::{ + CallInputs, CallScheme, CallValue, CreateInputs, FrameInput, InterpreterAction, + }, + interpreter_types::{InputsTr, LoopControl, RuntimeFlag, StackTr}, + CallInput, InstructionResult, + }, + primitives::{hardfork::SpecId, Address, Bytes, B256, U256}, +}; + +/// Implements the CREATE/CREATE2 instruction. +/// +/// Creates a new contract with provided bytecode. +pub fn create<'ext, const IS_CREATE2: bool, E: Ext>(context: Context<'_, 'ext, E>) { + require_non_staticcall!(context.interpreter); + + // EIP-1014: Skinny CREATE2 + if IS_CREATE2 { + check!(context.interpreter, PETERSBURG); + } + + popn!([value, code_offset, len], context.interpreter); + let len = as_usize_or_fail!(context.interpreter, len); + + let mut code = Bytes::new(); + if len != 0 { + // EIP-3860: Limit and meter initcode + if context.interpreter.runtime_flag.spec_id().is_enabled_in(SpecId::SHANGHAI) { + // Limit is set as double of max contract bytecode size + if len > context.host.max_initcode_size() { + context.interpreter.halt(InstructionResult::CreateInitCodeSizeLimit); + return; + } + gas_legacy!(context.interpreter, revm_gas::initcode_cost(len)); + } + + let code_offset = as_usize_or_fail!(context.interpreter, code_offset); + resize_memory!(context.interpreter, code_offset, len); + code = + Bytes::copy_from_slice(context.interpreter.memory.slice_len(code_offset, len).as_ref()); + } + + // EIP-1014: Skinny CREATE2 + let scheme = if IS_CREATE2 { + popn!([salt], context.interpreter); + // SAFETY: `len` is reasonable in size as gas for it is already deducted. + gas_or_fail!(context.interpreter, revm_gas::create2_cost(len)); + CreateScheme::Create2 { salt } + } else { + gas_legacy!(context.interpreter, revm_gas::CREATE); + CreateScheme::Create + }; + + let mut gas_limit = context.interpreter.gas.remaining(); + + // EIP-150: Gas cost changes for IO-heavy operations + if context.interpreter.runtime_flag.spec_id().is_enabled_in(SpecId::TANGERINE) { + // Take remaining gas and deduce l64 part of it. + gas_limit -= gas_limit / 64 + } + gas_legacy!(context.interpreter, gas_limit); + + // Call host to interact with target contract + context + .interpreter + .bytecode + .set_action(InterpreterAction::NewFrame(FrameInput::Create(Box::new(CreateInputs { + caller: context.interpreter.input.target_address(), + scheme, + value, + init_code: code, + gas_limit, + })))); +} + +/// Implements the CALL instruction. +/// +/// Message call with value transfer to another account. +pub fn call<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + popn!([local_gas_limit, to, value], context.interpreter); + let to = to.into_address(); + // Max gas limit is not possible in real ethereum situation. + let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX); + + let has_transfer = !value.is_zero(); + if context.interpreter.runtime_flag.is_static() && has_transfer { + context.interpreter.halt(InstructionResult::CallNotAllowedInsideStatic); + return; + } + + let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter) + else { + return; + }; + + let Some(account_load) = context.host.load_account_delegated(to) else { + context.interpreter.halt(InstructionResult::FatalExternalError); + return; + }; + + let Some(mut gas_limit) = + calc_call_gas(context.interpreter, account_load, has_transfer, local_gas_limit) + else { + return; + }; + + gas_legacy!(context.interpreter, gas_limit); + + // Add call stipend if there is value to be transferred. + if has_transfer { + gas_limit = gas_limit.saturating_add(revm_gas::CALL_STIPEND); + } + + // Call host to interact with target contract + context + .interpreter + .bytecode + .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs { + input: CallInput::SharedBuffer(input), + gas_limit, + target_address: to, + caller: context.interpreter.input.target_address(), + bytecode_address: to, + value: CallValue::Transfer(value), + scheme: CallScheme::Call, + is_static: context.interpreter.runtime_flag.is_static(), + return_memory_offset, + })))); +} + +/// Implements the CALLCODE instruction. +/// +/// Message call with alternative account's code. +pub fn call_code<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + popn!([local_gas_limit, to, value], context.interpreter); + let to = Address::from_word(B256::from(to)); + // Max gas limit is not possible in real ethereum situation. + let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX); + + //pop!(context.interpreter, value); + let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter) + else { + return; + }; + + let Some(mut load) = context.host.load_account_delegated(to) else { + context.interpreter.halt(InstructionResult::FatalExternalError); + return; + }; + + // Set `is_empty` to false as we are not creating this account. + load.is_empty = false; + let Some(mut gas_limit) = + calc_call_gas(context.interpreter, load, !value.is_zero(), local_gas_limit) + else { + return; + }; + + gas_legacy!(context.interpreter, gas_limit); + + // Add call stipend if there is value to be transferred. + if !value.is_zero() { + gas_limit = gas_limit.saturating_add(revm_gas::CALL_STIPEND); + } + + // Call host to interact with target contract + context + .interpreter + .bytecode + .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs { + input: CallInput::SharedBuffer(input), + gas_limit, + target_address: context.interpreter.input.target_address(), + caller: context.interpreter.input.target_address(), + bytecode_address: to, + value: CallValue::Transfer(value), + scheme: CallScheme::CallCode, + is_static: context.interpreter.runtime_flag.is_static(), + return_memory_offset, + })))); +} + +/// Implements the DELEGATECALL instruction. +/// +/// Message call with alternative account's code but same sender and value. +pub fn delegate_call<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, HOMESTEAD); + popn!([local_gas_limit, to], context.interpreter); + let to = Address::from_word(B256::from(to)); + // Max gas limit is not possible in real ethereum situation. + let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX); + + let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter) + else { + return; + }; + + let Some(mut load) = context.host.load_account_delegated(to) else { + context.interpreter.halt(InstructionResult::FatalExternalError); + return; + }; + + // Set is_empty to false as we are not creating this account. + load.is_empty = false; + let Some(gas_limit) = calc_call_gas(context.interpreter, load, false, local_gas_limit) else { + return; + }; + + gas_legacy!(context.interpreter, gas_limit); + + // Call host to interact with target contract + context + .interpreter + .bytecode + .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs { + input: CallInput::SharedBuffer(input), + gas_limit, + target_address: context.interpreter.input.target_address(), + caller: context.interpreter.input.caller_address(), + bytecode_address: to, + value: CallValue::Apparent(context.interpreter.input.call_value()), + scheme: CallScheme::DelegateCall, + is_static: context.interpreter.runtime_flag.is_static(), + return_memory_offset, + })))); +} + +/// Implements the STATICCALL instruction. +/// +/// Static message call (cannot modify state). +pub fn static_call<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, BYZANTIUM); + popn!([local_gas_limit, to], context.interpreter); + let to = Address::from_word(B256::from(to)); + // Max gas limit is not possible in real ethereum situation. + let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX); + + let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter) + else { + return; + }; + + let Some(mut load) = context.host.load_account_delegated(to) else { + context.interpreter.halt(InstructionResult::FatalExternalError); + return; + }; + // Set `is_empty` to false as we are not creating this account. + load.is_empty = false; + let Some(gas_limit) = calc_call_gas(context.interpreter, load, false, local_gas_limit) else { + return; + }; + gas_legacy!(context.interpreter, gas_limit); + + // Call host to interact with target contract + context + .interpreter + .bytecode + .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs { + input: CallInput::SharedBuffer(input), + gas_limit, + target_address: to, + caller: context.interpreter.input.target_address(), + bytecode_address: to, + value: CallValue::Transfer(U256::ZERO), + scheme: CallScheme::StaticCall, + is_static: true, + return_memory_offset, + })))); +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/contract/call_helpers.rs b/substrate/frame/revive/src/vm/evm/instructions/contract/call_helpers.rs new file mode 100644 index 000000000000..e60886ff5365 --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/contract/call_helpers.rs @@ -0,0 +1,88 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::vm::Ext; +use core::{cmp::min, ops::Range}; +use revm::{ + context_interface::{context::StateLoad, journaled_state::AccountLoad}, + interpreter::{ + gas as revm_gas, + interpreter_types::{MemoryTr, RuntimeFlag, StackTr}, + Interpreter, + }, + primitives::{hardfork::SpecId::*, U256}, +}; + +/// Gets memory input and output ranges for call instructions. +#[inline] +pub fn get_memory_input_and_out_ranges<'a, E: Ext>( + interpreter: &mut Interpreter>, +) -> Option<(Range, Range)> { + popn!([in_offset, in_len, out_offset, out_len], interpreter, None); + + let mut in_range = resize_memory(interpreter, in_offset, in_len)?; + + if !in_range.is_empty() { + let offset = <_ as MemoryTr>::local_memory_offset(&interpreter.memory); + in_range = in_range.start.saturating_add(offset)..in_range.end.saturating_add(offset); + } + + let ret_range = resize_memory(interpreter, out_offset, out_len)?; + Some((in_range, ret_range)) +} + +/// Resize memory and return range of memory. +/// If `len` is 0 dont touch memory and return `usize::MAX` as offset and 0 as length. +#[inline] +pub fn resize_memory<'a, E: Ext>( + interpreter: &mut Interpreter>, + offset: U256, + len: U256, +) -> Option> { + let len = as_usize_or_fail_ret!(interpreter, len, None); + let offset = if len != 0 { + let offset = as_usize_or_fail_ret!(interpreter, offset, None); + resize_memory!(interpreter, offset, len, None); + offset + } else { + usize::MAX //unrealistic value so we are sure it is not used + }; + Some(offset..offset + len) +} + +/// Calculates gas cost and limit for call instructions. +#[inline] +pub fn calc_call_gas<'a, E: Ext>( + interpreter: &mut Interpreter>, + account_load: StateLoad, + has_transfer: bool, + local_gas_limit: u64, +) -> Option { + let call_cost = + revm_gas::call_cost(interpreter.runtime_flag.spec_id(), has_transfer, account_load); + gas_legacy!(interpreter, call_cost, None); + + // EIP-150: Gas cost changes for IO-heavy operations + let gas_limit = if interpreter.runtime_flag.spec_id().is_enabled_in(TANGERINE) { + // Take l64 part of gas_limit + min(interpreter.gas.remaining_63_of_64_parts(), local_gas_limit) + } else { + local_gas_limit + }; + + Some(gas_limit) +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/control.rs b/substrate/frame/revive/src/vm/evm/instructions/control.rs new file mode 100644 index 000000000000..22415d02827c --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/control.rs @@ -0,0 +1,146 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::Context; +use crate::vm::Ext; +use revm::{ + interpreter::{ + gas as revm_gas, + interpreter_action::InterpreterAction, + interpreter_types::{Jumps, LoopControl, RuntimeFlag, StackTr}, + InstructionResult, Interpreter, + }, + primitives::{Bytes, U256}, +}; + +/// Implements the JUMP instruction. +/// +/// Unconditional jump to a valid destination. +pub fn jump<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::MID); + let Some([target]) = <_ as StackTr>::popn(&mut context.interpreter.stack) else { + context.interpreter.halt(InstructionResult::StackUnderflow); + return; + }; + jump_inner(context.interpreter, target); +} + +/// Implements the JUMPI instruction. +/// +/// Conditional jump to a valid destination if condition is true. +pub fn jumpi<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::HIGH); + let Some([target, cond]) = <_ as StackTr>::popn(&mut context.interpreter.stack) else { + context.interpreter.halt(InstructionResult::StackUnderflow); + return; + }; + + if !cond.is_zero() { + jump_inner(context.interpreter, target); + } +} + +#[inline(always)] +/// Internal helper function for jump operations. +/// +/// Validates jump target and performs the actual jump. +fn jump_inner( + interpreter: &mut Interpreter, + target: U256, +) { + let target = as_usize_or_fail!(interpreter, target, InstructionResult::InvalidJump); + if !interpreter.bytecode.is_valid_legacy_jump(target) { + interpreter.halt(InstructionResult::InvalidJump); + return; + } + // SAFETY: `is_valid_jump` ensures that `dest` is in bounds. + interpreter.bytecode.absolute_jump(target); +} + +/// Implements the JUMPDEST instruction. +/// +/// Marks a valid destination for jump operations. +pub fn jumpdest<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::JUMPDEST); +} + +/// Implements the PC instruction. +/// +/// Pushes the current program counter onto the stack. +pub fn pc<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + // - 1 because we have already advanced the instruction pointer in `Interpreter::step` + push!(context.interpreter, U256::from(context.interpreter.bytecode.pc() - 1)); +} + +#[inline] +/// Internal helper function for return operations. +/// +/// Handles memory data retrieval and sets the return action. +fn return_inner<'a, E: Ext>( + interpreter: &mut Interpreter>, + instruction_result: InstructionResult, +) { + // Zero gas cost + // gas_legacy!(interpreter, revm_gas::ZERO) + let Some([offset, len]) = <_ as StackTr>::popn(&mut interpreter.stack) else { + interpreter.halt(InstructionResult::StackUnderflow); + return; + }; + let len = as_usize_or_fail!(interpreter, len); + // Important: Offset must be ignored if len is zeros + let mut output = Bytes::default(); + if len != 0 { + let offset = as_usize_or_fail!(interpreter, offset); + resize_memory!(interpreter, offset, len); + output = interpreter.memory.slice_len(offset, len).to_vec().into() + } + + interpreter.bytecode.set_action(InterpreterAction::new_return( + instruction_result, + output, + interpreter.gas, + )); +} + +/// Implements the RETURN instruction. +/// +/// Halts execution and returns data from memory. +pub fn ret<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + return_inner(context.interpreter, InstructionResult::Return); +} + +/// EIP-140: REVERT instruction +pub fn revert<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, BYZANTIUM); + return_inner(context.interpreter, InstructionResult::Revert); +} + +/// Stop opcode. This opcode halts the execution. +pub fn stop<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + context.interpreter.halt(InstructionResult::Stop); +} + +/// Invalid opcode. This opcode halts the execution. +pub fn invalid<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + context.interpreter.halt(InstructionResult::InvalidFEOpcode); +} + +/// Unknown opcode. This opcode halts the execution. +pub fn unknown<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + context.interpreter.halt(InstructionResult::OpcodeNotFound); +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/host.rs b/substrate/frame/revive/src/vm/evm/instructions/host.rs new file mode 100644 index 000000000000..0ff40c29f2cb --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/host.rs @@ -0,0 +1,315 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::{ + utility::{IntoAddress, IntoU256}, + Context, +}; +use crate::vm::Ext; +use core::cmp::min; +use revm::{ + interpreter::{ + gas::{self, warm_cold_cost, CALL_STIPEND}, + host::Host, + interpreter_types::{InputsTr, RuntimeFlag, StackTr}, + InstructionResult, + }, + primitives::{hardfork::SpecId::*, Bytes, Log, LogData, B256, BLOCK_HASH_HISTORY, U256}, +}; + +/// Implements the BALANCE instruction. +/// +/// Gets the balance of the given account. +pub fn balance<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + popn_top!([], top, context.interpreter); + let address = top.into_address(); + let Some(balance) = context.host.balance(address) else { + context.interpreter.halt(InstructionResult::FatalExternalError); + return; + }; + let spec_id = context.interpreter.runtime_flag.spec_id(); + gas_legacy!( + context.interpreter, + if spec_id.is_enabled_in(BERLIN) { + warm_cold_cost(balance.is_cold) + } else if spec_id.is_enabled_in(ISTANBUL) { + // EIP-1884: Repricing for trie-size-dependent opcodes + 700 + } else if spec_id.is_enabled_in(TANGERINE) { + 400 + } else { + 20 + } + ); + *top = balance.data; +} + +/// EIP-1884: Repricing for trie-size-dependent opcodes +pub fn selfbalance<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, ISTANBUL); + gas_legacy!(context.interpreter, gas::LOW); + + let Some(balance) = context.host.balance(context.interpreter.input.target_address()) else { + context.interpreter.halt(InstructionResult::FatalExternalError); + return; + }; + push!(context.interpreter, balance.data); +} + +/// Implements the EXTCODESIZE instruction. +/// +/// Gets the size of an account's code. +pub fn extcodesize<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + popn_top!([], top, context.interpreter); + let address = top.into_address(); + let Some(code) = context.host.load_account_code(address) else { + context.interpreter.halt(InstructionResult::FatalExternalError); + return; + }; + let spec_id = context.interpreter.runtime_flag.spec_id(); + if spec_id.is_enabled_in(BERLIN) { + gas_legacy!(context.interpreter, warm_cold_cost(code.is_cold)); + } else if spec_id.is_enabled_in(TANGERINE) { + gas_legacy!(context.interpreter, 700); + } else { + gas_legacy!(context.interpreter, 20); + } + + *top = U256::from(code.len()); +} + +/// EIP-1052: EXTCODEHASH opcode +pub fn extcodehash<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, CONSTANTINOPLE); + popn_top!([], top, context.interpreter); + let address = top.into_address(); + let Some(code_hash) = context.host.load_account_code_hash(address) else { + context.interpreter.halt(InstructionResult::FatalExternalError); + return; + }; + let spec_id = context.interpreter.runtime_flag.spec_id(); + if spec_id.is_enabled_in(BERLIN) { + gas_legacy!(context.interpreter, warm_cold_cost(code_hash.is_cold)); + } else if spec_id.is_enabled_in(ISTANBUL) { + gas_legacy!(context.interpreter, 700); + } else { + gas_legacy!(context.interpreter, 400); + } + *top = code_hash.into_u256(); +} + +/// Implements the EXTCODECOPY instruction. +/// +/// Copies a portion of an account's code to memory. +pub fn extcodecopy<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + popn!([address, memory_offset, code_offset, len_u256], context.interpreter); + let address = address.into_address(); + let Some(code) = context.host.load_account_code(address) else { + context.interpreter.halt(InstructionResult::FatalExternalError); + return; + }; + + let len = as_usize_or_fail!(context.interpreter, len_u256); + gas_or_fail!( + context.interpreter, + gas::extcodecopy_cost(context.interpreter.runtime_flag.spec_id(), len, code.is_cold) + ); + if len == 0 { + return; + } + let memory_offset = as_usize_or_fail!(context.interpreter, memory_offset); + let code_offset = min(as_usize_saturated!(code_offset), code.len()); + resize_memory!(context.interpreter, memory_offset, len); + + // Note: This can't panic because we resized memory to fit. + context.interpreter.memory.set_data(memory_offset, code_offset, len, &code); +} + +/// Implements the BLOCKHASH instruction. +/// +/// Gets the hash of one of the 256 most recent complete blocks. +pub fn blockhash<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, gas::BLOCKHASH); + popn_top!([], number, context.interpreter); + + let requested_number = *number; + let block_number = context.host.block_number(); + + let Some(diff) = block_number.checked_sub(requested_number) else { + *number = U256::ZERO; + return; + }; + + let diff = as_u64_saturated!(diff); + + // blockhash should push zero if number is same as current block number. + if diff == 0 { + *number = U256::ZERO; + return; + } + + *number = if diff <= BLOCK_HASH_HISTORY { + let Some(hash) = context.host.block_hash(as_u64_saturated!(requested_number)) else { + context.interpreter.halt(InstructionResult::FatalExternalError); + return; + }; + U256::from_be_bytes(hash.0) + } else { + U256::ZERO + } +} + +/// Implements the SLOAD instruction. +/// +/// Loads a word from storage. +pub fn sload<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + popn_top!([], index, context.interpreter); + + let Some(value) = context.host.sload(context.interpreter.input.target_address(), *index) else { + context.interpreter.halt(InstructionResult::FatalExternalError); + return; + }; + + gas_legacy!( + context.interpreter, + gas::sload_cost(context.interpreter.runtime_flag.spec_id(), value.is_cold) + ); + *index = value.data; +} + +/// Implements the SSTORE instruction. +/// +/// Stores a word to storage. +pub fn sstore<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + require_non_staticcall!(context.interpreter); + + popn!([index, value], context.interpreter); + + let Some(state_load) = + context.host.sstore(context.interpreter.input.target_address(), index, value) + else { + context.interpreter.halt(InstructionResult::FatalExternalError); + return; + }; + + // EIP-1706 Disable SSTORE with gasleft lower than call stipend + if context.interpreter.runtime_flag.spec_id().is_enabled_in(ISTANBUL) && + context.interpreter.gas.remaining() <= CALL_STIPEND + { + context.interpreter.halt(InstructionResult::ReentrancySentryOOG); + return; + } + gas_legacy!( + context.interpreter, + gas::sstore_cost( + context.interpreter.runtime_flag.spec_id(), + &state_load.data, + state_load.is_cold + ) + ); + + context.interpreter.gas.record_refund(gas::sstore_refund( + context.interpreter.runtime_flag.spec_id(), + &state_load.data, + )); +} + +/// EIP-1153: Transient storage opcodes +/// Store value to transient storage +pub fn tstore<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, CANCUN); + require_non_staticcall!(context.interpreter); + gas_legacy!(context.interpreter, gas::WARM_STORAGE_READ_COST); + + popn!([index, value], context.interpreter); + + context.host.tstore(context.interpreter.input.target_address(), index, value); +} + +/// EIP-1153: Transient storage opcodes +/// Load value from transient storage +pub fn tload<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, CANCUN); + gas_legacy!(context.interpreter, gas::WARM_STORAGE_READ_COST); + + popn_top!([], index, context.interpreter); + + *index = context.host.tload(context.interpreter.input.target_address(), *index); +} + +/// Implements the LOG0-LOG4 instructions. +/// +/// Appends log record with N topics. +pub fn log<'ext, const N: usize, E: Ext>(context: Context<'_, 'ext, E>) { + require_non_staticcall!(context.interpreter); + + popn!([offset, len], context.interpreter); + let len = as_usize_or_fail!(context.interpreter, len); + gas_or_fail!(context.interpreter, gas::log_cost(N as u8, len as u64)); + let data = if len == 0 { + Bytes::new() + } else { + let offset = as_usize_or_fail!(context.interpreter, offset); + resize_memory!(context.interpreter, offset, len); + Bytes::copy_from_slice(context.interpreter.memory.slice_len(offset, len).as_ref()) + }; + if context.interpreter.stack.len() < N { + context.interpreter.halt(InstructionResult::StackUnderflow); + return; + } + let Some(topics) = <_ as StackTr>::popn::(&mut context.interpreter.stack) else { + context.interpreter.halt(InstructionResult::StackUnderflow); + return; + }; + + let log = Log { + address: context.interpreter.input.target_address(), + data: LogData::new(topics.into_iter().map(B256::from).collect(), data) + .expect("LogData should have <=4 topics"), + }; + + context.host.log(log); +} + +/// Implements the SELFDESTRUCT instruction. +/// +/// Halt execution and register account for later deletion. +pub fn selfdestruct<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + require_non_staticcall!(context.interpreter); + popn!([target], context.interpreter); + let target = target.into_address(); + + let Some(res) = context.host.selfdestruct(context.interpreter.input.target_address(), target) + else { + context.interpreter.halt(InstructionResult::FatalExternalError); + return; + }; + + // EIP-3529: Reduction in refunds + if !context.interpreter.runtime_flag.spec_id().is_enabled_in(LONDON) && + !res.previously_destroyed + { + context.interpreter.gas.record_refund(gas::SELFDESTRUCT) + } + + gas_legacy!( + context.interpreter, + gas::selfdestruct_cost(context.interpreter.runtime_flag.spec_id(), res) + ); + + context.interpreter.halt(InstructionResult::SelfDestruct); +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/i256.rs b/substrate/frame/revive/src/vm/evm/instructions/i256.rs new file mode 100644 index 000000000000..44f1b35a101b --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/i256.rs @@ -0,0 +1,273 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use core::cmp::Ordering; +use revm::primitives::U256; + +/// Represents the sign of a 256-bit signed integer value. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(i8)] +pub enum Sign { + // Same as `cmp::Ordering` + /// Negative value sign + Minus = -1, + /// Zero value sign + Zero = 0, + #[allow(dead_code)] // "constructed" with `mem::transmute` in `i256_sign` below + /// Positive value sign + Plus = 1, +} + +#[cfg(test)] +/// The maximum positive value for a 256-bit signed integer. +pub const MAX_POSITIVE_VALUE: U256 = U256::from_limbs([ + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0x7fffffffffffffff, +]); + +/// The minimum negative value for a 256-bit signed integer. +pub const MIN_NEGATIVE_VALUE: U256 = U256::from_limbs([ + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x8000000000000000, +]); + +const FLIPH_BITMASK_U64: u64 = 0x7FFF_FFFF_FFFF_FFFF; + +/// Determines the sign of a 256-bit signed integer. +#[inline] +pub fn i256_sign(val: &U256) -> Sign { + if val.bit(U256::BITS - 1) { + Sign::Minus + } else { + // SAFETY: false == 0 == Zero, true == 1 == Plus + unsafe { core::mem::transmute::(!val.is_zero()) } + } +} + +/// Determines the sign of a 256-bit signed integer and converts it to its absolute value. +#[inline] +pub fn i256_sign_compl(val: &mut U256) -> Sign { + let sign = i256_sign(val); + if sign == Sign::Minus { + two_compl_mut(val); + } + sign +} + +#[inline] +fn u256_remove_sign(val: &mut U256) { + // SAFETY: U256 does not have any padding bytes + unsafe { + val.as_limbs_mut()[3] &= FLIPH_BITMASK_U64; + } +} + +/// Computes the two's complement of a U256 value in place. +#[inline] +pub fn two_compl_mut(op: &mut U256) { + *op = two_compl(*op); +} + +/// Computes the two's complement of a U256 value. +#[inline] +pub fn two_compl(op: U256) -> U256 { + op.wrapping_neg() +} + +/// Compares two 256-bit signed integers. +#[inline] +pub fn i256_cmp(first: &U256, second: &U256) -> Ordering { + let first_sign = i256_sign(first); + let second_sign = i256_sign(second); + match first_sign.cmp(&second_sign) { + // Note: Adding `if first_sign != Sign::Zero` to short circuit zero comparisons performs + // slower on average, as of #582 + Ordering::Equal => first.cmp(second), + o => o, + } +} + +/// Performs signed division of two 256-bit integers. +#[inline] +pub fn i256_div(mut first: U256, mut second: U256) -> U256 { + let second_sign = i256_sign_compl(&mut second); + if second_sign == Sign::Zero { + return U256::ZERO; + } + + let first_sign = i256_sign_compl(&mut first); + if first == MIN_NEGATIVE_VALUE && second == U256::from(1) { + return two_compl(MIN_NEGATIVE_VALUE); + } + + // Necessary overflow checks are done above, perform the division + let mut d = first / second; + + // Set sign bit to zero + u256_remove_sign(&mut d); + + // Two's complement only if the signs are different + // Note: This condition has better codegen than an exhaustive match, as of #582 + if (first_sign == Sign::Minus && second_sign != Sign::Minus) || + (second_sign == Sign::Minus && first_sign != Sign::Minus) + { + two_compl(d) + } else { + d + } +} + +/// Performs signed modulo of two 256-bit integers. +#[inline] +pub fn i256_mod(mut first: U256, mut second: U256) -> U256 { + let first_sign = i256_sign_compl(&mut first); + if first_sign == Sign::Zero { + return U256::ZERO; + } + + let second_sign = i256_sign_compl(&mut second); + if second_sign == Sign::Zero { + return U256::ZERO; + } + + let mut r = first % second; + + // Set sign bit to zero + u256_remove_sign(&mut r); + + if first_sign == Sign::Minus { + two_compl(r) + } else { + r + } +} + +#[cfg(test)] +mod tests { + use super::*; + use core::num::Wrapping; + use revm::primitives::uint; + + #[test] + fn div_i256() { + // Sanity checks based on i8. Notice that we need to use `Wrapping` here because + // Rust will prevent the overflow by default whereas the EVM does not. + assert_eq!(Wrapping(i8::MIN) / Wrapping(-1), Wrapping(i8::MIN)); + assert_eq!(i8::MAX / -1, -i8::MAX); + + uint! { + assert_eq!(i256_div(MIN_NEGATIVE_VALUE, -1_U256), MIN_NEGATIVE_VALUE); + assert_eq!(i256_div(MIN_NEGATIVE_VALUE, 1_U256), MIN_NEGATIVE_VALUE); + assert_eq!(i256_div(MAX_POSITIVE_VALUE, 1_U256), MAX_POSITIVE_VALUE); + assert_eq!(i256_div(MAX_POSITIVE_VALUE, -1_U256), -1_U256 * MAX_POSITIVE_VALUE); + assert_eq!(i256_div(100_U256, -1_U256), -100_U256); + assert_eq!(i256_div(100_U256, 2_U256), 50_U256); + } + } + #[test] + fn test_i256_sign() { + uint! { + assert_eq!(i256_sign(&0_U256), Sign::Zero); + assert_eq!(i256_sign(&1_U256), Sign::Plus); + assert_eq!(i256_sign(&-1_U256), Sign::Minus); + assert_eq!(i256_sign(&MIN_NEGATIVE_VALUE), Sign::Minus); + assert_eq!(i256_sign(&MAX_POSITIVE_VALUE), Sign::Plus); + } + } + + #[test] + fn test_i256_sign_compl() { + uint! { + let mut zero = 0_U256; + let mut positive = 1_U256; + let mut negative = -1_U256; + assert_eq!(i256_sign_compl(&mut zero), Sign::Zero); + assert_eq!(i256_sign_compl(&mut positive), Sign::Plus); + assert_eq!(i256_sign_compl(&mut negative), Sign::Minus); + } + } + + #[test] + fn test_two_compl() { + uint! { + assert_eq!(two_compl(0_U256), 0_U256); + assert_eq!(two_compl(1_U256), -1_U256); + assert_eq!(two_compl(-1_U256), 1_U256); + assert_eq!(two_compl(2_U256), -2_U256); + assert_eq!(two_compl(-2_U256), 2_U256); + + // Two's complement of the min value is itself. + assert_eq!(two_compl(MIN_NEGATIVE_VALUE), MIN_NEGATIVE_VALUE); + } + } + + #[test] + fn test_two_compl_mut() { + uint! { + let mut value = 1_U256; + two_compl_mut(&mut value); + assert_eq!(value, -1_U256); + } + } + + #[test] + fn test_i256_cmp() { + uint! { + assert_eq!(i256_cmp(&1_U256, &2_U256), Ordering::Less); + assert_eq!(i256_cmp(&2_U256, &2_U256), Ordering::Equal); + assert_eq!(i256_cmp(&3_U256, &2_U256), Ordering::Greater); + assert_eq!(i256_cmp(&-1_U256, &-1_U256), Ordering::Equal); + assert_eq!(i256_cmp(&-1_U256, &-2_U256), Ordering::Greater); + assert_eq!(i256_cmp(&-1_U256, &0_U256), Ordering::Less); + assert_eq!(i256_cmp(&-2_U256, &2_U256), Ordering::Less); + } + } + + #[test] + fn test_i256_div() { + uint! { + assert_eq!(i256_div(1_U256, 0_U256), 0_U256); + assert_eq!(i256_div(0_U256, 1_U256), 0_U256); + assert_eq!(i256_div(0_U256, -1_U256), 0_U256); + assert_eq!(i256_div(MIN_NEGATIVE_VALUE, 1_U256), MIN_NEGATIVE_VALUE); + assert_eq!(i256_div(4_U256, 2_U256), 2_U256); + assert_eq!(i256_div(MIN_NEGATIVE_VALUE, MIN_NEGATIVE_VALUE), 1_U256); + assert_eq!(i256_div(2_U256, -1_U256), -2_U256); + assert_eq!(i256_div(-2_U256, -1_U256), 2_U256); + } + } + + #[test] + fn test_i256_mod() { + uint! { + assert_eq!(i256_mod(0_U256, 1_U256), 0_U256); + assert_eq!(i256_mod(1_U256, 0_U256), 0_U256); + assert_eq!(i256_mod(4_U256, 2_U256), 0_U256); + assert_eq!(i256_mod(3_U256, 2_U256), 1_U256); + assert_eq!(i256_mod(MIN_NEGATIVE_VALUE, 1_U256), 0_U256); + assert_eq!(i256_mod(2_U256, 2_U256), 0_U256); + assert_eq!(i256_mod(2_U256, 3_U256), 2_U256); + assert_eq!(i256_mod(-2_U256, 3_U256), -2_U256); + assert_eq!(i256_mod(2_U256, -3_U256), 2_U256); + assert_eq!(i256_mod(-2_U256, -3_U256), -2_U256); + } + } +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/macros.rs b/substrate/frame/revive/src/vm/evm/instructions/macros.rs new file mode 100644 index 000000000000..cb706d52add5 --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/macros.rs @@ -0,0 +1,274 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Utility macros to help implementing opcode instruction functions. + +/// `const` Option `?`. +#[macro_export] +macro_rules! tri { + ($e:expr) => { + match $e { + Some(v) => v, + None => return None, + } + }; +} + +/// Fails the instruction if the current call is static. +#[macro_export] +macro_rules! require_non_staticcall { + ($interpreter:expr) => { + if $interpreter.runtime_flag.is_static() { + $interpreter.halt(revm::interpreter::InstructionResult::StateChangeDuringStaticCall); + return; + } + }; +} + +/// Macro for optional try - returns early if the expression evaluates to None. +/// Similar to the `?` operator but for use in instruction implementations. +#[macro_export] +macro_rules! otry { + ($expression: expr) => {{ + let Some(value) = $expression else { + return; + }; + value + }}; +} + +/// Error if the current call is executing EOF. +#[macro_export] +macro_rules! require_eof { + ($interpreter:expr) => { + if !$interpreter.runtime_flag.is_eof() { + $interpreter.halt(revm::interpreter::InstructionResult::EOFOpcodeDisabledInLegacy); + return; + } + }; +} + +/// Check if the `SPEC` is enabled, and fail the instruction if it is not. +#[macro_export] +macro_rules! check { + ($interpreter:expr, $min:ident) => { + if !$interpreter + .runtime_flag + .spec_id() + .is_enabled_in(revm::primitives::hardfork::SpecId::$min) + { + $interpreter.halt(revm::interpreter::InstructionResult::NotActivated); + return; + } + }; +} + +/// Records a `gas` cost and fails the instruction if it would exceed the available gas. +#[macro_export] +macro_rules! gas_legacy { + ($interpreter:expr, $gas:expr) => { + gas_legacy!($interpreter, $gas, ()) + }; + ($interpreter:expr, $gas:expr, $ret:expr) => { + if $interpreter.extend.gas_meter_mut().charge_evm_gas($gas).is_err() { + $interpreter.halt(revm::interpreter::InstructionResult::OutOfGas); + return $ret; + } + }; +} + +#[macro_export] +macro_rules! gas { + ($interpreter:expr, $gas:expr) => { + gas!($interpreter, $gas, ()) + }; + ($interpreter:expr, $gas:expr, $ret:expr) => { + let meter = $interpreter.extend.gas_meter_mut(); + if meter.charge_evm_gas(1).is_err() || meter.charge($gas).is_err() { + $interpreter.halt(revm::interpreter::InstructionResult::OutOfGas); + return $ret; + } + }; +} + +/// Same as [`gas_legacy!`], but with `gas` as an option. +#[macro_export] +macro_rules! gas_or_fail { + ($interpreter:expr, $gas:expr) => { + gas_or_fail!($interpreter, $gas, ()) + }; + ($interpreter:expr, $gas:expr, $ret:expr) => { + match $gas { + Some(gas_used) => gas_legacy!($interpreter, gas_used, $ret), + None => { + $interpreter.halt(revm::interpreter::InstructionResult::OutOfGas); + return $ret; + }, + } + }; +} + +use crate::vm::Ext; +use revm::interpreter::gas::{MemoryExtensionResult, MemoryGas}; + +/// Adapted from +/// https://docs.rs/revm/latest/revm/interpreter/struct.Gas.html#method.record_memory_expansion +pub fn record_memory_expansion( + memory: &mut MemoryGas, + ext: &mut E, + new_len: usize, +) -> MemoryExtensionResult { + let Some(additional_cost) = memory.record_new_len(new_len) else { + return MemoryExtensionResult::Same; + }; + + if ext.gas_meter_mut().charge_evm_gas(additional_cost).is_err() { + return MemoryExtensionResult::OutOfGas; + } + + MemoryExtensionResult::Extended +} + +/// Resizes the interpreterreter memory if necessary. Fails the instruction if the memory or gas +/// limit is exceeded. +#[macro_export] +macro_rules! resize_memory { + ($interpreter:expr, $offset:expr, $len:expr) => { + resize_memory!($interpreter, $offset, $len, ()) + }; + ($interpreter:expr, $offset:expr, $len:expr, $ret:expr) => { + let words_num = revm::interpreter::num_words($offset.saturating_add($len)); + match crate::vm::evm::instructions::macros::record_memory_expansion( + $interpreter.gas.memory_mut(), + $interpreter.extend, + words_num, + ) { + revm::interpreter::gas::MemoryExtensionResult::Extended => { + $interpreter.memory.resize(words_num * 32); + }, + revm::interpreter::gas::MemoryExtensionResult::OutOfGas => { + $interpreter.halt(revm::interpreter::InstructionResult::MemoryOOG); + return $ret; + }, + revm::interpreter::gas::MemoryExtensionResult::Same => (), // no action + }; + }; +} + +/// Pops n values from the stack. Fails the instruction if n values can't be popped. +#[macro_export] +macro_rules! popn { + ([ $($x:ident),* ],$interpreterreter:expr $(,$ret:expr)? ) => { + let Some([$( $x ),*]) = <_ as StackTr>::popn(&mut $interpreterreter.stack) else { + $interpreterreter.halt(revm::interpreter::InstructionResult::StackUnderflow); + return $($ret)?; + }; + }; +} + +/// Pops n values from the stack and returns the top value. Fails the instruction if n values can't +/// be popped. +#[macro_export] +macro_rules! popn_top { + ([ $($x:ident),* ], $top:ident, $interpreter:expr $(,$ret:expr)? ) => { + let Some(([$($x),*], $top)) = <_ as StackTr>::popn_top(&mut $interpreter.stack) else { + $interpreter.halt(revm::interpreter::InstructionResult::StackUnderflow); + return $($ret)?; + }; + }; +} + +/// Pushes a `B256` value onto the stack. Fails the instruction if the stack is full. +#[macro_export] +macro_rules! push { + ($interpreter:expr, $x:expr $(,$ret:item)?) => ( + if !($interpreter.stack.push($x)) { + $interpreter.halt(revm::interpreter::InstructionResult::StackOverflow); + return $($ret)?; + } + ) +} + +/// Converts a `U256` value to a `u64`, saturating to `MAX` if the value is too large. +#[macro_export] +macro_rules! as_u64_saturated { + ($v:expr) => { + match $v.as_limbs() { + x => + if (x[1] == 0) & (x[2] == 0) & (x[3] == 0) { + x[0] + } else { + u64::MAX + }, + } + }; +} + +/// Converts a `U256` value to a `usize`, saturating to `MAX` if the value is too large. +#[macro_export] +macro_rules! as_usize_saturated { + ($v:expr) => { + usize::try_from(as_u64_saturated!($v)).unwrap_or(usize::MAX) + }; +} + +/// Converts a `U256` value to a `isize`, saturating to `isize::MAX` if the value is too large. +#[macro_export] +macro_rules! as_isize_saturated { + ($v:expr) => { + // `isize_try_from(u64::MAX)`` will fail and return isize::MAX + // This is expected behavior as we are saturating the value. + isize::try_from(as_u64_saturated!($v)).unwrap_or(isize::MAX) + }; +} + +/// Converts a `U256` value to a `usize`, failing the instruction if the value is too large. +#[macro_export] +macro_rules! as_usize_or_fail { + ($interpreter:expr, $v:expr) => { + as_usize_or_fail_ret!($interpreter, $v, ()) + }; + ($interpreter:expr, $v:expr, $reason:expr) => { + as_usize_or_fail_ret!($interpreter, $v, $reason, ()) + }; +} + +/// Converts a `U256` value to a `usize` and returns `ret`, +/// failing the instruction if the value is too large. +#[macro_export] +macro_rules! as_usize_or_fail_ret { + ($interpreter:expr, $v:expr, $ret:expr) => { + as_usize_or_fail_ret!( + $interpreter, + $v, + revm::interpreter::InstructionResult::InvalidOperandOOG, + $ret + ) + }; + + ($interpreter:expr, $v:expr, $reason:expr, $ret:expr) => { + match $v.as_limbs() { + x => { + if (x[0] > usize::MAX as u64) | (x[1] != 0) | (x[2] != 0) | (x[3] != 0) { + $interpreter.halt($reason); + return $ret; + } + x[0] as usize + }, + } + }; +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/memory.rs b/substrate/frame/revive/src/vm/evm/instructions/memory.rs new file mode 100644 index 000000000000..d767e3fe9dff --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/memory.rs @@ -0,0 +1,92 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::Context; +use crate::vm::Ext; +use core::cmp::max; +use revm::{ + interpreter::{ + gas as revm_gas, + interpreter_types::{MemoryTr, RuntimeFlag, StackTr}, + }, + primitives::U256, +}; + +/// Implements the MLOAD instruction. +/// +/// Loads a 32-byte word from memory. +pub fn mload<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([], top, context.interpreter); + let offset = as_usize_or_fail!(context.interpreter, top); + resize_memory!(context.interpreter, offset, 32); + *top = + U256::try_from_be_slice(context.interpreter.memory.slice_len(offset, 32).as_ref()).unwrap() +} + +/// Implements the MSTORE instruction. +/// +/// Stores a 32-byte word to memory. +pub fn mstore<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn!([offset, value], context.interpreter); + let offset = as_usize_or_fail!(context.interpreter, offset); + resize_memory!(context.interpreter, offset, 32); + context.interpreter.memory.set(offset, &value.to_be_bytes::<32>()); +} + +/// Implements the MSTORE8 instruction. +/// +/// Stores a single byte to memory. +pub fn mstore8<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn!([offset, value], context.interpreter); + let offset = as_usize_or_fail!(context.interpreter, offset); + resize_memory!(context.interpreter, offset, 1); + context.interpreter.memory.set(offset, &[value.byte(0)]); +} + +/// Implements the MSIZE instruction. +/// +/// Gets the size of active memory in bytes. +pub fn msize<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, U256::from(context.interpreter.memory.size())); +} + +/// Implements the MCOPY instruction. +/// +/// EIP-5656: Memory copying instruction that copies memory from one location to another. +pub fn mcopy<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, CANCUN); + popn!([dst, src, len], context.interpreter); + + // Into usize or fail + let len = as_usize_or_fail!(context.interpreter, len); + // Deduce gas + gas_or_fail!(context.interpreter, revm_gas::copy_cost_verylow(len)); + if len == 0 { + return; + } + + let dst = as_usize_or_fail!(context.interpreter, dst); + let src = as_usize_or_fail!(context.interpreter, src); + // Resize memory + resize_memory!(context.interpreter, max(dst, src), len); + // Copy memory in place + context.interpreter.memory.copy(dst, src, len); +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/mod.rs b/substrate/frame/revive/src/vm/evm/instructions/mod.rs new file mode 100644 index 000000000000..826c1febd474 --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/mod.rs @@ -0,0 +1,247 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! EVM opcode implementations. + +use crate::vm::{ + evm::{DummyHost, EVMInterpreter}, + Ext, +}; +use revm::interpreter::{Instruction, InstructionContext}; + +type Context<'ctx, 'ext, E> = + InstructionContext<'ctx, crate::vm::evm::DummyHost, crate::vm::evm::EVMInterpreter<'ext, E>>; + +#[macro_use] +mod macros; +/// Arithmetic operations (ADD, SUB, MUL, DIV, etc.). +mod arithmetic; +/// Bitwise operations (AND, OR, XOR, NOT, etc.). +mod bitwise; +/// Block information instructions (COINBASE, TIMESTAMP, etc.). +mod block_info; +/// Contract operations (CALL, CREATE, DELEGATECALL, etc.). +mod contract; +/// Control flow instructions (JUMP, JUMPI, REVERT, etc.). +mod control; +/// Host environment interactions (SLOAD, SSTORE, LOG, etc.). +mod host; +/// Signed 256-bit integer operations. +mod i256; +/// Memory operations (MLOAD, MSTORE, MSIZE, etc.). +mod memory; +/// Stack operations (PUSH, POP, DUP, SWAP, etc.). +mod stack; +/// System information instructions (ADDRESS, CALLER, etc.). +mod system; +/// Transaction information instructions (ORIGIN, GASPRICE, etc.). +mod tx_info; +/// Utility functions and helpers for instruction implementation. +mod utility; + +/// Returns the instruction table for the given spec. +pub const fn instruction_table<'a, E: Ext>() -> [Instruction, DummyHost>; 256] +{ + use revm::bytecode::opcode::*; + let mut table = [control::unknown as Instruction, DummyHost>; 256]; + + table[STOP as usize] = control::stop; + table[ADD as usize] = arithmetic::add; + table[MUL as usize] = arithmetic::mul; + table[SUB as usize] = arithmetic::sub; + table[DIV as usize] = arithmetic::div; + table[SDIV as usize] = arithmetic::sdiv; + table[MOD as usize] = arithmetic::rem; + table[SMOD as usize] = arithmetic::smod; + table[ADDMOD as usize] = arithmetic::addmod; + table[MULMOD as usize] = arithmetic::mulmod; + table[EXP as usize] = arithmetic::exp; + table[SIGNEXTEND as usize] = arithmetic::signextend; + + table[LT as usize] = bitwise::lt; + table[GT as usize] = bitwise::gt; + table[SLT as usize] = bitwise::slt; + table[SGT as usize] = bitwise::sgt; + table[EQ as usize] = bitwise::eq; + table[ISZERO as usize] = bitwise::iszero; + table[AND as usize] = bitwise::bitand; + table[OR as usize] = bitwise::bitor; + table[XOR as usize] = bitwise::bitxor; + table[NOT as usize] = bitwise::not; + table[BYTE as usize] = bitwise::byte; + table[SHL as usize] = bitwise::shl; + table[SHR as usize] = bitwise::shr; + table[SAR as usize] = bitwise::sar; + table[CLZ as usize] = bitwise::clz; + + table[KECCAK256 as usize] = system::keccak256; + + table[ADDRESS as usize] = system::address; + table[BALANCE as usize] = host::balance; + table[ORIGIN as usize] = tx_info::origin; + table[CALLER as usize] = system::caller; + table[CALLVALUE as usize] = system::callvalue; + table[CALLDATALOAD as usize] = system::calldataload; + table[CALLDATASIZE as usize] = system::calldatasize; + table[CALLDATACOPY as usize] = system::calldatacopy; + table[CODESIZE as usize] = system::codesize; + table[CODECOPY as usize] = system::codecopy; + + table[GASPRICE as usize] = tx_info::gasprice; + table[EXTCODESIZE as usize] = host::extcodesize; + table[EXTCODECOPY as usize] = host::extcodecopy; + table[RETURNDATASIZE as usize] = system::returndatasize; + table[RETURNDATACOPY as usize] = system::returndatacopy; + table[EXTCODEHASH as usize] = host::extcodehash; + table[BLOCKHASH as usize] = host::blockhash; + table[COINBASE as usize] = block_info::coinbase; + table[TIMESTAMP as usize] = block_info::timestamp; + table[NUMBER as usize] = block_info::block_number; + table[DIFFICULTY as usize] = block_info::difficulty; + table[GASLIMIT as usize] = block_info::gaslimit; + table[CHAINID as usize] = block_info::chainid; + table[SELFBALANCE as usize] = host::selfbalance; + table[BASEFEE as usize] = block_info::basefee; + table[BLOBHASH as usize] = tx_info::blob_hash; + table[BLOBBASEFEE as usize] = block_info::blob_basefee; + + table[POP as usize] = stack::pop; + table[MLOAD as usize] = memory::mload; + table[MSTORE as usize] = memory::mstore; + table[MSTORE8 as usize] = memory::mstore8; + table[SLOAD as usize] = host::sload; + table[SSTORE as usize] = host::sstore; + table[JUMP as usize] = control::jump; + table[JUMPI as usize] = control::jumpi; + table[PC as usize] = control::pc; + table[MSIZE as usize] = memory::msize; + table[GAS as usize] = system::gas; + table[JUMPDEST as usize] = control::jumpdest; + table[TLOAD as usize] = host::tload; + table[TSTORE as usize] = host::tstore; + table[MCOPY as usize] = memory::mcopy; + + table[PUSH0 as usize] = stack::push0; + table[PUSH1 as usize] = stack::push::<1, _>; + table[PUSH2 as usize] = stack::push::<2, _>; + table[PUSH3 as usize] = stack::push::<3, _>; + table[PUSH4 as usize] = stack::push::<4, _>; + table[PUSH5 as usize] = stack::push::<5, _>; + table[PUSH6 as usize] = stack::push::<6, _>; + table[PUSH7 as usize] = stack::push::<7, _>; + table[PUSH8 as usize] = stack::push::<8, _>; + table[PUSH9 as usize] = stack::push::<9, _>; + table[PUSH10 as usize] = stack::push::<10, _>; + table[PUSH11 as usize] = stack::push::<11, _>; + table[PUSH12 as usize] = stack::push::<12, _>; + table[PUSH13 as usize] = stack::push::<13, _>; + table[PUSH14 as usize] = stack::push::<14, _>; + table[PUSH15 as usize] = stack::push::<15, _>; + table[PUSH16 as usize] = stack::push::<16, _>; + table[PUSH17 as usize] = stack::push::<17, _>; + table[PUSH18 as usize] = stack::push::<18, _>; + table[PUSH19 as usize] = stack::push::<19, _>; + table[PUSH20 as usize] = stack::push::<20, _>; + table[PUSH21 as usize] = stack::push::<21, _>; + table[PUSH22 as usize] = stack::push::<22, _>; + table[PUSH23 as usize] = stack::push::<23, _>; + table[PUSH24 as usize] = stack::push::<24, _>; + table[PUSH25 as usize] = stack::push::<25, _>; + table[PUSH26 as usize] = stack::push::<26, _>; + table[PUSH27 as usize] = stack::push::<27, _>; + table[PUSH28 as usize] = stack::push::<28, _>; + table[PUSH29 as usize] = stack::push::<29, _>; + table[PUSH30 as usize] = stack::push::<30, _>; + table[PUSH31 as usize] = stack::push::<31, _>; + table[PUSH32 as usize] = stack::push::<32, _>; + + table[DUP1 as usize] = stack::dup::<1, _>; + table[DUP2 as usize] = stack::dup::<2, _>; + table[DUP3 as usize] = stack::dup::<3, _>; + table[DUP4 as usize] = stack::dup::<4, _>; + table[DUP5 as usize] = stack::dup::<5, _>; + table[DUP6 as usize] = stack::dup::<6, _>; + table[DUP7 as usize] = stack::dup::<7, _>; + table[DUP8 as usize] = stack::dup::<8, _>; + table[DUP9 as usize] = stack::dup::<9, _>; + table[DUP10 as usize] = stack::dup::<10, _>; + table[DUP11 as usize] = stack::dup::<11, _>; + table[DUP12 as usize] = stack::dup::<12, _>; + table[DUP13 as usize] = stack::dup::<13, _>; + table[DUP14 as usize] = stack::dup::<14, _>; + table[DUP15 as usize] = stack::dup::<15, _>; + table[DUP16 as usize] = stack::dup::<16, _>; + + table[SWAP1 as usize] = stack::swap::<1, _>; + table[SWAP2 as usize] = stack::swap::<2, _>; + table[SWAP3 as usize] = stack::swap::<3, _>; + table[SWAP4 as usize] = stack::swap::<4, _>; + table[SWAP5 as usize] = stack::swap::<5, _>; + table[SWAP6 as usize] = stack::swap::<6, _>; + table[SWAP7 as usize] = stack::swap::<7, _>; + table[SWAP8 as usize] = stack::swap::<8, _>; + table[SWAP9 as usize] = stack::swap::<9, _>; + table[SWAP10 as usize] = stack::swap::<10, _>; + table[SWAP11 as usize] = stack::swap::<11, _>; + table[SWAP12 as usize] = stack::swap::<12, _>; + table[SWAP13 as usize] = stack::swap::<13, _>; + table[SWAP14 as usize] = stack::swap::<14, _>; + table[SWAP15 as usize] = stack::swap::<15, _>; + table[SWAP16 as usize] = stack::swap::<16, _>; + + table[LOG0 as usize] = host::log::<0, _>; + table[LOG1 as usize] = host::log::<1, _>; + table[LOG2 as usize] = host::log::<2, _>; + table[LOG3 as usize] = host::log::<3, _>; + table[LOG4 as usize] = host::log::<4, _>; + + table[CREATE as usize] = contract::create::; + table[CALL as usize] = contract::call; + table[CALLCODE as usize] = contract::call_code; + table[RETURN as usize] = control::ret; + table[DELEGATECALL as usize] = contract::delegate_call; + table[CREATE2 as usize] = contract::create::; + + table[STATICCALL as usize] = contract::static_call; + table[REVERT as usize] = control::revert; + table[INVALID as usize] = control::invalid; + table[SELFDESTRUCT as usize] = host::selfdestruct; + table +} + +#[cfg(test)] +mod tests { + use super::instruction_table; + use revm::bytecode::opcode::*; + + #[test] + fn all_instructions_and_opcodes_used() { + // known unknown instruction we compare it with other instructions from table. + let unknown_instruction = 0x0C_usize; + + use crate::{exec::Stack, tests::Test, ContractBlob}; + let instr_table = instruction_table::<'static, Stack<'static, Test, ContractBlob>>(); + + let unknown_istr = instr_table[unknown_instruction]; + for (i, instr) in instr_table.iter().enumerate() { + let is_opcode_unknown = OpCode::new(i as u8).is_none(); + // + let is_instr_unknown = std::ptr::fn_addr_eq(*instr, unknown_istr); + assert_eq!(is_instr_unknown, is_opcode_unknown, "Opcode 0x{i:X?} is not handled",); + } + } +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/stack.rs b/substrate/frame/revive/src/vm/evm/instructions/stack.rs new file mode 100644 index 000000000000..a632b853d534 --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/stack.rs @@ -0,0 +1,81 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::{utility::cast_slice_to_u256, Context}; +use crate::vm::Ext; +use revm::{ + interpreter::{ + gas as revm_gas, + interpreter_types::{Immediates, Jumps, RuntimeFlag, StackTr}, + InstructionResult, + }, + primitives::U256, +}; + +/// Implements the POP instruction. +/// +/// Removes the top item from the stack. +pub fn pop<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + // Can ignore return. as relative N jump is safe operation. + popn!([_i], context.interpreter); +} + +/// EIP-3855: PUSH0 instruction +/// +/// Introduce a new instruction which pushes the constant value 0 onto the stack. +pub fn push0<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, SHANGHAI); + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, U256::ZERO); +} + +/// Implements the PUSH1-PUSH32 instructions. +/// +/// Pushes N bytes from bytecode onto the stack as a 32-byte value. +pub fn push<'ext, const N: usize, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + push!(context.interpreter, U256::ZERO); + popn_top!([], top, context.interpreter); + + let imm = context.interpreter.bytecode.read_slice(N); + cast_slice_to_u256(imm, top); + + // Can ignore return. as relative N jump is safe operation + context.interpreter.bytecode.relative_jump(N as isize); +} + +/// Implements the DUP1-DUP16 instructions. +/// +/// Duplicates the Nth stack item to the top of the stack. +pub fn dup<'ext, const N: usize, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + if !context.interpreter.stack.dup(N) { + context.interpreter.halt(InstructionResult::StackOverflow); + } +} + +/// Implements the SWAP1-SWAP16 instructions. +/// +/// Swaps the top stack item with the Nth stack item. +pub fn swap<'ext, const N: usize, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + assert!(N != 0); + if !context.interpreter.stack.exchange(0, N) { + context.interpreter.halt(InstructionResult::StackOverflow); + } +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/system.rs b/substrate/frame/revive/src/vm/evm/instructions/system.rs new file mode 100644 index 000000000000..fa83212b3772 --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/system.rs @@ -0,0 +1,237 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::Context; +use crate::vm::Ext; +use core::ptr; +use revm::{ + interpreter::{ + gas as revm_gas, + interpreter_types::{InputsTr, LegacyBytecode, MemoryTr, ReturnData, RuntimeFlag, StackTr}, + CallInput, InstructionResult, Interpreter, + }, + primitives::{B256, KECCAK_EMPTY, U256}, +}; + +/// Implements the KECCAK256 instruction. +/// +/// Computes Keccak-256 hash of memory data. +pub fn keccak256<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + popn_top!([offset], top, context.interpreter); + let len = as_usize_or_fail!(context.interpreter, top); + gas_or_fail!(context.interpreter, revm_gas::keccak256_cost(len)); + let hash = if len == 0 { + KECCAK_EMPTY + } else { + let from = as_usize_or_fail!(context.interpreter, offset); + resize_memory!(context.interpreter, from, len); + let data = context.interpreter.memory.slice_len(from, len); + let data: &[u8] = data.as_ref(); + revm::primitives::keccak256(data) + }; + *top = hash.into(); +} + +/// Implements the ADDRESS instruction. +/// +/// Pushes the current contract's address onto the stack. +pub fn address<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, context.interpreter.input.target_address().into_word().into()); +} + +/// Implements the CALLER instruction. +/// +/// Pushes the caller's address onto the stack. +pub fn caller<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, context.interpreter.input.caller_address().into_word().into()); +} + +/// Implements the CODESIZE instruction. +/// +/// Pushes the size of running contract's bytecode onto the stack. +pub fn codesize<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, U256::from(context.interpreter.bytecode.bytecode_len())); +} + +/// Implements the CODECOPY instruction. +/// +/// Copies running contract's bytecode to memory. +pub fn codecopy<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + popn!([memory_offset, code_offset, len], context.interpreter); + let len = as_usize_or_fail!(context.interpreter, len); + let Some(memory_offset) = memory_resize(context.interpreter, memory_offset, len) else { + return; + }; + let code_offset = as_usize_saturated!(code_offset); + + // Note: This can't panic because we resized memory to fit. + context.interpreter.memory.set_data( + memory_offset, + code_offset, + len, + context.interpreter.bytecode.bytecode_slice(), + ); +} + +/// Implements the CALLDATALOAD instruction. +/// +/// Loads 32 bytes of input data from the specified offset. +pub fn calldataload<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + //pop_top!(interpreter, offset_ptr); + popn_top!([], offset_ptr, context.interpreter); + let mut word = B256::ZERO; + let offset = as_usize_saturated!(offset_ptr); + let input = context.interpreter.input.input(); + let input_len = input.len(); + if offset < input_len { + let count = 32.min(input_len - offset); + + // SAFETY: `count` is bounded by the calldata length. + // This is `word[..count].copy_from_slice(input[offset..offset + count])`, written using + // raw pointers as apparently the compiler cannot optimize the slice version, and using + // `get_unchecked` twice is uglier. + match context.interpreter.input.input() { + CallInput::Bytes(bytes) => { + unsafe { + ptr::copy_nonoverlapping(bytes.as_ptr().add(offset), word.as_mut_ptr(), count) + }; + }, + CallInput::SharedBuffer(range) => { + let input_slice = context.interpreter.memory.global_slice(range.clone()); + unsafe { + ptr::copy_nonoverlapping( + input_slice.as_ptr().add(offset), + word.as_mut_ptr(), + count, + ) + }; + }, + } + } + *offset_ptr = word.into(); +} + +/// Implements the CALLDATASIZE instruction. +/// +/// Pushes the size of input data onto the stack. +pub fn calldatasize<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, U256::from(context.interpreter.input.input().len())); +} + +/// Implements the CALLVALUE instruction. +/// +/// Pushes the value sent with the current call onto the stack. +pub fn callvalue<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, context.interpreter.input.call_value()); +} + +/// Implements the CALLDATACOPY instruction. +/// +/// Copies input data to memory. +pub fn calldatacopy<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + popn!([memory_offset, data_offset, len], context.interpreter); + let len = as_usize_or_fail!(context.interpreter, len); + let Some(memory_offset) = memory_resize(context.interpreter, memory_offset, len) else { + return; + }; + + let data_offset = as_usize_saturated!(data_offset); + match context.interpreter.input.input() { + CallInput::Bytes(bytes) => { + context + .interpreter + .memory + .set_data(memory_offset, data_offset, len, bytes.as_ref()); + }, + CallInput::SharedBuffer(range) => { + context.interpreter.memory.set_data_from_global( + memory_offset, + data_offset, + len, + range.clone(), + ); + }, + } +} + +/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY +pub fn returndatasize<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, BYZANTIUM); + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, U256::from(context.interpreter.return_data.buffer().len())); +} + +/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY +pub fn returndatacopy<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, BYZANTIUM); + popn!([memory_offset, offset, len], context.interpreter); + + let len = as_usize_or_fail!(context.interpreter, len); + let data_offset = as_usize_saturated!(offset); + + // Old legacy behavior is to panic if data_end is out of scope of return buffer. + let data_end = data_offset.saturating_add(len); + if data_end > context.interpreter.return_data.buffer().len() { + context.interpreter.halt(InstructionResult::OutOfOffset); + return; + } + + let Some(memory_offset) = memory_resize(context.interpreter, memory_offset, len) else { + return; + }; + + // Note: This can't panic because we resized memory to fit. + context.interpreter.memory.set_data( + memory_offset, + data_offset, + len, + context.interpreter.return_data.buffer(), + ); +} + +/// Implements the GAS instruction. +/// +/// Pushes the amount of remaining gas onto the stack. +pub fn gas<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, U256::from(context.interpreter.gas.remaining())); +} + +/// Common logic for copying data from a source buffer to the EVM's memory. +/// +/// Handles memory expansion and gas calculation for data copy operations. +pub fn memory_resize<'a, E: Ext>( + interpreter: &mut Interpreter>, + memory_offset: U256, + len: usize, +) -> Option { + // Safe to cast usize to u64 + gas_or_fail!(interpreter, revm_gas::copy_cost_verylow(len), None); + if len == 0 { + return None; + } + let memory_offset = as_usize_or_fail_ret!(interpreter, memory_offset, None); + resize_memory!(interpreter, memory_offset, len, None); + + Some(memory_offset) +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/tx_info.rs b/substrate/frame/revive/src/vm/evm/instructions/tx_info.rs new file mode 100644 index 000000000000..1b7d1196be60 --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/tx_info.rs @@ -0,0 +1,55 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use revm::{ + interpreter::{ + gas as revm_gas, + host::Host, + interpreter_types::{RuntimeFlag, StackTr}, + }, + primitives::U256, +}; + +use super::Context; +use crate::vm::Ext; + +/// Implements the GASPRICE instruction. +/// +/// Gets the gas price of the originating transaction. +pub fn gasprice<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, U256::from(context.host.effective_gas_price())); +} + +/// Implements the ORIGIN instruction. +/// +/// Gets the execution origination address. +pub fn origin<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + gas_legacy!(context.interpreter, revm_gas::BASE); + push!(context.interpreter, context.host.caller().into_word().into()); +} + +/// Implements the BLOBHASH instruction. +/// +/// EIP-4844: Shard Blob Transactions - gets the hash of a transaction blob. +pub fn blob_hash<'ext, E: Ext>(context: Context<'_, 'ext, E>) { + check!(context.interpreter, CANCUN); + gas_legacy!(context.interpreter, revm_gas::VERYLOW); + popn_top!([], index, context.interpreter); + let i = as_usize_saturated!(index); + *index = context.host.blob_hash(i).unwrap_or_default(); +} diff --git a/substrate/frame/revive/src/vm/evm/instructions/utility.rs b/substrate/frame/revive/src/vm/evm/instructions/utility.rs new file mode 100644 index 000000000000..62f77674cf4e --- /dev/null +++ b/substrate/frame/revive/src/vm/evm/instructions/utility.rs @@ -0,0 +1,128 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use revm::primitives::{Address, B256, U256}; + +/// Pushes an arbitrary length slice of bytes onto the stack, padding the last word with zeros +/// if necessary. +/// +/// # Panics +/// +/// Panics if slice is longer than 32 bytes. +#[inline] +pub fn cast_slice_to_u256(slice: &[u8], dest: &mut U256) { + if slice.is_empty() { + return; + } + assert!(slice.len() <= 32, "slice too long"); + + let n_words = slice.len().div_ceil(32); + + // SAFETY: Length checked above. + unsafe { + //let dst = self.data.as_mut_ptr().add(self.data.len()).cast::(); + //self.data.set_len(new_len); + let dst = dest.as_limbs_mut().as_mut_ptr(); + + let mut i = 0; + + // Write full words + let words = slice.chunks_exact(32); + let partial_last_word = words.remainder(); + for word in words { + // Note: We unroll `U256::from_be_bytes` here to write directly into the buffer, + // instead of creating a 32 byte array on the stack and then copying it over. + for l in word.rchunks_exact(8) { + dst.add(i).write(u64::from_be_bytes(l.try_into().unwrap())); + i += 1; + } + } + + if partial_last_word.is_empty() { + return; + } + + // Write limbs of partial last word + let limbs = partial_last_word.rchunks_exact(8); + let partial_last_limb = limbs.remainder(); + for l in limbs { + dst.add(i).write(u64::from_be_bytes(l.try_into().unwrap())); + i += 1; + } + + // Write partial last limb by padding with zeros + if !partial_last_limb.is_empty() { + let mut tmp = [0u8; 8]; + tmp[8 - partial_last_limb.len()..].copy_from_slice(partial_last_limb); + dst.add(i).write(u64::from_be_bytes(tmp)); + i += 1; + } + + debug_assert_eq!(i.div_ceil(4), n_words, "wrote too much"); + + // Zero out upper bytes of last word + let m = i % 4; // 32 / 8 + if m != 0 { + dst.add(i).write_bytes(0, 4 - m); + } + } +} + +/// Trait for converting types into U256 values. +pub trait IntoU256 { + /// Converts the implementing type into a U256 value. + fn into_u256(self) -> U256; +} + +impl IntoU256 for Address { + fn into_u256(self) -> U256 { + self.into_word().into_u256() + } +} + +impl IntoU256 for B256 { + fn into_u256(self) -> U256 { + U256::from_be_bytes(self.0) + } +} + +/// Trait for converting types into Address values. +pub trait IntoAddress { + /// Converts the implementing type into an Address value. + fn into_address(self) -> Address; +} + +impl IntoAddress for U256 { + fn into_address(self) -> Address { + Address::from_word(B256::from(self.to_be_bytes())) + } +} + +#[cfg(test)] +mod tests { + use revm::primitives::address; + + use super::*; + + #[test] + fn test_into_u256() { + let addr = address!("0x0000000000000000000000000000000000000001"); + let u256 = addr.into_u256(); + assert_eq!(u256, U256::from(0x01)); + assert_eq!(u256.into_address(), addr); + } +} diff --git a/substrate/frame/revive/src/vm/mod.rs b/substrate/frame/revive/src/vm/mod.rs index 3c65cbbfccab..b13aaeac47c1 100644 --- a/substrate/frame/revive/src/vm/mod.rs +++ b/substrate/frame/revive/src/vm/mod.rs @@ -18,6 +18,7 @@ //! This module provides a means for executing contracts //! represented in vm bytecode. +pub mod evm; pub mod pvm; mod runtime_costs; @@ -25,19 +26,23 @@ pub use runtime_costs::RuntimeCosts; use crate::{ exec::{ExecResult, Executable, ExportedFunction, Ext}, + frame_support::{ensure, error::BadOrigin, traits::tokens::Restriction}, gas::{GasMeter, Token}, + storage::meter::Diff, weights::WeightInfo, - AccountIdOf, BadOrigin, BalanceOf, CodeInfoOf, CodeVec, Config, Error, HoldReason, - PristineCode, Weight, LOG_TARGET, + AccountIdOf, BalanceOf, CodeInfoOf, CodeRemoved, Config, Error, HoldReason, PristineCode, + Weight, LOG_TARGET, }; use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ dispatch::DispatchResult, - ensure, - traits::{fungible::MutateHold, tokens::Precision::BestEffort}, + traits::{ + fungible::MutateHold, + tokens::{Fortitude, Precision, Preservation}, + }, }; -use sp_core::{H256, U256}; +use sp_core::{Get, H256, U256}; use sp_runtime::DispatchError; /// Validated Vm module ready for execution. @@ -46,7 +51,7 @@ use sp_runtime::DispatchError; #[codec(mel_bound())] #[scale_info(skip_type_params(T))] pub struct ContractBlob { - code: CodeVec, + code: Vec, // This isn't needed for contract execution and is not stored alongside it. #[codec(skip)] code_info: CodeInfo, @@ -55,6 +60,16 @@ pub struct ContractBlob { code_hash: H256, } +#[derive( + PartialEq, Eq, Debug, Copy, Clone, Encode, Decode, MaxEncodedLen, scale_info::TypeInfo, +)] +pub enum BytecodeType { + /// The code is a PVM bytecode. + Pvm, + /// The code is an EVM bytecode. + Evm, +} + /// Contract code related data, such as: /// /// - owner of the contract, i.e. account uploaded its code, @@ -62,7 +77,9 @@ pub struct ContractBlob { /// - reference count, /// /// It is stored in a separate storage entry to avoid loading the code when not necessary. -#[derive(Clone, Encode, Decode, scale_info::TypeInfo, MaxEncodedLen)] +#[derive( + frame_support::DebugNoBound, Clone, Encode, Decode, scale_info::TypeInfo, MaxEncodedLen, +)] #[codec(mel_bound())] #[scale_info(skip_type_params(T))] pub struct CodeInfo { @@ -76,6 +93,8 @@ pub struct CodeInfo { refcount: u64, /// Length of the code in bytes. code_len: u32, + /// Bytecode type + code_type: BytecodeType, /// The behaviour version that this contract operates under. /// /// Whenever any observeable change (with the exception of weights) are made we need @@ -86,6 +105,14 @@ pub struct CodeInfo { behaviour_version: u32, } +/// Calculate the deposit required for storing code and its metadata. +pub fn calculate_code_deposit(code_len: u32) -> BalanceOf { + let bytes_added = code_len.saturating_add(>::max_encoded_len() as u32); + Diff { bytes_added, items_added: 2, ..Default::default() } + .update_contract::(None) + .charge_or_zero() +} + impl ExportedFunction { /// The vm export name for the function. fn identifier(&self) -> &str { @@ -99,26 +126,39 @@ impl ExportedFunction { /// Cost of code loading from storage. #[cfg_attr(test, derive(Debug, PartialEq, Eq))] #[derive(Clone, Copy)] -struct CodeLoadToken(u32); +struct CodeLoadToken { + code_len: u32, + code_type: BytecodeType, +} + +impl CodeLoadToken { + fn from_code_info(code_info: &CodeInfo) -> Self { + Self { code_len: code_info.code_len, code_type: code_info.code_type } + } +} impl Token for CodeLoadToken { fn weight(&self) -> Weight { - // the proof size impact is accounted for in the `call_with_code_per_byte` - // strictly speaking we are double charging for the first BASIC_BLOCK_SIZE - // instructions here. Let's consider this as a safety margin. - T::WeightInfo::call_with_code_per_byte(self.0) - .saturating_sub(T::WeightInfo::call_with_code_per_byte(0)) - .saturating_add( - T::WeightInfo::basic_block_compilation(1) - .saturating_sub(T::WeightInfo::basic_block_compilation(0)) - .set_proof_size(0), - ) + match self.code_type { + // the proof size impact is accounted for in the `call_with_pvm_code_per_byte` + // strictly speaking we are double charging for the first BASIC_BLOCK_SIZE + // instructions here. Let's consider this as a safety margin. + BytecodeType::Pvm => T::WeightInfo::call_with_pvm_code_per_byte(self.code_len) + .saturating_sub(T::WeightInfo::call_with_pvm_code_per_byte(0)) + .saturating_add( + T::WeightInfo::basic_block_compilation(1) + .saturating_sub(T::WeightInfo::basic_block_compilation(0)) + .set_proof_size(0), + ), + BytecodeType::Evm => T::WeightInfo::call_with_evm_code_per_byte(self.code_len) + .saturating_sub(T::WeightInfo::call_with_evm_code_per_byte(0)), + } } } #[cfg(test)] pub fn code_load_weight(code_len: u32) -> Weight { - Token::::weight(&CodeLoadToken(code_len)) + Token::::weight(&CodeLoadToken { code_len, code_type: BytecodeType::Pvm }) } impl ContractBlob @@ -133,12 +173,15 @@ where if let Some(code_info) = existing { ensure!(code_info.refcount == 0, >::CodeInUse); ensure!(&code_info.owner == origin, BadOrigin); - let _ = T::Currency::release( + T::Currency::transfer_on_hold( &HoldReason::CodeUploadDepositReserve.into(), + &crate::Pallet::::account_id(), &code_info.owner, code_info.deposit, - BestEffort, - ); + Precision::Exact, + Restriction::Free, + Fortitude::Polite, + )?; *existing = None; >::remove(&code_hash); @@ -152,6 +195,8 @@ where /// Puts the module blob into storage, and returns the deposit collected for the storage. pub fn store_code(&mut self, skip_transfer: bool) -> Result, Error> { let code_hash = *self.code_hash(); + ensure!(code_hash != H256::zero(), >::CodeNotFound); + >::mutate(code_hash, |stored_code_info| { match stored_code_info { // Contract code is already stored in storage. Nothing to be done here. @@ -164,18 +209,22 @@ where let deposit = self.code_info.deposit; if !skip_transfer { - T::Currency::hold( - &HoldReason::CodeUploadDepositReserve.into(), - &self.code_info.owner, - deposit, - ) .map_err(|err| { + T::Currency::transfer_and_hold( + &HoldReason::CodeUploadDepositReserve.into(), + &self.code_info.owner, + &crate::Pallet::::account_id(), + deposit, + Precision::Exact, + Preservation::Preserve, + Fortitude::Polite, + ) + .map_err(|err| { log::debug!(target: LOG_TARGET, "failed to hold store code deposit {deposit:?} for owner: {:?}: {err:?}", self.code_info.owner); >::StorageDepositNotEnoughFunds })?; } - self.code_info.refcount = 0; - >::insert(code_hash, &self.code); + >::insert(code_hash, &self.code.to_vec()); *stored_code_info = Some(self.code_info.clone()); Ok(deposit) }, @@ -192,6 +241,7 @@ impl CodeInfo { deposit: Default::default(), refcount: 0, code_len: 0, + code_type: BytecodeType::Pvm, behaviour_version: Default::default(), } } @@ -212,6 +262,11 @@ impl CodeInfo { self.code_len.into() } + /// Returns true if the executable is a PVM blob. + pub fn is_pvm(&self) -> bool { + matches!(self.code_type, BytecodeType::Pvm) + } + /// Returns the number of times the specified contract exists on the call stack. Delegated calls /// Increment the reference count of a stored code by one. /// @@ -234,21 +289,32 @@ impl CodeInfo { } /// Decrement the reference count of a stored code by one. - /// - /// # Note - /// - /// A contract whose reference count dropped to zero isn't automatically removed. A - /// `remove_code` transaction must be submitted by the original uploader to do so. - pub fn decrement_refcount(code_hash: H256) -> DispatchResult { - >::mutate(code_hash, |existing| { - if let Some(info) = existing { - info.refcount = info + /// Remove the code from storage when the reference count is zero. + pub fn decrement_refcount(code_hash: H256) -> Result { + >::try_mutate_exists(code_hash, |existing| { + let Some(code_info) = existing else { return Err(Error::::CodeNotFound.into()) }; + + if code_info.refcount == 1 { + T::Currency::transfer_on_hold( + &HoldReason::CodeUploadDepositReserve.into(), + &crate::Pallet::::account_id(), + &code_info.owner, + code_info.deposit, + Precision::Exact, + Restriction::Free, + Fortitude::Polite, + )?; + + *existing = None; + >::remove(&code_hash); + + Ok(CodeRemoved::Yes) + } else { + code_info.refcount = code_info .refcount .checked_sub(1) .ok_or_else(|| >::RefcountOverOrUnderflow)?; - Ok(()) - } else { - Err(Error::::CodeNotFound.into()) + Ok(CodeRemoved::No) } }) } @@ -260,7 +326,7 @@ where { fn from_storage(code_hash: H256, gas_meter: &mut GasMeter) -> Result { let code_info = >::get(code_hash).ok_or(Error::::CodeNotFound)?; - gas_meter.charge(CodeLoadToken(code_info.code_len))?; + gas_meter.charge(CodeLoadToken::from_code_info(&code_info))?; let code = >::get(&code_hash).ok_or(Error::::CodeNotFound)?; Ok(Self { code, code_info, code_hash }) } @@ -271,10 +337,16 @@ where function: ExportedFunction, input_data: Vec, ) -> ExecResult { - if self.is_pvm() { + if self.code_info().is_pvm() { let prepared_call = self.prepare_call(pvm::Runtime::new(ext, input_data), function, 0)?; prepared_call.call() + } else if T::AllowEVMBytecode::get() { + use crate::vm::evm::EVMInputs; + use revm::bytecode::Bytecode; + let inputs = EVMInputs::new(input_data); + let bytecode = Bytecode::new_raw(self.code.into()); + evm::call(bytecode, ext, inputs) } else { Err(Error::::CodeRejected.into()) } diff --git a/substrate/frame/revive/src/vm/pvm.rs b/substrate/frame/revive/src/vm/pvm.rs index b0a2ed8264b2..d9229eb00c0c 100644 --- a/substrate/frame/revive/src/vm/pvm.rs +++ b/substrate/frame/revive/src/vm/pvm.rs @@ -39,6 +39,14 @@ use pallet_revive_uapi::{CallFlags, ReturnErrorCode, ReturnFlags, StorageFlags}; use sp_core::{H160, H256, U256}; use sp_runtime::{DispatchError, RuntimeDebug}; +/// Extracts the code and data from a given program blob. +pub fn extract_code_and_data(data: &[u8]) -> Option<(Vec, Vec)> { + let blob_len = polkavm::ProgramBlob::blob_length(data)?; + let blob_len = blob_len.try_into().ok()?; + let (code, data) = data.split_at_checked(blob_len)?; + Some((code.to_vec(), data.to_vec())) +} + /// Abstraction over the memory access within syscalls. /// /// The reason for this abstraction is that we run syscalls on the host machine when diff --git a/substrate/frame/revive/src/vm/pvm/env.rs b/substrate/frame/revive/src/vm/pvm/env.rs index 0255670a4f52..fe0572126856 100644 --- a/substrate/frame/revive/src/vm/pvm/env.rs +++ b/substrate/frame/revive/src/vm/pvm/env.rs @@ -22,12 +22,11 @@ use crate::{ exec::Ext, limits, primitives::ExecReturnValue, - storage::meter::Diff, - vm::{ExportedFunction, RuntimeCosts}, + vm::{calculate_code_deposit, BytecodeType, ExportedFunction, RuntimeCosts}, AccountIdOf, BalanceOf, CodeInfo, Config, ContractBlob, Error, Weight, SENTINEL, }; use alloc::vec::Vec; -use codec::{Encode, MaxEncodedLen}; +use codec::Encode; use core::mem; use frame_support::traits::Get; use pallet_revive_proc_macro::define_env; @@ -66,11 +65,11 @@ impl ContractBlob { module_config.set_gas_metering(Some(polkavm::GasMeteringKind::Sync)); module_config.set_allow_sbrk(false); module_config.set_aux_data_size(aux_data_size); - let module = polkavm::Module::new(&engine, &module_config, self.code.into_inner().into()) - .map_err(|err| { - log::debug!(target: LOG_TARGET, "failed to create polkavm module: {err:?}"); - Error::::CodeRejected - })?; + let module = + polkavm::Module::new(&engine, &module_config, self.code.into()).map_err(|err| { + log::debug!(target: LOG_TARGET, "failed to create polkavm module: {err:?}"); + Error::::CodeRejected + })?; let entry_program_counter = module .exports() @@ -112,15 +111,14 @@ where let code = limits::code::enforce::(code, available_syscalls)?; let code_len = code.len() as u32; - let bytes_added = code_len.saturating_add(>::max_encoded_len() as u32); - let deposit = Diff { bytes_added, items_added: 2, ..Default::default() } - .update_contract::(None) - .charge_or_zero(); + let deposit = calculate_code_deposit::(code_len); + let code_info = CodeInfo { owner, deposit, refcount: 0, code_len, + code_type: BytecodeType::Pvm, behaviour_version: Default::default(), }; let code_hash = H256(sp_io::hashing::keccak_256(&code)); @@ -957,9 +955,11 @@ pub mod env { /// the immutable data of the new code hash. #[mutating] fn set_code_hash(&mut self, memory: &mut M, code_hash_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::SetCodeHash)?; + let charged = self.charge_gas(RuntimeCosts::SetCodeHash { old_code_removed: true })?; let code_hash: H256 = memory.read_h256(code_hash_ptr)?; - self.ext.set_code_hash(code_hash)?; + if matches!(self.ext.set_code_hash(code_hash)?, crate::CodeRemoved::No) { + self.adjust_gas(charged, RuntimeCosts::SetCodeHash { old_code_removed: false }); + } Ok(()) } @@ -1009,9 +1009,11 @@ pub mod env { /// See [`pallet_revive_uapi::HostFn::terminate`]. #[mutating] fn terminate(&mut self, memory: &mut M, beneficiary_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::Terminate)?; + let charged = self.charge_gas(RuntimeCosts::Terminate { code_removed: true })?; let beneficiary = memory.read_h160(beneficiary_ptr)?; - self.ext.terminate(&beneficiary)?; + if matches!(self.ext.terminate(&beneficiary)?, crate::CodeRemoved::No) { + self.adjust_gas(charged, RuntimeCosts::Terminate { code_removed: false }); + } Err(TrapReason::Termination) } diff --git a/substrate/frame/revive/src/vm/runtime_costs.rs b/substrate/frame/revive/src/vm/runtime_costs.rs index 7c71a1bb1b93..44fc68ab5e11 100644 --- a/substrate/frame/revive/src/vm/runtime_costs.rs +++ b/substrate/frame/revive/src/vm/runtime_costs.rs @@ -48,7 +48,7 @@ pub enum RuntimeCosts { CallDataSize, /// Weight of calling `seal_return_data_size`. ReturnDataSize, - /// Weight of calling `seal_to_account_id`. + /// Weight of calling `to_account_id`. ToAccountId, /// Weight of calling `seal_origin`. Origin, @@ -93,7 +93,7 @@ pub enum RuntimeCosts { /// Weight of calling `seal_weight_to_fee`. WeightToFee, /// Weight of calling `seal_terminate`. - Terminate, + Terminate { code_removed: bool }, /// Weight of calling `seal_deposit_event` with the given number of topics and event size. DepositEvent { num_topic: u32, len: u32 }, /// Weight of calling `seal_set_storage` for the given storage item sizes. @@ -151,7 +151,7 @@ pub enum RuntimeCosts { /// Weight charged by a precompile. Precompile(Weight), /// Weight of calling `seal_set_code_hash` - SetCodeHash, + SetCodeHash { old_code_removed: bool }, /// Weight of calling `ecdsa_to_eth_address` EcdsaToEthAddress, /// Weight of calling `get_immutable_dependency` @@ -233,7 +233,7 @@ impl Token for RuntimeCosts { CallDataCopy(len) => T::WeightInfo::seal_call_data_copy(len), Caller => T::WeightInfo::seal_caller(), Origin => T::WeightInfo::seal_origin(), - ToAccountId => T::WeightInfo::seal_to_account_id(), + ToAccountId => T::WeightInfo::to_account_id(), CodeHash => T::WeightInfo::seal_code_hash(), CodeSize => T::WeightInfo::seal_code_size(), OwnCodeHash => T::WeightInfo::seal_own_code_hash(), @@ -254,7 +254,7 @@ impl Token for RuntimeCosts { Now => T::WeightInfo::seal_now(), GasLimit => T::WeightInfo::seal_gas_limit(), WeightToFee => T::WeightInfo::seal_weight_to_fee(), - Terminate => T::WeightInfo::seal_terminate(), + Terminate { code_removed } => T::WeightInfo::seal_terminate(code_removed.into()), DepositEvent { num_topic, len } => T::WeightInfo::seal_deposit_event(num_topic, len), SetStorage { new_bytes, old_bytes } => { cost_storage!(write, seal_set_storage, new_bytes, old_bytes) @@ -300,7 +300,8 @@ impl Token for RuntimeCosts { EcdsaRecovery => T::WeightInfo::ecdsa_recover(), Sr25519Verify(len) => T::WeightInfo::seal_sr25519_verify(len), Precompile(weight) => weight, - SetCodeHash => T::WeightInfo::seal_set_code_hash(), + SetCodeHash { old_code_removed } => + T::WeightInfo::seal_set_code_hash(old_code_removed.into()), EcdsaToEthAddress => T::WeightInfo::seal_ecdsa_to_eth_address(), GetImmutableData(len) => T::WeightInfo::seal_get_immutable_data(len), SetImmutableData(len) => T::WeightInfo::seal_set_immutable_data(len), diff --git a/substrate/frame/revive/src/weights.rs b/substrate/frame/revive/src/weights.rs index caccdd672ae9..7a2f46555c7f 100644 --- a/substrate/frame/revive/src/weights.rs +++ b/substrate/frame/revive/src/weights.rs @@ -35,9 +35,9 @@ //! Autogenerated weights for `pallet_revive` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-08-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-08-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `c19fa2715a10`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `63d21d694e5f`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024` // Executed Command: @@ -73,7 +73,8 @@ use core::marker::PhantomData; pub trait WeightInfo { fn on_process_deletion_queue_batch() -> Weight; fn on_initialize_per_trie_key(k: u32, ) -> Weight; - fn call_with_code_per_byte(c: u32, ) -> Weight; + fn call_with_pvm_code_per_byte(c: u32, ) -> Weight; + fn call_with_evm_code_per_byte(c: u32, ) -> Weight; fn basic_block_compilation(b: u32, ) -> Weight; fn instantiate_with_code(c: u32, i: u32, ) -> Weight; fn eth_instantiate_with_code(c: u32, i: u32, d: u32, ) -> Weight; @@ -89,7 +90,7 @@ pub trait WeightInfo { fn noop_host_fn(r: u32, ) -> Weight; fn seal_caller() -> Weight; fn seal_origin() -> Weight; - fn seal_to_account_id() -> Weight; + fn to_account_id() -> Weight; fn seal_code_hash() -> Weight; fn seal_own_code_hash() -> Weight; fn seal_code_size() -> Weight; @@ -118,7 +119,7 @@ pub trait WeightInfo { fn seal_call_data_load() -> Weight; fn seal_call_data_copy(n: u32, ) -> Weight; fn seal_return(n: u32, ) -> Weight; - fn seal_terminate() -> Weight; + fn seal_terminate(r: u32, ) -> Weight; fn seal_deposit_event(t: u32, n: u32, ) -> Weight; fn get_storage_empty() -> Weight; fn get_storage_full() -> Weight; @@ -144,11 +145,11 @@ pub trait WeightInfo { fn seal_delegate_call() -> Weight; fn seal_instantiate(t: u32, d: u32, i: u32, ) -> Weight; fn sha2_256(n: u32, ) -> Weight; - fn hash_blake2_256(n: u32, ) -> Weight; - fn hash_blake2_128(n: u32, ) -> Weight; fn identity(n: u32, ) -> Weight; fn ripemd_160(n: u32, ) -> Weight; fn seal_hash_keccak_256(n: u32, ) -> Weight; + fn hash_blake2_256(n: u32, ) -> Weight; + fn hash_blake2_128(n: u32, ) -> Weight; fn seal_sr25519_verify(n: u32, ) -> Weight; fn ecdsa_recover() -> Weight; fn bn128_add() -> Weight; @@ -156,10 +157,12 @@ pub trait WeightInfo { fn bn128_pairing(n: u32, ) -> Weight; fn blake2f(n: u32, ) -> Weight; fn seal_ecdsa_to_eth_address() -> Weight; - fn seal_set_code_hash() -> Weight; + fn seal_set_code_hash(r: u32, ) -> Weight; + fn evm_opcode(r: u32, ) -> Weight; fn instr(r: u32, ) -> Weight; fn instr_empty_loop(r: u32, ) -> Weight; fn v1_migration_step() -> Weight; + fn v2_migration_step() -> Weight; } /// Weights for `pallet_revive` using the Substrate node and recommended hardware. @@ -171,8 +174,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `147` // Estimated: `1632` - // Minimum execution time: 3_008_000 picoseconds. - Weight::from_parts(3_256_000, 1632) + // Minimum execution time: 3_146_000 picoseconds. + Weight::from_parts(3_400_000, 1632) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -182,10 +185,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `458 + k * (69 ±0)` // Estimated: `448 + k * (70 ±0)` - // Minimum execution time: 14_584_000 picoseconds. - Weight::from_parts(772_449, 448) - // Standard Error: 1_278 - .saturating_add(Weight::from_parts(1_204_643, 0).saturating_mul(k.into())) + // Minimum execution time: 14_245_000 picoseconds. + Weight::from_parts(14_708_000, 448) + // Standard Error: 830 + .saturating_add(Weight::from_parts(1_175_004, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -197,22 +200,22 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Revive::AccountInfoOf` (r:1 w:1) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// The range of component `c` is `[0, 102400]`. - fn call_with_code_per_byte(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1171 + c * (1 ±0)` - // Estimated: `7106 + c * (1 ±0)` - // Minimum execution time: 86_230_000 picoseconds. - Weight::from_parts(124_424_225, 7106) - // Standard Error: 10 - .saturating_add(Weight::from_parts(1_256, 0).saturating_mul(c.into())) + fn call_with_pvm_code_per_byte(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1172 + c * (1 ±0)` + // Estimated: `7107 + c * (1 ±0)` + // Minimum execution time: 86_441_000 picoseconds. + Weight::from_parts(123_780_707, 7107) + // Standard Error: 11 + .saturating_add(Weight::from_parts(1_438, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -222,9 +225,33 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Revive::AccountInfoOf` (r:1 w:1) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) + /// Storage: `Revive::PristineCode` (r:1 w:0) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Timestamp::Now` (r:1 w:0) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// The range of component `c` is `[1, 10240]`. + fn call_with_evm_code_per_byte(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1112` + // Estimated: `7051` + // Minimum execution time: 81_282_000 picoseconds. + Weight::from_parts(85_248_488, 7051) + // Standard Error: 21 + .saturating_add(Weight::from_parts(36, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Revive::OriginalAccount` (r:2 w:0) + /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) + /// Storage: `Revive::AccountInfoOf` (r:1 w:1) + /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) + /// Storage: `Revive::CodeInfoOf` (r:1 w:0) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) @@ -232,15 +259,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `b` is `[0, 1]`. fn basic_block_compilation(_b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `4515` - // Estimated: `10455` - // Minimum execution time: 124_359_000 picoseconds. - Weight::from_parts(129_025_585, 10455) + // Measured: `4516` + // Estimated: `10456` + // Minimum execution time: 124_393_000 picoseconds. + Weight::from_parts(129_685_861, 10456) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Balances::Holds` (r:2 w:2) /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) /// Storage: `Revive::OriginalAccount` (r:1 w:0) @@ -252,24 +279,24 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:0 w:1) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `c` is `[0, 102400]`. /// The range of component `i` is `[0, 131072]`. fn instantiate_with_code(c: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1108` - // Estimated: `7041` - // Minimum execution time: 755_622_000 picoseconds. - Weight::from_parts(57_161_132, 7041) - // Standard Error: 36 - .saturating_add(Weight::from_parts(19_425, 0).saturating_mul(c.into())) - // Standard Error: 28 - .saturating_add(Weight::from_parts(5_000, 0).saturating_mul(i.into())) + // Measured: `1171` + // Estimated: `7104` + // Minimum execution time: 762_496_000 picoseconds. + Weight::from_parts(55_020_008, 7104) + // Standard Error: 44 + .saturating_add(Weight::from_parts(20_306, 0).saturating_mul(c.into())) + // Standard Error: 35 + .saturating_add(Weight::from_parts(5_068, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Balances::Holds` (r:2 w:2) /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) /// Storage: `Revive::OriginalAccount` (r:1 w:0) @@ -281,22 +308,22 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:0 w:1) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `c` is `[0, 102400]`. /// The range of component `i` is `[0, 131072]`. /// The range of component `d` is `[0, 1]`. fn eth_instantiate_with_code(c: u32, i: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1122` - // Estimated: `7062 + d * (2475 ±0)` - // Minimum execution time: 281_326_000 picoseconds. - Weight::from_parts(192_766_004, 7062) - // Standard Error: 15 - .saturating_add(Weight::from_parts(14_166, 0).saturating_mul(c.into())) - // Standard Error: 11 - .saturating_add(Weight::from_parts(403, 0).saturating_mul(i.into())) - // Standard Error: 983_169 - .saturating_add(Weight::from_parts(30_340_467, 0).saturating_mul(d.into())) + // Measured: `1185` + // Estimated: `7125 + d * (2475 ±0)` + // Minimum execution time: 284_562_000 picoseconds. + Weight::from_parts(163_089_642, 7125) + // Standard Error: 34 + .saturating_add(Weight::from_parts(15_162, 0).saturating_mul(c.into())) + // Standard Error: 27 + .saturating_add(Weight::from_parts(514, 0).saturating_mul(i.into())) + // Standard Error: 2_273_714 + .saturating_add(Weight::from_parts(38_746_748, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(d.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -304,9 +331,9 @@ impl WeightInfo for SubstrateWeight { .saturating_add(Weight::from_parts(0, 2475).saturating_mul(d.into())) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) /// Storage: `Revive::AccountInfoOf` (r:1 w:1) @@ -320,12 +347,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 131072]`. fn instantiate(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1912` - // Estimated: `5362` - // Minimum execution time: 172_513_000 picoseconds. - Weight::from_parts(178_290_134, 5362) + // Measured: `1913` + // Estimated: `5339` + // Minimum execution time: 171_348_000 picoseconds. + Weight::from_parts(176_612_673, 5339) // Standard Error: 11 - .saturating_add(Weight::from_parts(4_158, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(4_290, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -334,19 +361,19 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Revive::AccountInfoOf` (r:1 w:1) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `1792` - // Estimated: `7732` - // Minimum execution time: 87_638_000 picoseconds. - Weight::from_parts(90_000_000, 7732) + // Measured: `1794` + // Estimated: `7734` + // Minimum execution time: 88_764_000 picoseconds. + Weight::from_parts(93_353_000, 7734) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -355,9 +382,9 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Revive::AccountInfoOf` (r:2 w:2) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) @@ -365,12 +392,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `d` is `[0, 1]`. fn eth_call(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1792` - // Estimated: `7732 + d * (2475 ±0)` - // Minimum execution time: 85_839_000 picoseconds. - Weight::from_parts(90_556_373, 7732) - // Standard Error: 358_297 - .saturating_add(Weight::from_parts(27_649_126, 0).saturating_mul(d.into())) + // Measured: `1794` + // Estimated: `7734 + d * (2475 ±0)` + // Minimum execution time: 86_142_000 picoseconds. + Weight::from_parts(90_482_761, 7734) + // Standard Error: 430_134 + .saturating_add(Weight::from_parts(30_624_838, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(d.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -378,50 +405,56 @@ impl WeightInfo for SubstrateWeight { .saturating_add(Weight::from_parts(0, 2475).saturating_mul(d.into())) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:0 w:1) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `c` is `[0, 102400]`. fn upload_code(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `3970` - // Minimum execution time: 56_805_000 picoseconds. - Weight::from_parts(50_855_179, 3970) - // Standard Error: 35 - .saturating_add(Weight::from_parts(13_927, 0).saturating_mul(c.into())) + // Measured: `606` + // Estimated: `4071` + // Minimum execution time: 57_080_000 picoseconds. + Weight::from_parts(49_101_825, 4071) + // Standard Error: 18 + .saturating_add(Weight::from_parts(14_610, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:0 w:1) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) fn remove_code() -> Weight { // Proof Size summary in bytes: - // Measured: `658` - // Estimated: `4123` - // Minimum execution time: 47_344_000 picoseconds. - Weight::from_parts(48_892_000, 4123) + // Measured: `760` + // Estimated: `4225` + // Minimum execution time: 53_084_000 picoseconds. + Weight::from_parts(54_573_000, 4225) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Revive::AccountInfoOf` (r:1 w:1) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:2 w:2) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Revive::PristineCode` (r:0 w:1) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `530` - // Estimated: `6470` - // Minimum execution time: 20_627_000 picoseconds. - Weight::from_parts(21_451_000, 6470) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Measured: `1095` + // Estimated: `7035` + // Minimum execution time: 65_666_000 picoseconds. + Weight::from_parts(67_373_000, 7035) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Revive::OriginalAccount` (r:1 w:1) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) @@ -431,8 +464,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `813` // Estimated: `4278` - // Minimum execution time: 57_209_000 picoseconds. - Weight::from_parts(58_942_000, 4278) + // Minimum execution time: 55_888_000 picoseconds. + Weight::from_parts(57_747_000, 4278) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -444,8 +477,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3860` - // Minimum execution time: 42_757_000 picoseconds. - Weight::from_parts(44_178_000, 3860) + // Minimum execution time: 42_171_000 picoseconds. + Weight::from_parts(43_198_000, 3860) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -457,8 +490,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 13_062_000 picoseconds. - Weight::from_parts(13_660_000, 3610) + // Minimum execution time: 13_030_000 picoseconds. + Weight::from_parts(13_365_000, 3610) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -466,33 +499,33 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_588_000 picoseconds. - Weight::from_parts(8_755_261, 0) - // Standard Error: 236 - .saturating_add(Weight::from_parts(182_421, 0).saturating_mul(r.into())) + // Minimum execution time: 7_473_000 picoseconds. + Weight::from_parts(8_474_805, 0) + // Standard Error: 322 + .saturating_add(Weight::from_parts(178_929, 0).saturating_mul(r.into())) } fn seal_caller() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 335_000 picoseconds. - Weight::from_parts(390_000, 0) + // Minimum execution time: 355_000 picoseconds. + Weight::from_parts(397_000, 0) } fn seal_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 350_000 picoseconds. - Weight::from_parts(386_000, 0) + // Minimum execution time: 318_000 picoseconds. + Weight::from_parts(362_000, 0) } /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) - fn seal_to_account_id() -> Weight { + fn to_account_id() -> Weight { // Proof Size summary in bytes: - // Measured: `571` - // Estimated: `4036` - // Minimum execution time: 9_818_000 picoseconds. - Weight::from_parts(10_279_000, 4036) + // Measured: `567` + // Estimated: `4032` + // Minimum execution time: 7_507_000 picoseconds. + Weight::from_parts(8_064_000, 4032) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Revive::AccountInfoOf` (r:1 w:0) @@ -501,70 +534,70 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `403` // Estimated: `3868` - // Minimum execution time: 9_222_000 picoseconds. - Weight::from_parts(9_806_000, 3868) + // Minimum execution time: 9_458_000 picoseconds. + Weight::from_parts(10_105_000, 3868) .saturating_add(T::DbWeight::get().reads(1_u64)) } fn seal_own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 282_000 picoseconds. - Weight::from_parts(336_000, 0) + // Minimum execution time: 317_000 picoseconds. + Weight::from_parts(355_000, 0) } /// Storage: `Revive::AccountInfoOf` (r:1 w:0) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) fn seal_code_size() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `3939` - // Minimum execution time: 12_825_000 picoseconds. - Weight::from_parts(13_490_000, 3939) + // Measured: `475` + // Estimated: `3940` + // Minimum execution time: 13_105_000 picoseconds. + Weight::from_parts(13_354_000, 3940) .saturating_add(T::DbWeight::get().reads(2_u64)) } fn seal_caller_is_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 321_000 picoseconds. - Weight::from_parts(372_000, 0) + // Minimum execution time: 331_000 picoseconds. + Weight::from_parts(381_000, 0) } fn seal_caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 269_000 picoseconds. - Weight::from_parts(327_000, 0) + // Minimum execution time: 307_000 picoseconds. + Weight::from_parts(336_000, 0) } fn seal_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 304_000 picoseconds. - Weight::from_parts(343_000, 0) + // Minimum execution time: 323_000 picoseconds. + Weight::from_parts(368_000, 0) } fn seal_weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 700_000 picoseconds. - Weight::from_parts(802_000, 0) + // Minimum execution time: 701_000 picoseconds. + Weight::from_parts(785_000, 0) } fn seal_ref_time_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 263_000 picoseconds. - Weight::from_parts(325_000, 0) + // Minimum execution time: 278_000 picoseconds. + Weight::from_parts(334_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `506` + // Measured: `540` // Estimated: `0` - // Minimum execution time: 13_351_000 picoseconds. - Weight::from_parts(13_878_000, 0) + // Minimum execution time: 12_890_000 picoseconds. + Weight::from_parts(13_471_000, 0) } /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) @@ -576,8 +609,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `791` // Estimated: `4256` - // Minimum execution time: 18_603_000 picoseconds. - Weight::from_parts(19_511_000, 4256) + // Minimum execution time: 18_523_000 picoseconds. + Weight::from_parts(19_059_000, 4256) .saturating_add(T::DbWeight::get().reads(3_u64)) } /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) @@ -587,10 +620,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `271 + n * (1 ±0)` // Estimated: `3736 + n * (1 ±0)` - // Minimum execution time: 6_013_000 picoseconds. - Weight::from_parts(6_757_699, 3736) + // Minimum execution time: 6_027_000 picoseconds. + Weight::from_parts(6_736_994, 3736) // Standard Error: 5 - .saturating_add(Weight::from_parts(483, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(592, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -601,67 +634,67 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_052_000 picoseconds. - Weight::from_parts(2_330_454, 0) + // Minimum execution time: 2_033_000 picoseconds. + Weight::from_parts(2_294_007, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(525, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(565, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn seal_value_transferred() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 259_000 picoseconds. - Weight::from_parts(331_000, 0) + // Minimum execution time: 276_000 picoseconds. + Weight::from_parts(323_000, 0) } fn seal_minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 278_000 picoseconds. - Weight::from_parts(339_000, 0) + // Minimum execution time: 273_000 picoseconds. + Weight::from_parts(325_000, 0) } fn seal_return_data_size() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 272_000 picoseconds. - Weight::from_parts(326_000, 0) + // Minimum execution time: 265_000 picoseconds. + Weight::from_parts(302_000, 0) } fn seal_call_data_size() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 268_000 picoseconds. - Weight::from_parts(313_000, 0) + // Minimum execution time: 279_000 picoseconds. + Weight::from_parts(353_000, 0) } fn seal_gas_limit() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 436_000 picoseconds. - Weight::from_parts(509_000, 0) + // Minimum execution time: 518_000 picoseconds. + Weight::from_parts(572_000, 0) } fn seal_gas_price() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 262_000 picoseconds. - Weight::from_parts(317_000, 0) + // Minimum execution time: 308_000 picoseconds. + Weight::from_parts(339_000, 0) } fn seal_base_fee() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 289_000 picoseconds. - Weight::from_parts(347_000, 0) + // Minimum execution time: 283_000 picoseconds. + Weight::from_parts(315_000, 0) } fn seal_block_number() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 305_000 picoseconds. - Weight::from_parts(358_000, 0) + // Minimum execution time: 300_000 picoseconds. + Weight::from_parts(334_000, 0) } /// Storage: `Session::Validators` (r:1 w:0) /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -669,8 +702,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `141` // Estimated: `1626` - // Minimum execution time: 22_975_000 picoseconds. - Weight::from_parts(23_506_000, 1626) + // Minimum execution time: 22_163_000 picoseconds. + Weight::from_parts(22_643_000, 1626) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `System::BlockHash` (r:1 w:0) @@ -679,79 +712,91 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `30` // Estimated: `3495` - // Minimum execution time: 3_631_000 picoseconds. - Weight::from_parts(3_829_000, 3495) + // Minimum execution time: 3_625_000 picoseconds. + Weight::from_parts(3_850_000, 3495) .saturating_add(T::DbWeight::get().reads(1_u64)) } fn seal_now() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 271_000 picoseconds. - Weight::from_parts(337_000, 0) + // Minimum execution time: 293_000 picoseconds. + Weight::from_parts(349_000, 0) } fn seal_weight_to_fee() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_603_000 picoseconds. - Weight::from_parts(1_712_000, 0) + // Minimum execution time: 1_597_000 picoseconds. + Weight::from_parts(1_720_000, 0) } /// The range of component `n` is `[0, 1048572]`. fn seal_copy_to_contract(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 433_000 picoseconds. - Weight::from_parts(460_000, 0) + // Minimum execution time: 425_000 picoseconds. + Weight::from_parts(437_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(203, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(239, 0).saturating_mul(n.into())) } fn seal_call_data_load() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 293_000 picoseconds. - Weight::from_parts(325_000, 0) + // Minimum execution time: 277_000 picoseconds. + Weight::from_parts(313_000, 0) } /// The range of component `n` is `[0, 1048576]`. fn seal_call_data_copy(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 269_000 picoseconds. - Weight::from_parts(806_378, 0) + // Minimum execution time: 257_000 picoseconds. + Weight::from_parts(288_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(112, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(150, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 131072]`. fn seal_return(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 290_000 picoseconds. - Weight::from_parts(488_982, 0) + // Minimum execution time: 315_000 picoseconds. + Weight::from_parts(476_627, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(201, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(238, 0).saturating_mul(n.into())) } /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) /// Storage: `Revive::DeletionQueueCounter` (r:1 w:1) /// Proof: `Revive::DeletionQueueCounter` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Revive::DeletionQueue` (r:0 w:1) /// Proof: `Revive::DeletionQueue` (`max_values`: None, `max_size`: Some(142), added: 2617, mode: `Measured`) + /// Storage: `Revive::PristineCode` (r:0 w:1) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Revive::ImmutableDataOf` (r:0 w:1) /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) - fn seal_terminate() -> Weight { - // Proof Size summary in bytes: - // Measured: `582` - // Estimated: `4047` - // Minimum execution time: 17_674_000 picoseconds. - Weight::from_parts(18_031_000, 4047) + /// The range of component `r` is `[0, 1]`. + fn seal_terminate(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `583 + r * (670 ±0)` + // Estimated: `4048 + r * (2359 ±0)` + // Minimum execution time: 16_560_000 picoseconds. + Weight::from_parts(17_630_489, 4048) + // Standard Error: 66_463 + .saturating_add(Weight::from_parts(46_618_510, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 2359).saturating_mul(r.into())) } /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 416]`. @@ -759,12 +804,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_375_000 picoseconds. - Weight::from_parts(4_568_155, 0) - // Standard Error: 3_591 - .saturating_add(Weight::from_parts(223_460, 0).saturating_mul(t.into())) - // Standard Error: 39 - .saturating_add(Weight::from_parts(854, 0).saturating_mul(n.into())) + // Minimum execution time: 4_523_000 picoseconds. + Weight::from_parts(4_505_303, 0) + // Standard Error: 3_656 + .saturating_add(Weight::from_parts(240_684, 0).saturating_mul(t.into())) + // Standard Error: 40 + .saturating_add(Weight::from_parts(1_232, 0).saturating_mul(n.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -772,8 +817,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `648` // Estimated: `648` - // Minimum execution time: 7_272_000 picoseconds. - Weight::from_parts(7_635_000, 648) + // Minimum execution time: 7_228_000 picoseconds. + Weight::from_parts(7_734_000, 648) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -782,8 +827,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `10658` // Estimated: `10658` - // Minimum execution time: 41_207_000 picoseconds. - Weight::from_parts(41_863_000, 10658) + // Minimum execution time: 41_276_000 picoseconds. + Weight::from_parts(42_310_000, 10658) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -792,8 +837,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `648` // Estimated: `648` - // Minimum execution time: 8_492_000 picoseconds. - Weight::from_parts(9_013_000, 648) + // Minimum execution time: 8_396_000 picoseconds. + Weight::from_parts(8_776_000, 648) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -803,8 +848,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `10658` // Estimated: `10658` - // Minimum execution time: 42_398_000 picoseconds. - Weight::from_parts(44_113_000, 10658) + // Minimum execution time: 42_661_000 picoseconds. + Weight::from_parts(44_266_000, 10658) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -816,12 +861,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + o * (1 ±0)` // Estimated: `247 + o * (1 ±0)` - // Minimum execution time: 8_728_000 picoseconds. - Weight::from_parts(9_632_969, 247) - // Standard Error: 56 - .saturating_add(Weight::from_parts(556, 0).saturating_mul(n.into())) - // Standard Error: 56 - .saturating_add(Weight::from_parts(958, 0).saturating_mul(o.into())) + // Minimum execution time: 8_864_000 picoseconds. + Weight::from_parts(9_769_026, 247) + // Standard Error: 67 + .saturating_add(Weight::from_parts(81, 0).saturating_mul(n.into())) + // Standard Error: 67 + .saturating_add(Weight::from_parts(866, 0).saturating_mul(o.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(o.into())) @@ -833,10 +878,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 9_032_000 picoseconds. - Weight::from_parts(9_816_471, 247) - // Standard Error: 82 - .saturating_add(Weight::from_parts(582, 0).saturating_mul(n.into())) + // Minimum execution time: 8_552_000 picoseconds. + Weight::from_parts(9_609_466, 247) + // Standard Error: 88 + .saturating_add(Weight::from_parts(789, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -848,10 +893,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_313_000 picoseconds. - Weight::from_parts(9_381_907, 247) - // Standard Error: 91 - .saturating_add(Weight::from_parts(1_184, 0).saturating_mul(n.into())) + // Minimum execution time: 8_101_000 picoseconds. + Weight::from_parts(9_115_278, 247) + // Standard Error: 75 + .saturating_add(Weight::from_parts(1_381, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -862,10 +907,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 7_645_000 picoseconds. - Weight::from_parts(8_714_974, 247) - // Standard Error: 87 - .saturating_add(Weight::from_parts(717, 0).saturating_mul(n.into())) + // Minimum execution time: 7_594_000 picoseconds. + Weight::from_parts(8_575_324, 247) + // Standard Error: 78 + .saturating_add(Weight::from_parts(635, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -876,10 +921,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 9_388_000 picoseconds. - Weight::from_parts(10_430_193, 247) - // Standard Error: 77 - .saturating_add(Weight::from_parts(1_346, 0).saturating_mul(n.into())) + // Minimum execution time: 9_130_000 picoseconds. + Weight::from_parts(10_301_501, 247) + // Standard Error: 85 + .saturating_add(Weight::from_parts(1_584, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -888,36 +933,36 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_597_000 picoseconds. - Weight::from_parts(1_691_000, 0) + // Minimum execution time: 1_553_000 picoseconds. + Weight::from_parts(1_678_000, 0) } fn set_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_005_000 picoseconds. - Weight::from_parts(2_129_000, 0) + // Minimum execution time: 1_962_000 picoseconds. + Weight::from_parts(2_085_000, 0) } fn get_transient_storage_empty() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_602_000 picoseconds. - Weight::from_parts(1_721_000, 0) + // Minimum execution time: 1_599_000 picoseconds. + Weight::from_parts(1_715_000, 0) } fn get_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_796_000 picoseconds. - Weight::from_parts(1_951_000, 0) + // Minimum execution time: 1_837_000 picoseconds. + Weight::from_parts(1_930_000, 0) } fn rollback_transient_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_279_000 picoseconds. - Weight::from_parts(1_353_000, 0) + // Minimum execution time: 1_273_000 picoseconds. + Weight::from_parts(1_356_000, 0) } /// The range of component `n` is `[0, 416]`. /// The range of component `o` is `[0, 416]`. @@ -925,59 +970,61 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_407_000 picoseconds. - Weight::from_parts(2_715_278, 0) - // Standard Error: 18 - .saturating_add(Weight::from_parts(147, 0).saturating_mul(n.into())) - // Standard Error: 18 - .saturating_add(Weight::from_parts(292, 0).saturating_mul(o.into())) + // Minimum execution time: 2_307_000 picoseconds. + Weight::from_parts(2_700_633, 0) + // Standard Error: 22 + .saturating_add(Weight::from_parts(264, 0).saturating_mul(n.into())) + // Standard Error: 22 + .saturating_add(Weight::from_parts(241, 0).saturating_mul(o.into())) } /// The range of component `n` is `[0, 416]`. fn seal_clear_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_140_000 picoseconds. - Weight::from_parts(2_612_392, 0) - // Standard Error: 25 - .saturating_add(Weight::from_parts(305, 0).saturating_mul(n.into())) + // Minimum execution time: 2_159_000 picoseconds. + Weight::from_parts(2_531_527, 0) + // Standard Error: 22 + .saturating_add(Weight::from_parts(344, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 416]`. fn seal_get_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_034_000 picoseconds. - Weight::from_parts(2_357_344, 0) - // Standard Error: 21 - .saturating_add(Weight::from_parts(276, 0).saturating_mul(n.into())) + // Minimum execution time: 2_066_000 picoseconds. + Weight::from_parts(2_317_959, 0) + // Standard Error: 19 + .saturating_add(Weight::from_parts(218, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 416]`. fn seal_contains_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_888_000 picoseconds. - Weight::from_parts(2_137_193, 0) - // Standard Error: 16 - .saturating_add(Weight::from_parts(172, 0).saturating_mul(n.into())) + // Minimum execution time: 1_772_000 picoseconds. + Weight::from_parts(2_109_656, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(127, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 416]`. - fn seal_take_transient_storage(_n: u32, ) -> Weight { + fn seal_take_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_733_000 picoseconds. - Weight::from_parts(3_004_772, 0) + // Minimum execution time: 2_677_000 picoseconds. + Weight::from_parts(2_887_082, 0) + // Standard Error: 21 + .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) } /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) /// Storage: `Revive::AccountInfoOf` (r:1 w:1) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// The range of component `t` is `[0, 1]`. @@ -985,16 +1032,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 1048576]`. fn seal_call(t: u32, d: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2005` - // Estimated: `5470` - // Minimum execution time: 91_390_000 picoseconds. - Weight::from_parts(71_229_693, 5470) - // Standard Error: 146_616 - .saturating_add(Weight::from_parts(19_125_819, 0).saturating_mul(t.into())) - // Standard Error: 146_616 - .saturating_add(Weight::from_parts(26_490_547, 0).saturating_mul(d.into())) + // Measured: `1925` + // Estimated: `5390` + // Minimum execution time: 88_854_000 picoseconds. + Weight::from_parts(71_114_290, 5390) + // Standard Error: 191_071 + .saturating_add(Weight::from_parts(18_628_762, 0).saturating_mul(t.into())) + // Standard Error: 191_071 + .saturating_add(Weight::from_parts(25_344_741, 0).saturating_mul(d.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(4, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(2, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) @@ -1009,12 +1056,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `366 + d * (212 ±0)` // Estimated: `2021 + d * (2021 ±0)` - // Minimum execution time: 24_210_000 picoseconds. - Weight::from_parts(11_783_977, 2021) - // Standard Error: 49_916 - .saturating_add(Weight::from_parts(14_132_066, 0).saturating_mul(d.into())) + // Minimum execution time: 23_987_000 picoseconds. + Weight::from_parts(11_982_236, 2021) + // Standard Error: 52_781 + .saturating_add(Weight::from_parts(13_796_260, 0).saturating_mul(d.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(325, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(397, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(d.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(d.into()))) .saturating_add(Weight::from_parts(0, 2021).saturating_mul(d.into())) @@ -1022,21 +1069,21 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Revive::AccountInfoOf` (r:1 w:0) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) fn seal_delegate_call() -> Weight { // Proof Size summary in bytes: - // Measured: `1362` - // Estimated: `4827` - // Minimum execution time: 31_948_000 picoseconds. - Weight::from_parts(33_936_000, 4827) + // Measured: `1363` + // Estimated: `4828` + // Minimum execution time: 32_754_000 picoseconds. + Weight::from_parts(33_660_000, 4828) .saturating_add(T::DbWeight::get().reads(3_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Revive::AccountInfoOf` (r:1 w:1) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) @@ -1046,167 +1093,191 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 131072]`. fn seal_instantiate(t: u32, d: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1417` - // Estimated: `4876` - // Minimum execution time: 150_079_000 picoseconds. - Weight::from_parts(104_920_700, 4876) - // Standard Error: 456_076 - .saturating_add(Weight::from_parts(20_263_777, 0).saturating_mul(t.into())) - // Standard Error: 456_076 - .saturating_add(Weight::from_parts(30_617_352, 0).saturating_mul(d.into())) - // Standard Error: 5 - .saturating_add(Weight::from_parts(3_949, 0).saturating_mul(i.into())) + // Measured: `1413` + // Estimated: `4857 + d * (28 ±1) + t * (28 ±1)` + // Minimum execution time: 149_649_000 picoseconds. + Weight::from_parts(106_708_312, 4857) + // Standard Error: 531_299 + .saturating_add(Weight::from_parts(19_820_332, 0).saturating_mul(t.into())) + // Standard Error: 531_299 + .saturating_add(Weight::from_parts(30_026_552, 0).saturating_mul(d.into())) + // Standard Error: 6 + .saturating_add(Weight::from_parts(4_025, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 28).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(0, 28).saturating_mul(t.into())) } /// The range of component `n` is `[0, 1048576]`. fn sha2_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_165_000 picoseconds. - Weight::from_parts(9_566_786, 0) + // Minimum execution time: 1_183_000 picoseconds. + Weight::from_parts(12_193_562, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_251, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_286, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn identity(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 727_000 picoseconds. - Weight::from_parts(868_990, 0) + // Minimum execution time: 724_000 picoseconds. + Weight::from_parts(423_926, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(112, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(149, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn ripemd_160(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_228_000 picoseconds. - Weight::from_parts(8_112_183, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(3_718, 0).saturating_mul(n.into())) + // Minimum execution time: 1_235_000 picoseconds. + Weight::from_parts(6_941_606, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_767, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_keccak_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_142_000 picoseconds. - Weight::from_parts(12_135_609, 0) + // Minimum execution time: 1_148_000 picoseconds. + Weight::from_parts(12_850_349, 0) // Standard Error: 1 - .saturating_add(Weight::from_parts(3_539, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_590, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn hash_blake2_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_520_000 picoseconds. - Weight::from_parts(10_863_970, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_405, 0).saturating_mul(n.into())) + // Minimum execution time: 1_570_000 picoseconds. + Weight::from_parts(14_584_934, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_442, 0).saturating_mul(n.into())) } - /// The range of component `n` is `[0, 262144]`. + /// The range of component `n` is `[0, 1048576]`. fn hash_blake2_128(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 713_000 picoseconds. - Weight::from_parts(5_972_288, 0) + // Minimum execution time: 1_625_000 picoseconds. + Weight::from_parts(14_771_647, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_498, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_444, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048321]`. fn seal_sr25519_verify(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 42_872_000 picoseconds. - Weight::from_parts(83_548_865, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(4_865, 0).saturating_mul(n.into())) + // Minimum execution time: 42_969_000 picoseconds. + Weight::from_parts(90_649_318, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(4_813, 0).saturating_mul(n.into())) } fn ecdsa_recover() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 45_827_000 picoseconds. - Weight::from_parts(46_613_000, 0) + // Minimum execution time: 46_096_000 picoseconds. + Weight::from_parts(46_988_000, 0) } fn bn128_add() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 14_422_000 picoseconds. - Weight::from_parts(15_942_000, 0) + // Minimum execution time: 14_848_000 picoseconds. + Weight::from_parts(17_210_000, 0) } fn bn128_mul() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 974_593_000 picoseconds. - Weight::from_parts(980_966_000, 0) + // Minimum execution time: 991_766_000 picoseconds. + Weight::from_parts(996_123_000, 0) } /// The range of component `n` is `[0, 20]`. fn bn128_pairing(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 851_000 picoseconds. - Weight::from_parts(4_760_087_459, 0) - // Standard Error: 10_485_749 - .saturating_add(Weight::from_parts(5_940_723_809, 0).saturating_mul(n.into())) + // Minimum execution time: 848_000 picoseconds. + Weight::from_parts(4_990_945_553, 0) + // Standard Error: 10_630_771 + .saturating_add(Weight::from_parts(6_054_433_018, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1200]`. fn blake2f(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 953_000 picoseconds. - Weight::from_parts(1_258_163, 0) - // Standard Error: 50 - .saturating_add(Weight::from_parts(28_977, 0).saturating_mul(n.into())) + // Minimum execution time: 961_000 picoseconds. + Weight::from_parts(1_252_241, 0) + // Standard Error: 26 + .saturating_add(Weight::from_parts(30_105, 0).saturating_mul(n.into())) } fn seal_ecdsa_to_eth_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 13_049_000 picoseconds. - Weight::from_parts(13_232_000, 0) + // Minimum execution time: 13_095_000 picoseconds. + Weight::from_parts(13_230_000, 0) } - /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) - fn seal_set_code_hash() -> Weight { + /// Storage: `Revive::CodeInfoOf` (r:2 w:2) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Revive::PristineCode` (r:0 w:1) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `r` is `[0, 1]`. + fn seal_set_code_hash(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `391 + r * (703 ±0)` + // Estimated: `6331 + r * (2280 ±0)` + // Minimum execution time: 14_670_000 picoseconds. + Weight::from_parts(15_744_806, 6331) + // Standard Error: 54_003 + .saturating_add(Weight::from_parts(47_474_393, 0).saturating_mul(r.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 2280).saturating_mul(r.into())) + } + /// The range of component `r` is `[0, 10000]`. + fn evm_opcode(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `296` - // Estimated: `3761` - // Minimum execution time: 10_342_000 picoseconds. - Weight::from_parts(10_818_000, 3761) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_189_000 picoseconds. + Weight::from_parts(1_470_372, 0) + // Standard Error: 20 + .saturating_add(Weight::from_parts(6_508, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 10000]`. fn instr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_081_000 picoseconds. - Weight::from_parts(39_209_404, 0) - // Standard Error: 395 - .saturating_add(Weight::from_parts(106_585, 0).saturating_mul(r.into())) + // Minimum execution time: 12_052_000 picoseconds. + Weight::from_parts(56_794_418, 0) + // Standard Error: 416 + .saturating_add(Weight::from_parts(116_801, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 100000]`. fn instr_empty_loop(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_146_000 picoseconds. - Weight::from_parts(4_731_872, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(73_452, 0).saturating_mul(r.into())) + // Minimum execution time: 3_321_000 picoseconds. + Weight::from_parts(8_236_588, 0) + // Standard Error: 32 + .saturating_add(Weight::from_parts(71_473, 0).saturating_mul(r.into())) } /// Storage: UNKNOWN KEY `0x735f040a5d490f1107ad9c56f5ca00d2060e99e5378e562537cf3bc983e17b91` (r:2 w:1) /// Proof: UNKNOWN KEY `0x735f040a5d490f1107ad9c56f5ca00d2060e99e5378e562537cf3bc983e17b91` (r:2 w:1) @@ -1216,11 +1287,26 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `316` // Estimated: `6256` - // Minimum execution time: 12_136_000 picoseconds. - Weight::from_parts(12_668_000, 6256) + // Minimum execution time: 12_137_000 picoseconds. + Weight::from_parts(12_594_000, 6256) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Revive::CodeInfoOf` (r:2 w:1) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:2 w:2) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `MaxEncodedLen`) + fn v2_migration_step() -> Weight { + // Proof Size summary in bytes: + // Measured: `741` + // Estimated: `6794` + // Minimum execution time: 64_340_000 picoseconds. + Weight::from_parts(67_378_000, 6794) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } } // For backwards compatibility and tests. @@ -1231,8 +1317,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `147` // Estimated: `1632` - // Minimum execution time: 3_008_000 picoseconds. - Weight::from_parts(3_256_000, 1632) + // Minimum execution time: 3_146_000 picoseconds. + Weight::from_parts(3_400_000, 1632) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1242,10 +1328,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `458 + k * (69 ±0)` // Estimated: `448 + k * (70 ±0)` - // Minimum execution time: 14_584_000 picoseconds. - Weight::from_parts(772_449, 448) - // Standard Error: 1_278 - .saturating_add(Weight::from_parts(1_204_643, 0).saturating_mul(k.into())) + // Minimum execution time: 14_245_000 picoseconds. + Weight::from_parts(14_708_000, 448) + // Standard Error: 830 + .saturating_add(Weight::from_parts(1_175_004, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1257,22 +1343,22 @@ impl WeightInfo for () { /// Storage: `Revive::AccountInfoOf` (r:1 w:1) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// The range of component `c` is `[0, 102400]`. - fn call_with_code_per_byte(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1171 + c * (1 ±0)` - // Estimated: `7106 + c * (1 ±0)` - // Minimum execution time: 86_230_000 picoseconds. - Weight::from_parts(124_424_225, 7106) - // Standard Error: 10 - .saturating_add(Weight::from_parts(1_256, 0).saturating_mul(c.into())) + fn call_with_pvm_code_per_byte(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1172 + c * (1 ±0)` + // Estimated: `7107 + c * (1 ±0)` + // Minimum execution time: 86_441_000 picoseconds. + Weight::from_parts(123_780_707, 7107) + // Standard Error: 11 + .saturating_add(Weight::from_parts(1_438, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(c.into())) @@ -1282,9 +1368,33 @@ impl WeightInfo for () { /// Storage: `Revive::AccountInfoOf` (r:1 w:1) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) + /// Storage: `Revive::PristineCode` (r:1 w:0) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Timestamp::Now` (r:1 w:0) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// The range of component `c` is `[1, 10240]`. + fn call_with_evm_code_per_byte(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1112` + // Estimated: `7051` + // Minimum execution time: 81_282_000 picoseconds. + Weight::from_parts(85_248_488, 7051) + // Standard Error: 21 + .saturating_add(Weight::from_parts(36, 0).saturating_mul(c.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Revive::OriginalAccount` (r:2 w:0) + /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) + /// Storage: `Revive::AccountInfoOf` (r:1 w:1) + /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) + /// Storage: `Revive::CodeInfoOf` (r:1 w:0) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) @@ -1292,15 +1402,15 @@ impl WeightInfo for () { /// The range of component `b` is `[0, 1]`. fn basic_block_compilation(_b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `4515` - // Estimated: `10455` - // Minimum execution time: 124_359_000 picoseconds. - Weight::from_parts(129_025_585, 10455) + // Measured: `4516` + // Estimated: `10456` + // Minimum execution time: 124_393_000 picoseconds. + Weight::from_parts(129_685_861, 10456) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Balances::Holds` (r:2 w:2) /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) /// Storage: `Revive::OriginalAccount` (r:1 w:0) @@ -1312,24 +1422,24 @@ impl WeightInfo for () { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:0 w:1) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `c` is `[0, 102400]`. /// The range of component `i` is `[0, 131072]`. fn instantiate_with_code(c: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1108` - // Estimated: `7041` - // Minimum execution time: 755_622_000 picoseconds. - Weight::from_parts(57_161_132, 7041) - // Standard Error: 36 - .saturating_add(Weight::from_parts(19_425, 0).saturating_mul(c.into())) - // Standard Error: 28 - .saturating_add(Weight::from_parts(5_000, 0).saturating_mul(i.into())) + // Measured: `1171` + // Estimated: `7104` + // Minimum execution time: 762_496_000 picoseconds. + Weight::from_parts(55_020_008, 7104) + // Standard Error: 44 + .saturating_add(Weight::from_parts(20_306, 0).saturating_mul(c.into())) + // Standard Error: 35 + .saturating_add(Weight::from_parts(5_068, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Balances::Holds` (r:2 w:2) /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) /// Storage: `Revive::OriginalAccount` (r:1 w:0) @@ -1341,22 +1451,22 @@ impl WeightInfo for () { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:0 w:1) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `c` is `[0, 102400]`. /// The range of component `i` is `[0, 131072]`. /// The range of component `d` is `[0, 1]`. fn eth_instantiate_with_code(c: u32, i: u32, d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1122` - // Estimated: `7062 + d * (2475 ±0)` - // Minimum execution time: 281_326_000 picoseconds. - Weight::from_parts(192_766_004, 7062) - // Standard Error: 15 - .saturating_add(Weight::from_parts(14_166, 0).saturating_mul(c.into())) - // Standard Error: 11 - .saturating_add(Weight::from_parts(403, 0).saturating_mul(i.into())) - // Standard Error: 983_169 - .saturating_add(Weight::from_parts(30_340_467, 0).saturating_mul(d.into())) + // Measured: `1185` + // Estimated: `7125 + d * (2475 ±0)` + // Minimum execution time: 284_562_000 picoseconds. + Weight::from_parts(163_089_642, 7125) + // Standard Error: 34 + .saturating_add(Weight::from_parts(15_162, 0).saturating_mul(c.into())) + // Standard Error: 27 + .saturating_add(Weight::from_parts(514, 0).saturating_mul(i.into())) + // Standard Error: 2_273_714 + .saturating_add(Weight::from_parts(38_746_748, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(d.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1364,9 +1474,9 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(0, 2475).saturating_mul(d.into())) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) /// Storage: `Revive::AccountInfoOf` (r:1 w:1) @@ -1380,12 +1490,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 131072]`. fn instantiate(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1912` - // Estimated: `5362` - // Minimum execution time: 172_513_000 picoseconds. - Weight::from_parts(178_290_134, 5362) + // Measured: `1913` + // Estimated: `5339` + // Minimum execution time: 171_348_000 picoseconds. + Weight::from_parts(176_612_673, 5339) // Standard Error: 11 - .saturating_add(Weight::from_parts(4_158, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(4_290, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1394,19 +1504,19 @@ impl WeightInfo for () { /// Storage: `Revive::AccountInfoOf` (r:1 w:1) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `1792` - // Estimated: `7732` - // Minimum execution time: 87_638_000 picoseconds. - Weight::from_parts(90_000_000, 7732) + // Measured: `1794` + // Estimated: `7734` + // Minimum execution time: 88_764_000 picoseconds. + Weight::from_parts(93_353_000, 7734) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1415,9 +1525,9 @@ impl WeightInfo for () { /// Storage: `Revive::AccountInfoOf` (r:2 w:2) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) @@ -1425,12 +1535,12 @@ impl WeightInfo for () { /// The range of component `d` is `[0, 1]`. fn eth_call(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1792` - // Estimated: `7732 + d * (2475 ±0)` - // Minimum execution time: 85_839_000 picoseconds. - Weight::from_parts(90_556_373, 7732) - // Standard Error: 358_297 - .saturating_add(Weight::from_parts(27_649_126, 0).saturating_mul(d.into())) + // Measured: `1794` + // Estimated: `7734 + d * (2475 ±0)` + // Minimum execution time: 86_142_000 picoseconds. + Weight::from_parts(90_482_761, 7734) + // Standard Error: 430_134 + .saturating_add(Weight::from_parts(30_624_838, 0).saturating_mul(d.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(d.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -1438,50 +1548,56 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(0, 2475).saturating_mul(d.into())) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:0 w:1) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `c` is `[0, 102400]`. fn upload_code(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `505` - // Estimated: `3970` - // Minimum execution time: 56_805_000 picoseconds. - Weight::from_parts(50_855_179, 3970) - // Standard Error: 35 - .saturating_add(Weight::from_parts(13_927, 0).saturating_mul(c.into())) + // Measured: `606` + // Estimated: `4071` + // Minimum execution time: 57_080_000 picoseconds. + Weight::from_parts(49_101_825, 4071) + // Standard Error: 18 + .saturating_add(Weight::from_parts(14_610, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:0 w:1) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) fn remove_code() -> Weight { // Proof Size summary in bytes: - // Measured: `658` - // Estimated: `4123` - // Minimum execution time: 47_344_000 picoseconds. - Weight::from_parts(48_892_000, 4123) + // Measured: `760` + // Estimated: `4225` + // Minimum execution time: 53_084_000 picoseconds. + Weight::from_parts(54_573_000, 4225) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Revive::AccountInfoOf` (r:1 w:1) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:2 w:2) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Revive::PristineCode` (r:0 w:1) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `530` - // Estimated: `6470` - // Minimum execution time: 20_627_000 picoseconds. - Weight::from_parts(21_451_000, 6470) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Measured: `1095` + // Estimated: `7035` + // Minimum execution time: 65_666_000 picoseconds. + Weight::from_parts(67_373_000, 7035) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Revive::OriginalAccount` (r:1 w:1) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) @@ -1491,8 +1607,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `813` // Estimated: `4278` - // Minimum execution time: 57_209_000 picoseconds. - Weight::from_parts(58_942_000, 4278) + // Minimum execution time: 55_888_000 picoseconds. + Weight::from_parts(57_747_000, 4278) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1504,8 +1620,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `3860` - // Minimum execution time: 42_757_000 picoseconds. - Weight::from_parts(44_178_000, 3860) + // Minimum execution time: 42_171_000 picoseconds. + Weight::from_parts(43_198_000, 3860) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1517,8 +1633,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 13_062_000 picoseconds. - Weight::from_parts(13_660_000, 3610) + // Minimum execution time: 13_030_000 picoseconds. + Weight::from_parts(13_365_000, 3610) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -1526,33 +1642,33 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_588_000 picoseconds. - Weight::from_parts(8_755_261, 0) - // Standard Error: 236 - .saturating_add(Weight::from_parts(182_421, 0).saturating_mul(r.into())) + // Minimum execution time: 7_473_000 picoseconds. + Weight::from_parts(8_474_805, 0) + // Standard Error: 322 + .saturating_add(Weight::from_parts(178_929, 0).saturating_mul(r.into())) } fn seal_caller() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 335_000 picoseconds. - Weight::from_parts(390_000, 0) + // Minimum execution time: 355_000 picoseconds. + Weight::from_parts(397_000, 0) } fn seal_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 350_000 picoseconds. - Weight::from_parts(386_000, 0) + // Minimum execution time: 318_000 picoseconds. + Weight::from_parts(362_000, 0) } /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) - fn seal_to_account_id() -> Weight { + fn to_account_id() -> Weight { // Proof Size summary in bytes: - // Measured: `571` - // Estimated: `4036` - // Minimum execution time: 9_818_000 picoseconds. - Weight::from_parts(10_279_000, 4036) + // Measured: `567` + // Estimated: `4032` + // Minimum execution time: 7_507_000 picoseconds. + Weight::from_parts(8_064_000, 4032) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Revive::AccountInfoOf` (r:1 w:0) @@ -1561,70 +1677,70 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `403` // Estimated: `3868` - // Minimum execution time: 9_222_000 picoseconds. - Weight::from_parts(9_806_000, 3868) + // Minimum execution time: 9_458_000 picoseconds. + Weight::from_parts(10_105_000, 3868) .saturating_add(RocksDbWeight::get().reads(1_u64)) } fn seal_own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 282_000 picoseconds. - Weight::from_parts(336_000, 0) + // Minimum execution time: 317_000 picoseconds. + Weight::from_parts(355_000, 0) } /// Storage: `Revive::AccountInfoOf` (r:1 w:0) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) fn seal_code_size() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `3939` - // Minimum execution time: 12_825_000 picoseconds. - Weight::from_parts(13_490_000, 3939) + // Measured: `475` + // Estimated: `3940` + // Minimum execution time: 13_105_000 picoseconds. + Weight::from_parts(13_354_000, 3940) .saturating_add(RocksDbWeight::get().reads(2_u64)) } fn seal_caller_is_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 321_000 picoseconds. - Weight::from_parts(372_000, 0) + // Minimum execution time: 331_000 picoseconds. + Weight::from_parts(381_000, 0) } fn seal_caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 269_000 picoseconds. - Weight::from_parts(327_000, 0) + // Minimum execution time: 307_000 picoseconds. + Weight::from_parts(336_000, 0) } fn seal_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 304_000 picoseconds. - Weight::from_parts(343_000, 0) + // Minimum execution time: 323_000 picoseconds. + Weight::from_parts(368_000, 0) } fn seal_weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 700_000 picoseconds. - Weight::from_parts(802_000, 0) + // Minimum execution time: 701_000 picoseconds. + Weight::from_parts(785_000, 0) } fn seal_ref_time_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 263_000 picoseconds. - Weight::from_parts(325_000, 0) + // Minimum execution time: 278_000 picoseconds. + Weight::from_parts(334_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `506` + // Measured: `540` // Estimated: `0` - // Minimum execution time: 13_351_000 picoseconds. - Weight::from_parts(13_878_000, 0) + // Minimum execution time: 12_890_000 picoseconds. + Weight::from_parts(13_471_000, 0) } /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) @@ -1636,8 +1752,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `791` // Estimated: `4256` - // Minimum execution time: 18_603_000 picoseconds. - Weight::from_parts(19_511_000, 4256) + // Minimum execution time: 18_523_000 picoseconds. + Weight::from_parts(19_059_000, 4256) .saturating_add(RocksDbWeight::get().reads(3_u64)) } /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) @@ -1647,10 +1763,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `271 + n * (1 ±0)` // Estimated: `3736 + n * (1 ±0)` - // Minimum execution time: 6_013_000 picoseconds. - Weight::from_parts(6_757_699, 3736) + // Minimum execution time: 6_027_000 picoseconds. + Weight::from_parts(6_736_994, 3736) // Standard Error: 5 - .saturating_add(Weight::from_parts(483, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(592, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1661,67 +1777,67 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_052_000 picoseconds. - Weight::from_parts(2_330_454, 0) + // Minimum execution time: 2_033_000 picoseconds. + Weight::from_parts(2_294_007, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(525, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(565, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn seal_value_transferred() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 259_000 picoseconds. - Weight::from_parts(331_000, 0) + // Minimum execution time: 276_000 picoseconds. + Weight::from_parts(323_000, 0) } fn seal_minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 278_000 picoseconds. - Weight::from_parts(339_000, 0) + // Minimum execution time: 273_000 picoseconds. + Weight::from_parts(325_000, 0) } fn seal_return_data_size() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 272_000 picoseconds. - Weight::from_parts(326_000, 0) + // Minimum execution time: 265_000 picoseconds. + Weight::from_parts(302_000, 0) } fn seal_call_data_size() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 268_000 picoseconds. - Weight::from_parts(313_000, 0) + // Minimum execution time: 279_000 picoseconds. + Weight::from_parts(353_000, 0) } fn seal_gas_limit() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 436_000 picoseconds. - Weight::from_parts(509_000, 0) + // Minimum execution time: 518_000 picoseconds. + Weight::from_parts(572_000, 0) } fn seal_gas_price() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 262_000 picoseconds. - Weight::from_parts(317_000, 0) + // Minimum execution time: 308_000 picoseconds. + Weight::from_parts(339_000, 0) } fn seal_base_fee() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 289_000 picoseconds. - Weight::from_parts(347_000, 0) + // Minimum execution time: 283_000 picoseconds. + Weight::from_parts(315_000, 0) } fn seal_block_number() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 305_000 picoseconds. - Weight::from_parts(358_000, 0) + // Minimum execution time: 300_000 picoseconds. + Weight::from_parts(334_000, 0) } /// Storage: `Session::Validators` (r:1 w:0) /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -1729,8 +1845,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `141` // Estimated: `1626` - // Minimum execution time: 22_975_000 picoseconds. - Weight::from_parts(23_506_000, 1626) + // Minimum execution time: 22_163_000 picoseconds. + Weight::from_parts(22_643_000, 1626) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `System::BlockHash` (r:1 w:0) @@ -1739,79 +1855,91 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `30` // Estimated: `3495` - // Minimum execution time: 3_631_000 picoseconds. - Weight::from_parts(3_829_000, 3495) + // Minimum execution time: 3_625_000 picoseconds. + Weight::from_parts(3_850_000, 3495) .saturating_add(RocksDbWeight::get().reads(1_u64)) } fn seal_now() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 271_000 picoseconds. - Weight::from_parts(337_000, 0) + // Minimum execution time: 293_000 picoseconds. + Weight::from_parts(349_000, 0) } fn seal_weight_to_fee() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_603_000 picoseconds. - Weight::from_parts(1_712_000, 0) + // Minimum execution time: 1_597_000 picoseconds. + Weight::from_parts(1_720_000, 0) } /// The range of component `n` is `[0, 1048572]`. fn seal_copy_to_contract(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 433_000 picoseconds. - Weight::from_parts(460_000, 0) + // Minimum execution time: 425_000 picoseconds. + Weight::from_parts(437_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(203, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(239, 0).saturating_mul(n.into())) } fn seal_call_data_load() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 293_000 picoseconds. - Weight::from_parts(325_000, 0) + // Minimum execution time: 277_000 picoseconds. + Weight::from_parts(313_000, 0) } /// The range of component `n` is `[0, 1048576]`. fn seal_call_data_copy(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 269_000 picoseconds. - Weight::from_parts(806_378, 0) + // Minimum execution time: 257_000 picoseconds. + Weight::from_parts(288_000, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(112, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(150, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 131072]`. fn seal_return(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 290_000 picoseconds. - Weight::from_parts(488_982, 0) + // Minimum execution time: 315_000 picoseconds. + Weight::from_parts(476_627, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(201, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(238, 0).saturating_mul(n.into())) } /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) /// Storage: `Revive::DeletionQueueCounter` (r:1 w:1) /// Proof: `Revive::DeletionQueueCounter` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// Storage: `Revive::DeletionQueue` (r:0 w:1) /// Proof: `Revive::DeletionQueue` (`max_values`: None, `max_size`: Some(142), added: 2617, mode: `Measured`) + /// Storage: `Revive::PristineCode` (r:0 w:1) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Revive::ImmutableDataOf` (r:0 w:1) /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) - fn seal_terminate() -> Weight { - // Proof Size summary in bytes: - // Measured: `582` - // Estimated: `4047` - // Minimum execution time: 17_674_000 picoseconds. - Weight::from_parts(18_031_000, 4047) + /// The range of component `r` is `[0, 1]`. + fn seal_terminate(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `583 + r * (670 ±0)` + // Estimated: `4048 + r * (2359 ±0)` + // Minimum execution time: 16_560_000 picoseconds. + Weight::from_parts(17_630_489, 4048) + // Standard Error: 66_463 + .saturating_add(Weight::from_parts(46_618_510, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 2359).saturating_mul(r.into())) } /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 416]`. @@ -1819,12 +1947,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_375_000 picoseconds. - Weight::from_parts(4_568_155, 0) - // Standard Error: 3_591 - .saturating_add(Weight::from_parts(223_460, 0).saturating_mul(t.into())) - // Standard Error: 39 - .saturating_add(Weight::from_parts(854, 0).saturating_mul(n.into())) + // Minimum execution time: 4_523_000 picoseconds. + Weight::from_parts(4_505_303, 0) + // Standard Error: 3_656 + .saturating_add(Weight::from_parts(240_684, 0).saturating_mul(t.into())) + // Standard Error: 40 + .saturating_add(Weight::from_parts(1_232, 0).saturating_mul(n.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -1832,8 +1960,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `648` // Estimated: `648` - // Minimum execution time: 7_272_000 picoseconds. - Weight::from_parts(7_635_000, 648) + // Minimum execution time: 7_228_000 picoseconds. + Weight::from_parts(7_734_000, 648) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1842,8 +1970,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `10658` // Estimated: `10658` - // Minimum execution time: 41_207_000 picoseconds. - Weight::from_parts(41_863_000, 10658) + // Minimum execution time: 41_276_000 picoseconds. + Weight::from_parts(42_310_000, 10658) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1852,8 +1980,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `648` // Estimated: `648` - // Minimum execution time: 8_492_000 picoseconds. - Weight::from_parts(9_013_000, 648) + // Minimum execution time: 8_396_000 picoseconds. + Weight::from_parts(8_776_000, 648) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1863,8 +1991,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `10658` // Estimated: `10658` - // Minimum execution time: 42_398_000 picoseconds. - Weight::from_parts(44_113_000, 10658) + // Minimum execution time: 42_661_000 picoseconds. + Weight::from_parts(44_266_000, 10658) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1876,12 +2004,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + o * (1 ±0)` // Estimated: `247 + o * (1 ±0)` - // Minimum execution time: 8_728_000 picoseconds. - Weight::from_parts(9_632_969, 247) - // Standard Error: 56 - .saturating_add(Weight::from_parts(556, 0).saturating_mul(n.into())) - // Standard Error: 56 - .saturating_add(Weight::from_parts(958, 0).saturating_mul(o.into())) + // Minimum execution time: 8_864_000 picoseconds. + Weight::from_parts(9_769_026, 247) + // Standard Error: 67 + .saturating_add(Weight::from_parts(81, 0).saturating_mul(n.into())) + // Standard Error: 67 + .saturating_add(Weight::from_parts(866, 0).saturating_mul(o.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(o.into())) @@ -1893,10 +2021,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 9_032_000 picoseconds. - Weight::from_parts(9_816_471, 247) - // Standard Error: 82 - .saturating_add(Weight::from_parts(582, 0).saturating_mul(n.into())) + // Minimum execution time: 8_552_000 picoseconds. + Weight::from_parts(9_609_466, 247) + // Standard Error: 88 + .saturating_add(Weight::from_parts(789, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1908,10 +2036,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_313_000 picoseconds. - Weight::from_parts(9_381_907, 247) - // Standard Error: 91 - .saturating_add(Weight::from_parts(1_184, 0).saturating_mul(n.into())) + // Minimum execution time: 8_101_000 picoseconds. + Weight::from_parts(9_115_278, 247) + // Standard Error: 75 + .saturating_add(Weight::from_parts(1_381, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1922,10 +2050,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 7_645_000 picoseconds. - Weight::from_parts(8_714_974, 247) - // Standard Error: 87 - .saturating_add(Weight::from_parts(717, 0).saturating_mul(n.into())) + // Minimum execution time: 7_594_000 picoseconds. + Weight::from_parts(8_575_324, 247) + // Standard Error: 78 + .saturating_add(Weight::from_parts(635, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1936,10 +2064,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 9_388_000 picoseconds. - Weight::from_parts(10_430_193, 247) - // Standard Error: 77 - .saturating_add(Weight::from_parts(1_346, 0).saturating_mul(n.into())) + // Minimum execution time: 9_130_000 picoseconds. + Weight::from_parts(10_301_501, 247) + // Standard Error: 85 + .saturating_add(Weight::from_parts(1_584, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1948,36 +2076,36 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_597_000 picoseconds. - Weight::from_parts(1_691_000, 0) + // Minimum execution time: 1_553_000 picoseconds. + Weight::from_parts(1_678_000, 0) } fn set_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_005_000 picoseconds. - Weight::from_parts(2_129_000, 0) + // Minimum execution time: 1_962_000 picoseconds. + Weight::from_parts(2_085_000, 0) } fn get_transient_storage_empty() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_602_000 picoseconds. - Weight::from_parts(1_721_000, 0) + // Minimum execution time: 1_599_000 picoseconds. + Weight::from_parts(1_715_000, 0) } fn get_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_796_000 picoseconds. - Weight::from_parts(1_951_000, 0) + // Minimum execution time: 1_837_000 picoseconds. + Weight::from_parts(1_930_000, 0) } fn rollback_transient_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_279_000 picoseconds. - Weight::from_parts(1_353_000, 0) + // Minimum execution time: 1_273_000 picoseconds. + Weight::from_parts(1_356_000, 0) } /// The range of component `n` is `[0, 416]`. /// The range of component `o` is `[0, 416]`. @@ -1985,59 +2113,61 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_407_000 picoseconds. - Weight::from_parts(2_715_278, 0) - // Standard Error: 18 - .saturating_add(Weight::from_parts(147, 0).saturating_mul(n.into())) - // Standard Error: 18 - .saturating_add(Weight::from_parts(292, 0).saturating_mul(o.into())) + // Minimum execution time: 2_307_000 picoseconds. + Weight::from_parts(2_700_633, 0) + // Standard Error: 22 + .saturating_add(Weight::from_parts(264, 0).saturating_mul(n.into())) + // Standard Error: 22 + .saturating_add(Weight::from_parts(241, 0).saturating_mul(o.into())) } /// The range of component `n` is `[0, 416]`. fn seal_clear_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_140_000 picoseconds. - Weight::from_parts(2_612_392, 0) - // Standard Error: 25 - .saturating_add(Weight::from_parts(305, 0).saturating_mul(n.into())) + // Minimum execution time: 2_159_000 picoseconds. + Weight::from_parts(2_531_527, 0) + // Standard Error: 22 + .saturating_add(Weight::from_parts(344, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 416]`. fn seal_get_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_034_000 picoseconds. - Weight::from_parts(2_357_344, 0) - // Standard Error: 21 - .saturating_add(Weight::from_parts(276, 0).saturating_mul(n.into())) + // Minimum execution time: 2_066_000 picoseconds. + Weight::from_parts(2_317_959, 0) + // Standard Error: 19 + .saturating_add(Weight::from_parts(218, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 416]`. fn seal_contains_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_888_000 picoseconds. - Weight::from_parts(2_137_193, 0) - // Standard Error: 16 - .saturating_add(Weight::from_parts(172, 0).saturating_mul(n.into())) + // Minimum execution time: 1_772_000 picoseconds. + Weight::from_parts(2_109_656, 0) + // Standard Error: 17 + .saturating_add(Weight::from_parts(127, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 416]`. - fn seal_take_transient_storage(_n: u32, ) -> Weight { + fn seal_take_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_733_000 picoseconds. - Weight::from_parts(3_004_772, 0) + // Minimum execution time: 2_677_000 picoseconds. + Weight::from_parts(2_887_082, 0) + // Standard Error: 21 + .saturating_add(Weight::from_parts(3, 0).saturating_mul(n.into())) } /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) /// Storage: `Revive::AccountInfoOf` (r:1 w:1) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// The range of component `t` is `[0, 1]`. @@ -2045,16 +2175,16 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 1048576]`. fn seal_call(t: u32, d: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2005` - // Estimated: `5470` - // Minimum execution time: 91_390_000 picoseconds. - Weight::from_parts(71_229_693, 5470) - // Standard Error: 146_616 - .saturating_add(Weight::from_parts(19_125_819, 0).saturating_mul(t.into())) - // Standard Error: 146_616 - .saturating_add(Weight::from_parts(26_490_547, 0).saturating_mul(d.into())) + // Measured: `1925` + // Estimated: `5390` + // Minimum execution time: 88_854_000 picoseconds. + Weight::from_parts(71_114_290, 5390) + // Standard Error: 191_071 + .saturating_add(Weight::from_parts(18_628_762, 0).saturating_mul(t.into())) + // Standard Error: 191_071 + .saturating_add(Weight::from_parts(25_344_741, 0).saturating_mul(d.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(4, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(2, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) @@ -2069,12 +2199,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `366 + d * (212 ±0)` // Estimated: `2021 + d * (2021 ±0)` - // Minimum execution time: 24_210_000 picoseconds. - Weight::from_parts(11_783_977, 2021) - // Standard Error: 49_916 - .saturating_add(Weight::from_parts(14_132_066, 0).saturating_mul(d.into())) + // Minimum execution time: 23_987_000 picoseconds. + Weight::from_parts(11_982_236, 2021) + // Standard Error: 52_781 + .saturating_add(Weight::from_parts(13_796_260, 0).saturating_mul(d.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(325, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(397, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(d.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(d.into()))) .saturating_add(Weight::from_parts(0, 2021).saturating_mul(d.into())) @@ -2082,21 +2212,21 @@ impl WeightInfo for () { /// Storage: `Revive::AccountInfoOf` (r:1 w:0) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) fn seal_delegate_call() -> Weight { // Proof Size summary in bytes: - // Measured: `1362` - // Estimated: `4827` - // Minimum execution time: 31_948_000 picoseconds. - Weight::from_parts(33_936_000, 4827) + // Measured: `1363` + // Estimated: `4828` + // Minimum execution time: 32_754_000 picoseconds. + Weight::from_parts(33_660_000, 4828) .saturating_add(RocksDbWeight::get().reads(3_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) - /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(1048612), added: 1051087, mode: `Measured`) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Revive::AccountInfoOf` (r:1 w:1) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) @@ -2106,167 +2236,191 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 131072]`. fn seal_instantiate(t: u32, d: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1417` - // Estimated: `4876` - // Minimum execution time: 150_079_000 picoseconds. - Weight::from_parts(104_920_700, 4876) - // Standard Error: 456_076 - .saturating_add(Weight::from_parts(20_263_777, 0).saturating_mul(t.into())) - // Standard Error: 456_076 - .saturating_add(Weight::from_parts(30_617_352, 0).saturating_mul(d.into())) - // Standard Error: 5 - .saturating_add(Weight::from_parts(3_949, 0).saturating_mul(i.into())) + // Measured: `1413` + // Estimated: `4857 + d * (28 ±1) + t * (28 ±1)` + // Minimum execution time: 149_649_000 picoseconds. + Weight::from_parts(106_708_312, 4857) + // Standard Error: 531_299 + .saturating_add(Weight::from_parts(19_820_332, 0).saturating_mul(t.into())) + // Standard Error: 531_299 + .saturating_add(Weight::from_parts(30_026_552, 0).saturating_mul(d.into())) + // Standard Error: 6 + .saturating_add(Weight::from_parts(4_025, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 28).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(0, 28).saturating_mul(t.into())) } /// The range of component `n` is `[0, 1048576]`. fn sha2_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_165_000 picoseconds. - Weight::from_parts(9_566_786, 0) + // Minimum execution time: 1_183_000 picoseconds. + Weight::from_parts(12_193_562, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_251, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_286, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn identity(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 727_000 picoseconds. - Weight::from_parts(868_990, 0) + // Minimum execution time: 724_000 picoseconds. + Weight::from_parts(423_926, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(112, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(149, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn ripemd_160(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_228_000 picoseconds. - Weight::from_parts(8_112_183, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(3_718, 0).saturating_mul(n.into())) + // Minimum execution time: 1_235_000 picoseconds. + Weight::from_parts(6_941_606, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_767, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_keccak_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_142_000 picoseconds. - Weight::from_parts(12_135_609, 0) + // Minimum execution time: 1_148_000 picoseconds. + Weight::from_parts(12_850_349, 0) // Standard Error: 1 - .saturating_add(Weight::from_parts(3_539, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_590, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048576]`. fn hash_blake2_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_520_000 picoseconds. - Weight::from_parts(10_863_970, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_405, 0).saturating_mul(n.into())) + // Minimum execution time: 1_570_000 picoseconds. + Weight::from_parts(14_584_934, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_442, 0).saturating_mul(n.into())) } - /// The range of component `n` is `[0, 262144]`. + /// The range of component `n` is `[0, 1048576]`. fn hash_blake2_128(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 713_000 picoseconds. - Weight::from_parts(5_972_288, 0) + // Minimum execution time: 1_625_000 picoseconds. + Weight::from_parts(14_771_647, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_498, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_444, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1048321]`. fn seal_sr25519_verify(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 42_872_000 picoseconds. - Weight::from_parts(83_548_865, 0) - // Standard Error: 3 - .saturating_add(Weight::from_parts(4_865, 0).saturating_mul(n.into())) + // Minimum execution time: 42_969_000 picoseconds. + Weight::from_parts(90_649_318, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(4_813, 0).saturating_mul(n.into())) } fn ecdsa_recover() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 45_827_000 picoseconds. - Weight::from_parts(46_613_000, 0) + // Minimum execution time: 46_096_000 picoseconds. + Weight::from_parts(46_988_000, 0) } fn bn128_add() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 14_422_000 picoseconds. - Weight::from_parts(15_942_000, 0) + // Minimum execution time: 14_848_000 picoseconds. + Weight::from_parts(17_210_000, 0) } fn bn128_mul() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 974_593_000 picoseconds. - Weight::from_parts(980_966_000, 0) + // Minimum execution time: 991_766_000 picoseconds. + Weight::from_parts(996_123_000, 0) } /// The range of component `n` is `[0, 20]`. fn bn128_pairing(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 851_000 picoseconds. - Weight::from_parts(4_760_087_459, 0) - // Standard Error: 10_485_749 - .saturating_add(Weight::from_parts(5_940_723_809, 0).saturating_mul(n.into())) + // Minimum execution time: 848_000 picoseconds. + Weight::from_parts(4_990_945_553, 0) + // Standard Error: 10_630_771 + .saturating_add(Weight::from_parts(6_054_433_018, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 1200]`. fn blake2f(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 953_000 picoseconds. - Weight::from_parts(1_258_163, 0) - // Standard Error: 50 - .saturating_add(Weight::from_parts(28_977, 0).saturating_mul(n.into())) + // Minimum execution time: 961_000 picoseconds. + Weight::from_parts(1_252_241, 0) + // Standard Error: 26 + .saturating_add(Weight::from_parts(30_105, 0).saturating_mul(n.into())) } fn seal_ecdsa_to_eth_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 13_049_000 picoseconds. - Weight::from_parts(13_232_000, 0) + // Minimum execution time: 13_095_000 picoseconds. + Weight::from_parts(13_230_000, 0) } - /// Storage: `Revive::CodeInfoOf` (r:1 w:1) - /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) - fn seal_set_code_hash() -> Weight { + /// Storage: `Revive::CodeInfoOf` (r:2 w:2) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Revive::PristineCode` (r:0 w:1) + /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `r` is `[0, 1]`. + fn seal_set_code_hash(r: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `391 + r * (703 ±0)` + // Estimated: `6331 + r * (2280 ±0)` + // Minimum execution time: 14_670_000 picoseconds. + Weight::from_parts(15_744_806, 6331) + // Standard Error: 54_003 + .saturating_add(Weight::from_parts(47_474_393, 0).saturating_mul(r.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(r.into()))) + .saturating_add(Weight::from_parts(0, 2280).saturating_mul(r.into())) + } + /// The range of component `r` is `[0, 10000]`. + fn evm_opcode(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `296` - // Estimated: `3761` - // Minimum execution time: 10_342_000 picoseconds. - Weight::from_parts(10_818_000, 3761) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_189_000 picoseconds. + Weight::from_parts(1_470_372, 0) + // Standard Error: 20 + .saturating_add(Weight::from_parts(6_508, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 10000]`. fn instr(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_081_000 picoseconds. - Weight::from_parts(39_209_404, 0) - // Standard Error: 395 - .saturating_add(Weight::from_parts(106_585, 0).saturating_mul(r.into())) + // Minimum execution time: 12_052_000 picoseconds. + Weight::from_parts(56_794_418, 0) + // Standard Error: 416 + .saturating_add(Weight::from_parts(116_801, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 100000]`. fn instr_empty_loop(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_146_000 picoseconds. - Weight::from_parts(4_731_872, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(73_452, 0).saturating_mul(r.into())) + // Minimum execution time: 3_321_000 picoseconds. + Weight::from_parts(8_236_588, 0) + // Standard Error: 32 + .saturating_add(Weight::from_parts(71_473, 0).saturating_mul(r.into())) } /// Storage: UNKNOWN KEY `0x735f040a5d490f1107ad9c56f5ca00d2060e99e5378e562537cf3bc983e17b91` (r:2 w:1) /// Proof: UNKNOWN KEY `0x735f040a5d490f1107ad9c56f5ca00d2060e99e5378e562537cf3bc983e17b91` (r:2 w:1) @@ -2276,9 +2430,24 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `316` // Estimated: `6256` - // Minimum execution time: 12_136_000 picoseconds. - Weight::from_parts(12_668_000, 6256) + // Minimum execution time: 12_137_000 picoseconds. + Weight::from_parts(12_594_000, 6256) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Revive::CodeInfoOf` (r:2 w:1) + /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(97), added: 2572, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:2 w:2) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(427), added: 2902, mode: `MaxEncodedLen`) + fn v2_migration_step() -> Weight { + // Proof Size summary in bytes: + // Measured: `741` + // Estimated: `6794` + // Minimum execution time: 64_340_000 picoseconds. + Weight::from_parts(67_378_000, 6794) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } }