From 8012f45475edb459c486ac3e2fabab01039bdc9b Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Sat, 9 Aug 2025 20:52:37 +0200 Subject: [PATCH 01/63] Reflect `block_hash` already being stable in `uapi` --- substrate/frame/revive/uapi/src/host.rs | 1 - substrate/frame/revive/uapi/src/host/riscv64.rs | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs index c7684bd8cece4..5b89f9e199830 100644 --- a/substrate/frame/revive/uapi/src/host.rs +++ b/substrate/frame/revive/uapi/src/host.rs @@ -439,7 +439,6 @@ pub trait HostFn: private::Sealed { /// /// - `block_number`: A reference to the block number buffer. /// - `output`: A reference to the output data buffer to write the block number. - #[unstable_hostfn] fn block_hash(block_number: &[u8; 32], output: &mut [u8; 32]); /// Call into the chain extension provided by the chain if any. diff --git a/substrate/frame/revive/uapi/src/host/riscv64.rs b/substrate/frame/revive/uapi/src/host/riscv64.rs index b0cc4987e2cb7..a56a554b3872c 100644 --- a/substrate/frame/revive/uapi/src/host/riscv64.rs +++ b/substrate/frame/revive/uapi/src/host/riscv64.rs @@ -445,7 +445,10 @@ impl HostFn for HostFnImpl { unsafe { sys::ref_time_left() } } - #[unstable_hostfn] + fn to_account_id(address: &[u8; 20], output: &mut [u8]) { + unsafe { sys::to_account_id(address.as_ptr(), output.as_mut_ptr()) } + } + fn block_hash(block_number_ptr: &[u8; 32], output: &mut [u8; 32]) { unsafe { sys::block_hash(block_number_ptr.as_ptr(), output.as_mut_ptr()) }; } From db9f6c53534b555932b779f6e99e4eed8fb03bf5 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Sat, 9 Aug 2025 20:53:04 +0200 Subject: [PATCH 02/63] Remove `call_chain_extension` from `uapi` --- substrate/frame/revive/uapi/src/host.rs | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs index 5b89f9e199830..9d72030ab0313 100644 --- a/substrate/frame/revive/uapi/src/host.rs +++ b/substrate/frame/revive/uapi/src/host.rs @@ -441,31 +441,6 @@ pub trait HostFn: private::Sealed { /// - `output`: A reference to the output data buffer to write the block number. fn block_hash(block_number: &[u8; 32], output: &mut [u8; 32]); - /// Call into the chain extension provided by the chain if any. - /// - /// Handling of the input values is up to the specific chain extension and so is the - /// return value. The extension can decide to use the inputs as primitive inputs or as - /// in/out arguments by interpreting them as pointers. Any caller of this function - /// must therefore coordinate with the chain that it targets. - /// - /// # Note - /// - /// If no chain extension exists the contract will trap with the `NoChainExtension` - /// module error. - /// - /// # Parameters - /// - /// - `func_id`: The function id of the chain extension. - /// - `input`: The input data buffer. - /// - `output`: A reference to the output data buffer to write the call output buffer. If `None` - /// is provided then the output buffer is not copied. - /// - /// # Return - /// - /// The chain extension returned value, if executed successfully. - #[unstable_hostfn] - fn call_chain_extension(func_id: u32, input: &[u8], output: Option<&mut &mut [u8]>) -> u32; - /// Checks whether the caller of the current contract is the origin of the whole call stack. /// /// From 1b69351d4c719413590124e14f1551613b7b5c96 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Sun, 10 Aug 2025 18:21:33 +0200 Subject: [PATCH 03/63] Implement getters --- Cargo.lock | 24 ++++ .../frame/revive/fixtures/build/_Cargo.toml | 1 + .../contracts/call_caller_is_origin.rs | 55 +++++++++ .../fixtures/contracts/call_caller_is_root.rs | 45 ++++++++ .../contracts/call_diverging_out_len.rs | 45 +++++++- .../fixtures/contracts/call_own_code_hash.rs | 56 +++++++++ .../fixtures/contracts/caller_is_origin_n.rs | 23 +++- .../contracts/chain_extension_temp_storage.rs | 66 ----------- .../frame/revive/fixtures/contracts/drain.rs | 18 ++- .../{chain_extension.rs => gas_price_n.rs} | 16 +-- substrate/frame/revive/proc-macro/src/lib.rs | 2 +- substrate/frame/revive/src/benchmarking.rs | 10 +- substrate/frame/revive/src/exec.rs | 33 +----- substrate/frame/revive/src/exec/tests.rs | 106 ++++++++++++++++-- substrate/frame/revive/src/lib.rs | 2 +- substrate/frame/revive/src/precompiles.rs | 14 ++- .../revive/src/precompiles/builtin/system.rs | 75 ++++++++++++- substrate/frame/revive/src/tests.rs | 69 +++++++++++- substrate/frame/revive/src/vm/runtime.rs | 41 ------- substrate/frame/revive/uapi/Cargo.toml | 2 + substrate/frame/revive/uapi/src/host.rs | 53 +-------- .../frame/revive/uapi/src/host/riscv64.rs | 66 ----------- substrate/frame/revive/uapi/src/lib.rs | 6 +- .../frame/revive/uapi/src/precompile_utils.rs | 46 ++++++++ 24 files changed, 581 insertions(+), 293 deletions(-) create mode 100644 substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs create mode 100644 substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs create mode 100644 substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs delete mode 100644 substrate/frame/revive/fixtures/contracts/chain_extension_temp_storage.rs rename substrate/frame/revive/fixtures/contracts/{chain_extension.rs => gas_price_n.rs} (68%) create mode 100644 substrate/frame/revive/uapi/src/precompile_utils.rs diff --git a/Cargo.lock b/Cargo.lock index 4c4d0344bf222..fa7175159e98a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3459,6 +3459,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "const-crypto" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c06f1eb05f06cf2e380fdded278fbf056a38974299d77960555a311dcf91a52" +dependencies = [ + "keccak-const", + "sha2-const-stable", +] + [[package]] name = "const-hex" version = "1.14.0" @@ -8828,6 +8838,12 @@ dependencies = [ "sha3-asm", ] +[[package]] +name = "keccak-const" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d8d8ce877200136358e0bbff3a77965875db3af755a11e1fa6b1b3e2df13ea" + [[package]] name = "keccak-hash" version = "0.11.0" @@ -12977,6 +12993,8 @@ name = "pallet-revive-uapi" version = "0.1.0" dependencies = [ "bitflags 1.3.2", + "const-crypto", + "hex-literal", "pallet-revive-proc-macro", "parity-scale-codec", "polkavm-derive 0.27.0", @@ -21240,6 +21258,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" + [[package]] name = "sha3" version = "0.10.8" diff --git a/substrate/frame/revive/fixtures/build/_Cargo.toml b/substrate/frame/revive/fixtures/build/_Cargo.toml index af898cec525ef..67cc31e870f75 100644 --- a/substrate/frame/revive/fixtures/build/_Cargo.toml +++ b/substrate/frame/revive/fixtures/build/_Cargo.toml @@ -13,6 +13,7 @@ edition = "2021" # All paths are injected dynamically by the build script. [dependencies] uapi = { package = 'pallet-revive-uapi', features = ["unstable-hostfn"], default-features = false } +const-crypto = { version = "0.3.0", default-features = false } hex-literal = { version = "0.4.1", default-features = false } polkavm-derive = { version = "0.27.0" } diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs new file mode 100644 index 0000000000000..71482247d84c8 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.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. + +//! This fixture calls caller_is_origin `n` times. + +#![no_std] +#![no_main] +include!("../panic_handler.rs"); + +use uapi::{HostFn, HostFnImpl as api, u256_bytes}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + let mut data = [0u8; 4 + 32]; + const SELECTOR_BYTES: [u8; 4] = uapi::solidity_selector("callerIsOrigin()"); + data[..4].copy_from_slice(&SELECTOR_BYTES[..4]); + + let mut caller = [0; 20]; + api::caller(&mut caller); + let address_bytes = uapi::solidity_address(&caller); + data[4..36].copy_from_slice(&address_bytes[..32]); + + let mut output = [0u8; 1]; + let _ = api::call( + uapi::CallFlags::empty(), + &uapi::SYSTEM_PRECOMPILE_ADDR, + u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. + &[u8::MAX; 32], // No deposit limit. + &u256_bytes(0), + &data, + Some(&mut &mut output[..]), + ).unwrap(); + + api::return_value(uapi::ReturnFlags::empty(), &output); +} diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs new file mode 100644 index 0000000000000..9f964f5b5751e --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs @@ -0,0 +1,45 @@ +// 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. + +//! This fixture calls caller_is_origin `n` times. + +#![no_std] +#![no_main] +include!("../panic_handler.rs"); + +use uapi::{HostFn, HostFnImpl as api}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + let mut output = [0u8; 1]; + let _ = api::delegate_call( + uapi::CallFlags::empty(), + &uapi::SYSTEM_PRECOMPILE_ADDR, + u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. + &[u8::MAX; 32], // No deposit limit. + &uapi::solidity_selector("callerIsRoot()"), + Some(&mut &mut output[..]), + ).unwrap(); + + api::return_value(uapi::ReturnFlags::empty(), &output); +} diff --git a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs index 9e208845c3362..424e6773757a4 100644 --- a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs +++ b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs @@ -23,17 +23,24 @@ //! and also instantiate our own code hash (constructor and recursive calls //! always return `BUF_SIZE` bytes of data). +#![allow(unused_imports)] #![no_std] #![no_main] include!("../panic_handler.rs"); -use uapi::{HostFn, HostFnImpl as api}; +use core::num::NonZero; +//use uapi::{HostFn, HostFnImpl as api}; +//use alloy_sol_macro::sol; +//use alloy_core::sol_types::SolInterface; +use uapi::{HostFn, HostFnImpl as api, u256_bytes}; +use hex_literal::hex; const BUF_SIZE: usize = 8; static DATA: [u8; BUF_SIZE] = [1, 2, 3, 4, 5, 6, 7, 8]; /// Call `callee_address` with an output buf of size `N` /// and expect the call output to match `expected_output`. +#[allow(dead_code)] fn assert_call(callee_address: &[u8; 20], expected_output: [u8; BUF_SIZE]) { let mut output_buf = [0u8; BUF_SIZE]; let output_buf_capped = &mut &mut output_buf[..N]; @@ -55,11 +62,39 @@ fn assert_call(callee_address: &[u8; 20], expected_output: [u8; assert_eq!(output_buf, expected_output); } +/* +use alloy_sol_types::sol; +sol! { + //interface ISystem { + /// Returns the code hash of the currently executing contract. + function ownCodeHash() external pure returns (bytes32); + //} +} + + */ + +//use alloy_primitives::const_keccak256; + +//const TRANSFER_SELECTOR: [u8; 4] = + //const_keccak256!("transfer(address,uint256)").truncate(); + /// Instantiate this contract with an output buf of size `N` /// and expect the instantiate output to match `expected_output`. +#[allow(dead_code)] fn assert_instantiate(expected_output: [u8; BUF_SIZE]) { - let mut code_hash = [0; 32]; - api::own_code_hash(&mut code_hash); + let mut output_buf1 = [0u8; 32]; + let output1 = &mut &mut output_buf1[..]; + let _ = api::call( + uapi::CallFlags::empty(), + &uapi::SYSTEM_PRECOMPILE_ADDR, + u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. + &[u8::MAX; 32], // No deposit limit. + &u256_bytes(0), + &uapi::solidity_selector("ownCodeHash()"), + Some(output1), + ).unwrap(); + assert_ne!(output_buf1, [0u8; 32]); let mut output_buf = [0u8; BUF_SIZE]; let output_buf_capped = &mut &mut output_buf[..N]; @@ -68,8 +103,8 @@ fn assert_instantiate(expected_output: [u8; BUF_SIZE]) { u64::MAX, u64::MAX, &[u8::MAX; 32], - &[0; 32], - &code_hash, + &u256_bytes(0), + output_buf1.clone().as_slice(), None, Some(output_buf_capped), None, diff --git a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs new file mode 100644 index 0000000000000..e0662ea73dc07 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs @@ -0,0 +1,56 @@ +// 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. + +//! This tests that the correct output data is written when the provided +//! output buffer length is smaller than what was actually returned during +//! calls and instantiations. +//! +//! To not need an additional callee fixture, we call ourself recursively +//! and also instantiate our own code hash (constructor and recursive calls +//! always return `BUF_SIZE` bytes of data). + +#![allow(unused_imports)] +#![no_std] +#![no_main] +include!("../panic_handler.rs"); + +use core::num::NonZero; +use uapi::{HostFn, HostFnImpl as api, u256_bytes}; +use hex_literal::hex; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() { } + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + let mut output_buf1 = [0u8; 32]; + let output1 = &mut &mut output_buf1[..]; + let _ = api::call( + uapi::CallFlags::empty(), + &uapi::SYSTEM_PRECOMPILE_ADDR, + u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. + &[u8::MAX; 32], // No deposit limit. + &u256_bytes(0), // Value transferred to the contract. + &uapi::solidity_selector("ownCodeHash()"), + Some(output1), + ).unwrap(); + assert_ne!(output_buf1, [0u8; 32]); + api::return_value(uapi::ReturnFlags::empty(), &output_buf1); +} diff --git a/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs b/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs index f176dae12b8de..8bfee09684828 100644 --- a/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs +++ b/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs @@ -21,7 +21,7 @@ #![no_main] include!("../panic_handler.rs"); -use uapi::{input, HostFn, HostFnImpl as api}; +use uapi::{input, HostFn, HostFnImpl as api, u256_bytes, solidity_selector, solidity_address}; #[no_mangle] #[polkavm_derive::polkavm_export] @@ -32,7 +32,26 @@ pub extern "C" fn deploy() {} pub extern "C" fn call() { input!(n: u32, ); + const SELECTOR_BYTES: [u8; 4] = solidity_selector("callerIsOrigin(address)"); + + let mut caller = [0; 20]; + api::caller(&mut caller); + let address_bytes = solidity_address(&caller); + + let mut data = [0u8; 4 + 32]; + data[..4].copy_from_slice(&SELECTOR_BYTES[..4]); + data[4..36].copy_from_slice(&address_bytes[..32]); + for _ in 0..n { - let _ = api::caller_is_origin(); + let _ = api::call( + uapi::CallFlags::empty(), + &uapi::SYSTEM_PRECOMPILE_ADDR, + u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. + &[u8::MAX; 32], // No deposit limit. + &u256_bytes(0), + data.as_slice(), + None, + ).unwrap(); } } diff --git a/substrate/frame/revive/fixtures/contracts/chain_extension_temp_storage.rs b/substrate/frame/revive/fixtures/contracts/chain_extension_temp_storage.rs deleted file mode 100644 index 70aedf35fea56..0000000000000 --- a/substrate/frame/revive/fixtures/contracts/chain_extension_temp_storage.rs +++ /dev/null @@ -1,66 +0,0 @@ -// 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. - -//! Call chain extension two times with the specified func_ids -//! It then calls itself once -#![no_std] -#![no_main] -include!("../panic_handler.rs"); - -use uapi::{input, HostFn, HostFnImpl as api}; - -#[no_mangle] -#[polkavm_derive::polkavm_export] -pub extern "C" fn deploy() {} - -#[no_mangle] -#[polkavm_derive::polkavm_export] -pub extern "C" fn call() { - input!( - input, - func_id1: u32, - func_id2: u32, - stop_recurse: u8, - ); - - api::call_chain_extension(func_id1, input, None); - api::call_chain_extension(func_id2, input, None); - - if stop_recurse == 0 { - // Setup next call - input[0..4].copy_from_slice(&((3 << 16) | 2u32).to_le_bytes()); - input[4..8].copy_from_slice(&((3 << 16) | 3u32).to_le_bytes()); - input[8] = 1u8; - - // Read the contract address. - let mut addr = [0u8; 20]; - api::address(&mut addr); - - // call self - api::call( - uapi::CallFlags::ALLOW_REENTRY, - &addr, - u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. - u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. - &[u8::MAX; 32], // No deposit limit. - &[0u8; 32], // Value transferred to the contract. - input, - None, - ) - .unwrap(); - } -} diff --git a/substrate/frame/revive/fixtures/contracts/drain.rs b/substrate/frame/revive/fixtures/contracts/drain.rs index 13698205eb20a..6c4a875e0e023 100644 --- a/substrate/frame/revive/fixtures/contracts/drain.rs +++ b/substrate/frame/revive/fixtures/contracts/drain.rs @@ -19,7 +19,7 @@ #![no_main] include!("../panic_handler.rs"); -use uapi::{u256_bytes, u64_output, HostFn, HostFnImpl as api}; +use uapi::{u256_bytes, u64_output, HostFn, HostFnImpl as api, solidity_selector}; #[no_mangle] #[polkavm_derive::polkavm_export] @@ -29,7 +29,21 @@ pub extern "C" fn deploy() {} #[polkavm_derive::polkavm_export] pub extern "C" fn call() { let balance = u64_output!(api::balance,); - let minimum_balance = u64_output!(api::minimum_balance,); + + let mut output_buf1 = [0u8; 8]; + let output1 = &mut &mut output_buf1[..]; + let _ = api::call( + uapi::CallFlags::empty(), + &uapi::SYSTEM_PRECOMPILE_ADDR, + u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. + &[u8::MAX; 32], // No deposit limit. + &u256_bytes(0), + &solidity_selector("minimumBalance()"), + Some(output1), + ).unwrap(); + assert_ne!(output_buf1, [0u8; 8]); + let minimum_balance = u64::from_le_bytes(output_buf1); // Make the transferred value exceed the balance by adding the minimum balance. let balance = balance + minimum_balance; diff --git a/substrate/frame/revive/fixtures/contracts/chain_extension.rs b/substrate/frame/revive/fixtures/contracts/gas_price_n.rs similarity index 68% rename from substrate/frame/revive/fixtures/contracts/chain_extension.rs rename to substrate/frame/revive/fixtures/contracts/gas_price_n.rs index bd142b321c01f..52b0fa9b97c60 100644 --- a/substrate/frame/revive/fixtures/contracts/chain_extension.rs +++ b/substrate/frame/revive/fixtures/contracts/gas_price_n.rs @@ -15,7 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Call chain extension by passing through input and output of this contract. +//! Returns the gas price back to the caller. + #![no_std] #![no_main] include!("../panic_handler.rs"); @@ -29,14 +30,9 @@ pub extern "C" fn deploy() {} #[no_mangle] #[polkavm_derive::polkavm_export] pub extern "C" fn call() { - input!(input, 8, func_id: u32,); - - // the chain extension passes through the input and returns it as output - let mut output_buffer = [0u8; 32]; - let output = &mut &mut output_buffer[0..input.len()]; - - let ret_id = api::call_chain_extension(func_id, input, Some(output)); - assert_eq!(ret_id, func_id); + input!(n: u32, ); - api::return_value(uapi::ReturnFlags::empty(), output); + for _ in 0..n { + let _ = api::gas_price(); + } } diff --git a/substrate/frame/revive/proc-macro/src/lib.rs b/substrate/frame/revive/proc-macro/src/lib.rs index 42b34a628476f..87f7c699f461d 100644 --- a/substrate/frame/revive/proc-macro/src/lib.rs +++ b/substrate/frame/revive/proc-macro/src/lib.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Procedural macros used in the contracts module. +//! Procedural macros used in `pallet-revive`. //! //! Most likely you should use the [`#[define_env]`][`macro@define_env`] attribute macro which hides //! boilerplate of defining external environment for a polkavm module. diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index 84819744b2ffb..f5683f2d1ee01 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -606,6 +606,7 @@ mod benchmarks { ); } + /* #[benchmark(pov_mode = Measured)] fn seal_own_code_hash() { let len = ::max_encoded_len() as u32; @@ -622,6 +623,7 @@ mod benchmarks { contract.info().unwrap().code_hash ); } + */ #[benchmark(pov_mode = Measured)] fn seal_code_size() { @@ -637,6 +639,7 @@ mod benchmarks { assert_eq!(result.unwrap(), VmBinaryModule::dummy().code.len() as u64); } + /* #[benchmark(pov_mode = Measured)] fn seal_caller_is_origin() { build_runtime!(runtime, memory: []); @@ -663,6 +666,7 @@ mod benchmarks { } assert_eq!(result.unwrap(), 1u32); } + */ #[benchmark(pov_mode = Measured)] fn seal_address() { @@ -678,8 +682,9 @@ mod benchmarks { assert_eq!(::decode(&mut &memory[..]).unwrap(), runtime.ext().address()); } + /* #[benchmark(pov_mode = Measured)] - fn seal_weight_left() { + fn weight_left() { // use correct max_encoded_len when new version of parity-scale-codec is released let len = 18u32; assert!(::max_encoded_len() as u32 != len); @@ -696,6 +701,7 @@ mod benchmarks { runtime.ext().gas_meter().gas_left() ); } + */ #[benchmark(pov_mode = Measured)] fn seal_ref_time_left() { @@ -817,6 +823,7 @@ mod benchmarks { assert_eq!(U256::from_little_endian(&memory[..]), runtime.ext().value_transferred()); } + /* #[benchmark(pov_mode = Measured)] fn seal_minimum_balance() { build_runtime!(runtime, memory: [[0u8;32], ]); @@ -828,6 +835,7 @@ mod benchmarks { assert_ok!(result); assert_eq!(U256::from_little_endian(&memory[..]), runtime.ext().minimum_balance()); } + */ #[benchmark(pov_mode = Measured)] fn seal_return_data_size() { diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index ec277d562f825..f07c5960b3463 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -139,7 +139,7 @@ impl> From for ExecError { } } -/// The type of origins supported by the revive pallet. +/// The type of origins supported by revive pallet. #[derive(Clone, Encode, Decode, PartialEq, TypeInfo, RuntimeDebugNoBound)] pub enum Origin { Root, @@ -202,9 +202,6 @@ pub trait Ext: PrecompileWithInfoExt { /// call stack. fn terminate(&mut self, beneficiary: &H160) -> DispatchResult; - /// 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; @@ -284,8 +281,6 @@ pub trait PrecompileExt: sealing::Sealed { } /// Call (possibly transferring some amount of funds) into the specified account. - /// - /// Returns the code size of the called contract. fn call( &mut self, gas_limit: Weight, @@ -331,12 +326,6 @@ pub trait PrecompileExt: sealing::Sealed { /// Returns the code size of the contract at the given `address` or zero. fn code_size(&self, address: &H160) -> u64; - /// Check if the caller of the current contract is the origin of the whole call stack. - fn caller_is_origin(&self) -> bool; - - /// Check if the caller is origin, and this origin is root. - fn caller_is_root(&self) -> bool; - /// Returns a reference to the account id of the current contract. fn account_id(&self) -> &AccountIdOf; @@ -361,9 +350,6 @@ pub trait PrecompileExt: sealing::Sealed { /// Returns the timestamp of the current block in seconds. fn now(&self) -> U256; - /// Returns the minimum balance that is required for creating an account. - fn minimum_balance(&self) -> U256; - /// Deposit an event with the given topics. /// /// There should not be any duplicates in `topics`. @@ -1647,10 +1633,6 @@ where Ok(()) } - fn own_code_hash(&mut self) -> &H256 { - &self.top_frame_mut().contract_info().code_hash - } - /// TODO: This should be changed to run the constructor of the supplied `hash`. /// /// Because the immutable data is attached to a contract and not a code, @@ -1962,15 +1944,6 @@ where .unwrap_or_default() } - fn caller_is_origin(&self) -> bool { - self.origin == self.caller() - } - - fn caller_is_root(&self) -> bool { - // if the caller isn't origin, then it can't be root. - self.caller_is_origin() && self.origin == Origin::Root - } - fn balance(&self) -> U256 { self.account_balance(&self.top_frame().account_id) } @@ -1992,10 +1965,6 @@ where (self.timestamp / 1000u32.into()).into() } - fn minimum_balance(&self) -> U256 { - T::Currency::minimum_balance().into() - } - fn deposit_event(&mut self, topics: Vec, data: Vec) { let contract = T::AddressMapper::to_address(self.account_id()); if_tracing(|tracer| { diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index 381abc7c26117..0ea371e1e6529 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -830,6 +830,7 @@ fn code_hash_returns_proper_values() { }); } +/* #[test] fn own_code_hash_returns_proper_values() { let bob_ch = MockLoader::insert(Call, |ctx, _| { @@ -891,12 +892,38 @@ fn caller_is_origin_returns_proper_values() { assert_matches!(result, Ok(_)); }); } +*/ #[test] fn root_caller_succeeds() { let code_bob = MockLoader::insert(Call, |ctx, _| { // root is the origin of the call stack. - assert!(ctx.ext.caller_is_root()); + /* + assert_ok!(ctx.ext.call( + Weight::MAX, + U256::zero(), + &H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + U256::zero(), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + true, + true + )); + + */ + + + let ret = ctx.ext.delegate_call(Weight::MAX, U256::zero(), + H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + ) + .map(|_| ctx.ext.last_frame_output().clone()); + + let data = ret.unwrap().data ; + eprintln!("data: {:?}", data); + let caller_is_root = data == vec![1]; + assert!(caller_is_root); + + exec_success() }); @@ -922,7 +949,22 @@ fn root_caller_succeeds() { fn root_caller_does_not_succeed_when_value_not_zero() { let code_bob = MockLoader::insert(Call, |ctx, _| { // root is the origin of the call stack. - assert!(ctx.ext.caller_is_root()); + assert_ok!(ctx.ext.delegate_call(Weight::MAX, U256::zero(), + H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + )); + + /* + assert_ok!(ctx.ext.call( + Weight::MAX, + U256::zero(), + &H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + U256::zero(), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + true, + true + )); + */ exec_success() }); @@ -947,17 +989,66 @@ fn root_caller_does_not_succeed_when_value_not_zero() { #[test] fn root_caller_succeeds_with_consecutive_calls() { let code_charlie = MockLoader::insert(Call, |ctx, _| { + eprintln!("charlie received call"); // BOB is not root, even though the origin is root. - assert!(!ctx.ext.caller_is_root()); + + + let ret = ctx.ext.delegate_call(Weight::MAX, U256::zero(), + H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + ) + .map(|_| ctx.ext.last_frame_output().clone()); + + /* + let ret = ctx.ext.call( + Weight::MAX, + U256::zero(), + &H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + U256::zero(), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + true, + true + ) + .map(|_| ctx.ext.last_frame_output().clone()); + */ + let data = ret.unwrap().data ; + eprintln!("data: {:?}", data); + let caller_is_root = data == vec![1]; + assert!(!caller_is_root); + //assert!(!ctx.ext.caller_is_root()); exec_success() }); let code_bob = MockLoader::insert(Call, |ctx, _| { // root is the origin of the call stack. - assert!(ctx.ext.caller_is_root()); + //assert!(ctx.ext.caller_is_root()); + /* + let ret = ctx.ext.call( + Weight::MAX, + U256::zero(), + &H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + U256::zero(), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + true, + true + ) + .map(|_| ctx.ext.last_frame_output().clone()); + */ + let ret = ctx.ext.delegate_call(Weight::MAX, U256::zero(), + H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + ) + .map(|_| ctx.ext.last_frame_output().clone()); + + let data = ret.unwrap().data ; + eprintln!("data 2: {:?}", data); + let caller_is_root = data == vec![1]; + assert!(caller_is_root); + // BOB calls CHARLIE. + eprintln!("bob calls charlie"); ctx.ext - .call(Weight::zero(), U256::zero(), &CHARLIE_ADDR, U256::zero(), vec![], true, false) + .call(Weight::MAX, U256::zero(), &CHARLIE_ADDR, U256::zero(), vec![], true, false) .map(|_| ctx.ext.last_frame_output().clone()) }); @@ -1573,6 +1664,7 @@ fn call_deny_reentry() { #[test] fn nonce() { + let minimum_balance = ::Currency::minimum_balance(); let fail_code = MockLoader::insert(Constructor, |_, _| exec_trapped()); let success_code = MockLoader::insert(Constructor, |_, _| exec_success()); let succ_fail_code = MockLoader::insert(Constructor, move |ctx, _| { @@ -1581,7 +1673,7 @@ fn nonce() { Weight::MAX, U256::MAX, fail_code, - ctx.ext.minimum_balance() * 100, + (minimum_balance * 100).into(), vec![], Some(&[0; 32]), ) @@ -1598,7 +1690,7 @@ fn nonce() { Weight::MAX, U256::MAX, success_code, - ctx.ext.minimum_balance() * 100, + (minimum_balance * 100).into(), vec![], Some(&[0; 32]), ) diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 8b2d7f76e716a..69d1e49408eee 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -479,7 +479,7 @@ pub mod pallet { ReturnDataTooLarge = 0x31, } - /// A reason for the pallet revive placing a hold on funds. + /// A reason for the `pallet-revive` placing a hold on funds. #[pallet::composite_enum] pub enum HoldReason { /// The Pallet has reserved it for storing code on-chain. diff --git a/substrate/frame/revive/src/precompiles.rs b/substrate/frame/revive/src/precompiles.rs index b827caa27c09c..0968a7d927c58 100644 --- a/substrate/frame/revive/src/precompiles.rs +++ b/substrate/frame/revive/src/precompiles.rs @@ -41,7 +41,7 @@ pub use sp_core::{H160, H256, U256}; use crate::{ exec::ExecResult, precompiles::builtin::Builtin, primitives::ExecReturnValue, Config, - Error as CrateError, + Error as CrateError, LOG_TARGET, }; use alloc::vec::Vec; use alloy::sol_types::{Panic, PanicKind, Revert, SolError, SolInterface}; @@ -370,8 +370,11 @@ impl PrimitivePrecompile for P { input: Vec, env: &mut impl Ext, ) -> Result, Error> { - let call = ::Interface::abi_decode_validate(&input) - .map_err(|_| Error::Panic(PanicKind::ResourceError))?; + let call = + ::Interface::abi_decode_validate(&input).map_err(|err| { + log::debug!(target: LOG_TARGET, "`abi_decode_validate` for pre-compile failed: {err:?}"); + Error::Panic(PanicKind::ResourceError) + })?; ::call(address, &call, env) } @@ -381,7 +384,10 @@ impl PrimitivePrecompile for P { env: &mut impl ExtWithInfo, ) -> Result, Error> { let call = ::Interface::abi_decode_validate(&input) - .map_err(|_| Error::Panic(PanicKind::ResourceError))?; + .map_err(|err| { + log::debug!(target: LOG_TARGET, "`abi_decode_validate` for pre-compile (with info) failed: {err:?}"); + Error::Panic(PanicKind::ResourceError) + })?; ::call_with_info(address, &call, env) } } diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index aa8b537110461..0e31c7cd51f41 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -16,13 +16,16 @@ // limitations under the License. use crate::{ + address::AddressMapper, precompiles::{BuiltinAddressMatcher, BuiltinPrecompile, Error, Ext}, vm::RuntimeCosts, - Config, + Config, Origin, H160, }; use alloc::vec::Vec; use alloy_core::sol; +use codec::Encode; use core::{marker::PhantomData, num::NonZero}; +use frame_support::traits::fungible::Inspect; use sp_core::hexdisplay::AsBytesRef; pub struct System(PhantomData); @@ -31,8 +34,10 @@ sol! { interface ISystem { /// Computes the BLAKE2 256-bit hash on the given input. function hashBlake256(bytes memory input) external pure returns (bytes32 digest); + /// Computes the BLAKE2 128-bit hash on the given input. function hashBlake128(bytes memory input) external pure returns (bytes32 digest); + /// Retrieve the account id for a specified `H160` address. /// /// Calling this function on a native `H160` chain (`type AccountId = H160`) @@ -43,6 +48,32 @@ sol! { /// /// If no mapping exists for `addr`, the fallback account id will be returned. function toAccountId(address input) external view returns (bytes memory account_id); + + /// Check whether the `caller` is the origin of the whole call stack. + /// + /// todo If there is no address associated with the caller (e.g. because the caller is root) then + /// todo it traps with `BadOrigin`. + function callerIsOrigin() external pure returns (bool); + + /// Checks whether the caller of the current contract is root. + /// + /// Note that only the origin of the call stack can be root. Hence this function returning + /// `true` implies that the contract is being called by the origin. + /// + /// A return value of `true` indicates that this contract is being called by a root origin, + /// and `false` indicates that the caller is a signed origin. + function callerIsRoot() external pure returns (bool); + + /// Returns the minimum balance that is required for creating an account + /// (the existential deposit). + function minimumBalance() external pure returns (uint); + + /// Returns the code hash of the currently executing contract. + function ownCodeHash() external pure returns (bytes32); + + /// Returns the amount of weight left. + /// The data is encoded as `Weight`. + function weightLeft() external pure returns (uint); } } @@ -78,6 +109,48 @@ impl BuiltinPrecompile for System { T::AddressMapper::to_account_id(&crate::H160::from_slice(input.as_slice())); Ok(account_id.encode()) }, + ISystemCalls::callerIsOrigin(ISystem::callerIsOriginCall { }) => { + env.gas_meter_mut().charge(RuntimeCosts::CallerIsOrigin)?; + let is_origin = match env.origin() { + Origin::Root => { + // `Root` does not have an address + false + }, + Origin::Signed(account_id) => { + let origin_address = T::AddressMapper::to_address(&account_id).0; + let origin_address = T::AddressMapper::to_address(&env.caller()).0; + origin_address == caller_address + }, + }; + Ok(vec![is_origin as u8]) + }, + ISystemCalls::callerIsRoot(ISystem::callerIsRootCall {}) => { + env.gas_meter_mut().charge(RuntimeCosts::CallerIsRoot)?; + let caller_is_root = match env.caller() { + Origin::Root => true, + Origin::Signed(_) => false, + }; + Ok(vec![caller_is_root as u8]) + }, + ISystemCalls::ownCodeHash(ISystem::ownCodeHashCall {}) => { + env.gas_meter_mut().charge(RuntimeCosts::OwnCodeHash)?; + let caller = env.caller(); + let address = caller.account_id().unwrap().encode(); + let address = H160::from_slice(&address[..20]); + let output = env.code_hash(&address).encode(); + Ok(output) + }, + ISystemCalls::minimumBalance(ISystem::minimumBalanceCall {}) => { + env.gas_meter_mut().charge(RuntimeCosts::MinimumBalance)?; + let minimum_balance = T::Currency::minimum_balance(); + let output = minimum_balance.encode(); + Ok(output) + }, + ISystemCalls::weightLeft(ISystem::weightLeftCall {}) => { + env.gas_meter_mut().charge(RuntimeCosts::WeightLeft)?; + let gas_left = env.gas_meter().gas_left().encode(); + Ok(gas_left) + }, } } } diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 0cee2e3d9499a..c3c482af80286 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -854,7 +854,7 @@ fn run_out_of_fuel_host() { #[test] fn gas_syncs_work() { - let (code, _code_hash) = compile_module("caller_is_origin_n").unwrap(); + let (code, _code_hash) = compile_module("gas_price_n").unwrap(); ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); let contract = builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); @@ -864,7 +864,8 @@ fn gas_syncs_work() { let engine_consumed_noop = result.gas_consumed.ref_time(); let result = builder::bare_call(contract.addr).data(1u32.encode()).build(); - assert_ok!(result.result); + assert_ok!(result.result.clone()); + assert!(!result.result.clone().unwrap().did_revert()); let gas_consumed_once = result.gas_consumed.ref_time(); let host_consumed_once = ::WeightInfo::seal_caller_is_origin().ref_time(); let engine_consumed_once = gas_consumed_once - host_consumed_once - engine_consumed_noop; @@ -3853,6 +3854,70 @@ fn call_diverging_out_len_works() { }); } +#[test] +fn call_own_code_hash_works() { + let (code, code_hash) = compile_module("call_own_code_hash").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create the contract: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let ret = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(H256::from_slice(&ret.data[..]), code_hash); + }); +} + +#[test] +fn call_caller_is_root() { + let (code, _) = compile_module("call_caller_is_root").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create the contract: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let ret = builder::bare_call(addr).origin(RuntimeOrigin::root()).build_and_unwrap_result(); + assert_eq!(ret.data, vec![1]); + }); +} + +#[test] +fn call_caller_is_root_from_non_root() { + let (code, _) = compile_module("call_caller_is_root").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create the contract: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let ret = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(ret.data, vec![0]); + }); +} + +#[test] +fn call_caller_is_origin() { + let (code, _) = compile_module("call_caller_is_origin").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create the contract: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let ret = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(ret.data, vec![1]); + }); +} + #[test] fn chain_id_works() { let (code, _) = compile_module("chain_id").unwrap(); diff --git a/substrate/frame/revive/src/vm/runtime.rs b/substrate/frame/revive/src/vm/runtime.rs index 3a1cc07ab31a3..a35e67da883cb 100644 --- a/substrate/frame/revive/src/vm/runtime.rs +++ b/substrate/frame/revive/src/vm/runtime.rs @@ -1937,20 +1937,6 @@ pub mod env { Ok(self.ext.gas_meter().gas_left().ref_time()) } - /// Checks whether the caller of the current contract is the origin of the whole call stack. - /// See [`pallet_revive_uapi::HostFn::caller_is_origin`]. - fn caller_is_origin(&mut self, _memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::CallerIsOrigin)?; - Ok(self.ext.caller_is_origin() as u32) - } - - /// Checks whether the caller of the current contract is root. - /// See [`pallet_revive_uapi::HostFn::caller_is_root`]. - fn caller_is_root(&mut self, _memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::CallerIsRoot)?; - Ok(self.ext.caller_is_root() as u32) - } - /// Clear the value at the given key in the contract storage. /// See [`pallet_revive_uapi::HostFn::clear_storage`] #[mutating] @@ -1997,33 +1983,6 @@ pub mod env { } } - /// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::minimum_balance`]. - fn minimum_balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::MinimumBalance)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.minimum_balance().to_little_endian(), - false, - already_charged, - )?) - } - - /// Retrieve the code hash of the currently executing contract. - /// See [`pallet_revive_uapi::HostFn::own_code_hash`]. - fn own_code_hash(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::OwnCodeHash)?; - let code_hash = *self.ext.own_code_hash(); - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - code_hash.as_bytes(), - false, - already_charged, - )?) - } - /// Replace the contract code at the specified address with new code. /// See [`pallet_revive_uapi::HostFn::set_code_hash`]. /// diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml index f4221ca5ce313..32bafcbd16acf 100644 --- a/substrate/frame/revive/uapi/Cargo.toml +++ b/substrate/frame/revive/uapi/Cargo.toml @@ -20,6 +20,8 @@ bitflags = { workspace = true } codec = { features = ["derive", "max-encoded-len"], optional = true, workspace = true } pallet-revive-proc-macro = { workspace = true } scale-info = { features = ["derive"], optional = true, workspace = true } +hex-literal = { version = "0.4.1", default-features = false } +const-crypto = { version = "0.3.0", default-features = false} [target.'cfg(target_arch = "riscv64")'.dependencies] polkavm-derive = { version = "0.27.0" } diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs index 9d72030ab0313..71da29d815fa6 100644 --- a/substrate/frame/revive/uapi/src/host.rs +++ b/substrate/frame/revive/uapi/src/host.rs @@ -219,7 +219,7 @@ pub trait HostFn: private::Sealed { /// Retrieve the value under the given key from storage. /// - /// The key length must not exceed the maximum defined by the contracts module parameter. + /// The key length must not exceed the maximum defined by the `pallet-revive` parameter. /// /// # Parameters /// - `key`: The storage key. @@ -355,7 +355,7 @@ pub trait HostFn: private::Sealed { /// Set the value at the given key in the contract storage. /// - /// The key and value lengths must not exceed the maximums defined by the contracts module + /// The key and value lengths must not exceed the maximums defined by the `pallet-revive` /// parameters. /// /// # Parameters @@ -441,26 +441,6 @@ pub trait HostFn: private::Sealed { /// - `output`: A reference to the output data buffer to write the block number. fn block_hash(block_number: &[u8; 32], output: &mut [u8; 32]); - /// Checks whether the caller of the current contract is the origin of the whole call stack. - /// - /// - /// # Return - /// - /// A return value of `true` indicates that this contract is being called by a plain account - /// and `false` indicates that the caller is another contract. - #[unstable_hostfn] - fn caller_is_origin() -> bool; - - /// Checks whether the caller of the current contract is root. - /// - /// Note that only the origin of the call stack can be root. Hence this function returning - /// `true` implies that the contract is being called by the origin. - /// - /// A return value of `true` indicates that this contract is being called by a root origin, - /// and `false` indicates that the caller is a signed origin. - #[unstable_hostfn] - fn caller_is_root() -> bool; - /// Clear the value at the given key in the contract storage. /// /// # Parameters @@ -475,7 +455,7 @@ pub trait HostFn: private::Sealed { /// Checks whether there is a value stored under the given key. /// - /// The key length must not exceed the maximum defined by the contracts module parameter. + /// The key length must not exceed the maximum defined by the `pallet-revive` parameter. /// /// # Parameters /// - `key`: The storage key. @@ -500,22 +480,6 @@ pub trait HostFn: private::Sealed { #[unstable_hostfn] fn ecdsa_to_eth_address(pubkey: &[u8; 33], output: &mut [u8; 20]) -> Result; - /// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. - /// - /// # Parameters - /// - /// - `output`: A reference to the output data buffer to write the minimum balance. - #[unstable_hostfn] - fn minimum_balance(output: &mut [u8; 32]); - - /// Retrieve the code hash of the currently executing contract. - /// - /// # Parameters - /// - /// - `output`: A reference to the output data buffer to write the code hash. - #[unstable_hostfn] - fn own_code_hash(output: &mut [u8; 32]); - /// Replace the contract code at the specified address with new code. /// /// # Note @@ -589,17 +553,6 @@ pub trait HostFn: private::Sealed { /// - The deletion queue is full. #[unstable_hostfn] fn terminate(beneficiary: &[u8; 20]) -> !; - - /// Stores the amount of weight left into the supplied buffer. - /// The data is encoded as Weight. - /// - /// If the available space in `output` is less than the size of the value a trap is triggered. - /// - /// # Parameters - /// - /// - `output`: A reference to the output data buffer to write the weight left. - #[unstable_hostfn] - fn weight_left(output: &mut &mut [u8]); } mod private { diff --git a/substrate/frame/revive/uapi/src/host/riscv64.rs b/substrate/frame/revive/uapi/src/host/riscv64.rs index a56a554b3872c..27d1c79bb856c 100644 --- a/substrate/frame/revive/uapi/src/host/riscv64.rs +++ b/substrate/frame/revive/uapi/src/host/riscv64.rs @@ -97,12 +97,8 @@ mod sys { pub fn origin(out_ptr: *mut u8); pub fn code_hash(address_ptr: *const u8, out_ptr: *mut u8); pub fn code_size(address_ptr: *const u8) -> u64; - pub fn own_code_hash(out_ptr: *mut u8); - pub fn caller_is_origin() -> ReturnCode; - pub fn caller_is_root() -> ReturnCode; pub fn address(out_ptr: *mut u8); pub fn weight_to_fee(ref_time: u64, proof_size: u64, out_ptr: *mut u8); - pub fn weight_left(out_ptr: *mut u8, out_len_ptr: *mut u32); pub fn ref_time_left() -> u64; pub fn get_immutable_data(out_ptr: *mut u8, out_len_ptr: *mut u32); pub fn set_immutable_data(ptr: *const u8, len: u32); @@ -112,7 +108,6 @@ mod sys { pub fn value_transferred(out_ptr: *mut u8); pub fn now(out_ptr: *mut u8); pub fn gas_limit() -> u64; - pub fn minimum_balance(out_ptr: *mut u8); pub fn deposit_event( topics_ptr: *const [u8; 32], num_topic: u32, @@ -126,13 +121,6 @@ mod sys { pub fn block_hash(block_number_ptr: *const u8, out_ptr: *mut u8); pub fn block_author(out_ptr: *mut u8); pub fn hash_keccak_256(input_ptr: *const u8, input_len: u32, out_ptr: *mut u8); - pub fn call_chain_extension( - id: u32, - input_ptr: *const u8, - input_len: u32, - out_ptr: *mut u8, - out_len_ptr: *mut u32, - ) -> ReturnCode; pub fn sr25519_verify( signature_ptr: *const u8, pub_key_ptr: *const u8, @@ -445,52 +433,15 @@ impl HostFn for HostFnImpl { unsafe { sys::ref_time_left() } } - fn to_account_id(address: &[u8; 20], output: &mut [u8]) { - unsafe { sys::to_account_id(address.as_ptr(), output.as_mut_ptr()) } - } - fn block_hash(block_number_ptr: &[u8; 32], output: &mut [u8; 32]) { unsafe { sys::block_hash(block_number_ptr.as_ptr(), output.as_mut_ptr()) }; } - #[unstable_hostfn] - fn call_chain_extension(func_id: u32, input: &[u8], mut output: Option<&mut &mut [u8]>) -> u32 { - let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output); - let ret_code = { - unsafe { - sys::call_chain_extension( - func_id, - input.as_ptr(), - input.len() as u32, - output_ptr, - &mut output_len, - ) - } - }; - - if let Some(ref mut output) = output { - extract_from_slice(output, output_len as usize); - } - ret_code.into_u32() - } - fn call_data_copy(output: &mut [u8], offset: u32) { let len = output.len() as u32; unsafe { sys::call_data_copy(output.as_mut_ptr(), len, offset) }; } - #[unstable_hostfn] - fn caller_is_origin() -> bool { - let ret_val = unsafe { sys::caller_is_origin() }; - ret_val.into_bool() - } - - #[unstable_hostfn] - fn caller_is_root() -> bool { - let ret_val = unsafe { sys::caller_is_root() }; - ret_val.into_bool() - } - #[unstable_hostfn] fn clear_storage(flags: StorageFlags, key: &[u8]) -> Option { let ret_code = unsafe { sys::clear_storage(flags.bits(), key.as_ptr(), key.len() as u32) }; @@ -510,16 +461,6 @@ impl HostFn for HostFnImpl { ret_code.into() } - #[unstable_hostfn] - fn minimum_balance(output: &mut [u8; 32]) { - unsafe { sys::minimum_balance(output.as_mut_ptr()) } - } - - #[unstable_hostfn] - fn own_code_hash(output: &mut [u8; 32]) { - unsafe { sys::own_code_hash(output.as_mut_ptr()) } - } - #[unstable_hostfn] fn set_code_hash(code_hash: &[u8; 32]) { unsafe { sys::set_code_hash(code_hash.as_ptr()) } @@ -561,11 +502,4 @@ impl HostFn for HostFnImpl { unsafe { sys::terminate(beneficiary.as_ptr()) } panic!("terminate does not return"); } - - #[unstable_hostfn] - fn weight_left(output: &mut &mut [u8]) { - let mut output_len = output.len() as u32; - unsafe { sys::weight_left(output.as_mut_ptr(), &mut output_len) } - extract_from_slice(output, output_len as usize) - } } diff --git a/substrate/frame/revive/uapi/src/lib.rs b/substrate/frame/revive/uapi/src/lib.rs index 66cf4ffcd6ded..18c308228e367 100644 --- a/substrate/frame/revive/uapi/src/lib.rs +++ b/substrate/frame/revive/uapi/src/lib.rs @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! External C API to communicate with substrate contracts runtime module. +//! External C API to communicate with Polkadot SDK's `pallet-revive` module. //! -//! Refer to substrate FRAME contract module for more documentation. +//! Refer to the FRAME `pallet-revive` module for more documentation. #![no_std] #![cfg_attr(docsrs, feature(doc_cfg))] @@ -23,6 +23,8 @@ mod flags; pub use flags::*; mod host; mod macros; +mod precompile_utils; +pub use precompile_utils::*; pub use host::{HostFn, HostFnImpl}; diff --git a/substrate/frame/revive/uapi/src/precompile_utils.rs b/substrate/frame/revive/uapi/src/precompile_utils.rs new file mode 100644 index 0000000000000..4b3cc7c20a230 --- /dev/null +++ b/substrate/frame/revive/uapi/src/precompile_utils.rs @@ -0,0 +1,46 @@ +// 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. + +//! Helper utilities around pre-compiles. + +/// The contract address for the System pre-compile. +pub const SYSTEM_PRECOMPILE_ADDR: [u8; 20] = + hex_literal::hex!("0000000000000000000000000000000000000900"); + +/// Returns the Solidity selector for `fn_sig`. +/// +/// Note that this is a const function, it is evaluated at compile time. +/// +/// # Usage +/// +/// ``` +/// # use pallet_revive_uapi::solidity_selector; +/// let sel = solidity_selector("ownCodeHash()"); +/// assert_eq!(sel, [219, 107, 220, 138]); +/// ``` +pub const fn solidity_selector(fn_sig: &str) -> [u8; 4] { + let output: [u8; 32] = + const_crypto::sha3::Keccak256::new().update(fn_sig.as_bytes()).finalize(); + [output[0], output[1], output[2], output[3]] +} + +/// Encodes a `[u8; 20]` address for Solidity. +pub fn solidity_address(address: &[u8; 20]) -> [u8; 32] { + let mut buf = [0u8; 32]; + buf[12..32].copy_from_slice(address); + buf +} From cc83058020faeaac62d215beb49403ae18c541a8 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 01:16:05 +0200 Subject: [PATCH 04/63] Remove `address` arg --- .../contracts/call_caller_is_origin.rs | 16 ++---- .../fixtures/contracts/caller_is_origin_n.rs | 17 ++---- .../frame/revive/fixtures/contracts/drain.rs | 4 +- substrate/frame/revive/src/exec/tests.rs | 53 +++++++++++-------- .../revive/src/precompiles/builtin/system.rs | 17 ++++-- 5 files changed, 52 insertions(+), 55 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs index 71482247d84c8..af57cb5d9febf 100644 --- a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs @@ -21,7 +21,7 @@ #![no_main] include!("../panic_handler.rs"); -use uapi::{HostFn, HostFnImpl as api, u256_bytes}; +use uapi::{HostFn, HostFnImpl as api}; #[no_mangle] #[polkavm_derive::polkavm_export] @@ -30,24 +30,14 @@ pub extern "C" fn deploy() {} #[no_mangle] #[polkavm_derive::polkavm_export] pub extern "C" fn call() { - let mut data = [0u8; 4 + 32]; - const SELECTOR_BYTES: [u8; 4] = uapi::solidity_selector("callerIsOrigin()"); - data[..4].copy_from_slice(&SELECTOR_BYTES[..4]); - - let mut caller = [0; 20]; - api::caller(&mut caller); - let address_bytes = uapi::solidity_address(&caller); - data[4..36].copy_from_slice(&address_bytes[..32]); - let mut output = [0u8; 1]; - let _ = api::call( + let _ = api::delegate_call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. - &u256_bytes(0), - &data, + &uapi::solidity_selector("callerIsOrigin()"), Some(&mut &mut output[..]), ).unwrap(); diff --git a/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs b/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs index 8bfee09684828..8553b61336890 100644 --- a/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs +++ b/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs @@ -21,7 +21,7 @@ #![no_main] include!("../panic_handler.rs"); -use uapi::{input, HostFn, HostFnImpl as api, u256_bytes, solidity_selector, solidity_address}; +use uapi::{input, HostFn, HostFnImpl as api}; #[no_mangle] #[polkavm_derive::polkavm_export] @@ -32,25 +32,14 @@ pub extern "C" fn deploy() {} pub extern "C" fn call() { input!(n: u32, ); - const SELECTOR_BYTES: [u8; 4] = solidity_selector("callerIsOrigin(address)"); - - let mut caller = [0; 20]; - api::caller(&mut caller); - let address_bytes = solidity_address(&caller); - - let mut data = [0u8; 4 + 32]; - data[..4].copy_from_slice(&SELECTOR_BYTES[..4]); - data[4..36].copy_from_slice(&address_bytes[..32]); - for _ in 0..n { - let _ = api::call( + let _ = api::delegate_call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. - &u256_bytes(0), - data.as_slice(), + &uapi::solidity_selector("callerIsOrigin()"), None, ).unwrap(); } diff --git a/substrate/frame/revive/fixtures/contracts/drain.rs b/substrate/frame/revive/fixtures/contracts/drain.rs index 6c4a875e0e023..517a7a883df8c 100644 --- a/substrate/frame/revive/fixtures/contracts/drain.rs +++ b/substrate/frame/revive/fixtures/contracts/drain.rs @@ -19,7 +19,7 @@ #![no_main] include!("../panic_handler.rs"); -use uapi::{u256_bytes, u64_output, HostFn, HostFnImpl as api, solidity_selector}; +use uapi::{u256_bytes, u64_output, HostFn, HostFnImpl as api}; #[no_mangle] #[polkavm_derive::polkavm_export] @@ -39,7 +39,7 @@ pub extern "C" fn call() { u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. &u256_bytes(0), - &solidity_selector("minimumBalance()"), + &uapi::solidity_selector("minimumBalance()"), Some(output1), ).unwrap(); assert_ne!(output_buf1, [0u8; 8]); diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index 0ea371e1e6529..3152c39ef039f 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -911,19 +911,21 @@ fn root_caller_succeeds() { */ - - let ret = ctx.ext.delegate_call(Weight::MAX, U256::zero(), - H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), - ) + let ret = ctx + .ext + .delegate_call( + Weight::MAX, + U256::zero(), + H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + ) .map(|_| ctx.ext.last_frame_output().clone()); - let data = ret.unwrap().data ; + let data = ret.unwrap().data; eprintln!("data: {:?}", data); let caller_is_root = data == vec![1]; assert!(caller_is_root); - exec_success() }); @@ -949,9 +951,11 @@ fn root_caller_succeeds() { fn root_caller_does_not_succeed_when_value_not_zero() { let code_bob = MockLoader::insert(Call, |ctx, _| { // root is the origin of the call stack. - assert_ok!(ctx.ext.delegate_call(Weight::MAX, U256::zero(), - H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + assert_ok!(ctx.ext.delegate_call( + Weight::MAX, + U256::zero(), + H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), )); /* @@ -992,11 +996,14 @@ fn root_caller_succeeds_with_consecutive_calls() { eprintln!("charlie received call"); // BOB is not root, even though the origin is root. - - let ret = ctx.ext.delegate_call(Weight::MAX, U256::zero(), - H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), - ) + let ret = ctx + .ext + .delegate_call( + Weight::MAX, + U256::zero(), + H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + ) .map(|_| ctx.ext.last_frame_output().clone()); /* @@ -1011,7 +1018,7 @@ fn root_caller_succeeds_with_consecutive_calls() { ) .map(|_| ctx.ext.last_frame_output().clone()); */ - let data = ret.unwrap().data ; + let data = ret.unwrap().data; eprintln!("data: {:?}", data); let caller_is_root = data == vec![1]; assert!(!caller_is_root); @@ -1034,13 +1041,17 @@ fn root_caller_succeeds_with_consecutive_calls() { ) .map(|_| ctx.ext.last_frame_output().clone()); */ - let ret = ctx.ext.delegate_call(Weight::MAX, U256::zero(), - H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), - ) + let ret = ctx + .ext + .delegate_call( + Weight::MAX, + U256::zero(), + H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + ) .map(|_| ctx.ext.last_frame_output().clone()); - let data = ret.unwrap().data ; + let data = ret.unwrap().data; eprintln!("data 2: {:?}", data); let caller_is_root = data == vec![1]; assert!(caller_is_root); diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index 0e31c7cd51f41..583a5d3f5e19d 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -109,17 +109,24 @@ impl BuiltinPrecompile for System { T::AddressMapper::to_account_id(&crate::H160::from_slice(input.as_slice())); Ok(account_id.encode()) }, - ISystemCalls::callerIsOrigin(ISystem::callerIsOriginCall { }) => { + ISystemCalls::callerIsOrigin(ISystem::callerIsOriginCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::CallerIsOrigin)?; let is_origin = match env.origin() { Origin::Root => { // `Root` does not have an address false }, - Origin::Signed(account_id) => { - let origin_address = T::AddressMapper::to_address(&account_id).0; - let origin_address = T::AddressMapper::to_address(&env.caller()).0; - origin_address == caller_address + Origin::Signed(origin_account_id) => { + let origin_address = T::AddressMapper::to_address(&origin_account_id).0; + //let caller_address = T::AddressMapper::to_address(&env.caller()).0; + match env.caller() { + Origin::Signed(caller_account_id) => { + let caller_address = + T::AddressMapper::to_address(&caller_account_id).0; + origin_address == caller_address + }, + Origin::Root => false, + } }, }; Ok(vec![is_origin as u8]) From 085a84e08ecfb9a4a4b07e1ec9f125b3ec8bb3bf Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 01:30:38 +0200 Subject: [PATCH 05/63] Migrate calls to delegate_calls --- .../contracts/call_diverging_out_len.rs | 3 +- .../fixtures/contracts/call_own_code_hash.rs | 3 +- substrate/frame/revive/src/exec/tests.rs | 87 +++++++++---------- .../revive/src/precompiles/builtin/system.rs | 13 +-- 4 files changed, 49 insertions(+), 57 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs index 424e6773757a4..88537cdf63c90 100644 --- a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs +++ b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs @@ -84,13 +84,12 @@ sol! { fn assert_instantiate(expected_output: [u8; BUF_SIZE]) { let mut output_buf1 = [0u8; 32]; let output1 = &mut &mut output_buf1[..]; - let _ = api::call( + let _ = api::delegate_call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. - &u256_bytes(0), &uapi::solidity_selector("ownCodeHash()"), Some(output1), ).unwrap(); diff --git a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs index e0662ea73dc07..600f46e6af117 100644 --- a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs +++ b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs @@ -41,13 +41,12 @@ pub extern "C" fn deploy() { } pub extern "C" fn call() { let mut output_buf1 = [0u8; 32]; let output1 = &mut &mut output_buf1[..]; - let _ = api::call( + let _ = api::delegate_call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. - &u256_bytes(0), // Value transferred to the contract. &uapi::solidity_selector("ownCodeHash()"), Some(output1), ).unwrap(); diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index 3152c39ef039f..c23c6a8c83d05 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -830,12 +830,24 @@ fn code_hash_returns_proper_values() { }); } -/* #[test] fn own_code_hash_returns_proper_values() { let bob_ch = MockLoader::insert(Call, |ctx, _| { let code_hash = ctx.ext.code_hash(&BOB_ADDR); - assert_eq!(*ctx.ext.own_code_hash(), code_hash); + + let ret = ctx + .ext + .delegate_call( + Weight::MAX, + U256::zero(), + H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + pallet_revive_uapi::solidity_selector("ownCodeHash()").to_vec(), + ) + .map(|_| ctx.ext.last_frame_output().clone()); + + let data = ret.unwrap().data; + assert_eq!(data, code_hash.0.to_vec()); + exec_success() }); @@ -861,16 +873,42 @@ fn own_code_hash_returns_proper_values() { fn caller_is_origin_returns_proper_values() { let code_charlie = MockLoader::insert(Call, |ctx, _| { // BOB is not the origin of the stack call - assert!(!ctx.ext.caller_is_origin()); + let ret = ctx + .ext + .delegate_call( + Weight::MAX, + U256::zero(), + H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + pallet_revive_uapi::solidity_selector("callerIsOrigin()").to_vec(), + ) + .map(|_| ctx.ext.last_frame_output().clone()); + + let data = ret.unwrap().data; + eprintln!("data: {:?}", data); + let caller_is_origin = data == vec![1]; + assert!(!caller_is_origin); exec_success() }); let code_bob = MockLoader::insert(Call, |ctx, _| { // ALICE is the origin of the call stack - assert!(ctx.ext.caller_is_origin()); + let ret = ctx + .ext + .delegate_call( + Weight::MAX, + U256::zero(), + H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + pallet_revive_uapi::solidity_selector("callerIsOrigin()").to_vec(), + ) + .map(|_| ctx.ext.last_frame_output().clone()); + + let data = ret.unwrap().data; + eprintln!("data: {:?}", data); + let caller_is_origin = data == vec![1]; + assert!(caller_is_origin); // BOB calls CHARLIE ctx.ext - .call(Weight::zero(), U256::zero(), &CHARLIE_ADDR, U256::zero(), vec![], true, false) + .call(Weight::MAX, U256::zero(), &CHARLIE_ADDR, U256::zero(), vec![], true, false) .map(|_| ctx.ext.last_frame_output().clone()) }); @@ -892,25 +930,11 @@ fn caller_is_origin_returns_proper_values() { assert_matches!(result, Ok(_)); }); } -*/ #[test] fn root_caller_succeeds() { let code_bob = MockLoader::insert(Call, |ctx, _| { // root is the origin of the call stack. - /* - assert_ok!(ctx.ext.call( - Weight::MAX, - U256::zero(), - &H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - U256::zero(), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), - true, - true - )); - - */ - let ret = ctx .ext .delegate_call( @@ -957,18 +981,6 @@ fn root_caller_does_not_succeed_when_value_not_zero() { H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), )); - - /* - assert_ok!(ctx.ext.call( - Weight::MAX, - U256::zero(), - &H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - U256::zero(), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), - true, - true - )); - */ exec_success() }); @@ -1028,19 +1040,6 @@ fn root_caller_succeeds_with_consecutive_calls() { let code_bob = MockLoader::insert(Call, |ctx, _| { // root is the origin of the call stack. - //assert!(ctx.ext.caller_is_root()); - /* - let ret = ctx.ext.call( - Weight::MAX, - U256::zero(), - &H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - U256::zero(), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), - true, - true - ) - .map(|_| ctx.ext.last_frame_output().clone()); - */ let ret = ctx .ext .delegate_call( diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index 583a5d3f5e19d..e183cad7f0b13 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -49,16 +49,13 @@ sol! { /// If no mapping exists for `addr`, the fallback account id will be returned. function toAccountId(address input) external view returns (bytes memory account_id); - /// Check whether the `caller` is the origin of the whole call stack. - /// - /// todo If there is no address associated with the caller (e.g. because the caller is root) then - /// todo it traps with `BadOrigin`. + /// Checks whether the contract caller is the origin of the whole call stack. function callerIsOrigin() external pure returns (bool); /// Checks whether the caller of the current contract is root. /// - /// Note that only the origin of the call stack can be root. Hence this function returning - /// `true` implies that the contract is being called by the origin. + /// Note that only the origin of the call stack can be root. Hence this + /// function returning `true` implies that the contract is being called by the origin. /// /// A return value of `true` indicates that this contract is being called by a root origin, /// and `false` indicates that the caller is a signed origin. @@ -141,9 +138,7 @@ impl BuiltinPrecompile for System { }, ISystemCalls::ownCodeHash(ISystem::ownCodeHashCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::OwnCodeHash)?; - let caller = env.caller(); - let address = caller.account_id().unwrap().encode(); - let address = H160::from_slice(&address[..20]); + let address = env.address(); let output = env.code_hash(&address).encode(); Ok(output) }, From 85681903fedc80d8b62e7da5d819bc4d31f8cd0c Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 10:26:18 +0200 Subject: [PATCH 06/63] Rename pre-compile weights --- substrate/frame/revive/src/benchmarking.rs | 8 ++--- substrate/frame/revive/src/vm/runtime.rs | 14 ++++----- substrate/frame/revive/src/weights.rs | 36 +++++++++++----------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index f5683f2d1ee01..2d32a973ce4d2 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -608,7 +608,7 @@ mod benchmarks { /* #[benchmark(pov_mode = Measured)] - fn seal_own_code_hash() { + fn own_code_hash() { let len = ::max_encoded_len() as u32; build_runtime!(runtime, contract, memory: [vec![0u8; len as _], ]); let result; @@ -641,7 +641,7 @@ mod benchmarks { /* #[benchmark(pov_mode = Measured)] - fn seal_caller_is_origin() { + fn caller_is_origin() { build_runtime!(runtime, memory: []); let result; @@ -653,7 +653,7 @@ mod benchmarks { } #[benchmark(pov_mode = Measured)] - fn seal_caller_is_root() { + fn caller_is_root() { let mut setup = CallSetup::::default(); setup.set_origin(Origin::Root); let (mut ext, _) = setup.ext(); @@ -825,7 +825,7 @@ mod benchmarks { /* #[benchmark(pov_mode = Measured)] - fn seal_minimum_balance() { + fn minimum_balance() { build_runtime!(runtime, memory: [[0u8;32], ]); let result; #[block] diff --git a/substrate/frame/revive/src/vm/runtime.rs b/substrate/frame/revive/src/vm/runtime.rs index a35e67da883cb..abd3dba4a7af7 100644 --- a/substrate/frame/revive/src/vm/runtime.rs +++ b/substrate/frame/revive/src/vm/runtime.rs @@ -275,25 +275,25 @@ pub enum RuntimeCosts { CallDataSize, /// Weight of calling `seal_return_data_size`. ReturnDataSize, - /// Weight of calling `seal_to_account_id`. + /// Weight of calling `toAccountId` on the `System` pre-compile. ToAccountId, /// Weight of calling `seal_origin`. Origin, /// Weight of calling `seal_code_hash`. CodeHash, - /// Weight of calling `seal_own_code_hash`. + /// Weight of calling `ownCodeHash` on the `System` pre-compile. OwnCodeHash, /// Weight of calling `seal_code_size`. CodeSize, - /// Weight of calling `seal_caller_is_origin`. + /// Weight of calling `callerIsOrigin` on the `System` pre-compile. CallerIsOrigin, - /// Weight of calling `caller_is_root`. + /// Weight of calling `callerIsRoot` on the `System` pre-compile. CallerIsRoot, /// Weight of calling `seal_address`. Address, /// Weight of calling `seal_ref_time_left`. RefTimeLeft, - /// Weight of calling `seal_weight_left`. + /// Weight of calling `weightLeft` on the `System` pre-compile. WeightLeft, /// Weight of calling `seal_balance`. Balance, @@ -301,7 +301,7 @@ pub enum RuntimeCosts { BalanceOf, /// Weight of calling `seal_value_transferred`. ValueTransferred, - /// Weight of calling `seal_minimum_balance`. + /// Weight of calling `minimumBalance` on the `System` pre-compile. MinimumBalance, /// Weight of calling `seal_block_number`. BlockNumber, @@ -472,7 +472,7 @@ impl Token for RuntimeCosts { Balance => T::WeightInfo::seal_balance(), BalanceOf => T::WeightInfo::seal_balance_of(), ValueTransferred => T::WeightInfo::seal_value_transferred(), - MinimumBalance => T::WeightInfo::seal_minimum_balance(), + MinimumBalance => T::WeightInfo::minimum_balance(), BlockNumber => T::WeightInfo::seal_block_number(), BlockHash => T::WeightInfo::seal_block_hash(), BlockAuthor => T::WeightInfo::seal_block_author(), diff --git a/substrate/frame/revive/src/weights.rs b/substrate/frame/revive/src/weights.rs index caccdd672ae95..25a5d94f8163c 100644 --- a/substrate/frame/revive/src/weights.rs +++ b/substrate/frame/revive/src/weights.rs @@ -89,21 +89,21 @@ 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 own_code_hash() -> Weight; fn seal_code_size() -> Weight; - fn seal_caller_is_origin() -> Weight; - fn seal_caller_is_root() -> Weight; + fn caller_is_origin() -> Weight; + fn caller_is_root() -> Weight; fn seal_address() -> Weight; - fn seal_weight_left() -> Weight; + fn weight_left() -> Weight; fn seal_ref_time_left() -> Weight; fn seal_balance() -> Weight; fn seal_balance_of() -> Weight; fn seal_get_immutable_data(n: u32, ) -> Weight; fn seal_set_immutable_data(n: u32, ) -> Weight; fn seal_value_transferred() -> Weight; - fn seal_minimum_balance() -> Weight; + fn minimum_balance() -> Weight; fn seal_return_data_size() -> Weight; fn seal_call_data_size() -> Weight; fn seal_gas_limit() -> Weight; @@ -487,7 +487,7 @@ impl WeightInfo for SubstrateWeight { } /// 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` @@ -505,7 +505,7 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(9_806_000, 3868) .saturating_add(T::DbWeight::get().reads(1_u64)) } - fn seal_own_code_hash() -> Weight { + fn own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -524,14 +524,14 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(13_490_000, 3939) .saturating_add(T::DbWeight::get().reads(2_u64)) } - fn seal_caller_is_origin() -> Weight { + fn 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) } - fn seal_caller_is_root() -> Weight { + fn caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -545,7 +545,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 304_000 picoseconds. Weight::from_parts(343_000, 0) } - fn seal_weight_left() -> Weight { + fn weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -614,7 +614,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 259_000 picoseconds. Weight::from_parts(331_000, 0) } - fn seal_minimum_balance() -> Weight { + fn minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -1547,7 +1547,7 @@ impl WeightInfo for () { } /// 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` @@ -1565,7 +1565,7 @@ impl WeightInfo for () { Weight::from_parts(9_806_000, 3868) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - fn seal_own_code_hash() -> Weight { + fn own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -1584,14 +1584,14 @@ impl WeightInfo for () { Weight::from_parts(13_490_000, 3939) .saturating_add(RocksDbWeight::get().reads(2_u64)) } - fn seal_caller_is_origin() -> Weight { + fn 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) } - fn seal_caller_is_root() -> Weight { + fn caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -1605,7 +1605,7 @@ impl WeightInfo for () { // Minimum execution time: 304_000 picoseconds. Weight::from_parts(343_000, 0) } - fn seal_weight_left() -> Weight { + fn weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -1674,7 +1674,7 @@ impl WeightInfo for () { // Minimum execution time: 259_000 picoseconds. Weight::from_parts(331_000, 0) } - fn seal_minimum_balance() -> Weight { + fn minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` From 077bede892ffef0d61f9cbcbaa70c88d53908d54 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 11:16:30 +0200 Subject: [PATCH 07/63] Migrate benchmarks --- .../contracts/call_diverging_out_len.rs | 19 ----- substrate/frame/revive/src/benchmarking.rs | 74 ++++++++++++------- substrate/frame/revive/src/exec.rs | 2 +- substrate/frame/revive/src/exec/tests.rs | 21 ------ substrate/frame/revive/src/lib.rs | 2 +- .../revive/src/precompiles/builtin/system.rs | 1 - substrate/frame/revive/src/tests.rs | 2 +- substrate/frame/revive/src/vm/runtime.rs | 10 +-- 8 files changed, 55 insertions(+), 76 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs index 88537cdf63c90..69b6e2b077bdd 100644 --- a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs +++ b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs @@ -29,9 +29,6 @@ include!("../panic_handler.rs"); use core::num::NonZero; -//use uapi::{HostFn, HostFnImpl as api}; -//use alloy_sol_macro::sol; -//use alloy_core::sol_types::SolInterface; use uapi::{HostFn, HostFnImpl as api, u256_bytes}; use hex_literal::hex; @@ -62,22 +59,6 @@ fn assert_call(callee_address: &[u8; 20], expected_output: [u8; assert_eq!(output_buf, expected_output); } -/* -use alloy_sol_types::sol; -sol! { - //interface ISystem { - /// Returns the code hash of the currently executing contract. - function ownCodeHash() external pure returns (bytes32); - //} -} - - */ - -//use alloy_primitives::const_keccak256; - -//const TRANSFER_SELECTOR: [u8; 4] = - //const_keccak256!("transfer(address,uint256)").truncate(); - /// Instantiate this contract with an output buf of size `N` /// and expect the instantiate output to match `expected_output`. #[allow(dead_code)] diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index 2d32a973ce4d2..133bbe3e01ed5 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -606,24 +606,26 @@ mod benchmarks { ); } - /* #[benchmark(pov_mode = Measured)] fn own_code_hash() { - let len = ::max_encoded_len() as u32; - build_runtime!(runtime, contract, memory: [vec![0u8; len as _], ]); + let input_bytes = + ISystem::ISystemCalls::ownCodeHash(ISystem::ownCodeHashCall {}).abi_encode(); + let mut call_setup = CallSetup::::default(); + let (mut ext, _) = call_setup.ext(); + let result; #[block] { - result = runtime.bench_own_code_hash(memory.as_mut_slice(), 0); + result = run_builtin_precompile( + &mut ext, + H160(BenchmarkSystem::::MATCHER.base_address()).as_fixed_bytes(), + input_bytes, + ); } - - assert_ok!(result); - assert_eq!( - ::decode(&mut &memory[..]).unwrap(), - contract.info().unwrap().code_hash - ); + assert!(result.is_ok()); + let pre_compile_code_hash = VmBinaryModule::dummy().hash; + assert_eq!(pre_compile_code_hash.0.to_vec(), result.unwrap().data); } - */ #[benchmark(pov_mode = Measured)] fn seal_code_size() { @@ -639,34 +641,47 @@ mod benchmarks { assert_eq!(result.unwrap(), VmBinaryModule::dummy().code.len() as u64); } - /* #[benchmark(pov_mode = Measured)] fn caller_is_origin() { - build_runtime!(runtime, memory: []); + let input_bytes = + ISystem::ISystemCalls::callerIsOrigin(ISystem::callerIsOriginCall {}).abi_encode(); + + let mut call_setup = CallSetup::::default(); + let (mut ext, _) = call_setup.ext(); let result; #[block] { - result = runtime.bench_caller_is_origin(memory.as_mut_slice()); + result = run_builtin_precompile( + &mut ext, + H160(BenchmarkSystem::::MATCHER.base_address()).as_fixed_bytes(), + input_bytes, + ); } - assert_eq!(result.unwrap(), 1u32); + assert_eq!(result.unwrap().data, vec![1u8]); } #[benchmark(pov_mode = Measured)] fn caller_is_root() { + let input_bytes = + ISystem::ISystemCalls::callerIsRoot(ISystem::callerIsRootCall {}).abi_encode(); + let mut setup = CallSetup::::default(); setup.set_origin(Origin::Root); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::new(&mut ext, vec![]); + let mut runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, vec![]); let result; #[block] { - result = runtime.bench_caller_is_root([0u8; 0].as_mut_slice()); + result = run_builtin_precompile( + &mut ext, + H160(BenchmarkSystem::::MATCHER.base_address()).as_fixed_bytes(), + input_bytes, + ); } - assert_eq!(result.unwrap(), 1u32); + assert_eq!(result.unwrap().data, vec![1u8]); } - */ #[benchmark(pov_mode = Measured)] fn seal_address() { @@ -682,7 +697,6 @@ mod benchmarks { assert_eq!(::decode(&mut &memory[..]).unwrap(), runtime.ext().address()); } - /* #[benchmark(pov_mode = Measured)] fn weight_left() { // use correct max_encoded_len when new version of parity-scale-codec is released @@ -701,7 +715,6 @@ mod benchmarks { runtime.ext().gas_meter().gas_left() ); } - */ #[benchmark(pov_mode = Measured)] fn seal_ref_time_left() { @@ -823,19 +836,26 @@ mod benchmarks { assert_eq!(U256::from_little_endian(&memory[..]), runtime.ext().value_transferred()); } - /* #[benchmark(pov_mode = Measured)] fn minimum_balance() { - build_runtime!(runtime, memory: [[0u8;32], ]); + let input_bytes = + ISystem::ISystemCalls::minimumBalance(ISystem::minimumBalanceCall {}).abi_encode(); + + let mut call_setup = CallSetup::::default(); + let (mut ext, _) = call_setup.ext(); + let result; #[block] { - result = runtime.bench_minimum_balance(memory.as_mut_slice(), 0); + result = run_builtin_precompile( + &mut ext, + H160(BenchmarkSystem::::MATCHER.base_address()).as_fixed_bytes(), + input_bytes, + ); } - assert_ok!(result); - assert_eq!(U256::from_little_endian(&memory[..]), runtime.ext().minimum_balance()); + let min = T::Currency::minimum_balance(); + assert_eq!(result.unwrap().data, min.encode()); } - */ #[benchmark(pov_mode = Measured)] fn seal_return_data_size() { diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index f07c5960b3463..2a714ca7886d5 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -139,7 +139,7 @@ impl> From for ExecError { } } -/// The type of origins supported by revive pallet. +/// The type of origins supported by the revive pallet. #[derive(Clone, Encode, Decode, PartialEq, TypeInfo, RuntimeDebugNoBound)] pub enum Origin { Root, diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index c23c6a8c83d05..baddab2bb72d2 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -884,7 +884,6 @@ fn caller_is_origin_returns_proper_values() { .map(|_| ctx.ext.last_frame_output().clone()); let data = ret.unwrap().data; - eprintln!("data: {:?}", data); let caller_is_origin = data == vec![1]; assert!(!caller_is_origin); exec_success() @@ -903,7 +902,6 @@ fn caller_is_origin_returns_proper_values() { .map(|_| ctx.ext.last_frame_output().clone()); let data = ret.unwrap().data; - eprintln!("data: {:?}", data); let caller_is_origin = data == vec![1]; assert!(caller_is_origin); // BOB calls CHARLIE @@ -946,7 +944,6 @@ fn root_caller_succeeds() { .map(|_| ctx.ext.last_frame_output().clone()); let data = ret.unwrap().data; - eprintln!("data: {:?}", data); let caller_is_root = data == vec![1]; assert!(caller_is_root); @@ -1005,7 +1002,6 @@ fn root_caller_does_not_succeed_when_value_not_zero() { #[test] fn root_caller_succeeds_with_consecutive_calls() { let code_charlie = MockLoader::insert(Call, |ctx, _| { - eprintln!("charlie received call"); // BOB is not root, even though the origin is root. let ret = ctx @@ -1017,24 +1013,9 @@ fn root_caller_succeeds_with_consecutive_calls() { pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), ) .map(|_| ctx.ext.last_frame_output().clone()); - - /* - let ret = ctx.ext.call( - Weight::MAX, - U256::zero(), - &H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - U256::zero(), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), - true, - true - ) - .map(|_| ctx.ext.last_frame_output().clone()); - */ let data = ret.unwrap().data; - eprintln!("data: {:?}", data); let caller_is_root = data == vec![1]; assert!(!caller_is_root); - //assert!(!ctx.ext.caller_is_root()); exec_success() }); @@ -1051,12 +1032,10 @@ fn root_caller_succeeds_with_consecutive_calls() { .map(|_| ctx.ext.last_frame_output().clone()); let data = ret.unwrap().data; - eprintln!("data 2: {:?}", data); let caller_is_root = data == vec![1]; assert!(caller_is_root); // BOB calls CHARLIE. - eprintln!("bob calls charlie"); ctx.ext .call(Weight::MAX, U256::zero(), &CHARLIE_ADDR, U256::zero(), vec![], true, false) .map(|_| ctx.ext.last_frame_output().clone()) diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 69d1e49408eee..8b2d7f76e716a 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -479,7 +479,7 @@ pub mod pallet { ReturnDataTooLarge = 0x31, } - /// A reason for the `pallet-revive` placing a hold on funds. + /// A reason for the pallet revive placing a hold on funds. #[pallet::composite_enum] pub enum HoldReason { /// The Pallet has reserved it for storing code on-chain. diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index e183cad7f0b13..366b8faf6eb2b 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -115,7 +115,6 @@ impl BuiltinPrecompile for System { }, Origin::Signed(origin_account_id) => { let origin_address = T::AddressMapper::to_address(&origin_account_id).0; - //let caller_address = T::AddressMapper::to_address(&env.caller()).0; match env.caller() { Origin::Signed(caller_account_id) => { let caller_address = diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index c3c482af80286..4de8aeb08a00c 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -867,7 +867,7 @@ fn gas_syncs_work() { assert_ok!(result.result.clone()); assert!(!result.result.clone().unwrap().did_revert()); let gas_consumed_once = result.gas_consumed.ref_time(); - let host_consumed_once = ::WeightInfo::seal_caller_is_origin().ref_time(); + let host_consumed_once = ::WeightInfo::caller_is_origin().ref_time(); let engine_consumed_once = gas_consumed_once - host_consumed_once - engine_consumed_noop; let result = builder::bare_call(contract.addr).data(2u32.encode()).build(); diff --git a/substrate/frame/revive/src/vm/runtime.rs b/substrate/frame/revive/src/vm/runtime.rs index abd3dba4a7af7..a3bb121d9c674 100644 --- a/substrate/frame/revive/src/vm/runtime.rs +++ b/substrate/frame/revive/src/vm/runtime.rs @@ -460,15 +460,15 @@ 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(), - CallerIsOrigin => T::WeightInfo::seal_caller_is_origin(), - CallerIsRoot => T::WeightInfo::seal_caller_is_root(), + OwnCodeHash => T::WeightInfo::own_code_hash(), + CallerIsOrigin => T::WeightInfo::caller_is_origin(), + CallerIsRoot => T::WeightInfo::caller_is_root(), Address => T::WeightInfo::seal_address(), RefTimeLeft => T::WeightInfo::seal_ref_time_left(), - WeightLeft => T::WeightInfo::seal_weight_left(), + WeightLeft => T::WeightInfo::weight_left(), Balance => T::WeightInfo::seal_balance(), BalanceOf => T::WeightInfo::seal_balance_of(), ValueTransferred => T::WeightInfo::seal_value_transferred(), From 54cd40b854d039598f02733a0028f8a3b1b92001 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 12:13:34 +0200 Subject: [PATCH 08/63] Remove unused functionality --- substrate/frame/revive/uapi/src/precompile_utils.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/substrate/frame/revive/uapi/src/precompile_utils.rs b/substrate/frame/revive/uapi/src/precompile_utils.rs index 4b3cc7c20a230..a2c6d498b9786 100644 --- a/substrate/frame/revive/uapi/src/precompile_utils.rs +++ b/substrate/frame/revive/uapi/src/precompile_utils.rs @@ -37,10 +37,3 @@ pub const fn solidity_selector(fn_sig: &str) -> [u8; 4] { const_crypto::sha3::Keccak256::new().update(fn_sig.as_bytes()).finalize(); [output[0], output[1], output[2], output[3]] } - -/// Encodes a `[u8; 20]` address for Solidity. -pub fn solidity_address(address: &[u8; 20]) -> [u8; 32] { - let mut buf = [0u8; 32]; - buf[12..32].copy_from_slice(address); - buf -} From 7e2b99d84bc7566894a9d42c219038d1f3df2971 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 12:23:04 +0200 Subject: [PATCH 09/63] Clean up code --- .../revive/fixtures/contracts/call_diverging_out_len.rs | 5 ----- substrate/frame/revive/src/benchmarking.rs | 2 +- substrate/frame/revive/src/precompiles/builtin/system.rs | 3 +-- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs index 69b6e2b077bdd..fdcf99a8f9b5c 100644 --- a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs +++ b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs @@ -23,21 +23,17 @@ //! and also instantiate our own code hash (constructor and recursive calls //! always return `BUF_SIZE` bytes of data). -#![allow(unused_imports)] #![no_std] #![no_main] include!("../panic_handler.rs"); -use core::num::NonZero; use uapi::{HostFn, HostFnImpl as api, u256_bytes}; -use hex_literal::hex; const BUF_SIZE: usize = 8; static DATA: [u8; BUF_SIZE] = [1, 2, 3, 4, 5, 6, 7, 8]; /// Call `callee_address` with an output buf of size `N` /// and expect the call output to match `expected_output`. -#[allow(dead_code)] fn assert_call(callee_address: &[u8; 20], expected_output: [u8; BUF_SIZE]) { let mut output_buf = [0u8; BUF_SIZE]; let output_buf_capped = &mut &mut output_buf[..N]; @@ -61,7 +57,6 @@ fn assert_call(callee_address: &[u8; 20], expected_output: [u8; /// Instantiate this contract with an output buf of size `N` /// and expect the instantiate output to match `expected_output`. -#[allow(dead_code)] fn assert_instantiate(expected_output: [u8; BUF_SIZE]) { let mut output_buf1 = [0u8; 32]; let output1 = &mut &mut output_buf1[..]; diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index 133bbe3e01ed5..15869b8c5acd1 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -669,7 +669,7 @@ mod benchmarks { let mut setup = CallSetup::::default(); setup.set_origin(Origin::Root); let (mut ext, _) = setup.ext(); - let mut runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, vec![]); + let runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, vec![]); let result; #[block] diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index 366b8faf6eb2b..93c39141d35ae 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -103,7 +103,7 @@ impl BuiltinPrecompile for System { use codec::Encode; env.gas_meter_mut().charge(RuntimeCosts::ToAccountId)?; let account_id = - T::AddressMapper::to_account_id(&crate::H160::from_slice(input.as_slice())); + T::AddressMapper::to_account_id(&H160::from_slice(input.as_slice())); Ok(account_id.encode()) }, ISystemCalls::callerIsOrigin(ISystem::callerIsOriginCall {}) => { @@ -165,7 +165,6 @@ mod tests { pallet, precompiles::{tests::run_test_vectors, BuiltinPrecompile}, tests::{ExtBuilder, Test}, - H160, }; use codec::Decode; use frame_support::traits::fungible::Mutate; From ec00d2aa9553613f85935bde2d9c6320ce2c8d0e Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 12:24:32 +0200 Subject: [PATCH 10/63] Fix `unused_parens` --- substrate/frame/revive/src/evm/runtime.rs | 2 +- substrate/frame/revive/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 48380f83899bd..f4c768004aa4e 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -352,7 +352,7 @@ pub trait EthExtra { } 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))), + blob_len.try_into().ok().and_then(|blob_len| data.split_at_checked(blob_len)), _ => None, }; diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 8b2d7f76e716a..e1ee0c4ffc019 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -1335,7 +1335,7 @@ where Some(blob_len) => blob_len .try_into() .ok() - .and_then(|blob_len| (input.split_at_checked(blob_len))) + .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"); From dd607efa581f532ab8f65e6939e630681dd4d9c3 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 15:29:23 +0200 Subject: [PATCH 11/63] Migrate benchmark for `weight_left` --- .../contracts/call_caller_is_origin.rs | 3 +- .../fixtures/contracts/call_caller_is_root.rs | 3 +- .../fixtures/contracts/call_own_code_hash.rs | 9 ++---- .../revive/fixtures/contracts/gas_price_n.rs | 2 +- substrate/frame/revive/src/benchmarking.rs | 29 ++++++++++++------- substrate/frame/revive/src/exec/tests.rs | 7 +---- substrate/frame/revive/src/vm/runtime.rs | 20 ------------- 7 files changed, 26 insertions(+), 47 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs index af57cb5d9febf..896ec01dec8e3 100644 --- a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs @@ -15,7 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! This fixture calls caller_is_origin `n` times. +//! This fixture calls the `callerIsOrigin` function on the +//! `System` pre-compile. #![no_std] #![no_main] diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs index 9f964f5b5751e..a018065818994 100644 --- a/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs @@ -15,7 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! This fixture calls caller_is_origin `n` times. +//! This fixture calls the `callerIsRoot` function on the +//! `System` pre-compile. #![no_std] #![no_main] diff --git a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs index 600f46e6af117..f361a821643f5 100644 --- a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs +++ b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs @@ -15,13 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! This tests that the correct output data is written when the provided -//! output buffer length is smaller than what was actually returned during -//! calls and instantiations. -//! -//! To not need an additional callee fixture, we call ourself recursively -//! and also instantiate our own code hash (constructor and recursive calls -//! always return `BUF_SIZE` bytes of data). +//! This fixture calls the `ownCodeHash` function on the +//! `System` pre-compile. #![allow(unused_imports)] #![no_std] diff --git a/substrate/frame/revive/fixtures/contracts/gas_price_n.rs b/substrate/frame/revive/fixtures/contracts/gas_price_n.rs index 52b0fa9b97c60..51cfc3a6aea85 100644 --- a/substrate/frame/revive/fixtures/contracts/gas_price_n.rs +++ b/substrate/frame/revive/fixtures/contracts/gas_price_n.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Returns the gas price back to the caller. +//! This fixture calls `gas_price` `n` times. #![no_std] #![no_main] diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index 15869b8c5acd1..1acc90848bad2 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -669,7 +669,6 @@ mod benchmarks { let mut setup = CallSetup::::default(); setup.set_origin(Origin::Root); let (mut ext, _) = setup.ext(); - let runtime = crate::vm::Runtime::<_, [u8]>::new(&mut ext, vec![]); let result; #[block] @@ -699,21 +698,29 @@ mod benchmarks { #[benchmark(pov_mode = Measured)] fn weight_left() { - // use correct max_encoded_len when new version of parity-scale-codec is released - let len = 18u32; - assert!(::max_encoded_len() as u32 != len); - build_runtime!(runtime, memory: [32u32.to_le_bytes(), vec![0u8; len as _], ]); + let input_bytes = + ISystem::ISystemCalls::weightLeft(ISystem::weightLeftCall {}).abi_encode(); + + let mut call_setup = CallSetup::::default(); + let (mut ext, _) = call_setup.ext(); + let weight_left_before = ext.gas_meter().gas_left(); let result; #[block] { - result = runtime.bench_weight_left(memory.as_mut_slice(), 4, 0); + result = run_builtin_precompile( + &mut ext, + H160(BenchmarkSystem::::MATCHER.base_address()).as_fixed_bytes(), + input_bytes, + ); } - assert_ok!(result); - assert_eq!( - ::decode(&mut &memory[4..]).unwrap(), - runtime.ext().gas_meter().gas_left() - ); + let weight_left_after = ext.gas_meter().gas_left(); + assert_ne!(weight_left_after.ref_time(), 0); + assert!(weight_left_before.ref_time() > weight_left_after.ref_time()); + + let mut data = result.unwrap().data; + let ret: Weight = Decode::decode(&mut &data[..]).unwrap(); + assert_eq!(weight_left_after.ref_time(), ret.ref_time()); } #[benchmark(pov_mode = Measured)] diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index baddab2bb72d2..ee4e017f73f3e 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -834,7 +834,6 @@ fn code_hash_returns_proper_values() { fn own_code_hash_returns_proper_values() { let bob_ch = MockLoader::insert(Call, |ctx, _| { let code_hash = ctx.ext.code_hash(&BOB_ADDR); - let ret = ctx .ext .delegate_call( @@ -844,10 +843,7 @@ fn own_code_hash_returns_proper_values() { pallet_revive_uapi::solidity_selector("ownCodeHash()").to_vec(), ) .map(|_| ctx.ext.last_frame_output().clone()); - - let data = ret.unwrap().data; - assert_eq!(data, code_hash.0.to_vec()); - + assert_eq!(ret.unwrap().data, code_hash.0.to_vec()); exec_success() }); @@ -1003,7 +999,6 @@ fn root_caller_does_not_succeed_when_value_not_zero() { fn root_caller_succeeds_with_consecutive_calls() { let code_charlie = MockLoader::insert(Call, |ctx, _| { // BOB is not root, even though the origin is root. - let ret = ctx .ext .delegate_call( diff --git a/substrate/frame/revive/src/vm/runtime.rs b/substrate/frame/revive/src/vm/runtime.rs index a3bb121d9c674..e841e2c3ff98c 100644 --- a/substrate/frame/revive/src/vm/runtime.rs +++ b/substrate/frame/revive/src/vm/runtime.rs @@ -2047,24 +2047,4 @@ pub mod env { self.ext.terminate(&beneficiary)?; Err(TrapReason::Termination) } - - /// Stores the amount of weight left into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::weight_left`]. - fn weight_left( - &mut self, - memory: &mut M, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::WeightLeft)?; - let gas_left = &self.ext.gas_meter().gas_left().encode(); - Ok(self.write_sandbox_output( - memory, - out_ptr, - out_len_ptr, - gas_left, - false, - already_charged, - )?) - } } From 66799e32c1f52e16af6822d82333fcc7515731e5 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 15:41:31 +0200 Subject: [PATCH 12/63] Add prdoc file --- prdoc/pr_9517.prdoc | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 prdoc/pr_9517.prdoc diff --git a/prdoc/pr_9517.prdoc b/prdoc/pr_9517.prdoc new file mode 100644 index 0000000000000..d6acb1576afcb --- /dev/null +++ b/prdoc/pr_9517.prdoc @@ -0,0 +1,13 @@ +title: '[pallet-revive] Migrate various getters to `System` pre-compile' +doc: +- audience: Runtime Dev + description: Migrates `own_code_hash`, `caller_is_origin`, `caller_is_root`, + `weight_left`, `minimum_balance`. Contains minor other fixes (removing leftovers + from deprecating chain extensions, stabilizing `block_hash` in overlooked crates, …). +crates: +- name: pallet-revive + bump: patch +- name: pallet-revive-fixtures + bump: patch +- name: pallet-revive-uapi + bump: major From 64f680fe9ff5318681e292103addbefc8aa4eabb Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 15:43:59 +0200 Subject: [PATCH 13/63] Code cleanups --- substrate/frame/revive/src/exec/tests.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index ee4e017f73f3e..61f3a67dd2c06 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -878,9 +878,7 @@ fn caller_is_origin_returns_proper_values() { pallet_revive_uapi::solidity_selector("callerIsOrigin()").to_vec(), ) .map(|_| ctx.ext.last_frame_output().clone()); - - let data = ret.unwrap().data; - let caller_is_origin = data == vec![1]; + let caller_is_origin = ret.unwrap().data == vec![1]; assert!(!caller_is_origin); exec_success() }); @@ -896,10 +894,9 @@ fn caller_is_origin_returns_proper_values() { pallet_revive_uapi::solidity_selector("callerIsOrigin()").to_vec(), ) .map(|_| ctx.ext.last_frame_output().clone()); - - let data = ret.unwrap().data; - let caller_is_origin = data == vec![1]; + let caller_is_origin = ret.unwrap().data == vec![1]; assert!(caller_is_origin); + // BOB calls CHARLIE ctx.ext .call(Weight::MAX, U256::zero(), &CHARLIE_ADDR, U256::zero(), vec![], true, false) @@ -938,11 +935,8 @@ fn root_caller_succeeds() { pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), ) .map(|_| ctx.ext.last_frame_output().clone()); - - let data = ret.unwrap().data; - let caller_is_root = data == vec![1]; + let caller_is_root = ret.unwrap().data == vec![1]; assert!(caller_is_root); - exec_success() }); @@ -1008,8 +1002,7 @@ fn root_caller_succeeds_with_consecutive_calls() { pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), ) .map(|_| ctx.ext.last_frame_output().clone()); - let data = ret.unwrap().data; - let caller_is_root = data == vec![1]; + let caller_is_root = ret.unwrap().data == vec![1]; assert!(!caller_is_root); exec_success() }); @@ -1025,9 +1018,7 @@ fn root_caller_succeeds_with_consecutive_calls() { pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), ) .map(|_| ctx.ext.last_frame_output().clone()); - - let data = ret.unwrap().data; - let caller_is_root = data == vec![1]; + let caller_is_root = ret.unwrap().data == vec![1]; assert!(caller_is_root); // BOB calls CHARLIE. From c4c34be741bfa6a229f5677f8d58fdcadc482a62 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 15:54:21 +0200 Subject: [PATCH 14/63] Apply `taplo` suggestions --- substrate/frame/revive/uapi/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml index 32bafcbd16acf..6c527918dadfb 100644 --- a/substrate/frame/revive/uapi/Cargo.toml +++ b/substrate/frame/revive/uapi/Cargo.toml @@ -18,10 +18,10 @@ targets = ["riscv64imac-unknown-none-elf"] [dependencies] bitflags = { workspace = true } codec = { features = ["derive", "max-encoded-len"], optional = true, workspace = true } +const-crypto = { version = "0.3.0", default-features = false } +hex-literal = { version = "0.4.1", default-features = false } pallet-revive-proc-macro = { workspace = true } scale-info = { features = ["derive"], optional = true, workspace = true } -hex-literal = { version = "0.4.1", default-features = false } -const-crypto = { version = "0.3.0", default-features = false} [target.'cfg(target_arch = "riscv64")'.dependencies] polkavm-derive = { version = "0.27.0" } From ccdaa48ceabcc4acc46ce2bb709031ad215eda47 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 16:14:09 +0200 Subject: [PATCH 15/63] Update function signatures --- prdoc/pr_9517.prdoc | 2 +- .../frame/revive/src/precompiles/builtin/system.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/prdoc/pr_9517.prdoc b/prdoc/pr_9517.prdoc index d6acb1576afcb..f6bf64e071456 100644 --- a/prdoc/pr_9517.prdoc +++ b/prdoc/pr_9517.prdoc @@ -8,6 +8,6 @@ crates: - name: pallet-revive bump: patch - name: pallet-revive-fixtures - bump: patch + bump: minor - name: pallet-revive-uapi bump: major diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index 93c39141d35ae..d8f1adf315184 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -50,7 +50,7 @@ sol! { function toAccountId(address input) external view returns (bytes memory account_id); /// Checks whether the contract caller is the origin of the whole call stack. - function callerIsOrigin() external pure returns (bool); + function callerIsOrigin() external view returns (bool); /// Checks whether the caller of the current contract is root. /// @@ -59,18 +59,18 @@ sol! { /// /// A return value of `true` indicates that this contract is being called by a root origin, /// and `false` indicates that the caller is a signed origin. - function callerIsRoot() external pure returns (bool); + function callerIsRoot() external view returns (bool); /// Returns the minimum balance that is required for creating an account /// (the existential deposit). - function minimumBalance() external pure returns (uint); + function minimumBalance() external view returns (uint); /// Returns the code hash of the currently executing contract. - function ownCodeHash() external pure returns (bytes32); + function ownCodeHash() external view returns (bytes32); /// Returns the amount of weight left. /// The data is encoded as `Weight`. - function weightLeft() external pure returns (uint); + function weightLeft() external view returns (uint); } } From 860b65e37e79149946c6b6c84c9c815a87e3e8b0 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 16:22:01 +0200 Subject: [PATCH 16/63] Make CI happy --- prdoc/pr_9517.prdoc | 2 +- substrate/frame/revive/src/benchmarking.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/prdoc/pr_9517.prdoc b/prdoc/pr_9517.prdoc index f6bf64e071456..d6bab909344be 100644 --- a/prdoc/pr_9517.prdoc +++ b/prdoc/pr_9517.prdoc @@ -8,6 +8,6 @@ crates: - name: pallet-revive bump: patch - name: pallet-revive-fixtures - bump: minor + bump: major - name: pallet-revive-uapi bump: major diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index 1acc90848bad2..c17243fe90330 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -718,7 +718,7 @@ mod benchmarks { assert_ne!(weight_left_after.ref_time(), 0); assert!(weight_left_before.ref_time() > weight_left_after.ref_time()); - let mut data = result.unwrap().data; + let data = result.unwrap().data; let ret: Weight = Decode::decode(&mut &data[..]).unwrap(); assert_eq!(weight_left_after.ref_time(), ret.ref_time()); } From 19ca21e02aa30bad7787a41483fc7e5dac168407 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 16:35:00 +0200 Subject: [PATCH 17/63] Import `vec` --- substrate/frame/revive/src/precompiles/builtin/system.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index d8f1adf315184..d10a50ad8c3cf 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -21,7 +21,7 @@ use crate::{ vm::RuntimeCosts, Config, Origin, H160, }; -use alloc::vec::Vec; +use alloc::{vec, vec::Vec}; use alloy_core::sol; use codec::Encode; use core::{marker::PhantomData, num::NonZero}; From 61fd201825287b6587a9eca4eef9d218c145c43b Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 17:08:59 +0200 Subject: [PATCH 18/63] Adapt semver changes based on CI check pallet-revive-uapi (substrate/frame/revive/uapi): Predicted semver change: Minor +pub const pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR: [u8; 20] pallet-revive (substrate/frame/revive): Predicted semver change: Major Major API change found but prdoc specified Patch -pub fn Ext::caller_is_origin(&self) -> bool +pub fn SubstrateWeight::caller_is_origin() -> weight_v2::Weight pallet-revive-fixtures (substrate/frame/revive/fixtures): Predicted semver change: Patch pallet-revive-proc-macro (substrate/frame/revive/proc-macro): Files changed but crate not listed in PR Doc --- prdoc/pr_9517.prdoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prdoc/pr_9517.prdoc b/prdoc/pr_9517.prdoc index d6bab909344be..ec77e4a0a3060 100644 --- a/prdoc/pr_9517.prdoc +++ b/prdoc/pr_9517.prdoc @@ -6,8 +6,8 @@ doc: from deprecating chain extensions, stabilizing `block_hash` in overlooked crates, …). crates: - name: pallet-revive - bump: patch -- name: pallet-revive-fixtures bump: major +- name: pallet-revive-fixtures + bump: patch - name: pallet-revive-uapi - bump: major + bump: minor From 7bfd2fc7e3ac235e463e820d74fba2bb6c30d58a Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 19 Aug 2025 17:27:57 +0200 Subject: [PATCH 19/63] Update semver --- prdoc/pr_9517.prdoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prdoc/pr_9517.prdoc b/prdoc/pr_9517.prdoc index ec77e4a0a3060..d6bab909344be 100644 --- a/prdoc/pr_9517.prdoc +++ b/prdoc/pr_9517.prdoc @@ -6,8 +6,8 @@ doc: from deprecating chain extensions, stabilizing `block_hash` in overlooked crates, …). crates: - name: pallet-revive - bump: major -- name: pallet-revive-fixtures bump: patch +- name: pallet-revive-fixtures + bump: major - name: pallet-revive-uapi - bump: minor + bump: major From 202b1df32b0cff0e2a5ffec06026744c6e7c2daa Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 22 Aug 2025 13:33:48 +0200 Subject: [PATCH 20/63] Revert lockfile changes --- Cargo.lock | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 240f87d24bfde..6cf96d8e81b69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3621,16 +3621,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "const-crypto" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c06f1eb05f06cf2e380fdded278fbf056a38974299d77960555a311dcf91a52" -dependencies = [ - "keccak-const", - "sha2-const-stable", -] - [[package]] name = "const-hex" version = "1.14.0" @@ -9010,12 +9000,6 @@ dependencies = [ "sha3-asm", ] -[[package]] -name = "keccak-const" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d8d8ce877200136358e0bbff3a77965875db3af755a11e1fa6b1b3e2df13ea" - [[package]] name = "keccak-hash" version = "0.11.0" @@ -13202,8 +13186,6 @@ name = "pallet-revive-uapi" version = "0.1.0" dependencies = [ "bitflags 1.3.2", - "const-crypto", - "hex-literal", "pallet-revive-proc-macro", "parity-scale-codec", "polkavm-derive 0.27.0", @@ -21739,12 +21721,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha2-const-stable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" - [[package]] name = "sha3" version = "0.10.8" From 0b41ce0f648f4ea966c929632652066c38db0bb6 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 22 Aug 2025 13:35:37 +0200 Subject: [PATCH 21/63] Revert merge changes --- Cargo.lock | 24 + substrate/frame/revive/src/vm/runtime.rs | 2050 ---------------------- 2 files changed, 24 insertions(+), 2050 deletions(-) delete mode 100644 substrate/frame/revive/src/vm/runtime.rs diff --git a/Cargo.lock b/Cargo.lock index 6cf96d8e81b69..240f87d24bfde 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3621,6 +3621,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "const-crypto" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c06f1eb05f06cf2e380fdded278fbf056a38974299d77960555a311dcf91a52" +dependencies = [ + "keccak-const", + "sha2-const-stable", +] + [[package]] name = "const-hex" version = "1.14.0" @@ -9000,6 +9010,12 @@ dependencies = [ "sha3-asm", ] +[[package]] +name = "keccak-const" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d8d8ce877200136358e0bbff3a77965875db3af755a11e1fa6b1b3e2df13ea" + [[package]] name = "keccak-hash" version = "0.11.0" @@ -13186,6 +13202,8 @@ name = "pallet-revive-uapi" version = "0.1.0" dependencies = [ "bitflags 1.3.2", + "const-crypto", + "hex-literal", "pallet-revive-proc-macro", "parity-scale-codec", "polkavm-derive 0.27.0", @@ -21721,6 +21739,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" + [[package]] name = "sha3" version = "0.10.8" diff --git a/substrate/frame/revive/src/vm/runtime.rs b/substrate/frame/revive/src/vm/runtime.rs deleted file mode 100644 index e841e2c3ff98c..0000000000000 --- a/substrate/frame/revive/src/vm/runtime.rs +++ /dev/null @@ -1,2050 +0,0 @@ -// 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. - -//! Environment definition of the vm smart-contract runtime. - -use crate::{ - address::AddressMapper, - evm::runtime::GAS_PRICE, - exec::{ExecError, ExecResult, Ext, Key}, - gas::{ChargedAmount, Token}, - limits, - precompiles::{All as AllPrecompiles, Precompiles}, - primitives::ExecReturnValue, - weights::WeightInfo, - Config, Error, Pallet, LOG_TARGET, SENTINEL, -}; -use alloc::{vec, vec::Vec}; -use codec::Encode; -use core::{fmt, marker::PhantomData, mem}; -use frame_support::{ensure, traits::Get, weights::Weight}; -use pallet_revive_proc_macro::define_env; -use pallet_revive_uapi::{CallFlags, ReturnErrorCode, ReturnFlags, StorageFlags}; -use sp_core::{H160, H256, U256}; -use sp_io::hashing::keccak_256; -use sp_runtime::{DispatchError, RuntimeDebug}; - -/// Abstraction over the memory access within syscalls. -/// -/// The reason for this abstraction is that we run syscalls on the host machine when -/// benchmarking them. In that case we have direct access to the contract's memory. However, when -/// running within PolkaVM we need to resort to copying as we can't map the contracts memory into -/// the host (as of now). -pub trait Memory { - /// Read designated chunk from the sandbox memory into the supplied buffer. - /// - /// Returns `Err` if one of the following conditions occurs: - /// - /// - requested buffer is not within the bounds of the sandbox memory. - fn read_into_buf(&self, ptr: u32, buf: &mut [u8]) -> Result<(), DispatchError>; - - /// Write the given buffer to the designated location in the sandbox memory. - /// - /// Returns `Err` if one of the following conditions occurs: - /// - /// - designated area is not within the bounds of the sandbox memory. - fn write(&mut self, ptr: u32, buf: &[u8]) -> Result<(), DispatchError>; - - /// Zero the designated location in the sandbox memory. - /// - /// Returns `Err` if one of the following conditions occurs: - /// - /// - designated area is not within the bounds of the sandbox memory. - fn zero(&mut self, ptr: u32, len: u32) -> Result<(), DispatchError>; - - /// This will reset all compilation artifacts of the currently executing instance. - /// - /// This is used before we call into a new contract to free up some memory. Doing - /// so we make sure that we only ever have to hold one compilation cache at a time - /// independtently of of our call stack depth. - fn reset_interpreter_cache(&mut self); - - /// Read designated chunk from the sandbox memory. - /// - /// Returns `Err` if one of the following conditions occurs: - /// - /// - requested buffer is not within the bounds of the sandbox memory. - fn read(&self, ptr: u32, len: u32) -> Result, DispatchError> { - let mut buf = vec![0u8; len as usize]; - self.read_into_buf(ptr, buf.as_mut_slice())?; - Ok(buf) - } - - /// Same as `read` but reads into a fixed size buffer. - fn read_array(&self, ptr: u32) -> Result<[u8; N], DispatchError> { - let mut buf = [0u8; N]; - self.read_into_buf(ptr, &mut buf)?; - Ok(buf) - } - - /// Read a `u32` from the sandbox memory. - fn read_u32(&self, ptr: u32) -> Result { - let buf: [u8; 4] = self.read_array(ptr)?; - Ok(u32::from_le_bytes(buf)) - } - - /// Read a `U256` from the sandbox memory. - fn read_u256(&self, ptr: u32) -> Result { - let buf: [u8; 32] = self.read_array(ptr)?; - Ok(U256::from_little_endian(&buf)) - } - - /// Read a `H160` from the sandbox memory. - fn read_h160(&self, ptr: u32) -> Result { - let mut buf = H160::default(); - self.read_into_buf(ptr, buf.as_bytes_mut())?; - Ok(buf) - } - - /// Read a `H256` from the sandbox memory. - fn read_h256(&self, ptr: u32) -> Result { - let mut code_hash = H256::default(); - self.read_into_buf(ptr, code_hash.as_bytes_mut())?; - Ok(code_hash) - } -} - -/// Allows syscalls access to the PolkaVM instance they are executing in. -/// -/// In case a contract is executing within PolkaVM its `memory` argument will also implement -/// this trait. The benchmarking implementation of syscalls will only require `Memory` -/// to be implemented. -pub trait PolkaVmInstance: Memory { - fn gas(&self) -> polkavm::Gas; - fn set_gas(&mut self, gas: polkavm::Gas); - fn read_input_regs(&self) -> (u64, u64, u64, u64, u64, u64); - fn write_output(&mut self, output: u64); -} - -// Memory implementation used in benchmarking where guest memory is mapped into the host. -// -// Please note that we could optimize the `read_as_*` functions by decoding directly from -// memory without a copy. However, we don't do that because as it would change the behaviour -// of those functions: A `read_as` with a `len` larger than the actual type can succeed -// in the streaming implementation while it could fail with a segfault in the copy implementation. -#[cfg(feature = "runtime-benchmarks")] -impl Memory for [u8] { - fn read_into_buf(&self, ptr: u32, buf: &mut [u8]) -> Result<(), DispatchError> { - let ptr = ptr as usize; - let bound_checked = - self.get(ptr..ptr + buf.len()).ok_or_else(|| Error::::OutOfBounds)?; - buf.copy_from_slice(bound_checked); - Ok(()) - } - - fn write(&mut self, ptr: u32, buf: &[u8]) -> Result<(), DispatchError> { - let ptr = ptr as usize; - let bound_checked = - self.get_mut(ptr..ptr + buf.len()).ok_or_else(|| Error::::OutOfBounds)?; - bound_checked.copy_from_slice(buf); - Ok(()) - } - - fn zero(&mut self, ptr: u32, len: u32) -> Result<(), DispatchError> { - <[u8] as Memory>::write(self, ptr, &vec![0; len as usize]) - } - - fn reset_interpreter_cache(&mut self) {} -} - -impl Memory for polkavm::RawInstance { - fn read_into_buf(&self, ptr: u32, buf: &mut [u8]) -> Result<(), DispatchError> { - self.read_memory_into(ptr, buf) - .map(|_| ()) - .map_err(|_| Error::::OutOfBounds.into()) - } - - fn write(&mut self, ptr: u32, buf: &[u8]) -> Result<(), DispatchError> { - self.write_memory(ptr, buf).map_err(|_| Error::::OutOfBounds.into()) - } - - fn zero(&mut self, ptr: u32, len: u32) -> Result<(), DispatchError> { - self.zero_memory(ptr, len).map_err(|_| Error::::OutOfBounds.into()) - } - - fn reset_interpreter_cache(&mut self) { - self.reset_interpreter_cache(); - } -} - -impl PolkaVmInstance for polkavm::RawInstance { - fn gas(&self) -> polkavm::Gas { - self.gas() - } - - fn set_gas(&mut self, gas: polkavm::Gas) { - self.set_gas(gas) - } - - fn read_input_regs(&self) -> (u64, u64, u64, u64, u64, u64) { - ( - self.reg(polkavm::Reg::A0), - self.reg(polkavm::Reg::A1), - self.reg(polkavm::Reg::A2), - self.reg(polkavm::Reg::A3), - self.reg(polkavm::Reg::A4), - self.reg(polkavm::Reg::A5), - ) - } - - fn write_output(&mut self, output: u64) { - self.set_reg(polkavm::Reg::A0, output); - } -} - -impl From<&ExecReturnValue> for ReturnErrorCode { - fn from(from: &ExecReturnValue) -> Self { - if from.flags.contains(ReturnFlags::REVERT) { - Self::CalleeReverted - } else { - Self::Success - } - } -} - -/// The data passed through when a contract uses `seal_return`. -#[derive(RuntimeDebug)] -pub struct ReturnData { - /// The flags as passed through by the contract. They are still unchecked and - /// will later be parsed into a `ReturnFlags` bitflags struct. - flags: u32, - /// The output buffer passed by the contract as return data. - data: Vec, -} - -/// Enumerates all possible reasons why a trap was generated. -/// -/// This is either used to supply the caller with more information about why an error -/// occurred (the SupervisorError variant). -/// The other case is where the trap does not constitute an error but rather was invoked -/// as a quick way to terminate the application (all other variants). -#[derive(RuntimeDebug)] -pub enum TrapReason { - /// The supervisor trapped the contract because of an error condition occurred during - /// execution in privileged code. - SupervisorError(DispatchError), - /// Signals that trap was generated in response to call `seal_return` host function. - Return(ReturnData), - /// Signals that a trap was generated in response to a successful call to the - /// `seal_terminate` host function. - Termination, -} - -impl> From for TrapReason { - fn from(from: T) -> Self { - Self::SupervisorError(from.into()) - } -} - -impl fmt::Display for TrapReason { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - Ok(()) - } -} - -#[cfg_attr(test, derive(Debug, PartialEq, Eq))] -#[derive(Copy, Clone)] -pub enum RuntimeCosts { - /// Base Weight of calling a host function. - HostFn, - /// Weight charged for copying data from the sandbox. - CopyFromContract(u32), - /// Weight charged for copying data to the sandbox. - CopyToContract(u32), - /// Weight of calling `seal_call_data_load``. - CallDataLoad, - /// Weight of calling `seal_call_data_copy`. - CallDataCopy(u32), - /// Weight of calling `seal_caller`. - Caller, - /// Weight of calling `seal_call_data_size`. - CallDataSize, - /// Weight of calling `seal_return_data_size`. - ReturnDataSize, - /// Weight of calling `toAccountId` on the `System` pre-compile. - ToAccountId, - /// Weight of calling `seal_origin`. - Origin, - /// Weight of calling `seal_code_hash`. - CodeHash, - /// Weight of calling `ownCodeHash` on the `System` pre-compile. - OwnCodeHash, - /// Weight of calling `seal_code_size`. - CodeSize, - /// Weight of calling `callerIsOrigin` on the `System` pre-compile. - CallerIsOrigin, - /// Weight of calling `callerIsRoot` on the `System` pre-compile. - CallerIsRoot, - /// Weight of calling `seal_address`. - Address, - /// Weight of calling `seal_ref_time_left`. - RefTimeLeft, - /// Weight of calling `weightLeft` on the `System` pre-compile. - WeightLeft, - /// Weight of calling `seal_balance`. - Balance, - /// Weight of calling `seal_balance_of`. - BalanceOf, - /// Weight of calling `seal_value_transferred`. - ValueTransferred, - /// Weight of calling `minimumBalance` on the `System` pre-compile. - MinimumBalance, - /// Weight of calling `seal_block_number`. - BlockNumber, - /// Weight of calling `seal_block_hash`. - BlockHash, - /// Weight of calling `seal_block_author`. - BlockAuthor, - /// Weight of calling `seal_gas_price`. - GasPrice, - /// Weight of calling `seal_base_fee`. - BaseFee, - /// Weight of calling `seal_now`. - Now, - /// Weight of calling `seal_gas_limit`. - GasLimit, - /// Weight of calling `seal_weight_to_fee`. - WeightToFee, - /// Weight of calling `seal_terminate`. - Terminate, - /// 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. - SetStorage { old_bytes: u32, new_bytes: u32 }, - /// Weight of calling `seal_clear_storage` per cleared byte. - ClearStorage(u32), - /// Weight of calling `seal_contains_storage` per byte of the checked item. - ContainsStorage(u32), - /// Weight of calling `seal_get_storage` with the specified size in storage. - GetStorage(u32), - /// Weight of calling `seal_take_storage` for the given size. - TakeStorage(u32), - /// Weight of calling `seal_set_transient_storage` for the given storage item sizes. - SetTransientStorage { old_bytes: u32, new_bytes: u32 }, - /// Weight of calling `seal_clear_transient_storage` per cleared byte. - ClearTransientStorage(u32), - /// Weight of calling `seal_contains_transient_storage` per byte of the checked item. - ContainsTransientStorage(u32), - /// Weight of calling `seal_get_transient_storage` with the specified size in storage. - GetTransientStorage(u32), - /// Weight of calling `seal_take_transient_storage` for the given size. - TakeTransientStorage(u32), - /// Base weight of calling `seal_call`. - CallBase, - /// Weight of calling `seal_delegate_call` for the given input size. - DelegateCallBase, - /// Weight of calling a precompile. - PrecompileBase, - /// Weight of calling a precompile that has a contract info. - PrecompileWithInfoBase, - /// Weight of reading and decoding the input to a precompile. - PrecompileDecode(u32), - /// Weight of the transfer performed during a call. - /// parameter `dust_transfer` indicates whether the transfer has a `dust` value. - CallTransferSurcharge { dust_transfer: bool }, - /// Weight per byte that is cloned by supplying the `CLONE_INPUT` flag. - CallInputCloned(u32), - /// Weight of calling `seal_instantiate`. - Instantiate { input_data_len: u32, balance_transfer: bool, dust_transfer: bool }, - /// Weight of calling `Ripemd160` precompile for the given input size. - Ripemd160(u32), - /// Weight of calling `Sha256` precompile for the given input size. - HashSha256(u32), - /// Weight of calling `seal_hash_keccak_256` for the given input size. - HashKeccak256(u32), - /// Weight of calling the `System::hashBlake256` precompile function for the given input - /// size. - HashBlake256(u32), - /// Weight of calling `System::hashBlake128` precompile function for the given input size. - HashBlake128(u32), - /// Weight of calling `ECERecover` precompile. - EcdsaRecovery, - /// Weight of calling `seal_sr25519_verify` for the given input size. - Sr25519Verify(u32), - /// Weight charged by a precompile. - Precompile(Weight), - /// Weight of calling `seal_set_code_hash` - SetCodeHash, - /// Weight of calling `ecdsa_to_eth_address` - EcdsaToEthAddress, - /// Weight of calling `get_immutable_dependency` - GetImmutableData(u32), - /// Weight of calling `set_immutable_dependency` - SetImmutableData(u32), - /// Weight of calling `Bn128Add` precompile - Bn128Add, - /// Weight of calling `Bn128Add` precompile - Bn128Mul, - /// Weight of calling `Bn128Pairing` precompile for the given number of input pairs. - Bn128Pairing(u32), - /// Weight of calling `Identity` precompile for the given number of input length. - Identity(u32), - /// Weight of calling `Blake2F` precompile for the given number of rounds. - Blake2F(u32), - /// Weight of calling `Modexp` precompile - Modexp(u64), -} - -/// For functions that modify storage, benchmarks are performed with one item in the -/// storage. To account for the worst-case scenario, the weight of the overhead of -/// writing to or reading from full storage is included. For transient storage writes, -/// the rollback weight is added to reflect the worst-case scenario for this operation. -macro_rules! cost_storage { - (write_transient, $name:ident $(, $arg:expr )*) => { - T::WeightInfo::$name($( $arg ),*) - .saturating_add(T::WeightInfo::rollback_transient_storage()) - .saturating_add(T::WeightInfo::set_transient_storage_full() - .saturating_sub(T::WeightInfo::set_transient_storage_empty())) - }; - - (read_transient, $name:ident $(, $arg:expr )*) => { - T::WeightInfo::$name($( $arg ),*) - .saturating_add(T::WeightInfo::get_transient_storage_full() - .saturating_sub(T::WeightInfo::get_transient_storage_empty())) - }; - - (write, $name:ident $(, $arg:expr )*) => { - T::WeightInfo::$name($( $arg ),*) - .saturating_add(T::WeightInfo::set_storage_full() - .saturating_sub(T::WeightInfo::set_storage_empty())) - }; - - (read, $name:ident $(, $arg:expr )*) => { - T::WeightInfo::$name($( $arg ),*) - .saturating_add(T::WeightInfo::get_storage_full() - .saturating_sub(T::WeightInfo::get_storage_empty())) - }; -} - -macro_rules! cost_args { - // cost_args!(name, a, b, c) -> T::WeightInfo::name(a, b, c).saturating_sub(T::WeightInfo::name(0, 0, 0)) - ($name:ident, $( $arg: expr ),+) => { - (T::WeightInfo::$name($( $arg ),+).saturating_sub(cost_args!(@call_zero $name, $( $arg ),+))) - }; - // Transform T::WeightInfo::name(a, b, c) into T::WeightInfo::name(0, 0, 0) - (@call_zero $name:ident, $( $arg:expr ),*) => { - T::WeightInfo::$name($( cost_args!(@replace_token $arg) ),*) - }; - // Replace the token with 0. - (@replace_token $_in:tt) => { 0 }; -} - -impl Token for RuntimeCosts { - fn influence_lowest_gas_limit(&self) -> bool { - true - } - - fn weight(&self) -> Weight { - use self::RuntimeCosts::*; - match *self { - HostFn => cost_args!(noop_host_fn, 1), - CopyToContract(len) => T::WeightInfo::seal_copy_to_contract(len), - CopyFromContract(len) => T::WeightInfo::seal_return(len), - CallDataSize => T::WeightInfo::seal_call_data_size(), - ReturnDataSize => T::WeightInfo::seal_return_data_size(), - CallDataLoad => T::WeightInfo::seal_call_data_load(), - CallDataCopy(len) => T::WeightInfo::seal_call_data_copy(len), - Caller => T::WeightInfo::seal_caller(), - Origin => T::WeightInfo::seal_origin(), - ToAccountId => T::WeightInfo::to_account_id(), - CodeHash => T::WeightInfo::seal_code_hash(), - CodeSize => T::WeightInfo::seal_code_size(), - OwnCodeHash => T::WeightInfo::own_code_hash(), - CallerIsOrigin => T::WeightInfo::caller_is_origin(), - CallerIsRoot => T::WeightInfo::caller_is_root(), - Address => T::WeightInfo::seal_address(), - RefTimeLeft => T::WeightInfo::seal_ref_time_left(), - WeightLeft => T::WeightInfo::weight_left(), - Balance => T::WeightInfo::seal_balance(), - BalanceOf => T::WeightInfo::seal_balance_of(), - ValueTransferred => T::WeightInfo::seal_value_transferred(), - MinimumBalance => T::WeightInfo::minimum_balance(), - BlockNumber => T::WeightInfo::seal_block_number(), - BlockHash => T::WeightInfo::seal_block_hash(), - BlockAuthor => T::WeightInfo::seal_block_author(), - GasPrice => T::WeightInfo::seal_gas_price(), - BaseFee => T::WeightInfo::seal_base_fee(), - Now => T::WeightInfo::seal_now(), - GasLimit => T::WeightInfo::seal_gas_limit(), - WeightToFee => T::WeightInfo::seal_weight_to_fee(), - Terminate => T::WeightInfo::seal_terminate(), - 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) - }, - ClearStorage(len) => cost_storage!(write, seal_clear_storage, len), - ContainsStorage(len) => cost_storage!(read, seal_contains_storage, len), - GetStorage(len) => cost_storage!(read, seal_get_storage, len), - TakeStorage(len) => cost_storage!(write, seal_take_storage, len), - SetTransientStorage { new_bytes, old_bytes } => { - cost_storage!(write_transient, seal_set_transient_storage, new_bytes, old_bytes) - }, - ClearTransientStorage(len) => { - cost_storage!(write_transient, seal_clear_transient_storage, len) - }, - ContainsTransientStorage(len) => { - cost_storage!(read_transient, seal_contains_transient_storage, len) - }, - GetTransientStorage(len) => { - cost_storage!(read_transient, seal_get_transient_storage, len) - }, - TakeTransientStorage(len) => { - cost_storage!(write_transient, seal_take_transient_storage, len) - }, - CallBase => T::WeightInfo::seal_call(0, 0, 0), - DelegateCallBase => T::WeightInfo::seal_delegate_call(), - PrecompileBase => T::WeightInfo::seal_call_precompile(0, 0), - PrecompileWithInfoBase => T::WeightInfo::seal_call_precompile(1, 0), - PrecompileDecode(len) => cost_args!(seal_call_precompile, 0, len), - CallTransferSurcharge { dust_transfer } => - cost_args!(seal_call, 1, dust_transfer.into(), 0), - CallInputCloned(len) => cost_args!(seal_call, 0, 0, len), - Instantiate { input_data_len, balance_transfer, dust_transfer } => - T::WeightInfo::seal_instantiate( - input_data_len, - balance_transfer.into(), - dust_transfer.into(), - ), - HashSha256(len) => T::WeightInfo::sha2_256(len), - Ripemd160(len) => T::WeightInfo::ripemd_160(len), - HashKeccak256(len) => T::WeightInfo::seal_hash_keccak_256(len), - HashBlake256(len) => T::WeightInfo::hash_blake2_256(len), - HashBlake128(len) => T::WeightInfo::hash_blake2_128(len), - EcdsaRecovery => T::WeightInfo::ecdsa_recover(), - Sr25519Verify(len) => T::WeightInfo::seal_sr25519_verify(len), - Precompile(weight) => weight, - SetCodeHash => T::WeightInfo::seal_set_code_hash(), - 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), - Bn128Add => T::WeightInfo::bn128_add(), - Bn128Mul => T::WeightInfo::bn128_mul(), - Bn128Pairing(len) => T::WeightInfo::bn128_pairing(len), - Identity(len) => T::WeightInfo::identity(len), - Blake2F(rounds) => T::WeightInfo::blake2f(rounds), - Modexp(gas) => { - use frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND; - /// Current approximation of the gas/s consumption considering - /// EVM execution over compiled WASM (on 4.4Ghz CPU). - /// Given the 2000ms Weight, from which 75% only are used for transactions, - /// the total EVM execution gas limit is: GAS_PER_SECOND * 2 * 0.75 ~= 60_000_000. - const GAS_PER_SECOND: u64 = 40_000_000; - - /// Approximate ratio of the amount of Weight per Gas. - /// u64 works for approximations because Weight is a very small unit compared to - /// gas. - const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND; - Weight::from_parts(gas.saturating_mul(WEIGHT_PER_GAS), 0) - }, - } - } -} - -/// Same as [`Runtime::charge_gas`]. -/// -/// We need this access as a macro because sometimes hiding the lifetimes behind -/// a function won't work out. -macro_rules! charge_gas { - ($runtime:expr, $costs:expr) => {{ - $runtime.ext.gas_meter_mut().charge($costs) - }}; -} - -/// The kind of call that should be performed. -enum CallType { - /// Execute another instantiated contract - Call { value_ptr: u32 }, - /// Execute another contract code in the context (storage, account ID, value) of the caller - /// contract - DelegateCall, -} - -impl CallType { - fn cost(&self) -> RuntimeCosts { - match self { - CallType::Call { .. } => RuntimeCosts::CallBase, - CallType::DelegateCall => RuntimeCosts::DelegateCallBase, - } - } -} - -/// This is only appropriate when writing out data of constant size that does not depend on user -/// input. In this case the costs for this copy was already charged as part of the token at -/// the beginning of the API entry point. -fn already_charged(_: u32) -> Option { - None -} - -/// Helper to extract two `u32` values from a given `u64` register. -fn extract_hi_lo(reg: u64) -> (u32, u32) { - ((reg >> 32) as u32, reg as u32) -} - -/// Provides storage variants to support standard and Etheruem compatible semantics. -enum StorageValue { - /// Indicates that the storage value should be read from a memory buffer. - /// - `ptr`: A pointer to the start of the data in sandbox memory. - /// - `len`: The length (in bytes) of the data. - Memory { ptr: u32, len: u32 }, - - /// Indicates that the storage value is provided inline as a fixed-size (256-bit) value. - /// This is used by set_storage_or_clear() to avoid double reads. - /// This variant is used to implement Ethereum SSTORE-like semantics. - Value(Vec), -} - -/// Controls the output behavior for storage reads, both when a key is found and when it is not. -enum StorageReadMode { - /// VariableOutput mode: if the key exists, the full stored value is returned - /// using the caller‑provided output length. - VariableOutput { output_len_ptr: u32 }, - /// Ethereum commpatible(FixedOutput32) mode: always write a 32-byte value into the output - /// buffer. If the key is missing, write 32 bytes of zeros. - FixedOutput32, -} - -/// Can only be used for one call. -pub struct Runtime<'a, E: Ext, M: ?Sized> { - ext: &'a mut E, - input_data: Option>, - _phantom_data: PhantomData, -} - -impl<'a, E: Ext, M: PolkaVmInstance> Runtime<'a, E, M> { - pub fn handle_interrupt( - &mut self, - interrupt: Result, - module: &polkavm::Module, - instance: &mut M, - ) -> Option { - use polkavm::InterruptKind::*; - - match interrupt { - Err(error) => { - // in contrast to the other returns this "should" not happen: log level error - log::error!(target: LOG_TARGET, "polkavm execution error: {error}"); - Some(Err(Error::::ExecutionFailed.into())) - }, - Ok(Finished) => - Some(Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })), - Ok(Trap) => Some(Err(Error::::ContractTrapped.into())), - Ok(Segfault(_)) => Some(Err(Error::::ExecutionFailed.into())), - Ok(NotEnoughGas) => Some(Err(Error::::OutOfGas.into())), - Ok(Step) => None, - Ok(Ecalli(idx)) => { - // This is a special hard coded syscall index which is used by benchmarks - // to abort contract execution. It is used to terminate the execution without - // breaking up a basic block. The fixed index is used so that the benchmarks - // don't have to deal with import tables. - if cfg!(feature = "runtime-benchmarks") && idx == SENTINEL { - return Some(Ok(ExecReturnValue { - flags: ReturnFlags::empty(), - data: Vec::new(), - })) - } - let Some(syscall_symbol) = module.imports().get(idx) else { - return Some(Err(>::InvalidSyscall.into())); - }; - match self.handle_ecall(instance, syscall_symbol.as_bytes()) { - Ok(None) => None, - Ok(Some(return_value)) => { - instance.write_output(return_value); - None - }, - Err(TrapReason::Return(ReturnData { flags, data })) => - match ReturnFlags::from_bits(flags) { - None => Some(Err(Error::::InvalidCallFlags.into())), - Some(flags) => Some(Ok(ExecReturnValue { flags, data })), - }, - Err(TrapReason::Termination) => Some(Ok(Default::default())), - Err(TrapReason::SupervisorError(error)) => Some(Err(error.into())), - } - }, - } - } -} - -impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { - pub fn new(ext: &'a mut E, input_data: Vec) -> Self { - Self { ext, input_data: Some(input_data), _phantom_data: Default::default() } - } - - /// Get a mutable reference to the inner `Ext`. - pub fn ext(&mut self) -> &mut E { - self.ext - } - - /// Charge the gas meter with the specified token. - /// - /// Returns `Err(HostError)` if there is not enough gas. - fn charge_gas(&mut self, costs: RuntimeCosts) -> Result { - charge_gas!(self, costs) - } - - /// 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 - /// refunded to match the actual amount. - fn adjust_gas(&mut self, charged: ChargedAmount, actual_costs: RuntimeCosts) { - self.ext.gas_meter_mut().adjust_gas(charged, actual_costs); - } - - /// Write the given buffer and its length to the designated locations in sandbox memory and - /// charge gas according to the token returned by `create_token`. - /// - /// `out_ptr` is the location in sandbox memory where `buf` should be written to. - /// `out_len_ptr` is an in-out location in sandbox memory. It is read to determine the - /// length of the buffer located at `out_ptr`. If that buffer is smaller than the actual - /// `buf.len()`, only what fits into that buffer is written to `out_ptr`. - /// The actual amount of bytes copied to `out_ptr` is written to `out_len_ptr`. - /// - /// If `out_ptr` is set to the sentinel value of `SENTINEL` and `allow_skip` is true the - /// operation is skipped and `Ok` is returned. This is supposed to help callers to make copying - /// output optional. For example to skip copying back the output buffer of an `seal_call` - /// when the caller is not interested in the result. - /// - /// `create_token` can optionally instruct this function to charge the gas meter with the token - /// it returns. `create_token` receives the variable amount of bytes that are about to be copied - /// by this function. - /// - /// In addition to the error conditions of `Memory::write` this functions returns - /// `Err` if the size of the buffer located at `out_ptr` is too small to fit `buf`. - pub fn write_sandbox_output( - &mut self, - memory: &mut M, - out_ptr: u32, - out_len_ptr: u32, - buf: &[u8], - allow_skip: bool, - create_token: impl FnOnce(u32) -> Option, - ) -> Result<(), DispatchError> { - if allow_skip && out_ptr == SENTINEL { - return Ok(()); - } - - let len = memory.read_u32(out_len_ptr)?; - let buf_len = len.min(buf.len() as u32); - - if let Some(costs) = create_token(buf_len) { - self.charge_gas(costs)?; - } - - memory.write(out_ptr, &buf[..buf_len as usize])?; - memory.write(out_len_ptr, &buf_len.encode()) - } - - /// Same as `write_sandbox_output` but for static size output. - pub fn write_fixed_sandbox_output( - &mut self, - memory: &mut M, - out_ptr: u32, - buf: &[u8], - allow_skip: bool, - create_token: impl FnOnce(u32) -> Option, - ) -> Result<(), DispatchError> { - if buf.is_empty() || (allow_skip && out_ptr == SENTINEL) { - return Ok(()); - } - - let buf_len = buf.len() as u32; - if let Some(costs) = create_token(buf_len) { - self.charge_gas(costs)?; - } - - memory.write(out_ptr, buf) - } - - /// Computes the given hash function on the supplied input. - /// - /// Reads from the sandboxed input buffer into an intermediate buffer. - /// Returns the result directly to the output buffer of the sandboxed memory. - /// - /// It is the callers responsibility to provide an output buffer that - /// is large enough to hold the expected amount of bytes returned by the - /// chosen hash function. - /// - /// # Note - /// - /// The `input` and `output` buffers may overlap. - fn compute_hash_on_intermediate_buffer( - &self, - memory: &mut M, - hash_fn: F, - input_ptr: u32, - input_len: u32, - output_ptr: u32, - ) -> Result<(), DispatchError> - where - F: FnOnce(&[u8]) -> R, - R: AsRef<[u8]>, - { - // Copy input into supervisor memory. - let input = memory.read(input_ptr, input_len)?; - // Compute the hash on the input buffer using the given hash function. - let hash = hash_fn(&input); - // Write the resulting hash back into the sandboxed output buffer. - memory.write(output_ptr, hash.as_ref())?; - Ok(()) - } - - /// Fallible conversion of a `ExecError` to `ReturnErrorCode`. - /// - /// This is used when converting the error returned from a subcall in order to decide - /// whether to trap the caller or allow handling of the error. - fn exec_error_into_return_code(from: ExecError) -> Result { - use crate::exec::ErrorOrigin::Callee; - use ReturnErrorCode::*; - - let transfer_failed = Error::::TransferFailed.into(); - let out_of_gas = Error::::OutOfGas.into(); - let out_of_deposit = Error::::StorageDepositLimitExhausted.into(); - let duplicate_contract = Error::::DuplicateContract.into(); - let unsupported_precompile = Error::::UnsupportedPrecompileAddress.into(); - - // errors in the callee do not trap the caller - match (from.error, from.origin) { - (err, _) if err == transfer_failed => Ok(TransferFailed), - (err, _) if err == duplicate_contract => Ok(DuplicateContractAddress), - (err, _) if err == unsupported_precompile => Err(err), - (err, Callee) if err == out_of_gas || err == out_of_deposit => Ok(OutOfResources), - (_, Callee) => Ok(CalleeTrapped), - (err, _) => Err(err), - } - } - - fn decode_key(&self, memory: &M, key_ptr: u32, key_len: u32) -> Result { - let res = match key_len { - SENTINEL => { - let mut buffer = [0u8; 32]; - memory.read_into_buf(key_ptr, buffer.as_mut())?; - Ok(Key::from_fixed(buffer)) - }, - len => { - ensure!(len <= limits::STORAGE_KEY_BYTES, Error::::DecodingFailed); - let key = memory.read(key_ptr, len)?; - Key::try_from_var(key) - }, - }; - - res.map_err(|_| Error::::DecodingFailed.into()) - } - - fn is_transient(flags: u32) -> Result { - StorageFlags::from_bits(flags) - .ok_or_else(|| >::InvalidStorageFlags.into()) - .map(|flags| flags.contains(StorageFlags::TRANSIENT)) - } - - fn set_storage( - &mut self, - memory: &M, - flags: u32, - key_ptr: u32, - key_len: u32, - value: StorageValue, - ) -> Result { - let transient = Self::is_transient(flags)?; - let costs = |new_bytes: u32, old_bytes: u32| { - if transient { - RuntimeCosts::SetTransientStorage { new_bytes, old_bytes } - } else { - RuntimeCosts::SetStorage { new_bytes, old_bytes } - } - }; - - let value_len = match &value { - StorageValue::Memory { ptr: _, len } => *len, - StorageValue::Value(data) => data.len() as u32, - }; - - let max_size = self.ext.max_value_size(); - let charged = self.charge_gas(costs(value_len, self.ext.max_value_size()))?; - if value_len > max_size { - return Err(Error::::ValueTooLarge.into()); - } - - let key = self.decode_key(memory, key_ptr, key_len)?; - - let value = match value { - StorageValue::Memory { ptr, len } => Some(memory.read(ptr, len)?), - StorageValue::Value(data) => Some(data), - }; - - let write_outcome = if transient { - self.ext.set_transient_storage(&key, value, false)? - } else { - self.ext.set_storage(&key, value, false)? - }; - - self.adjust_gas(charged, costs(value_len, write_outcome.old_len())); - Ok(write_outcome.old_len_with_sentinel()) - } - - fn clear_storage( - &mut self, - memory: &M, - flags: u32, - key_ptr: u32, - key_len: u32, - ) -> Result { - let transient = Self::is_transient(flags)?; - let costs = |len| { - if transient { - RuntimeCosts::ClearTransientStorage(len) - } else { - RuntimeCosts::ClearStorage(len) - } - }; - let charged = self.charge_gas(costs(self.ext.max_value_size()))?; - let key = self.decode_key(memory, key_ptr, key_len)?; - let outcome = if transient { - self.ext.set_transient_storage(&key, None, false)? - } else { - self.ext.set_storage(&key, None, false)? - }; - self.adjust_gas(charged, costs(outcome.old_len())); - Ok(outcome.old_len_with_sentinel()) - } - - fn get_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - out_ptr: u32, - read_mode: StorageReadMode, - ) -> Result { - let transient = Self::is_transient(flags)?; - let costs = |len| { - if transient { - RuntimeCosts::GetTransientStorage(len) - } else { - RuntimeCosts::GetStorage(len) - } - }; - let charged = self.charge_gas(costs(self.ext.max_value_size()))?; - let key = self.decode_key(memory, key_ptr, key_len)?; - let outcome = if transient { - self.ext.get_transient_storage(&key) - } else { - self.ext.get_storage(&key) - }; - - if let Some(value) = outcome { - self.adjust_gas(charged, costs(value.len() as u32)); - - match read_mode { - StorageReadMode::FixedOutput32 => { - let mut fixed_output = [0u8; 32]; - let len = value.len().min(fixed_output.len()); - fixed_output[..len].copy_from_slice(&value[..len]); - - self.write_fixed_sandbox_output( - memory, - out_ptr, - &fixed_output, - false, - already_charged, - )?; - Ok(ReturnErrorCode::Success) - }, - StorageReadMode::VariableOutput { output_len_ptr: out_len_ptr } => { - self.write_sandbox_output( - memory, - out_ptr, - out_len_ptr, - &value, - false, - already_charged, - )?; - Ok(ReturnErrorCode::Success) - }, - } - } else { - self.adjust_gas(charged, costs(0)); - - match read_mode { - StorageReadMode::FixedOutput32 => { - self.write_fixed_sandbox_output( - memory, - out_ptr, - &[0u8; 32], - false, - already_charged, - )?; - Ok(ReturnErrorCode::Success) - }, - StorageReadMode::VariableOutput { .. } => Ok(ReturnErrorCode::KeyNotFound), - } - } - } - - fn contains_storage( - &mut self, - memory: &M, - flags: u32, - key_ptr: u32, - key_len: u32, - ) -> Result { - let transient = Self::is_transient(flags)?; - let costs = |len| { - if transient { - RuntimeCosts::ContainsTransientStorage(len) - } else { - RuntimeCosts::ContainsStorage(len) - } - }; - let charged = self.charge_gas(costs(self.ext.max_value_size()))?; - let key = self.decode_key(memory, key_ptr, key_len)?; - let outcome = if transient { - self.ext.get_transient_storage_size(&key) - } else { - self.ext.get_storage_size(&key) - }; - self.adjust_gas(charged, costs(outcome.unwrap_or(0))); - Ok(outcome.unwrap_or(SENTINEL)) - } - - fn take_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result { - let transient = Self::is_transient(flags)?; - let costs = |len| { - if transient { - RuntimeCosts::TakeTransientStorage(len) - } else { - RuntimeCosts::TakeStorage(len) - } - }; - let charged = self.charge_gas(costs(self.ext.max_value_size()))?; - let key = self.decode_key(memory, key_ptr, key_len)?; - let outcome = if transient { - self.ext.set_transient_storage(&key, None, true)? - } else { - self.ext.set_storage(&key, None, true)? - }; - - if let crate::storage::WriteOutcome::Taken(value) = outcome { - self.adjust_gas(charged, costs(value.len() as u32)); - self.write_sandbox_output( - memory, - out_ptr, - out_len_ptr, - &value, - false, - already_charged, - )?; - Ok(ReturnErrorCode::Success) - } else { - self.adjust_gas(charged, costs(0)); - Ok(ReturnErrorCode::KeyNotFound) - } - } - - fn call( - &mut self, - memory: &mut M, - flags: CallFlags, - call_type: CallType, - callee_ptr: u32, - deposit_ptr: u32, - weight: Weight, - input_data_ptr: u32, - input_data_len: u32, - output_ptr: u32, - output_len_ptr: u32, - ) -> Result { - let callee = memory.read_h160(callee_ptr)?; - let precompile = >::get::(&callee.as_fixed_bytes()); - match &precompile { - Some(precompile) if precompile.has_contract_info() => - self.charge_gas(RuntimeCosts::PrecompileWithInfoBase)?, - Some(_) => self.charge_gas(RuntimeCosts::PrecompileBase)?, - None => self.charge_gas(call_type.cost())?, - }; - - let deposit_limit = memory.read_u256(deposit_ptr)?; - - // we do check this in exec.rs but we want to error out early - if input_data_len > limits::CALLDATA_BYTES { - Err(>::CallDataTooLarge)?; - } - - let input_data = if flags.contains(CallFlags::CLONE_INPUT) { - let input = self.input_data.as_ref().ok_or(Error::::InputForwarded)?; - charge_gas!(self, RuntimeCosts::CallInputCloned(input.len() as u32))?; - input.clone() - } else if flags.contains(CallFlags::FORWARD_INPUT) { - self.input_data.take().ok_or(Error::::InputForwarded)? - } else { - if precompile.is_some() { - self.charge_gas(RuntimeCosts::PrecompileDecode(input_data_len))?; - } else { - self.charge_gas(RuntimeCosts::CopyFromContract(input_data_len))?; - } - memory.read(input_data_ptr, input_data_len)? - }; - - memory.reset_interpreter_cache(); - - let call_outcome = match call_type { - CallType::Call { value_ptr } => { - let read_only = flags.contains(CallFlags::READ_ONLY); - let value = memory.read_u256(value_ptr)?; - if value > 0u32.into() { - // If the call value is non-zero and state change is not allowed, issue an - // error. - if read_only || self.ext.is_read_only() { - return Err(Error::::StateChangeDenied.into()); - } - - self.charge_gas(RuntimeCosts::CallTransferSurcharge { - dust_transfer: Pallet::::has_dust(value), - })?; - } - self.ext.call( - weight, - deposit_limit, - &callee, - value, - input_data, - flags.contains(CallFlags::ALLOW_REENTRY), - read_only, - ) - }, - CallType::DelegateCall => { - if flags.intersects(CallFlags::ALLOW_REENTRY | CallFlags::READ_ONLY) { - return Err(Error::::InvalidCallFlags.into()); - } - self.ext.delegate_call(weight, deposit_limit, callee, input_data) - }, - }; - - match call_outcome { - // `TAIL_CALL` only matters on an `OK` result. Otherwise the call stack comes to - // a halt anyways without anymore code being executed. - Ok(_) if flags.contains(CallFlags::TAIL_CALL) => { - let output = mem::take(self.ext.last_frame_output_mut()); - return Err(TrapReason::Return(ReturnData { - flags: output.flags.bits(), - data: output.data, - })); - }, - Ok(_) => { - let output = mem::take(self.ext.last_frame_output_mut()); - let write_result = self.write_sandbox_output( - memory, - output_ptr, - output_len_ptr, - &output.data, - true, - |len| Some(RuntimeCosts::CopyToContract(len)), - ); - *self.ext.last_frame_output_mut() = output; - write_result?; - Ok(self.ext.last_frame_output().into()) - }, - Err(err) => { - let error_code = Self::exec_error_into_return_code(err)?; - memory.write(output_len_ptr, &0u32.to_le_bytes())?; - Ok(error_code) - }, - } - } - - fn instantiate( - &mut self, - memory: &mut M, - code_hash_ptr: u32, - weight: Weight, - deposit_ptr: u32, - value_ptr: u32, - input_data_ptr: u32, - input_data_len: u32, - address_ptr: u32, - output_ptr: u32, - output_len_ptr: u32, - salt_ptr: u32, - ) -> Result { - let value = match memory.read_u256(value_ptr) { - Ok(value) => { - self.charge_gas(RuntimeCosts::Instantiate { - input_data_len, - balance_transfer: Pallet::::has_balance(value), - dust_transfer: Pallet::::has_dust(value), - })?; - value - }, - Err(err) => { - self.charge_gas(RuntimeCosts::Instantiate { - input_data_len: 0, - balance_transfer: false, - dust_transfer: false, - })?; - return Err(err.into()); - }, - }; - let deposit_limit: U256 = memory.read_u256(deposit_ptr)?; - let code_hash = memory.read_h256(code_hash_ptr)?; - if input_data_len > limits::CALLDATA_BYTES { - Err(>::CallDataTooLarge)?; - } - let input_data = memory.read(input_data_ptr, input_data_len)?; - let salt = if salt_ptr == SENTINEL { - None - } else { - let salt: [u8; 32] = memory.read_array(salt_ptr)?; - Some(salt) - }; - - memory.reset_interpreter_cache(); - - match self.ext.instantiate( - weight, - deposit_limit, - code_hash, - value, - input_data, - salt.as_ref(), - ) { - Ok(address) => { - if !self.ext.last_frame_output().flags.contains(ReturnFlags::REVERT) { - self.write_fixed_sandbox_output( - memory, - address_ptr, - &address.as_bytes(), - true, - already_charged, - )?; - } - let output = mem::take(self.ext.last_frame_output_mut()); - let write_result = self.write_sandbox_output( - memory, - output_ptr, - output_len_ptr, - &output.data, - true, - |len| Some(RuntimeCosts::CopyToContract(len)), - ); - *self.ext.last_frame_output_mut() = output; - write_result?; - Ok(self.ext.last_frame_output().into()) - }, - Err(err) => Ok(Self::exec_error_into_return_code(err)?), - } - } -} - -// This is the API exposed to contracts. -// -// # Note -// -// Any input that leads to a out of bound error (reading or writing) or failing to decode -// data passed to the supervisor will lead to a trap. This is not documented explicitly -// for every function. -#[define_env] -pub mod env { - /// Noop function used to benchmark the time it takes to execute an empty function. - /// - /// Marked as stable because it needs to be called from benchmarks even when the benchmarked - /// parachain has unstable functions disabled. - #[cfg(feature = "runtime-benchmarks")] - #[stable] - fn noop(&mut self, memory: &mut M) -> Result<(), TrapReason> { - Ok(()) - } - - /// Set the value at the given key in the contract storage. - /// See [`pallet_revive_uapi::HostFn::set_storage_v2`] - #[stable] - #[mutating] - fn set_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - value_ptr: u32, - value_len: u32, - ) -> Result { - self.set_storage( - memory, - flags, - key_ptr, - key_len, - StorageValue::Memory { ptr: value_ptr, len: value_len }, - ) - } - - /// Sets the storage at a fixed 256-bit key with a fixed 256-bit value. - /// See [`pallet_revive_uapi::HostFn::set_storage_or_clear`]. - #[stable] - #[mutating] - fn set_storage_or_clear( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - value_ptr: u32, - ) -> Result { - let value = memory.read(value_ptr, 32)?; - - if value.iter().all(|&b| b == 0) { - self.clear_storage(memory, flags, key_ptr, SENTINEL) - } else { - self.set_storage(memory, flags, key_ptr, SENTINEL, StorageValue::Value(value)) - } - } - - /// Retrieve the value under the given key from storage. - /// See [`pallet_revive_uapi::HostFn::get_storage`] - #[stable] - fn get_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result { - self.get_storage( - memory, - flags, - key_ptr, - key_len, - out_ptr, - StorageReadMode::VariableOutput { output_len_ptr: out_len_ptr }, - ) - } - - /// Reads the storage at a fixed 256-bit key and writes back a fixed 256-bit value. - /// See [`pallet_revive_uapi::HostFn::get_storage_or_zero`]. - #[stable] - fn get_storage_or_zero( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - out_ptr: u32, - ) -> Result<(), TrapReason> { - let _ = self.get_storage( - memory, - flags, - key_ptr, - SENTINEL, - out_ptr, - StorageReadMode::FixedOutput32, - )?; - - Ok(()) - } - - /// Make a call to another contract. - /// See [`pallet_revive_uapi::HostFn::call`]. - #[stable] - fn call( - &mut self, - memory: &mut M, - flags_and_callee: u64, - ref_time_limit: u64, - proof_size_limit: u64, - deposit_and_value: u64, - input_data: u64, - output_data: u64, - ) -> Result { - let (flags, callee_ptr) = extract_hi_lo(flags_and_callee); - let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value); - let (input_data_len, input_data_ptr) = extract_hi_lo(input_data); - let (output_len_ptr, output_ptr) = extract_hi_lo(output_data); - - self.call( - memory, - CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, - CallType::Call { value_ptr }, - callee_ptr, - deposit_ptr, - Weight::from_parts(ref_time_limit, proof_size_limit), - input_data_ptr, - input_data_len, - output_ptr, - output_len_ptr, - ) - } - - /// Execute code in the context (storage, caller, value) of the current contract. - /// See [`pallet_revive_uapi::HostFn::delegate_call`]. - #[stable] - fn delegate_call( - &mut self, - memory: &mut M, - flags_and_callee: u64, - ref_time_limit: u64, - proof_size_limit: u64, - deposit_ptr: u32, - input_data: u64, - output_data: u64, - ) -> Result { - let (flags, address_ptr) = extract_hi_lo(flags_and_callee); - let (input_data_len, input_data_ptr) = extract_hi_lo(input_data); - let (output_len_ptr, output_ptr) = extract_hi_lo(output_data); - - self.call( - memory, - CallFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?, - CallType::DelegateCall, - address_ptr, - deposit_ptr, - Weight::from_parts(ref_time_limit, proof_size_limit), - input_data_ptr, - input_data_len, - output_ptr, - output_len_ptr, - ) - } - - /// Instantiate a contract with the specified code hash. - /// See [`pallet_revive_uapi::HostFn::instantiate`]. - #[stable] - #[mutating] - fn instantiate( - &mut self, - memory: &mut M, - ref_time_limit: u64, - proof_size_limit: u64, - deposit_and_value: u64, - input_data: u64, - output_data: u64, - address_and_salt: u64, - ) -> Result { - let (deposit_ptr, value_ptr) = extract_hi_lo(deposit_and_value); - let (input_data_len, code_hash_ptr) = extract_hi_lo(input_data); - let (output_len_ptr, output_ptr) = extract_hi_lo(output_data); - let (address_ptr, salt_ptr) = extract_hi_lo(address_and_salt); - let Some(input_data_ptr) = code_hash_ptr.checked_add(32) else { - return Err(Error::::OutOfBounds.into()); - }; - let Some(input_data_len) = input_data_len.checked_sub(32) else { - return Err(Error::::OutOfBounds.into()); - }; - - self.instantiate( - memory, - code_hash_ptr, - Weight::from_parts(ref_time_limit, proof_size_limit), - deposit_ptr, - value_ptr, - input_data_ptr, - input_data_len, - address_ptr, - output_ptr, - output_len_ptr, - salt_ptr, - ) - } - - /// Returns the total size of the contract call input data. - /// See [`pallet_revive_uapi::HostFn::call_data_size `]. - #[stable] - fn call_data_size(&mut self, memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::CallDataSize)?; - Ok(self - .input_data - .as_ref() - .map(|input| input.len().try_into().expect("usize fits into u64; qed")) - .unwrap_or_default()) - } - - /// Stores the input passed by the caller into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::call_data_copy`]. - #[stable] - fn call_data_copy( - &mut self, - memory: &mut M, - out_ptr: u32, - out_len: u32, - offset: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::CallDataCopy(out_len))?; - - let Some(input) = self.input_data.as_ref() else { - return Err(Error::::InputForwarded.into()); - }; - - let start = offset as usize; - if start >= input.len() { - memory.zero(out_ptr, out_len)?; - return Ok(()); - } - - let end = start.saturating_add(out_len as usize).min(input.len()); - memory.write(out_ptr, &input[start..end])?; - - let bytes_written = (end - start) as u32; - memory.zero(out_ptr.saturating_add(bytes_written), out_len - bytes_written)?; - - Ok(()) - } - - /// Stores the U256 value at given call input `offset` into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::call_data_load`]. - #[stable] - fn call_data_load( - &mut self, - memory: &mut M, - out_ptr: u32, - offset: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::CallDataLoad)?; - - let Some(input) = self.input_data.as_ref() else { - return Err(Error::::InputForwarded.into()); - }; - - let mut data = [0; 32]; - let start = offset as usize; - let data = if start >= input.len() { - data // Any index is valid to request; OOB offsets return zero. - } else { - let end = start.saturating_add(32).min(input.len()); - data[..end - start].copy_from_slice(&input[start..end]); - data.reverse(); - data // Solidity expects right-padded data - }; - - self.write_fixed_sandbox_output(memory, out_ptr, &data, false, already_charged)?; - - Ok(()) - } - - /// Cease contract execution and save a data buffer as a result of the execution. - /// See [`pallet_revive_uapi::HostFn::return_value`]. - #[stable] - fn seal_return( - &mut self, - memory: &mut M, - flags: u32, - data_ptr: u32, - data_len: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::CopyFromContract(data_len))?; - if data_len > limits::CALLDATA_BYTES { - Err(>::ReturnDataTooLarge)?; - } - Err(TrapReason::Return(ReturnData { flags, data: memory.read(data_ptr, data_len)? })) - } - - /// Stores the address of the caller into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::caller`]. - #[stable] - fn caller(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::Caller)?; - let caller = ::AddressMapper::to_address(self.ext.caller().account_id()?); - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - caller.as_bytes(), - false, - already_charged, - )?) - } - - /// Stores the address of the call stack origin into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::origin`]. - #[stable] - fn origin(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::Origin)?; - let origin = ::AddressMapper::to_address(self.ext.origin().account_id()?); - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - origin.as_bytes(), - false, - already_charged, - )?) - } - - /// Retrieve the code hash for a specified contract address. - /// See [`pallet_revive_uapi::HostFn::code_hash`]. - #[stable] - fn code_hash(&mut self, memory: &mut M, addr_ptr: u32, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::CodeHash)?; - let address = memory.read_h160(addr_ptr)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.code_hash(&address).as_bytes(), - false, - already_charged, - )?) - } - - /// Retrieve the code size for a given contract address. - /// See [`pallet_revive_uapi::HostFn::code_size`]. - #[stable] - fn code_size(&mut self, memory: &mut M, addr_ptr: u32) -> Result { - self.charge_gas(RuntimeCosts::CodeSize)?; - let address = memory.read_h160(addr_ptr)?; - Ok(self.ext.code_size(&address)) - } - - /// Stores the address of the current contract into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::address`]. - #[stable] - fn address(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::Address)?; - let address = self.ext.address(); - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - address.as_bytes(), - false, - already_charged, - )?) - } - - /// Stores the price for the specified amount of weight into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::weight_to_fee`]. - #[stable] - fn weight_to_fee( - &mut self, - memory: &mut M, - ref_time_limit: u64, - proof_size_limit: u64, - out_ptr: u32, - ) -> Result<(), TrapReason> { - let weight = Weight::from_parts(ref_time_limit, proof_size_limit); - self.charge_gas(RuntimeCosts::WeightToFee)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.get_weight_price(weight).encode(), - false, - already_charged, - )?) - } - - /// Stores the immutable data into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::get_immutable_data`]. - #[stable] - fn get_immutable_data( - &mut self, - memory: &mut M, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result<(), TrapReason> { - // quering the length is free as it is stored with the contract metadata - let len = self.ext.immutable_data_len(); - self.charge_gas(RuntimeCosts::GetImmutableData(len))?; - let data = self.ext.get_immutable_data()?; - self.write_sandbox_output(memory, out_ptr, out_len_ptr, &data, false, already_charged)?; - Ok(()) - } - - /// Attaches the supplied immutable data to the currently executing contract. - /// See [`pallet_revive_uapi::HostFn::set_immutable_data`]. - #[stable] - fn set_immutable_data(&mut self, memory: &mut M, ptr: u32, len: u32) -> Result<(), TrapReason> { - if len > limits::IMMUTABLE_BYTES { - return Err(Error::::OutOfBounds.into()); - } - self.charge_gas(RuntimeCosts::SetImmutableData(len))?; - let buf = memory.read(ptr, len)?; - let data = buf.try_into().expect("bailed out earlier; qed"); - self.ext.set_immutable_data(data)?; - Ok(()) - } - - /// Stores the *free* balance of the current account into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::balance`]. - #[stable] - fn balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::Balance)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.balance().to_little_endian(), - false, - already_charged, - )?) - } - - /// Stores the *free* balance of the supplied address into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::balance`]. - #[stable] - fn balance_of( - &mut self, - memory: &mut M, - addr_ptr: u32, - out_ptr: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::BalanceOf)?; - let address = memory.read_h160(addr_ptr)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.balance_of(&address).to_little_endian(), - false, - already_charged, - )?) - } - - /// Returns the chain ID. - /// See [`pallet_revive_uapi::HostFn::chain_id`]. - #[stable] - fn chain_id(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &U256::from(::ChainId::get()).to_little_endian(), - false, - |_| Some(RuntimeCosts::CopyToContract(32)), - )?) - } - - /// Returns the block ref_time limit. - /// See [`pallet_revive_uapi::HostFn::gas_limit`]. - #[stable] - fn gas_limit(&mut self, memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::GasLimit)?; - Ok(::BlockWeights::get().max_block.ref_time()) - } - - /// Stores the value transferred along with this call/instantiate into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::value_transferred`]. - #[stable] - fn value_transferred(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::ValueTransferred)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.value_transferred().to_little_endian(), - false, - already_charged, - )?) - } - - /// Returns the simulated ethereum `GASPRICE` value. - /// See [`pallet_revive_uapi::HostFn::gas_price`]. - #[stable] - fn gas_price(&mut self, memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::GasPrice)?; - Ok(GAS_PRICE.into()) - } - - /// Returns the simulated ethereum `BASEFEE` value. - /// See [`pallet_revive_uapi::HostFn::base_fee`]. - #[stable] - fn base_fee(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::BaseFee)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &U256::zero().to_little_endian(), - false, - already_charged, - )?) - } - - /// Load the latest block timestamp into the supplied buffer - /// See [`pallet_revive_uapi::HostFn::now`]. - #[stable] - fn now(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::Now)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.now().to_little_endian(), - false, - already_charged, - )?) - } - - /// Deposit a contract event with the data buffer and optional list of topics. - /// See [pallet_revive_uapi::HostFn::deposit_event] - #[stable] - #[mutating] - fn deposit_event( - &mut self, - memory: &mut M, - topics_ptr: u32, - num_topic: u32, - data_ptr: u32, - data_len: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::DepositEvent { num_topic, len: data_len })?; - - if num_topic > limits::NUM_EVENT_TOPICS { - return Err(Error::::TooManyTopics.into()); - } - - if data_len > self.ext.max_value_size() { - return Err(Error::::ValueTooLarge.into()); - } - - let topics: Vec = match num_topic { - 0 => Vec::new(), - _ => { - let mut v = Vec::with_capacity(num_topic as usize); - let topics_len = num_topic * H256::len_bytes() as u32; - let buf = memory.read(topics_ptr, topics_len)?; - for chunk in buf.chunks_exact(H256::len_bytes()) { - v.push(H256::from_slice(chunk)); - } - v - }, - }; - - let event_data = memory.read(data_ptr, data_len)?; - self.ext.deposit_event(topics, event_data); - Ok(()) - } - - /// Stores the current block number of the current contract into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::block_number`]. - #[stable] - fn block_number(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::BlockNumber)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.block_number().to_little_endian(), - false, - already_charged, - )?) - } - - /// Stores the block hash at given block height into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::block_hash`]. - #[stable] - fn block_hash( - &mut self, - memory: &mut M, - block_number_ptr: u32, - out_ptr: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::BlockHash)?; - let block_number = memory.read_u256(block_number_ptr)?; - let block_hash = self.ext.block_hash(block_number).unwrap_or(H256::zero()); - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &block_hash.as_bytes(), - false, - already_charged, - )?) - } - - /// Stores the current block author into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::block_author`]. - #[stable] - fn block_author(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::BlockAuthor)?; - let block_author = self.ext.block_author().unwrap_or(H160::zero()); - - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &block_author.as_bytes(), - false, - already_charged, - )?) - } - - /// Computes the KECCAK 256-bit hash on the given input buffer. - /// See [`pallet_revive_uapi::HostFn::hash_keccak_256`]. - #[stable] - fn hash_keccak_256( - &mut self, - memory: &mut M, - input_ptr: u32, - input_len: u32, - output_ptr: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::HashKeccak256(input_len))?; - Ok(self.compute_hash_on_intermediate_buffer( - memory, keccak_256, input_ptr, input_len, output_ptr, - )?) - } - - /// Stores the length of the data returned by the last call into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::return_data_size`]. - #[stable] - fn return_data_size(&mut self, memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::ReturnDataSize)?; - Ok(self - .ext - .last_frame_output() - .data - .len() - .try_into() - .expect("usize fits into u64; qed")) - } - - /// Stores data returned by the last call, starting from `offset`, into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::return_data`]. - #[stable] - fn return_data_copy( - &mut self, - memory: &mut M, - out_ptr: u32, - out_len_ptr: u32, - offset: u32, - ) -> Result<(), TrapReason> { - let output = mem::take(self.ext.last_frame_output_mut()); - let result = if offset as usize > output.data.len() { - Err(Error::::OutOfBounds.into()) - } else { - self.write_sandbox_output( - memory, - out_ptr, - out_len_ptr, - &output.data[offset as usize..], - false, - |len| Some(RuntimeCosts::CopyToContract(len)), - ) - }; - *self.ext.last_frame_output_mut() = output; - Ok(result?) - } - - /// Returns the amount of ref_time left. - /// See [`pallet_revive_uapi::HostFn::ref_time_left`]. - #[stable] - fn ref_time_left(&mut self, memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::RefTimeLeft)?; - Ok(self.ext.gas_meter().gas_left().ref_time()) - } - - /// Clear the value at the given key in the contract storage. - /// See [`pallet_revive_uapi::HostFn::clear_storage`] - #[mutating] - fn clear_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - ) -> Result { - self.clear_storage(memory, flags, key_ptr, key_len) - } - - /// Checks whether there is a value stored under the given key. - /// See [`pallet_revive_uapi::HostFn::contains_storage`] - fn contains_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - ) -> Result { - self.contains_storage(memory, flags, key_ptr, key_len) - } - - /// Calculates Ethereum address from the ECDSA compressed public key and stores - /// See [`pallet_revive_uapi::HostFn::ecdsa_to_eth_address`]. - fn ecdsa_to_eth_address( - &mut self, - memory: &mut M, - key_ptr: u32, - out_ptr: u32, - ) -> Result { - self.charge_gas(RuntimeCosts::EcdsaToEthAddress)?; - let mut compressed_key: [u8; 33] = [0; 33]; - memory.read_into_buf(key_ptr, &mut compressed_key)?; - let result = self.ext.ecdsa_to_eth_address(&compressed_key); - match result { - Ok(eth_address) => { - memory.write(out_ptr, eth_address.as_ref())?; - Ok(ReturnErrorCode::Success) - }, - Err(_) => Ok(ReturnErrorCode::EcdsaRecoveryFailed), - } - } - - /// Replace the contract code at the specified address with new code. - /// See [`pallet_revive_uapi::HostFn::set_code_hash`]. - /// - /// Disabled until the internal implementation takes care of collecting - /// 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 code_hash: H256 = memory.read_h256(code_hash_ptr)?; - self.ext.set_code_hash(code_hash)?; - Ok(()) - } - - /// Verify a sr25519 signature - /// See [`pallet_revive_uapi::HostFn::sr25519_verify`]. - fn sr25519_verify( - &mut self, - memory: &mut M, - signature_ptr: u32, - pub_key_ptr: u32, - message_len: u32, - message_ptr: u32, - ) -> Result { - self.charge_gas(RuntimeCosts::Sr25519Verify(message_len))?; - - let mut signature: [u8; 64] = [0; 64]; - memory.read_into_buf(signature_ptr, &mut signature)?; - - let mut pub_key: [u8; 32] = [0; 32]; - memory.read_into_buf(pub_key_ptr, &mut pub_key)?; - - let message: Vec = memory.read(message_ptr, message_len)?; - - if self.ext.sr25519_verify(&signature, &message, &pub_key) { - Ok(ReturnErrorCode::Success) - } else { - Ok(ReturnErrorCode::Sr25519VerifyFailed) - } - } - - /// Retrieve and remove the value under the given key from storage. - /// See [`pallet_revive_uapi::HostFn::take_storage`] - #[mutating] - fn take_storage( - &mut self, - memory: &mut M, - flags: u32, - key_ptr: u32, - key_len: u32, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result { - self.take_storage(memory, flags, key_ptr, key_len, out_ptr, out_len_ptr) - } - - /// Remove the calling account and transfer remaining **free** balance. - /// 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 beneficiary = memory.read_h160(beneficiary_ptr)?; - self.ext.terminate(&beneficiary)?; - Err(TrapReason::Termination) - } -} From 72979fd9e4ba6911edcdf98843927a247eaf69c7 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 22 Aug 2025 13:44:39 +0200 Subject: [PATCH 22/63] Fix merge issues --- substrate/frame/revive/src/benchmarking.rs | 1 - substrate/frame/revive/src/exec/mock_ext.rs | 16 ----- substrate/frame/revive/src/tests/pvm.rs | 68 ++++++++++++++++++- substrate/frame/revive/src/vm/pvm/env.rs | 61 ----------------- .../frame/revive/src/vm/runtime_costs.rs | 24 +++---- 5 files changed, 78 insertions(+), 92 deletions(-) diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index 7896b73a29b45..72c03b80cfe71 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -670,7 +670,6 @@ mod benchmarks { let mut setup = CallSetup::::default(); setup.set_origin(Origin::Root); let (mut ext, _) = setup.ext(); - let mut runtime = pvm::Runtime::new(&mut ext, vec![]); let result; #[block] diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index 63b10c60eedda..a0da6108b1829 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -86,14 +86,6 @@ impl PrecompileExt for MockExt { panic!("MockExt::code_size") } - fn caller_is_origin(&self) -> bool { - panic!("MockExt::caller_is_origin") - } - - fn caller_is_root(&self) -> bool { - panic!("MockExt::caller_is_root") - } - fn account_id(&self) -> &AccountIdOf { panic!("MockExt::account_id") } @@ -114,10 +106,6 @@ impl PrecompileExt for MockExt { panic!("MockExt::now") } - fn minimum_balance(&self) -> U256 { - panic!("MockExt::minimum_balance") - } - fn deposit_event(&mut self, _topics: Vec, _data: Vec) { panic!("MockExt::deposit_event") } @@ -237,10 +225,6 @@ impl Ext for MockExt { panic!("MockExt::terminate") } - fn own_code_hash(&mut self) -> &H256 { - panic!("MockExt::own_code_hash") - } - fn set_code_hash(&mut self, _hash: H256) -> DispatchResult { panic!("MockExt::set_code_hash") } diff --git a/substrate/frame/revive/src/tests/pvm.rs b/substrate/frame/revive/src/tests/pvm.rs index 81aab74f72f2f..467d86c1772d7 100644 --- a/substrate/frame/revive/src/tests/pvm.rs +++ b/substrate/frame/revive/src/tests/pvm.rs @@ -455,7 +455,7 @@ fn run_out_of_fuel_host() { #[test] fn gas_syncs_work() { - let (code, _code_hash) = compile_module("caller_is_origin_n").unwrap(); + let (code, _code_hash) = compile_module("gas_price_n").unwrap(); ExtBuilder::default().existential_deposit(200).build().execute_with(|| { let _ = ::Currency::set_balance(&ALICE, 1_000_000); let contract = builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); @@ -467,7 +467,7 @@ fn gas_syncs_work() { let result = builder::bare_call(contract.addr).data(1u32.encode()).build(); assert_ok!(result.result); let gas_consumed_once = result.gas_consumed.ref_time(); - let host_consumed_once = ::WeightInfo::seal_caller_is_origin().ref_time(); + let host_consumed_once = ::WeightInfo::caller_is_origin().ref_time(); let engine_consumed_once = gas_consumed_once - host_consumed_once - engine_consumed_noop; let result = builder::bare_call(contract.addr).data(2u32.encode()).build(); @@ -3445,6 +3445,70 @@ fn call_diverging_out_len_works() { }); } +#[test] +fn call_own_code_hash_works() { + let (code, code_hash) = compile_module("call_own_code_hash").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create the contract: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let ret = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(H256::from_slice(&ret.data[..]), code_hash); + }); +} + +#[test] +fn call_caller_is_root() { + let (code, _) = compile_module("call_caller_is_root").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create the contract: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let ret = builder::bare_call(addr).origin(RuntimeOrigin::root()).build_and_unwrap_result(); + assert_eq!(ret.data, vec![1]); + }); +} + +#[test] +fn call_caller_is_root_from_non_root() { + let (code, _) = compile_module("call_caller_is_root").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create the contract: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let ret = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(ret.data, vec![0]); + }); +} + +#[test] +fn call_caller_is_origin() { + let (code, _) = compile_module("call_caller_is_origin").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create the contract: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let ret = builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(ret.data, vec![1]); + }); +} + #[test] fn chain_id_works() { let (code, _) = compile_module("chain_id").unwrap(); diff --git a/substrate/frame/revive/src/vm/pvm/env.rs b/substrate/frame/revive/src/vm/pvm/env.rs index 0255670a4f529..a1d964cf8dddd 100644 --- a/substrate/frame/revive/src/vm/pvm/env.rs +++ b/substrate/frame/revive/src/vm/pvm/env.rs @@ -863,20 +863,6 @@ pub mod env { Ok(self.ext.gas_meter().gas_left().ref_time()) } - /// Checks whether the caller of the current contract is the origin of the whole call stack. - /// See [`pallet_revive_uapi::HostFn::caller_is_origin`]. - fn caller_is_origin(&mut self, _memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::CallerIsOrigin)?; - Ok(self.ext.caller_is_origin() as u32) - } - - /// Checks whether the caller of the current contract is root. - /// See [`pallet_revive_uapi::HostFn::caller_is_root`]. - fn caller_is_root(&mut self, _memory: &mut M) -> Result { - self.charge_gas(RuntimeCosts::CallerIsRoot)?; - Ok(self.ext.caller_is_root() as u32) - } - /// Clear the value at the given key in the contract storage. /// See [`pallet_revive_uapi::HostFn::clear_storage`] #[mutating] @@ -923,33 +909,6 @@ pub mod env { } } - /// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::minimum_balance`]. - fn minimum_balance(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::MinimumBalance)?; - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - &self.ext.minimum_balance().to_little_endian(), - false, - already_charged, - )?) - } - - /// Retrieve the code hash of the currently executing contract. - /// See [`pallet_revive_uapi::HostFn::own_code_hash`]. - fn own_code_hash(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::OwnCodeHash)?; - let code_hash = *self.ext.own_code_hash(); - Ok(self.write_fixed_sandbox_output( - memory, - out_ptr, - code_hash.as_bytes(), - false, - already_charged, - )?) - } - /// Replace the contract code at the specified address with new code. /// See [`pallet_revive_uapi::HostFn::set_code_hash`]. /// @@ -1014,24 +973,4 @@ pub mod env { self.ext.terminate(&beneficiary)?; Err(TrapReason::Termination) } - - /// Stores the amount of weight left into the supplied buffer. - /// See [`pallet_revive_uapi::HostFn::weight_left`]. - fn weight_left( - &mut self, - memory: &mut M, - out_ptr: u32, - out_len_ptr: u32, - ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::WeightLeft)?; - let gas_left = &self.ext.gas_meter().gas_left().encode(); - Ok(self.write_sandbox_output( - memory, - out_ptr, - out_len_ptr, - gas_left, - false, - already_charged, - )?) - } } diff --git a/substrate/frame/revive/src/vm/runtime_costs.rs b/substrate/frame/revive/src/vm/runtime_costs.rs index 7c71a1bb1b933..75ae87b4b6f00 100644 --- a/substrate/frame/revive/src/vm/runtime_costs.rs +++ b/substrate/frame/revive/src/vm/runtime_costs.rs @@ -48,25 +48,25 @@ pub enum RuntimeCosts { CallDataSize, /// Weight of calling `seal_return_data_size`. ReturnDataSize, - /// Weight of calling `seal_to_account_id`. + /// Weight of calling `toAccountId` on the `System` pre-compile. ToAccountId, /// Weight of calling `seal_origin`. Origin, /// Weight of calling `seal_code_hash`. CodeHash, - /// Weight of calling `seal_own_code_hash`. + /// Weight of calling `ownCodeHash` on the `System` pre-compile. OwnCodeHash, /// Weight of calling `seal_code_size`. CodeSize, - /// Weight of calling `seal_caller_is_origin`. + /// Weight of calling `callerIsOrigin` on the `System` pre-compile. CallerIsOrigin, - /// Weight of calling `caller_is_root`. + /// Weight of calling `callerIsRoot` on the `System` pre-compile. CallerIsRoot, /// Weight of calling `seal_address`. Address, /// Weight of calling `seal_ref_time_left`. RefTimeLeft, - /// Weight of calling `seal_weight_left`. + /// Weight of calling `weightLeft` on the `System` pre-compile. WeightLeft, /// Weight of calling `seal_balance`. Balance, @@ -74,7 +74,7 @@ pub enum RuntimeCosts { BalanceOf, /// Weight of calling `seal_value_transferred`. ValueTransferred, - /// Weight of calling `seal_minimum_balance`. + /// Weight of calling `minimumBalance` on the `System` pre-compile. MinimumBalance, /// Weight of calling `seal_block_number`. BlockNumber, @@ -233,19 +233,19 @@ 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(), - CallerIsOrigin => T::WeightInfo::seal_caller_is_origin(), - CallerIsRoot => T::WeightInfo::seal_caller_is_root(), + OwnCodeHash => T::WeightInfo::own_code_hash(), + CallerIsOrigin => T::WeightInfo::caller_is_origin(), + CallerIsRoot => T::WeightInfo::caller_is_root(), Address => T::WeightInfo::seal_address(), RefTimeLeft => T::WeightInfo::seal_ref_time_left(), - WeightLeft => T::WeightInfo::seal_weight_left(), + WeightLeft => T::WeightInfo::weight_left(), Balance => T::WeightInfo::seal_balance(), BalanceOf => T::WeightInfo::seal_balance_of(), ValueTransferred => T::WeightInfo::seal_value_transferred(), - MinimumBalance => T::WeightInfo::seal_minimum_balance(), + MinimumBalance => T::WeightInfo::minimum_balance(), BlockNumber => T::WeightInfo::seal_block_number(), BlockHash => T::WeightInfo::seal_block_hash(), BlockAuthor => T::WeightInfo::seal_block_author(), From 121eb9350287e9e056ae068aa6d2b15b6f4ab95e Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Mon, 25 Aug 2025 17:11:50 +0200 Subject: [PATCH 23/63] Apply git diff From https://github.com/paritytech/polkadot-sdk/actions/runs/17210940480/artifacts/3844399827 --- substrate/frame/revive/src/weights.rs | 1124 +++++++++++++------------ 1 file changed, 564 insertions(+), 560 deletions(-) diff --git a/substrate/frame/revive/src/weights.rs b/substrate/frame/revive/src/weights.rs index 25a5d94f8163c..a3934adc386cb 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-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `c19fa2715a10`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `81a68b229a53`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024` // Executed Command: @@ -144,11 +144,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; @@ -171,8 +171,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_131_000 picoseconds. + Weight::from_parts(3_253_000, 1632) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -182,10 +182,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_384_000 picoseconds. + Weight::from_parts(14_764_000, 448) + // Standard Error: 1_618 + .saturating_add(Weight::from_parts(1_203_833, 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)) @@ -209,10 +209,10 @@ impl WeightInfo for SubstrateWeight { // 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) + // Minimum execution time: 87_100_000 picoseconds. + Weight::from_parts(123_604_530, 7106) // Standard Error: 10 - .saturating_add(Weight::from_parts(1_256, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_532, 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())) @@ -230,12 +230,14 @@ 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`) /// The range of component `b` is `[0, 1]`. - fn basic_block_compilation(_b: u32, ) -> Weight { + 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) + // Minimum execution time: 125_622_000 picoseconds. + Weight::from_parts(130_167_471, 10455) + // Standard Error: 479_835 + .saturating_add(Weight::from_parts(246_028, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -259,12 +261,12 @@ impl WeightInfo for SubstrateWeight { // 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())) + // Minimum execution time: 773_932_000 picoseconds. + Weight::from_parts(44_874_518, 7041) + // Standard Error: 35 + .saturating_add(Weight::from_parts(23_111, 0).saturating_mul(c.into())) + // Standard Error: 27 + .saturating_add(Weight::from_parts(5_232, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -289,14 +291,14 @@ impl WeightInfo for SubstrateWeight { // 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())) + // Minimum execution time: 286_264_000 picoseconds. + Weight::from_parts(139_441_930, 7062) + // Standard Error: 37 + .saturating_add(Weight::from_parts(17_938, 0).saturating_mul(c.into())) + // Standard Error: 29 + .saturating_add(Weight::from_parts(697, 0).saturating_mul(i.into())) + // Standard Error: 2_471_344 + .saturating_add(Weight::from_parts(54_177_742, 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)) @@ -320,12 +322,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) - // Standard Error: 11 - .saturating_add(Weight::from_parts(4_158, 0).saturating_mul(i.into())) + // Measured: `1922` + // Estimated: `5379` + // Minimum execution time: 174_126_000 picoseconds. + Weight::from_parts(180_912_129, 5379) + // Standard Error: 10 + .saturating_add(Weight::from_parts(4_266, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -343,10 +345,10 @@ impl WeightInfo for SubstrateWeight { /// 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: `1887` + // Estimated: `7827` + // Minimum execution time: 90_318_000 picoseconds. + Weight::from_parts(93_215_000, 7827) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -365,12 +367,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: `1887` + // Estimated: `7827 + d * (2475 ±0)` + // Minimum execution time: 88_320_000 picoseconds. + Weight::from_parts(93_190_328, 7827) + // Standard Error: 411_628 + .saturating_add(Weight::from_parts(25_847_871, 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)) @@ -388,10 +390,10 @@ impl WeightInfo for SubstrateWeight { // 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())) + // Minimum execution time: 57_825_000 picoseconds. + Weight::from_parts(43_965_864, 3970) + // Standard Error: 20 + .saturating_add(Weight::from_parts(14_354, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -405,8 +407,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `658` // Estimated: `4123` - // Minimum execution time: 47_344_000 picoseconds. - Weight::from_parts(48_892_000, 4123) + // Minimum execution time: 46_536_000 picoseconds. + Weight::from_parts(48_057_000, 4123) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -418,8 +420,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `530` // Estimated: `6470` - // Minimum execution time: 20_627_000 picoseconds. - Weight::from_parts(21_451_000, 6470) + // Minimum execution time: 19_930_000 picoseconds. + Weight::from_parts(20_910_000, 6470) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -431,8 +433,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: 56_875_000 picoseconds. + Weight::from_parts(58_037_000, 4278) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -444,8 +446,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_816_000 picoseconds. + Weight::from_parts(44_166_000, 3860) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -457,8 +459,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: 12_778_000 picoseconds. + Weight::from_parts(13_350_000, 3610) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -466,33 +468,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_401_000 picoseconds. + Weight::from_parts(8_599_195, 0) + // Standard Error: 274 + .saturating_add(Weight::from_parts(174_652, 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: 327_000 picoseconds. + Weight::from_parts(454_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: 300_000 picoseconds. + Weight::from_parts(370_000, 0) } /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) 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_850_000 picoseconds. + Weight::from_parts(8_275_000, 4032) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Revive::AccountInfoOf` (r:1 w:0) @@ -501,16 +503,16 @@ 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: 8_948_000 picoseconds. + Weight::from_parts(9_688_000, 3868) .saturating_add(T::DbWeight::get().reads(1_u64)) } fn own_code_hash() -> Weight { // Proof Size summary in bytes: - // Measured: `0` + // Measured: `366` // Estimated: `0` - // Minimum execution time: 282_000 picoseconds. - Weight::from_parts(336_000, 0) + // Minimum execution time: 6_912_000 picoseconds. + Weight::from_parts(7_374_000, 0) } /// Storage: `Revive::AccountInfoOf` (r:1 w:0) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) @@ -520,51 +522,51 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `474` // Estimated: `3939` - // Minimum execution time: 12_825_000 picoseconds. - Weight::from_parts(13_490_000, 3939) + // Minimum execution time: 12_653_000 picoseconds. + Weight::from_parts(13_325_000, 3939) .saturating_add(T::DbWeight::get().reads(2_u64)) } fn 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: 1_120_000 picoseconds. + Weight::from_parts(1_247_000, 0) } fn 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: 1_087_000 picoseconds. + Weight::from_parts(1_180_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: 322_000 picoseconds. + Weight::from_parts(365_000, 0) } fn 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: 1_174_000 picoseconds. + Weight::from_parts(1_266_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: 298_000 picoseconds. + Weight::from_parts(320_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `506` + // Measured: `467` // Estimated: `0` - // Minimum execution time: 13_351_000 picoseconds. - Weight::from_parts(13_878_000, 0) + // Minimum execution time: 12_378_000 picoseconds. + Weight::from_parts(12_951_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 +578,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_544_000 picoseconds. + Weight::from_parts(19_413_000, 4256) .saturating_add(T::DbWeight::get().reads(3_u64)) } /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) @@ -587,10 +589,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) - // Standard Error: 5 - .saturating_add(Weight::from_parts(483, 0).saturating_mul(n.into())) + // Minimum execution time: 5_779_000 picoseconds. + Weight::from_parts(6_636_121, 3736) + // Standard Error: 6 + .saturating_add(Weight::from_parts(554, 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 +603,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: 1_953_000 picoseconds. + Weight::from_parts(2_226_414, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(525, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(585, 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: 301_000 picoseconds. + Weight::from_parts(335_000, 0) } fn 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: 1_121_000 picoseconds. + Weight::from_parts(1_193_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: 308_000 picoseconds. + Weight::from_parts(346_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: 266_000 picoseconds. + Weight::from_parts(304_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: 455_000 picoseconds. + Weight::from_parts(547_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: 287_000 picoseconds. + Weight::from_parts(331_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: 309_000 picoseconds. + Weight::from_parts(335_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: 270_000 picoseconds. + Weight::from_parts(310_000, 0) } /// Storage: `Session::Validators` (r:1 w:0) /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -669,8 +671,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: 21_944_000 picoseconds. + Weight::from_parts(22_529_000, 1626) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `System::BlockHash` (r:1 w:0) @@ -679,60 +681,60 @@ 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_564_000 picoseconds. + Weight::from_parts(3_795_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: 306_000 picoseconds. + Weight::from_parts(343_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_627_000 picoseconds. + Weight::from_parts(1_762_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: 409_000 picoseconds. + Weight::from_parts(427_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: 261_000 picoseconds. + Weight::from_parts(327_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: 264_000 picoseconds. + Weight::from_parts(20_949, 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: 310_000 picoseconds. + Weight::from_parts(508_241, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(201, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(237, 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`) @@ -748,8 +750,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `582` // Estimated: `4047` - // Minimum execution time: 17_674_000 picoseconds. - Weight::from_parts(18_031_000, 4047) + // Minimum execution time: 16_950_000 picoseconds. + Weight::from_parts(17_612_000, 4047) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -759,12 +761,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())) + // Minimum execution time: 4_500_000 picoseconds. + Weight::from_parts(4_429_500, 0) + // Standard Error: 3_575 + .saturating_add(Weight::from_parts(253_239, 0).saturating_mul(t.into())) // Standard Error: 39 - .saturating_add(Weight::from_parts(854, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_250, 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 +774,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_207_000 picoseconds. + Weight::from_parts(7_700_000, 648) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -782,8 +784,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_177_000 picoseconds. + Weight::from_parts(42_500_000, 10658) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -792,8 +794,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_357_000 picoseconds. + Weight::from_parts(8_908_000, 648) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -803,8 +805,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: 43_254_000 picoseconds. + Weight::from_parts(44_108_000, 10658) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -816,12 +818,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_875_000 picoseconds. + Weight::from_parts(9_536_487, 247) + // Standard Error: 78 + .saturating_add(Weight::from_parts(429, 0).saturating_mul(n.into())) + // Standard Error: 78 + .saturating_add(Weight::from_parts(981, 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 +835,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_683_000 picoseconds. + Weight::from_parts(9_509_866, 247) + // Standard Error: 88 + .saturating_add(Weight::from_parts(699, 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 +850,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: 7_942_000 picoseconds. + Weight::from_parts(9_295_886, 247) + // Standard Error: 154 + .saturating_add(Weight::from_parts(1_026, 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 +864,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_711_000 picoseconds. + Weight::from_parts(8_578_310, 247) + // Standard Error: 72 + .saturating_add(Weight::from_parts(510, 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 +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_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: 8_946_000 picoseconds. + Weight::from_parts(10_164_342, 247) + // Standard Error: 109 + .saturating_add(Weight::from_parts(2_053, 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 +890,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_517_000 picoseconds. + Weight::from_parts(1_626_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_995_000 picoseconds. + Weight::from_parts(2_058_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_474_000 picoseconds. + Weight::from_parts(1_623_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_730_000 picoseconds. + Weight::from_parts(1_815_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_257_000 picoseconds. + Weight::from_parts(1_329_000, 0) } /// The range of component `n` is `[0, 416]`. /// The range of component `o` is `[0, 416]`. @@ -925,50 +927,50 @@ 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_334_000 picoseconds. + Weight::from_parts(2_662_549, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(159, 0).saturating_mul(n.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(313, 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_171_000 picoseconds. + Weight::from_parts(2_545_194, 0) + // Standard Error: 29 + .saturating_add(Weight::from_parts(391, 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: 1_938_000 picoseconds. + Weight::from_parts(2_239_258, 0) + // Standard Error: 24 + .saturating_add(Weight::from_parts(233, 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_775_000 picoseconds. + Weight::from_parts(2_102_603, 0) + // Standard Error: 20 + .saturating_add(Weight::from_parts(112, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 416]`. 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_645_000 picoseconds. + Weight::from_parts(2_910_829, 0) } /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) @@ -985,16 +987,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: `1923` + // Estimated: `5388` + // Minimum execution time: 89_541_000 picoseconds. + Weight::from_parts(71_161_380, 5388) + // Standard Error: 189_467 + .saturating_add(Weight::from_parts(18_572_466, 0).saturating_mul(t.into())) + // Standard Error: 189_467 + .saturating_add(Weight::from_parts(26_102_974, 0).saturating_mul(d.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(4, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(3, 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 +1011,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: 24_013_000 picoseconds. + Weight::from_parts(11_373_944, 2021) + // Standard Error: 75_255 + .saturating_add(Weight::from_parts(14_031_008, 0).saturating_mul(d.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(325, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(400, 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())) @@ -1029,8 +1031,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1362` // Estimated: `4827` - // Minimum execution time: 31_948_000 picoseconds. - Weight::from_parts(33_936_000, 4827) + // Minimum execution time: 32_480_000 picoseconds. + Weight::from_parts(33_750_000, 4827) .saturating_add(T::DbWeight::get().reads(3_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) @@ -1046,16 +1048,16 @@ 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: `1391` + // Estimated: `4875` + // Minimum execution time: 151_939_000 picoseconds. + Weight::from_parts(105_668_049, 4875) + // Standard Error: 552_011 + .saturating_add(Weight::from_parts(21_741_234, 0).saturating_mul(t.into())) + // Standard Error: 552_011 + .saturating_add(Weight::from_parts(30_473_339, 0).saturating_mul(d.into())) + // Standard Error: 6 + .saturating_add(Weight::from_parts(4_029, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -1064,118 +1066,118 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_165_000 picoseconds. - Weight::from_parts(9_566_786, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_251, 0).saturating_mul(n.into())) + // Minimum execution time: 1_328_000 picoseconds. + Weight::from_parts(11_124_892, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_287, 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: 897_000 picoseconds. + Weight::from_parts(732_342, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(112, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(148, 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_212_000 picoseconds. + Weight::from_parts(4_979_689, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_772, 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_157_000 picoseconds. + Weight::from_parts(12_383_659, 0) // Standard Error: 1 - .saturating_add(Weight::from_parts(3_539, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_592, 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) + // Minimum execution time: 1_727_000 picoseconds. + Weight::from_parts(15_513_788, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_405, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_436, 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_655_000 picoseconds. + Weight::from_parts(11_482_429, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_498, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_452, 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_506_000 picoseconds. + Weight::from_parts(83_323_965, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(4_863, 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: 45_740_000 picoseconds. + Weight::from_parts(46_352_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_754_000 picoseconds. + Weight::from_parts(15_827_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: 979_136_000 picoseconds. + Weight::from_parts(986_169_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: 891_000 picoseconds. + Weight::from_parts(4_804_994_796, 0) + // Standard Error: 10_884_646 + .saturating_add(Weight::from_parts(5_987_093_761, 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: 1_001_000 picoseconds. + Weight::from_parts(1_240_185, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(28_785, 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_190_000 picoseconds. + Weight::from_parts(13_617_000, 0) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -1183,8 +1185,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `296` // Estimated: `3761` - // Minimum execution time: 10_342_000 picoseconds. - Weight::from_parts(10_818_000, 3761) + // Minimum execution time: 9_844_000 picoseconds. + Weight::from_parts(10_553_000, 3761) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -1193,20 +1195,20 @@ impl WeightInfo for SubstrateWeight { // 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: 13_327_000 picoseconds. + Weight::from_parts(58_544_456, 0) + // Standard Error: 1_004 + .saturating_add(Weight::from_parts(142_512, 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_211_000 picoseconds. + Weight::from_parts(5_819_787, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(71_490, 0).saturating_mul(r.into())) } /// Storage: UNKNOWN KEY `0x735f040a5d490f1107ad9c56f5ca00d2060e99e5378e562537cf3bc983e17b91` (r:2 w:1) /// Proof: UNKNOWN KEY `0x735f040a5d490f1107ad9c56f5ca00d2060e99e5378e562537cf3bc983e17b91` (r:2 w:1) @@ -1216,8 +1218,8 @@ 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: 11_773_000 picoseconds. + Weight::from_parts(12_322_000, 6256) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -1231,8 +1233,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_131_000 picoseconds. + Weight::from_parts(3_253_000, 1632) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1242,10 +1244,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_384_000 picoseconds. + Weight::from_parts(14_764_000, 448) + // Standard Error: 1_618 + .saturating_add(Weight::from_parts(1_203_833, 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)) @@ -1269,10 +1271,10 @@ impl WeightInfo for () { // 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) + // Minimum execution time: 87_100_000 picoseconds. + Weight::from_parts(123_604_530, 7106) // Standard Error: 10 - .saturating_add(Weight::from_parts(1_256, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_532, 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())) @@ -1290,12 +1292,14 @@ impl WeightInfo for () { /// 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 `b` is `[0, 1]`. - fn basic_block_compilation(_b: u32, ) -> Weight { + 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) + // Minimum execution time: 125_622_000 picoseconds. + Weight::from_parts(130_167_471, 10455) + // Standard Error: 479_835 + .saturating_add(Weight::from_parts(246_028, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1319,12 +1323,12 @@ impl WeightInfo for () { // 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())) + // Minimum execution time: 773_932_000 picoseconds. + Weight::from_parts(44_874_518, 7041) + // Standard Error: 35 + .saturating_add(Weight::from_parts(23_111, 0).saturating_mul(c.into())) + // Standard Error: 27 + .saturating_add(Weight::from_parts(5_232, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1349,14 +1353,14 @@ impl WeightInfo for () { // 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())) + // Minimum execution time: 286_264_000 picoseconds. + Weight::from_parts(139_441_930, 7062) + // Standard Error: 37 + .saturating_add(Weight::from_parts(17_938, 0).saturating_mul(c.into())) + // Standard Error: 29 + .saturating_add(Weight::from_parts(697, 0).saturating_mul(i.into())) + // Standard Error: 2_471_344 + .saturating_add(Weight::from_parts(54_177_742, 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)) @@ -1380,12 +1384,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) - // Standard Error: 11 - .saturating_add(Weight::from_parts(4_158, 0).saturating_mul(i.into())) + // Measured: `1922` + // Estimated: `5379` + // Minimum execution time: 174_126_000 picoseconds. + Weight::from_parts(180_912_129, 5379) + // Standard Error: 10 + .saturating_add(Weight::from_parts(4_266, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1403,10 +1407,10 @@ impl WeightInfo for () { /// 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: `1887` + // Estimated: `7827` + // Minimum execution time: 90_318_000 picoseconds. + Weight::from_parts(93_215_000, 7827) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1425,12 +1429,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: `1887` + // Estimated: `7827 + d * (2475 ±0)` + // Minimum execution time: 88_320_000 picoseconds. + Weight::from_parts(93_190_328, 7827) + // Standard Error: 411_628 + .saturating_add(Weight::from_parts(25_847_871, 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)) @@ -1448,10 +1452,10 @@ impl WeightInfo for () { // 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())) + // Minimum execution time: 57_825_000 picoseconds. + Weight::from_parts(43_965_864, 3970) + // Standard Error: 20 + .saturating_add(Weight::from_parts(14_354, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1465,8 +1469,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `658` // Estimated: `4123` - // Minimum execution time: 47_344_000 picoseconds. - Weight::from_parts(48_892_000, 4123) + // Minimum execution time: 46_536_000 picoseconds. + Weight::from_parts(48_057_000, 4123) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1478,8 +1482,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `530` // Estimated: `6470` - // Minimum execution time: 20_627_000 picoseconds. - Weight::from_parts(21_451_000, 6470) + // Minimum execution time: 19_930_000 picoseconds. + Weight::from_parts(20_910_000, 6470) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1491,8 +1495,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: 56_875_000 picoseconds. + Weight::from_parts(58_037_000, 4278) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1504,8 +1508,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_816_000 picoseconds. + Weight::from_parts(44_166_000, 3860) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1517,8 +1521,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: 12_778_000 picoseconds. + Weight::from_parts(13_350_000, 3610) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -1526,33 +1530,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_401_000 picoseconds. + Weight::from_parts(8_599_195, 0) + // Standard Error: 274 + .saturating_add(Weight::from_parts(174_652, 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: 327_000 picoseconds. + Weight::from_parts(454_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: 300_000 picoseconds. + Weight::from_parts(370_000, 0) } /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) 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_850_000 picoseconds. + Weight::from_parts(8_275_000, 4032) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Revive::AccountInfoOf` (r:1 w:0) @@ -1561,16 +1565,16 @@ 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: 8_948_000 picoseconds. + Weight::from_parts(9_688_000, 3868) .saturating_add(RocksDbWeight::get().reads(1_u64)) } fn own_code_hash() -> Weight { // Proof Size summary in bytes: - // Measured: `0` + // Measured: `366` // Estimated: `0` - // Minimum execution time: 282_000 picoseconds. - Weight::from_parts(336_000, 0) + // Minimum execution time: 6_912_000 picoseconds. + Weight::from_parts(7_374_000, 0) } /// Storage: `Revive::AccountInfoOf` (r:1 w:0) /// Proof: `Revive::AccountInfoOf` (`max_values`: None, `max_size`: Some(247), added: 2722, mode: `Measured`) @@ -1580,51 +1584,51 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `474` // Estimated: `3939` - // Minimum execution time: 12_825_000 picoseconds. - Weight::from_parts(13_490_000, 3939) + // Minimum execution time: 12_653_000 picoseconds. + Weight::from_parts(13_325_000, 3939) .saturating_add(RocksDbWeight::get().reads(2_u64)) } fn 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: 1_120_000 picoseconds. + Weight::from_parts(1_247_000, 0) } fn 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: 1_087_000 picoseconds. + Weight::from_parts(1_180_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: 322_000 picoseconds. + Weight::from_parts(365_000, 0) } fn 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: 1_174_000 picoseconds. + Weight::from_parts(1_266_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: 298_000 picoseconds. + Weight::from_parts(320_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `506` + // Measured: `467` // Estimated: `0` - // Minimum execution time: 13_351_000 picoseconds. - Weight::from_parts(13_878_000, 0) + // Minimum execution time: 12_378_000 picoseconds. + Weight::from_parts(12_951_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 +1640,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_544_000 picoseconds. + Weight::from_parts(19_413_000, 4256) .saturating_add(RocksDbWeight::get().reads(3_u64)) } /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) @@ -1647,10 +1651,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) - // Standard Error: 5 - .saturating_add(Weight::from_parts(483, 0).saturating_mul(n.into())) + // Minimum execution time: 5_779_000 picoseconds. + Weight::from_parts(6_636_121, 3736) + // Standard Error: 6 + .saturating_add(Weight::from_parts(554, 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 +1665,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: 1_953_000 picoseconds. + Weight::from_parts(2_226_414, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(525, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(585, 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: 301_000 picoseconds. + Weight::from_parts(335_000, 0) } fn 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: 1_121_000 picoseconds. + Weight::from_parts(1_193_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: 308_000 picoseconds. + Weight::from_parts(346_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: 266_000 picoseconds. + Weight::from_parts(304_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: 455_000 picoseconds. + Weight::from_parts(547_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: 287_000 picoseconds. + Weight::from_parts(331_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: 309_000 picoseconds. + Weight::from_parts(335_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: 270_000 picoseconds. + Weight::from_parts(310_000, 0) } /// Storage: `Session::Validators` (r:1 w:0) /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -1729,8 +1733,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: 21_944_000 picoseconds. + Weight::from_parts(22_529_000, 1626) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `System::BlockHash` (r:1 w:0) @@ -1739,60 +1743,60 @@ 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_564_000 picoseconds. + Weight::from_parts(3_795_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: 306_000 picoseconds. + Weight::from_parts(343_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_627_000 picoseconds. + Weight::from_parts(1_762_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: 409_000 picoseconds. + Weight::from_parts(427_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: 261_000 picoseconds. + Weight::from_parts(327_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: 264_000 picoseconds. + Weight::from_parts(20_949, 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: 310_000 picoseconds. + Weight::from_parts(508_241, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(201, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(237, 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`) @@ -1808,8 +1812,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `582` // Estimated: `4047` - // Minimum execution time: 17_674_000 picoseconds. - Weight::from_parts(18_031_000, 4047) + // Minimum execution time: 16_950_000 picoseconds. + Weight::from_parts(17_612_000, 4047) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1819,12 +1823,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())) + // Minimum execution time: 4_500_000 picoseconds. + Weight::from_parts(4_429_500, 0) + // Standard Error: 3_575 + .saturating_add(Weight::from_parts(253_239, 0).saturating_mul(t.into())) // Standard Error: 39 - .saturating_add(Weight::from_parts(854, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_250, 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 +1836,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_207_000 picoseconds. + Weight::from_parts(7_700_000, 648) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1842,8 +1846,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_177_000 picoseconds. + Weight::from_parts(42_500_000, 10658) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1852,8 +1856,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_357_000 picoseconds. + Weight::from_parts(8_908_000, 648) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1863,8 +1867,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: 43_254_000 picoseconds. + Weight::from_parts(44_108_000, 10658) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1876,12 +1880,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_875_000 picoseconds. + Weight::from_parts(9_536_487, 247) + // Standard Error: 78 + .saturating_add(Weight::from_parts(429, 0).saturating_mul(n.into())) + // Standard Error: 78 + .saturating_add(Weight::from_parts(981, 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 +1897,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_683_000 picoseconds. + Weight::from_parts(9_509_866, 247) + // Standard Error: 88 + .saturating_add(Weight::from_parts(699, 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 +1912,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: 7_942_000 picoseconds. + Weight::from_parts(9_295_886, 247) + // Standard Error: 154 + .saturating_add(Weight::from_parts(1_026, 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 +1926,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_711_000 picoseconds. + Weight::from_parts(8_578_310, 247) + // Standard Error: 72 + .saturating_add(Weight::from_parts(510, 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 +1940,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: 8_946_000 picoseconds. + Weight::from_parts(10_164_342, 247) + // Standard Error: 109 + .saturating_add(Weight::from_parts(2_053, 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 +1952,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_517_000 picoseconds. + Weight::from_parts(1_626_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_995_000 picoseconds. + Weight::from_parts(2_058_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_474_000 picoseconds. + Weight::from_parts(1_623_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_730_000 picoseconds. + Weight::from_parts(1_815_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_257_000 picoseconds. + Weight::from_parts(1_329_000, 0) } /// The range of component `n` is `[0, 416]`. /// The range of component `o` is `[0, 416]`. @@ -1985,50 +1989,50 @@ 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_334_000 picoseconds. + Weight::from_parts(2_662_549, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(159, 0).saturating_mul(n.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(313, 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_171_000 picoseconds. + Weight::from_parts(2_545_194, 0) + // Standard Error: 29 + .saturating_add(Weight::from_parts(391, 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: 1_938_000 picoseconds. + Weight::from_parts(2_239_258, 0) + // Standard Error: 24 + .saturating_add(Weight::from_parts(233, 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_775_000 picoseconds. + Weight::from_parts(2_102_603, 0) + // Standard Error: 20 + .saturating_add(Weight::from_parts(112, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 416]`. 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_645_000 picoseconds. + Weight::from_parts(2_910_829, 0) } /// Storage: `Revive::OriginalAccount` (r:1 w:0) /// Proof: `Revive::OriginalAccount` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `Measured`) @@ -2045,16 +2049,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: `1923` + // Estimated: `5388` + // Minimum execution time: 89_541_000 picoseconds. + Weight::from_parts(71_161_380, 5388) + // Standard Error: 189_467 + .saturating_add(Weight::from_parts(18_572_466, 0).saturating_mul(t.into())) + // Standard Error: 189_467 + .saturating_add(Weight::from_parts(26_102_974, 0).saturating_mul(d.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(4, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(3, 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 +2073,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: 24_013_000 picoseconds. + Weight::from_parts(11_373_944, 2021) + // Standard Error: 75_255 + .saturating_add(Weight::from_parts(14_031_008, 0).saturating_mul(d.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(325, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(400, 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())) @@ -2089,8 +2093,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1362` // Estimated: `4827` - // Minimum execution time: 31_948_000 picoseconds. - Weight::from_parts(33_936_000, 4827) + // Minimum execution time: 32_480_000 picoseconds. + Weight::from_parts(33_750_000, 4827) .saturating_add(RocksDbWeight::get().reads(3_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) @@ -2106,16 +2110,16 @@ 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: `1391` + // Estimated: `4875` + // Minimum execution time: 151_939_000 picoseconds. + Weight::from_parts(105_668_049, 4875) + // Standard Error: 552_011 + .saturating_add(Weight::from_parts(21_741_234, 0).saturating_mul(t.into())) + // Standard Error: 552_011 + .saturating_add(Weight::from_parts(30_473_339, 0).saturating_mul(d.into())) + // Standard Error: 6 + .saturating_add(Weight::from_parts(4_029, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2124,118 +2128,118 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_165_000 picoseconds. - Weight::from_parts(9_566_786, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_251, 0).saturating_mul(n.into())) + // Minimum execution time: 1_328_000 picoseconds. + Weight::from_parts(11_124_892, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_287, 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: 897_000 picoseconds. + Weight::from_parts(732_342, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(112, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(148, 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_212_000 picoseconds. + Weight::from_parts(4_979_689, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(3_772, 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_157_000 picoseconds. + Weight::from_parts(12_383_659, 0) // Standard Error: 1 - .saturating_add(Weight::from_parts(3_539, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_592, 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) + // Minimum execution time: 1_727_000 picoseconds. + Weight::from_parts(15_513_788, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_405, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_436, 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_655_000 picoseconds. + Weight::from_parts(11_482_429, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_498, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_452, 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_506_000 picoseconds. + Weight::from_parts(83_323_965, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(4_863, 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: 45_740_000 picoseconds. + Weight::from_parts(46_352_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_754_000 picoseconds. + Weight::from_parts(15_827_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: 979_136_000 picoseconds. + Weight::from_parts(986_169_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: 891_000 picoseconds. + Weight::from_parts(4_804_994_796, 0) + // Standard Error: 10_884_646 + .saturating_add(Weight::from_parts(5_987_093_761, 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: 1_001_000 picoseconds. + Weight::from_parts(1_240_185, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(28_785, 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_190_000 picoseconds. + Weight::from_parts(13_617_000, 0) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -2243,8 +2247,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `296` // Estimated: `3761` - // Minimum execution time: 10_342_000 picoseconds. - Weight::from_parts(10_818_000, 3761) + // Minimum execution time: 9_844_000 picoseconds. + Weight::from_parts(10_553_000, 3761) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2253,20 +2257,20 @@ impl WeightInfo for () { // 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: 13_327_000 picoseconds. + Weight::from_parts(58_544_456, 0) + // Standard Error: 1_004 + .saturating_add(Weight::from_parts(142_512, 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_211_000 picoseconds. + Weight::from_parts(5_819_787, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(71_490, 0).saturating_mul(r.into())) } /// Storage: UNKNOWN KEY `0x735f040a5d490f1107ad9c56f5ca00d2060e99e5378e562537cf3bc983e17b91` (r:2 w:1) /// Proof: UNKNOWN KEY `0x735f040a5d490f1107ad9c56f5ca00d2060e99e5378e562537cf3bc983e17b91` (r:2 w:1) @@ -2276,8 +2280,8 @@ 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: 11_773_000 picoseconds. + Weight::from_parts(12_322_000, 6256) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } From f9e1034557aebeeb8944c506ac07b582141e4aa8 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 26 Aug 2025 07:08:45 +0200 Subject: [PATCH 24/63] Simplify variable naming --- .../revive/fixtures/contracts/call_own_code_hash.rs | 10 +++++----- substrate/frame/revive/fixtures/contracts/drain.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs index f361a821643f5..bf0b5cd6293cc 100644 --- a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs +++ b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs @@ -34,8 +34,8 @@ pub extern "C" fn deploy() { } #[no_mangle] #[polkavm_derive::polkavm_export] pub extern "C" fn call() { - let mut output_buf1 = [0u8; 32]; - let output1 = &mut &mut output_buf1[..]; + let mut output_buf = [0u8; 32]; + let output = &mut &mut output_buf[..]; let _ = api::delegate_call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, @@ -43,8 +43,8 @@ pub extern "C" fn call() { u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. &uapi::solidity_selector("ownCodeHash()"), - Some(output1), + Some(output), ).unwrap(); - assert_ne!(output_buf1, [0u8; 32]); - api::return_value(uapi::ReturnFlags::empty(), &output_buf1); + assert_ne!(output_buf, [0u8; 32]); + api::return_value(uapi::ReturnFlags::empty(), &output_buf); } diff --git a/substrate/frame/revive/fixtures/contracts/drain.rs b/substrate/frame/revive/fixtures/contracts/drain.rs index 517a7a883df8c..861f5385e0421 100644 --- a/substrate/frame/revive/fixtures/contracts/drain.rs +++ b/substrate/frame/revive/fixtures/contracts/drain.rs @@ -30,8 +30,8 @@ pub extern "C" fn deploy() {} pub extern "C" fn call() { let balance = u64_output!(api::balance,); - let mut output_buf1 = [0u8; 8]; - let output1 = &mut &mut output_buf1[..]; + let mut output_buf = [0u8; 8]; + let output = &mut &mut output_buf[..]; let _ = api::call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, @@ -40,10 +40,10 @@ pub extern "C" fn call() { &[u8::MAX; 32], // No deposit limit. &u256_bytes(0), &uapi::solidity_selector("minimumBalance()"), - Some(output1), + Some(output), ).unwrap(); - assert_ne!(output_buf1, [0u8; 8]); - let minimum_balance = u64::from_le_bytes(output_buf1); + assert_ne!(output_buf, [0u8; 8]); + let minimum_balance = u64::from_le_bytes(output_buf); // Make the transferred value exceed the balance by adding the minimum balance. let balance = balance + minimum_balance; From 0f6e7ed0324d78114a2688723983e22eaf89e516 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 26 Aug 2025 07:37:34 +0200 Subject: [PATCH 25/63] Fix test --- substrate/frame/revive/src/tests/pvm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/tests/pvm.rs b/substrate/frame/revive/src/tests/pvm.rs index 467d86c1772d7..afae7c4a242e0 100644 --- a/substrate/frame/revive/src/tests/pvm.rs +++ b/substrate/frame/revive/src/tests/pvm.rs @@ -467,7 +467,7 @@ fn gas_syncs_work() { let result = builder::bare_call(contract.addr).data(1u32.encode()).build(); assert_ok!(result.result); let gas_consumed_once = result.gas_consumed.ref_time(); - let host_consumed_once = ::WeightInfo::caller_is_origin().ref_time(); + let host_consumed_once = ::WeightInfo::seal_gas_price().ref_time(); let engine_consumed_once = gas_consumed_once - host_consumed_once - engine_consumed_noop; let result = builder::bare_call(contract.addr).data(2u32.encode()).build(); From 4dc44bef09364b77150cdf5e953617ab835669ec Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 26 Aug 2025 23:13:40 +0200 Subject: [PATCH 26/63] Allow pre-compiles access to `convert_native_to_evm` --- substrate/frame/revive/src/exec.rs | 9 +++++++++ substrate/frame/revive/src/exec/mock_ext.rs | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 4c3bd0215848e..04b9b8cc0b1d4 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -407,6 +407,9 @@ pub trait PrecompileExt: sealing::Sealed { /// Returns a mutable reference to the output of the last executed call frame. fn last_frame_output_mut(&mut self) -> &mut ExecReturnValue; + + /// Convert a native balance to EVM balance. + fn convert_native_to_evm(&self, value: BalanceOf) -> U256; } /// Describes the different functions that can be exported by an [`Executable`]. @@ -2057,6 +2060,12 @@ where fn last_frame_output_mut(&mut self) -> &mut ExecReturnValue { &mut self.top_frame_mut().last_frame_output } + + /// Convert a native balance to EVM balance. + //fn convert_native_to_evm(value: impl Into>>) -> U256 { + fn convert_native_to_evm(&self, value: BalanceOf) -> U256 { + crate::Pallet::::convert_native_to_evm(value) + } } mod sealing { diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index a0da6108b1829..153b11ab5a3fd 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -175,6 +175,10 @@ impl PrecompileExt for MockExt { fn last_frame_output_mut(&mut self) -> &mut ExecReturnValue { panic!("MockExt::last_frame_output_mut") } + + fn convert_native_to_evm(&self, _value: crate::BalanceOf) -> U256 { + panic!("MockExt::convert_native_to_evm") + } } impl PrecompileWithInfoExt for MockExt { From 80c58a387c5120f2ee8ce1aee5dc7991764db7de Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 26 Aug 2025 23:13:10 +0200 Subject: [PATCH 27/63] Encode as Solidity types --- .../contracts/call_caller_is_origin.rs | 2 +- .../fixtures/contracts/call_caller_is_root.rs | 2 +- .../frame/revive/fixtures/contracts/drain.rs | 12 ++-- substrate/frame/revive/src/benchmarking.rs | 60 ++++++++++++++----- substrate/frame/revive/src/exec/tests.rs | 11 ++-- .../revive/src/precompiles/builtin/system.rs | 47 +++++++++------ .../builtin/testdata/900-to_account_id.json | 2 +- substrate/frame/revive/src/tests/pvm.rs | 10 +++- 8 files changed, 98 insertions(+), 48 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs index 896ec01dec8e3..e68349e4d2115 100644 --- a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs @@ -31,7 +31,7 @@ pub extern "C" fn deploy() {} #[no_mangle] #[polkavm_derive::polkavm_export] pub extern "C" fn call() { - let mut output = [0u8; 1]; + let mut output = [0u8; 32]; let _ = api::delegate_call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs index a018065818994..fdd968e4deeed 100644 --- a/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs @@ -31,7 +31,7 @@ pub extern "C" fn deploy() {} #[no_mangle] #[polkavm_derive::polkavm_export] pub extern "C" fn call() { - let mut output = [0u8; 1]; + let mut output = [0u8; 32]; let _ = api::delegate_call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, diff --git a/substrate/frame/revive/fixtures/contracts/drain.rs b/substrate/frame/revive/fixtures/contracts/drain.rs index 861f5385e0421..303072a0bb1a2 100644 --- a/substrate/frame/revive/fixtures/contracts/drain.rs +++ b/substrate/frame/revive/fixtures/contracts/drain.rs @@ -30,20 +30,22 @@ pub extern "C" fn deploy() {} pub extern "C" fn call() { let balance = u64_output!(api::balance,); - let mut output_buf = [0u8; 8]; + let mut output_buf = [0u8; 32]; let output = &mut &mut output_buf[..]; - let _ = api::call( + let _ = api::delegate_call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. - &u256_bytes(0), &uapi::solidity_selector("minimumBalance()"), Some(output), ).unwrap(); - assert_ne!(output_buf, [0u8; 8]); - let minimum_balance = u64::from_le_bytes(output_buf); + assert_ne!(output_buf, [0u8; 32]); + + let mut u64_buf = [0u8; 8]; + u64_buf[..8].copy_from_slice(&output_buf[24..32]); + let minimum_balance = u64::from_be_bytes(u64_buf); // Make the transferred value exceed the balance by adding the minimum balance. let balance = balance + minimum_balance; diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index 72c03b80cfe71..3fa9ab3f0b64c 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -24,14 +24,20 @@ use crate::{ exec::{Key, MomentOf, PrecompileExt}, limits, precompiles::{ - self, run::builtin as run_builtin_precompile, BenchmarkSystem, BuiltinPrecompile, ISystem, + self, + alloy::sol_types::{ + sol_data::{Bool, Bytes, FixedBytes, Uint}, + SolType, + }, + run::builtin as run_builtin_precompile, + BenchmarkSystem, BuiltinPrecompile, ISystem, }, storage::WriteOutcome, vm::pvm, Pallet as Contracts, *, }; use alloc::{vec, vec::Vec}; -use alloy_core::sol_types::SolInterface; +use alloy_core::sol_types::{SolInterface, SolValue}; use codec::{Encode, MaxEncodedLen}; use frame_benchmarking::v2::*; use frame_support::{ @@ -579,13 +585,14 @@ mod benchmarks { input_bytes, ); } - let data = result.unwrap().data; + let raw_data = result.unwrap().data; + let data = Bytes::abi_decode(&raw_data).expect("decoding failed"); assert_ne!( - data.as_slice()[20..32], + data.0.as_ref()[20..32], [0xEE; 12], "fallback suffix found where none should be" ); - assert_eq!(T::AccountId::decode(&mut data.as_slice()), Ok(account_id),); + assert_eq!(T::AccountId::decode(&mut data.as_ref()), Ok(account_id),); } #[benchmark(pov_mode = Measured)] @@ -659,7 +666,9 @@ mod benchmarks { input_bytes, ); } - assert_eq!(result.unwrap().data, vec![1u8]); + let raw_data = result.unwrap().data; + let is_origin = Bool::abi_decode(&raw_data[..]).expect("decoding failed"); + assert!(is_origin); } #[benchmark(pov_mode = Measured)] @@ -680,7 +689,9 @@ mod benchmarks { input_bytes, ); } - assert_eq!(result.unwrap().data, vec![1u8]); + let raw_data = result.unwrap().data; + let is_root = Bool::abi_decode(&raw_data).expect("decoding failed"); + assert!(is_root); } #[benchmark(pov_mode = Measured)] @@ -719,9 +730,10 @@ mod benchmarks { assert_ne!(weight_left_after.ref_time(), 0); assert!(weight_left_before.ref_time() > weight_left_after.ref_time()); - let data = result.unwrap().data; - let ret: Weight = Decode::decode(&mut &data[..]).unwrap(); - assert_eq!(weight_left_after.ref_time(), ret.ref_time()); + let raw_data = result.unwrap().data; + type MyTy = (Uint<64>, Uint<64>); + let foo = MyTy::abi_decode(&raw_data[..]).unwrap(); + assert_eq!(weight_left_after.ref_time(), foo.0); } #[benchmark(pov_mode = Measured)] @@ -861,8 +873,16 @@ mod benchmarks { input_bytes, ); } - let min = T::Currency::minimum_balance(); - assert_eq!(result.unwrap().data, min.encode()); + let min: U256 = crate::Pallet::::convert_native_to_evm(T::Currency::minimum_balance()); + let min = + crate::precompiles::alloy::primitives::aliases::U256::abi_decode(&min.to_big_endian()) + .unwrap(); + + let raw_data = result.unwrap().data; + let returned_min = + crate::precompiles::alloy::primitives::aliases::U256::abi_decode(&raw_data) + .expect("decoding failed"); + assert_eq!(returned_min, min); } #[benchmark(pov_mode = Measured)] @@ -2034,7 +2054,13 @@ mod benchmarks { input_bytes, ); } - assert_eq!(sp_io::hashing::blake2_256(&input).to_vec(), result.unwrap().data); + let truth: [u8; 32] = sp_io::hashing::blake2_256(&input); + let truth = FixedBytes::<32>::abi_encode(&truth); + let truth = FixedBytes::<32>::abi_decode(&truth[..]).expect("decoding failed"); + + let raw_data = result.unwrap().data; + let ret_hash = FixedBytes::<32>::abi_decode(&raw_data[..]).expect("decoding failed"); + assert_eq!(truth, ret_hash); } // `n`: Input to hash in bytes @@ -2058,7 +2084,13 @@ mod benchmarks { input_bytes, ); } - assert_eq!(sp_io::hashing::blake2_128(&input).to_vec(), result.unwrap().data); + let truth: [u8; 16] = sp_io::hashing::blake2_128(&input); + let truth = FixedBytes::<16>::abi_encode(&truth); + let truth = FixedBytes::<16>::abi_decode(&truth[..]).expect("decoding failed"); + + let raw_data = result.unwrap().data; + let ret_hash = FixedBytes::<16>::abi_decode(&raw_data[..]).expect("decoding failed"); + assert_eq!(truth, ret_hash); } // `n`: Message input length to verify in bytes. diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index 4ecdeb1a0becb..fa4dd3dfb23d9 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -25,6 +25,7 @@ use super::*; use crate::{ exec::ExportedFunction::*, gas::GasMeter, + precompiles::alloy::sol_types::{sol_data::Bool, SolType}, test_utils::*, tests::{ test_utils::{get_balance, place_contract, set_balance}, @@ -898,7 +899,9 @@ fn caller_is_origin_returns_proper_values() { pallet_revive_uapi::solidity_selector("callerIsOrigin()").to_vec(), ) .map(|_| ctx.ext.last_frame_output().clone()); - let caller_is_origin = ret.unwrap().data == vec![1]; + + let raw_data = ret.unwrap().data; + let caller_is_origin = Bool::abi_decode(&raw_data).expect("decoding to bool failed"); assert!(caller_is_origin); // BOB calls CHARLIE @@ -939,7 +942,7 @@ fn root_caller_succeeds() { pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), ) .map(|_| ctx.ext.last_frame_output().clone()); - let caller_is_root = ret.unwrap().data == vec![1]; + let caller_is_root = Bool::abi_decode(&ret.unwrap().data).expect("decoding to bool failed"); assert!(caller_is_root); exec_success() }); @@ -1006,7 +1009,7 @@ fn root_caller_succeeds_with_consecutive_calls() { pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), ) .map(|_| ctx.ext.last_frame_output().clone()); - let caller_is_root = ret.unwrap().data == vec![1]; + let caller_is_root = Bool::abi_decode(&ret.unwrap().data).expect("decoding to bool failed"); assert!(!caller_is_root); exec_success() }); @@ -1022,7 +1025,7 @@ fn root_caller_succeeds_with_consecutive_calls() { pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), ) .map(|_| ctx.ext.last_frame_output().clone()); - let caller_is_root = ret.unwrap().data == vec![1]; + let caller_is_root = Bool::abi_decode(&ret.unwrap().data).expect("decoding to bool failed"); assert!(caller_is_root); // BOB calls CHARLIE. diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index d10a50ad8c3cf..93d0baa43d999 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -21,8 +21,8 @@ use crate::{ vm::RuntimeCosts, Config, Origin, H160, }; -use alloc::{vec, vec::Vec}; -use alloy_core::sol; +use alloc::vec::Vec; +use alloy_core::{sol, sol_types::SolValue}; use codec::Encode; use core::{marker::PhantomData, num::NonZero}; use frame_support::traits::fungible::Inspect; @@ -70,7 +70,7 @@ sol! { /// Returns the amount of weight left. /// The data is encoded as `Weight`. - function weightLeft() external view returns (uint); + function weightLeft() external view returns (uint64 refTime, uint64 proofSize); } } @@ -91,12 +91,12 @@ impl BuiltinPrecompile for System { ISystemCalls::hashBlake256(ISystem::hashBlake256Call { input }) => { env.gas_meter_mut().charge(RuntimeCosts::HashBlake256(input.len() as u32))?; let output = sp_io::hashing::blake2_256(input.as_bytes_ref()); - Ok(output.to_vec()) + Ok(output.abi_encode()) }, ISystemCalls::hashBlake128(ISystem::hashBlake128Call { input }) => { env.gas_meter_mut().charge(RuntimeCosts::HashBlake128(input.len() as u32))?; let output = sp_io::hashing::blake2_128(input.as_bytes_ref()); - Ok(output.to_vec()) + Ok(output.abi_encode()) }, ISystemCalls::toAccountId(ISystem::toAccountIdCall { input }) => { use crate::address::AddressMapper; @@ -104,7 +104,7 @@ impl BuiltinPrecompile for System { env.gas_meter_mut().charge(RuntimeCosts::ToAccountId)?; let account_id = T::AddressMapper::to_account_id(&H160::from_slice(input.as_slice())); - Ok(account_id.encode()) + Ok(account_id.encode().abi_encode()) }, ISystemCalls::callerIsOrigin(ISystem::callerIsOriginCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::CallerIsOrigin)?; @@ -125,15 +125,15 @@ impl BuiltinPrecompile for System { } }, }; - Ok(vec![is_origin as u8]) + Ok(is_origin.abi_encode()) }, ISystemCalls::callerIsRoot(ISystem::callerIsRootCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::CallerIsRoot)?; - let caller_is_root = match env.caller() { + let is_root = match env.caller() { Origin::Root => true, Origin::Signed(_) => false, }; - Ok(vec![caller_is_root as u8]) + Ok(is_root.abi_encode()) }, ISystemCalls::ownCodeHash(ISystem::ownCodeHashCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::OwnCodeHash)?; @@ -144,13 +144,15 @@ impl BuiltinPrecompile for System { ISystemCalls::minimumBalance(ISystem::minimumBalanceCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::MinimumBalance)?; let minimum_balance = T::Currency::minimum_balance(); - let output = minimum_balance.encode(); - Ok(output) + let minimum_balance_as_evm_value = env.convert_native_to_evm(minimum_balance); + Ok(minimum_balance_as_evm_value.to_big_endian().abi_encode()) }, ISystemCalls::weightLeft(ISystem::weightLeftCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::WeightLeft)?; - let gas_left = env.gas_meter().gas_left().encode(); - Ok(gas_left) + let ref_time = env.gas_meter().gas_left().ref_time(); + let proof_size = env.gas_meter().gas_left().proof_size(); + let res = (ref_time, proof_size); + Ok(res.abi_encode()) }, } } @@ -163,7 +165,11 @@ mod tests { address::AddressMapper, call_builder::{caller_funding, CallSetup}, pallet, - precompiles::{tests::run_test_vectors, BuiltinPrecompile}, + precompiles::{ + alloy::sol_types::{sol_data::Bytes, SolType}, + tests::run_test_vectors, + BuiltinPrecompile, + }, tests::{ExtBuilder, Test}, }; use codec::Decode; @@ -188,13 +194,15 @@ mod tests { let input = ISystem::ISystemCalls::toAccountId(ISystem::toAccountIdCall { input: unmapped_address.0.into(), }); - let expected_fallback_account_id = + let raw_data = >::call(&>::MATCHER.base_address(), &input, &mut ext) .unwrap(); // then + let expected_fallback_account_id = + Bytes::abi_decode(&raw_data).expect("decoding failed"); assert_eq!( - expected_fallback_account_id[20..32], + expected_fallback_account_id.0.as_ref()[20..32], [0xEE; 12], "no fallback suffix found where one should be" ); @@ -219,18 +227,19 @@ mod tests { let input = ISystem::ISystemCalls::toAccountId(ISystem::toAccountIdCall { input: mapped_address.0.into(), }); - let data = + let raw_data = >::call(&>::MATCHER.base_address(), &input, &mut ext) .unwrap(); // then + let data = Bytes::abi_decode(&raw_data).expect("decoding failed"); assert_ne!( - data.as_slice()[20..32], + data.0.as_ref()[20..32], [0xEE; 12], "fallback suffix found where none should be" ); assert_eq!( - ::AccountId::decode(&mut data.as_slice()), + ::AccountId::decode(&mut data.as_ref()), Ok(EVE), ); }) diff --git a/substrate/frame/revive/src/precompiles/builtin/testdata/900-to_account_id.json b/substrate/frame/revive/src/precompiles/builtin/testdata/900-to_account_id.json index b88909e923b33..a87e2d60f146a 100644 --- a/substrate/frame/revive/src/precompiles/builtin/testdata/900-to_account_id.json +++ b/substrate/frame/revive/src/precompiles/builtin/testdata/900-to_account_id.json @@ -1,7 +1,7 @@ [ { "Input": "cf5231cc00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", - "Expected": "0000000000000000000000000000000000000020eeeeeeeeeeeeeeeeeeeeeeee", + "Expected": "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000020eeeeeeeeeeeeeeeeeeeeeeee", "Name": "vector 1", "Gas": 8000000, "NoBenchmark": false diff --git a/substrate/frame/revive/src/tests/pvm.rs b/substrate/frame/revive/src/tests/pvm.rs index afae7c4a242e0..3ead77d705063 100644 --- a/substrate/frame/revive/src/tests/pvm.rs +++ b/substrate/frame/revive/src/tests/pvm.rs @@ -27,6 +27,7 @@ use crate::{ evm::{runtime::GAS_PRICE, CallTrace, CallTracer, CallType, GenericTransaction}, exec::Key, limits, + precompiles::alloy::sol_types::{sol_data::Bool, SolType}, storage::DeletionQueueManager, test_utils::builder::Contract, tests::{ @@ -3473,7 +3474,8 @@ fn call_caller_is_root() { builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); let ret = builder::bare_call(addr).origin(RuntimeOrigin::root()).build_and_unwrap_result(); - assert_eq!(ret.data, vec![1]); + let is_root = Bool::abi_decode(&ret.data).expect("decoding failed"); + assert!(is_root); }); } @@ -3489,7 +3491,8 @@ fn call_caller_is_root_from_non_root() { builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); let ret = builder::bare_call(addr).build_and_unwrap_result(); - assert_eq!(ret.data, vec![0]); + let is_root = Bool::abi_decode(&ret.data).expect("decoding failed"); + assert!(!is_root); }); } @@ -3505,7 +3508,8 @@ fn call_caller_is_origin() { builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); let ret = builder::bare_call(addr).build_and_unwrap_result(); - assert_eq!(ret.data, vec![1]); + let is_origin = Bool::abi_decode(&ret.data).expect("decoding failed"); + assert!(is_origin); }); } From d4e0b5cc62fcf735ea8c27ed8a843bada95cf11e Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Mon, 1 Sep 2025 14:02:39 +0200 Subject: [PATCH 28/63] Follow-up to `master` merge --- substrate/frame/revive/src/exec/mock_ext.rs | 4 --- substrate/frame/revive/src/weights.rs | 30 ++++++++++----------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index 0eed3cff3757a..049bda708da8f 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -239,10 +239,6 @@ impl Ext for MockExt { panic!("MockExt::set_code_hash") } - fn own_code_hash(&mut self) -> &H256 { - panic!("MockExt::own_code_hash") - } - fn immutable_data_len(&mut self) -> u32 { panic!("MockExt::immutable_data_len") } diff --git a/substrate/frame/revive/src/weights.rs b/substrate/frame/revive/src/weights.rs index 7a2f46555c7fa..119ae7a94509b 100644 --- a/substrate/frame/revive/src/weights.rs +++ b/substrate/frame/revive/src/weights.rs @@ -92,19 +92,19 @@ pub trait WeightInfo { fn seal_origin() -> Weight; fn to_account_id() -> Weight; fn seal_code_hash() -> Weight; - fn seal_own_code_hash() -> Weight; + fn own_code_hash() -> Weight; fn seal_code_size() -> Weight; - fn seal_caller_is_origin() -> Weight; - fn seal_caller_is_root() -> Weight; + fn caller_is_origin() -> Weight; + fn caller_is_root() -> Weight; fn seal_address() -> Weight; - fn seal_weight_left() -> Weight; + fn weight_left() -> Weight; fn seal_ref_time_left() -> Weight; fn seal_balance() -> Weight; fn seal_balance_of() -> Weight; fn seal_get_immutable_data(n: u32, ) -> Weight; fn seal_set_immutable_data(n: u32, ) -> Weight; fn seal_value_transferred() -> Weight; - fn seal_minimum_balance() -> Weight; + fn minimum_balance() -> Weight; fn seal_return_data_size() -> Weight; fn seal_call_data_size() -> Weight; fn seal_gas_limit() -> Weight; @@ -538,7 +538,7 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(10_105_000, 3868) .saturating_add(T::DbWeight::get().reads(1_u64)) } - fn seal_own_code_hash() -> Weight { + fn own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -557,14 +557,14 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(13_354_000, 3940) .saturating_add(T::DbWeight::get().reads(2_u64)) } - fn seal_caller_is_origin() -> Weight { + fn caller_is_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 331_000 picoseconds. Weight::from_parts(381_000, 0) } - fn seal_caller_is_root() -> Weight { + fn caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -578,7 +578,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 323_000 picoseconds. Weight::from_parts(368_000, 0) } - fn seal_weight_left() -> Weight { + fn weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -647,7 +647,7 @@ impl WeightInfo for SubstrateWeight { // Minimum execution time: 276_000 picoseconds. Weight::from_parts(323_000, 0) } - fn seal_minimum_balance() -> Weight { + fn minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -1681,7 +1681,7 @@ impl WeightInfo for () { Weight::from_parts(10_105_000, 3868) .saturating_add(RocksDbWeight::get().reads(1_u64)) } - fn seal_own_code_hash() -> Weight { + fn own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -1700,14 +1700,14 @@ impl WeightInfo for () { Weight::from_parts(13_354_000, 3940) .saturating_add(RocksDbWeight::get().reads(2_u64)) } - fn seal_caller_is_origin() -> Weight { + fn caller_is_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 331_000 picoseconds. Weight::from_parts(381_000, 0) } - fn seal_caller_is_root() -> Weight { + fn caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -1721,7 +1721,7 @@ impl WeightInfo for () { // Minimum execution time: 323_000 picoseconds. Weight::from_parts(368_000, 0) } - fn seal_weight_left() -> Weight { + fn weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -1790,7 +1790,7 @@ impl WeightInfo for () { // Minimum execution time: 276_000 picoseconds. Weight::from_parts(323_000, 0) } - fn seal_minimum_balance() -> Weight { + fn minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` From 8576e7fdd1b28b2d708868f002b68751b32e6bdc Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Mon, 1 Sep 2025 14:03:00 +0200 Subject: [PATCH 29/63] Remove dead code --- substrate/frame/revive/src/exec.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index a76ee36795486..0fa8edc0719d6 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -2080,7 +2080,6 @@ where } /// Convert a native balance to EVM balance. - //fn convert_native_to_evm(value: impl Into>>) -> U256 { fn convert_native_to_evm(&self, value: BalanceOf) -> U256 { crate::Pallet::::convert_native_to_evm(value) } From 64e145b0654fc3bd3a45a7395f0b9e1c1580076e Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 2 Sep 2025 14:55:14 +0200 Subject: [PATCH 30/63] Resolve merge test failures --- substrate/frame/revive/src/exec/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index adec64dfa2485..fbdf6be6f7830 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -1658,7 +1658,7 @@ fn nonce() { Weight::MAX, U256::MAX, Code::Existing(fail_code), - ctx.ext.minimum_balance() * 100, + (minimum_balance * 100).into(), vec![], Some(&[0; 32]), ) @@ -1675,7 +1675,7 @@ fn nonce() { Weight::MAX, U256::MAX, Code::Existing(success_code), - ctx.ext.minimum_balance() * 100, + (minimum_balance * 100).into(), vec![], Some(&[0; 32]), ) From 6b1263f1a935b0d0565ab2f16186e373398d6c22 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 9 Sep 2025 19:20:21 +0200 Subject: [PATCH 31/63] Rollback ext removals --- substrate/frame/revive/src/exec.rs | 29 +++++ substrate/frame/revive/src/exec/mock_ext.rs | 16 +++ substrate/frame/revive/src/exec/tests.rs | 116 ++++---------------- 3 files changed, 68 insertions(+), 93 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 5d4a78f360948..262e830c5f222 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -205,6 +205,9 @@ pub trait Ext: PrecompileWithInfoExt { /// call stack. 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. /// Returns whether the old code was removed as a result of this operation. fn set_code_hash(&mut self, hash: H256) -> Result; @@ -330,6 +333,12 @@ pub trait PrecompileExt: sealing::Sealed { /// Returns the code size of the contract at the given `address` or zero. fn code_size(&self, address: &H160) -> u64; + /// Check if the caller of the current contract is the origin of the whole call stack. + fn caller_is_origin(&self) -> bool; + + /// Check if the caller is origin, and this origin is root. + fn caller_is_root(&self) -> bool; + /// Returns a reference to the account id of the current contract. fn account_id(&self) -> &AccountIdOf; @@ -354,6 +363,9 @@ pub trait PrecompileExt: sealing::Sealed { /// Returns the timestamp of the current block in seconds. fn now(&self) -> U256; + /// Returns the minimum balance that is required for creating an account. + fn minimum_balance(&self) -> U256; + /// Deposit an event with the given topics. /// /// There should not be any duplicates in `topics`. @@ -1692,6 +1704,10 @@ where Ok(removed) } + fn own_code_hash(&mut self) -> &H256 { + &self.top_frame_mut().contract_info().code_hash + } + /// TODO: This should be changed to run the constructor of the supplied `hash`. /// /// Because the immutable data is attached to a contract and not a code, @@ -2013,6 +2029,15 @@ where .unwrap_or_default() } + fn caller_is_origin(&self) -> bool { + self.origin == self.caller() + } + + fn caller_is_root(&self) -> bool { + // if the caller isn't origin, then it can't be root. + self.caller_is_origin() && self.origin == Origin::Root + } + fn balance(&self) -> U256 { self.account_balance(&self.top_frame().account_id) } @@ -2034,6 +2059,10 @@ where (self.timestamp / 1000u32.into()).into() } + fn minimum_balance(&self) -> U256 { + T::Currency::minimum_balance().into() + } + fn deposit_event(&mut self, topics: Vec, data: Vec) { let contract = T::AddressMapper::to_address(self.account_id()); if_tracing(|tracer| { diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index d9dbd720a263a..279bba2e6f0ed 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -92,6 +92,14 @@ impl PrecompileExt for MockExt { panic!("MockExt::code_size") } + fn caller_is_origin(&self) -> bool { + panic!("MockExt::caller_is_origin") + } + + fn caller_is_root(&self) -> bool { + panic!("MockExt::caller_is_root") + } + fn account_id(&self) -> &AccountIdOf { panic!("MockExt::account_id") } @@ -112,6 +120,10 @@ impl PrecompileExt for MockExt { panic!("MockExt::now") } + fn minimum_balance(&self) -> U256 { + panic!("MockExt::minimum_balance") + } + fn deposit_event(&mut self, _topics: Vec, _data: Vec) { panic!("MockExt::deposit_event") } @@ -243,6 +255,10 @@ impl Ext for MockExt { panic!("MockExt::delegate_call") } + fn own_code_hash(&mut self) -> &H256 { + panic!("MockExt::own_code_hash") + } + fn terminate(&mut self, _beneficiary: &H160) -> Result { panic!("MockExt::terminate") } diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index fbdf6be6f7830..32c886fd3173f 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -25,7 +25,6 @@ use super::*; use crate::{ exec::ExportedFunction::*, gas::GasMeter, - precompiles::alloy::sol_types::{sol_data::Bool, SolType}, test_utils::*, tests::{ test_utils::{get_balance, place_contract, set_balance}, @@ -254,7 +253,7 @@ fn transfer_works() { Pallet::::convert_native_to_evm(value), &mut storage_meter, ) - .unwrap(); + .unwrap(); let min_balance = ::Currency::minimum_balance(); assert!(min_balance > 0); @@ -351,7 +350,7 @@ fn correct_transfer_on_call() { vec![], false, ) - .unwrap(); + .unwrap(); assert_eq!(get_balance(&ALICE), 100 - value); assert_eq!(get_balance(&BOB_FALLBACK), balance + value); @@ -465,7 +464,7 @@ fn changes_are_reverted_on_failing_call() { vec![], false, ) - .unwrap(); + .unwrap(); assert!(output.did_revert()); assert_eq!(get_balance(&ALICE), 100); @@ -842,16 +841,7 @@ fn code_hash_returns_proper_values() { fn own_code_hash_returns_proper_values() { let bob_ch = MockLoader::insert(Call, |ctx, _| { let code_hash = ctx.ext.code_hash(&BOB_ADDR); - let ret = ctx - .ext - .delegate_call( - Weight::MAX, - U256::zero(), - H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - pallet_revive_uapi::solidity_selector("ownCodeHash()").to_vec(), - ) - .map(|_| ctx.ext.last_frame_output().clone()); - assert_eq!(ret.unwrap().data, code_hash.0.to_vec()); + assert_eq!(*ctx.ext.own_code_hash(), code_hash); exec_success() }); @@ -877,39 +867,16 @@ fn own_code_hash_returns_proper_values() { fn caller_is_origin_returns_proper_values() { let code_charlie = MockLoader::insert(Call, |ctx, _| { // BOB is not the origin of the stack call - let ret = ctx - .ext - .delegate_call( - Weight::MAX, - U256::zero(), - H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - pallet_revive_uapi::solidity_selector("callerIsOrigin()").to_vec(), - ) - .map(|_| ctx.ext.last_frame_output().clone()); - let caller_is_origin = ret.unwrap().data == vec![1]; - assert!(!caller_is_origin); + assert!(!ctx.ext.caller_is_origin()); exec_success() }); let code_bob = MockLoader::insert(Call, |ctx, _| { // ALICE is the origin of the call stack - let ret = ctx - .ext - .delegate_call( - Weight::MAX, - U256::zero(), - H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - pallet_revive_uapi::solidity_selector("callerIsOrigin()").to_vec(), - ) - .map(|_| ctx.ext.last_frame_output().clone()); - - let raw_data = ret.unwrap().data; - let caller_is_origin = Bool::abi_decode(&raw_data).expect("decoding to bool failed"); - assert!(caller_is_origin); - + assert!(ctx.ext.caller_is_origin()); // BOB calls CHARLIE ctx.ext - .call(Weight::MAX, U256::zero(), &CHARLIE_ADDR, U256::zero(), vec![], true, false) + .call(Weight::zero(), U256::zero(), &CHARLIE_ADDR, U256::zero(), vec![], true, false) .map(|_| ctx.ext.last_frame_output().clone()) }); @@ -936,17 +903,7 @@ fn caller_is_origin_returns_proper_values() { fn root_caller_succeeds() { let code_bob = MockLoader::insert(Call, |ctx, _| { // root is the origin of the call stack. - let ret = ctx - .ext - .delegate_call( - Weight::MAX, - U256::zero(), - H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), - ) - .map(|_| ctx.ext.last_frame_output().clone()); - let caller_is_root = Bool::abi_decode(&ret.unwrap().data).expect("decoding to bool failed"); - assert!(caller_is_root); + assert!(ctx.ext.caller_is_root()); exec_success() }); @@ -972,12 +929,7 @@ fn root_caller_succeeds() { fn root_caller_does_not_succeed_when_value_not_zero() { let code_bob = MockLoader::insert(Call, |ctx, _| { // root is the origin of the call stack. - assert_ok!(ctx.ext.delegate_call( - Weight::MAX, - U256::zero(), - H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), - )); + assert!(ctx.ext.caller_is_root()); exec_success() }); @@ -1003,37 +955,16 @@ fn root_caller_does_not_succeed_when_value_not_zero() { fn root_caller_succeeds_with_consecutive_calls() { let code_charlie = MockLoader::insert(Call, |ctx, _| { // BOB is not root, even though the origin is root. - let ret = ctx - .ext - .delegate_call( - Weight::MAX, - U256::zero(), - H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), - ) - .map(|_| ctx.ext.last_frame_output().clone()); - let caller_is_root = Bool::abi_decode(&ret.unwrap().data).expect("decoding to bool failed"); - assert!(!caller_is_root); + assert!(!ctx.ext.caller_is_root()); exec_success() }); let code_bob = MockLoader::insert(Call, |ctx, _| { // root is the origin of the call stack. - let ret = ctx - .ext - .delegate_call( - Weight::MAX, - U256::zero(), - H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), - ) - .map(|_| ctx.ext.last_frame_output().clone()); - let caller_is_root = Bool::abi_decode(&ret.unwrap().data).expect("decoding to bool failed"); - assert!(caller_is_root); - + assert!(ctx.ext.caller_is_root()); // BOB calls CHARLIE. ctx.ext - .call(Weight::MAX, U256::zero(), &CHARLIE_ADDR, U256::zero(), vec![], true, false) + .call(Weight::zero(), U256::zero(), &CHARLIE_ADDR, U256::zero(), vec![], true, false) .map(|_| ctx.ext.last_frame_output().clone()) }); @@ -1547,7 +1478,7 @@ fn cannot_send_more_balance_than_available_to_self() { vec![], false, ) - .unwrap(); + .unwrap(); }); } @@ -1649,7 +1580,6 @@ fn call_deny_reentry() { #[test] fn nonce() { - let minimum_balance = ::Currency::minimum_balance(); let fail_code = MockLoader::insert(Constructor, |_, _| exec_trapped()); let success_code = MockLoader::insert(Constructor, |_, _| exec_success()); let succ_fail_code = MockLoader::insert(Constructor, move |ctx, _| { @@ -1658,7 +1588,7 @@ fn nonce() { Weight::MAX, U256::MAX, Code::Existing(fail_code), - (minimum_balance * 100).into(), + ctx.ext.minimum_balance() * 100, vec![], Some(&[0; 32]), ) @@ -1675,7 +1605,7 @@ fn nonce() { Weight::MAX, U256::MAX, Code::Existing(success_code), - (minimum_balance * 100).into(), + ctx.ext.minimum_balance() * 100, vec![], Some(&[0; 32]), ) @@ -1729,7 +1659,7 @@ fn nonce() { false, BumpNonce::Yes, ) - .ok(); + .ok(); assert_eq!(System::account_nonce(&ALICE), 0); assert_ok!(MockStack::run_instantiate( @@ -2481,7 +2411,7 @@ fn last_frame_output_works_on_instantiate() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2666,7 +2596,7 @@ fn immutable_data_access_checks_work() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2735,7 +2665,7 @@ fn correct_immutable_data_in_delegate_call() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2775,8 +2705,8 @@ fn immutable_data_set_overrides() { false, BumpNonce::Yes, ) - .unwrap() - .0; + .unwrap() + .0; MockStack::run_call( origin, @@ -2787,7 +2717,7 @@ fn immutable_data_set_overrides() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2833,7 +2763,7 @@ fn immutable_data_set_errors_with_empty_data() { vec![], false, ) - .unwrap() + .unwrap() }); } From 24f6f08c5de9afc358b24948c908c4c462774a22 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 10 Sep 2025 17:12:58 +0200 Subject: [PATCH 32/63] Rollback removal of `to_account_id` --- substrate/frame/revive/src/exec.rs | 9 +++++++ substrate/frame/revive/src/exec/tests.rs | 34 ++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 262e830c5f222..b78b96863e881 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -155,6 +155,7 @@ impl Origin { pub fn from_account_id(account_id: T::AccountId) -> Self { Origin::Signed(account_id) } + /// Creates a new Origin from a `RuntimeOrigin`. pub fn from_runtime_origin(o: OriginFor) -> Result { match o.into() { @@ -163,6 +164,7 @@ impl Origin { _ => Err(BadOrigin.into()), } } + /// Returns the AccountId of a Signed Origin or an error if the origin is Root. pub fn account_id(&self) -> Result<&T::AccountId, DispatchError> { match self { @@ -326,6 +328,9 @@ pub trait PrecompileExt: sealing::Sealed { /// Return the origin of the whole call stack. fn origin(&self) -> &Origin; + /// Returns the account id for the given `address`. + fn to_account_id(&self, address: &H160) -> AccountIdOf; + /// Returns the code hash of the contract for the given `address`. /// If not a contract but account exists then `keccak_256([])` is returned, otherwise `zero`. fn code_hash(&self, address: &H160) -> H256; @@ -2003,6 +2008,10 @@ where &self.origin } + fn to_account_id(&self, address: &H160) -> T::AccountId { + T::AddressMapper::to_account_id(address) + } + fn code_hash(&self, address: &H160) -> H256 { if let Some(code) = >::code(address.as_fixed_bytes()) { return sp_io::hashing::keccak_256(code).into() diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index 32c886fd3173f..6500076a5d5a9 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -800,6 +800,40 @@ fn origin_returns_proper_values() { assert_eq!(WitnessedCallerCharlie::get(), Some(ALICE_ADDR)); } +#[test] +fn to_account_id_returns_proper_values() { + let bob_code_hash = MockLoader::insert(Call, |ctx, _| { + let alice_account_id = ::AddressMapper::to_account_id(&ALICE_ADDR); + assert_eq!(ctx.ext.to_account_id(&ALICE_ADDR), alice_account_id); + + const UNMAPPED_ADDR: H160 = H160([99u8; 20]); + let mut unmapped_fallback_account_id = [0xEE; 32]; + unmapped_fallback_account_id[..20].copy_from_slice(UNMAPPED_ADDR.as_bytes()); + assert_eq!( + ctx.ext.to_account_id(&UNMAPPED_ADDR), + AccountId32::new(unmapped_fallback_account_id) + ); + + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + place_contract(&BOB, bob_code_hash); + let origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new(0); + let result = MockStack::run_call( + origin, + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + U256::zero(), + vec![0], + false, + ); + assert_matches!(result, Ok(_)); + }); +} + #[test] fn code_hash_returns_proper_values() { let bob_code_hash = MockLoader::insert(Call, |ctx, _| { From 3faa774e3d0989558d3bad4e4cce198a021093ec Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 9 Sep 2025 23:23:47 +0200 Subject: [PATCH 33/63] Add tests --- substrate/frame/revive/src/exec.rs | 2 +- substrate/frame/revive/src/exec/mock_ext.rs | 5 +- substrate/frame/revive/src/exec/tests.rs | 38 +++---- .../revive/src/precompiles/builtin/system.rs | 100 ++++++++++++++---- 4 files changed, 100 insertions(+), 45 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index b78b96863e881..8317680af6b24 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -59,7 +59,7 @@ use sp_runtime::{ }; #[cfg(test)] -mod tests; +pub mod tests; #[cfg(test)] pub mod mock_ext; diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index 279bba2e6f0ed..eea445954dd9e 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -204,10 +204,9 @@ impl PrecompileExt for MockExt { fn copy_code_slice(&mut self, _buf: &mut [u8], _address: &H160, _code_offset: usize) { panic!("MockExt::copy_code_slice") - } - fn convert_native_to_evm(&self, _value: crate::BalanceOf) -> U256 { - panic!("MockExt::convert_native_to_evm") + fn convert_native_to_evm(&self, _value: crate::BalanceOf) -> U256 { + panic!("MockExt::convert_native_to_evm") } } diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index 6500076a5d5a9..18580e51c6a4e 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -43,7 +43,7 @@ use std::{cell::RefCell, collections::hash_map::HashMap, rc::Rc}; type System = frame_system::Pallet; -type MockStack<'a> = Stack<'a, Test, MockExecutable>; +pub type MockStack<'a> = Stack<'a, Test, MockExecutable>; parameter_types! { static Loader: MockLoader = MockLoader::default(); @@ -59,13 +59,13 @@ fn events() -> Vec> { .collect() } -struct MockCtx<'a> { - ext: &'a mut MockStack<'a>, +pub struct MockCtx<'a> { + pub ext: &'a mut MockStack<'a>, input_data: Vec, } #[derive(Clone)] -struct MockExecutable { +pub struct MockExecutable { func: Rc Fn(MockCtx<'a>, &Self) -> ExecResult + 'static>, constructor: Rc Fn(MockCtx<'a>, &Self) -> ExecResult + 'static>, code_hash: H256, @@ -83,7 +83,7 @@ impl MockLoader { Loader::get().map.keys().copied().collect() } - fn insert( + pub fn insert( func_type: ExportedFunction, f: impl Fn(MockCtx, &MockExecutable) -> ExecResult + 'static, ) -> H256 { @@ -192,11 +192,11 @@ impl Executable for MockExecutable { } } -fn exec_success() -> ExecResult { +pub fn exec_success() -> ExecResult { Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }) } -fn exec_trapped() -> ExecResult { +pub fn exec_trapped() -> ExecResult { Err(ExecError { error: >::ContractTrapped.into(), origin: ErrorOrigin::Callee }) } @@ -253,7 +253,7 @@ fn transfer_works() { Pallet::::convert_native_to_evm(value), &mut storage_meter, ) - .unwrap(); + .unwrap(); let min_balance = ::Currency::minimum_balance(); assert!(min_balance > 0); @@ -350,7 +350,7 @@ fn correct_transfer_on_call() { vec![], false, ) - .unwrap(); + .unwrap(); assert_eq!(get_balance(&ALICE), 100 - value); assert_eq!(get_balance(&BOB_FALLBACK), balance + value); @@ -464,7 +464,7 @@ fn changes_are_reverted_on_failing_call() { vec![], false, ) - .unwrap(); + .unwrap(); assert!(output.did_revert()); assert_eq!(get_balance(&ALICE), 100); @@ -1512,7 +1512,7 @@ fn cannot_send_more_balance_than_available_to_self() { vec![], false, ) - .unwrap(); + .unwrap(); }); } @@ -1693,7 +1693,7 @@ fn nonce() { false, BumpNonce::Yes, ) - .ok(); + .ok(); assert_eq!(System::account_nonce(&ALICE), 0); assert_ok!(MockStack::run_instantiate( @@ -2445,7 +2445,7 @@ fn last_frame_output_works_on_instantiate() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2630,7 +2630,7 @@ fn immutable_data_access_checks_work() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2699,7 +2699,7 @@ fn correct_immutable_data_in_delegate_call() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2739,8 +2739,8 @@ fn immutable_data_set_overrides() { false, BumpNonce::Yes, ) - .unwrap() - .0; + .unwrap() + .0; MockStack::run_call( origin, @@ -2751,7 +2751,7 @@ fn immutable_data_set_overrides() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2797,7 +2797,7 @@ fn immutable_data_set_errors_with_empty_data() { vec![], false, ) - .unwrap() + .unwrap() }); } diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index 93d0baa43d999..ced9df7c56864 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -108,31 +108,12 @@ impl BuiltinPrecompile for System { }, ISystemCalls::callerIsOrigin(ISystem::callerIsOriginCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::CallerIsOrigin)?; - let is_origin = match env.origin() { - Origin::Root => { - // `Root` does not have an address - false - }, - Origin::Signed(origin_account_id) => { - let origin_address = T::AddressMapper::to_address(&origin_account_id).0; - match env.caller() { - Origin::Signed(caller_account_id) => { - let caller_address = - T::AddressMapper::to_address(&caller_account_id).0; - origin_address == caller_address - }, - Origin::Root => false, - } - }, - }; + let is_origin = env.caller_is_origin(); Ok(is_origin.abi_encode()) }, ISystemCalls::callerIsRoot(ISystem::callerIsRootCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::CallerIsRoot)?; - let is_root = match env.caller() { - Origin::Root => true, - Origin::Signed(_) => false, - }; + let is_root = env.caller_is_root(); Ok(is_root.abi_encode()) }, ISystemCalls::ownCodeHash(ISystem::ownCodeHashCall {}) => { @@ -164,14 +145,20 @@ mod tests { use crate::{ address::AddressMapper, call_builder::{caller_funding, CallSetup}, + exec::ExportedFunction::Call, + gas::GasMeter, pallet, precompiles::{ alloy::sol_types::{sol_data::Bytes, SolType}, tests::run_test_vectors, BuiltinPrecompile, }, - tests::{ExtBuilder, Test}, + storage, + test_utils::{BOB, BOB_ADDR, GAS_LIMIT}, + tests::{test_utils::place_contract, ExtBuilder, Test}, + U256, }; + use assert_matches::assert_matches; use codec::Decode; use frame_support::traits::fungible::Mutate; @@ -244,4 +231,73 @@ mod tests { ); }) } + + /* + use crate::Weight; + use alloy_core::sol_types::{sol_data::Bool}; + use crate::exec::Ext; + use crate::exec::PrecompileExt; + + #[test] + fn root_caller_succeeds() { + let code_bob = crate::exec::tests::MockLoader::insert(Call, |ctx, _| { + let ret = ctx.ext + .delegate_call( + Weight::MAX, + U256::zero(), + H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + ) + .map(|_| ctx.ext.last_frame_output().clone()); + let caller_is_root = Bool::abi_decode(&ret.unwrap().data).expect("decoding to bool failed"); + assert!(caller_is_root); + crate::exec::tests::exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + place_contract(&BOB, code_bob); + let result = crate::exec::tests::MockStack::run_call( + Origin::Root, + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage::meter::Meter::new(0), + U256::zero(), + vec![0], + false, + ); + assert_matches!(result, Ok(_)); + }); + } + + #[test] + fn root_caller_fails() { + let code_bob = crate::exec::tests::MockLoader::insert(Call, |ctx, _| { + let ret = ctx.ext + .delegate_call( + Weight::MAX, + U256::zero(), + H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), + pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), + ) + .map(|_| ctx.ext.last_frame_output().clone()); + let caller_is_root = Bool::abi_decode(&ret.unwrap().data).expect("decoding to bool failed"); + assert!(!caller_is_root); + crate::exec::tests::exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + place_contract(&BOB, code_bob); + let result = crate::exec::tests::MockStack::run_call( + Origin::Signed(BOB), + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage::meter::Meter::new(0), + U256::zero(), + vec![0], + false, + ); + assert_matches!(result, Ok(_)); + }); + } + */ } From e6a04edbfebee9e86396da5860e09d5cf427a8a3 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 10 Sep 2025 17:14:31 +0200 Subject: [PATCH 34/63] Use `to_account_id` from `Ext` in pre-compile --- substrate/frame/revive/src/exec/mock_ext.rs | 5 +++++ .../frame/revive/src/precompiles/builtin/system.rs | 10 +++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index eea445954dd9e..bda5d2e65135f 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -205,9 +205,14 @@ impl PrecompileExt for MockExt { fn copy_code_slice(&mut self, _buf: &mut [u8], _address: &H160, _code_offset: usize) { panic!("MockExt::copy_code_slice") } + fn convert_native_to_evm(&self, _value: crate::BalanceOf) -> U256 { panic!("MockExt::convert_native_to_evm") } + + fn to_account_id(&self, address: &H160) -> AccountIdOf { + panic!("MockExt::to_account_id") + } } impl PrecompileWithInfoExt for MockExt { diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index ced9df7c56864..4f8efbd5384dd 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -99,11 +99,8 @@ impl BuiltinPrecompile for System { Ok(output.abi_encode()) }, ISystemCalls::toAccountId(ISystem::toAccountIdCall { input }) => { - use crate::address::AddressMapper; - use codec::Encode; env.gas_meter_mut().charge(RuntimeCosts::ToAccountId)?; - let account_id = - T::AddressMapper::to_account_id(&H160::from_slice(input.as_slice())); + let account_id = env.to_account_id(&H160::from_slice(input.as_slice())); Ok(account_id.encode().abi_encode()) }, ISystemCalls::callerIsOrigin(ISystem::callerIsOriginCall {}) => { @@ -124,9 +121,8 @@ impl BuiltinPrecompile for System { }, ISystemCalls::minimumBalance(ISystem::minimumBalanceCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::MinimumBalance)?; - let minimum_balance = T::Currency::minimum_balance(); - let minimum_balance_as_evm_value = env.convert_native_to_evm(minimum_balance); - Ok(minimum_balance_as_evm_value.to_big_endian().abi_encode()) + let minimum_balance = env.minimum_balance(); + Ok(minimum_balance.to_big_endian().abi_encode()) }, ISystemCalls::weightLeft(ISystem::weightLeftCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::WeightLeft)?; From a71467ce886f2e790a5a85638f0ff51ec3dc7228 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 10 Sep 2025 21:00:37 +0200 Subject: [PATCH 35/63] Revert "Add tests" This reverts commit 3faa774e3d0989558d3bad4e4cce198a021093ec. --- substrate/frame/revive/src/exec.rs | 2 +- substrate/frame/revive/src/exec/mock_ext.rs | 1 + substrate/frame/revive/src/exec/tests.rs | 38 +++---- .../revive/src/precompiles/builtin/system.rs | 100 ++++-------------- 4 files changed, 43 insertions(+), 98 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 8317680af6b24..b78b96863e881 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -59,7 +59,7 @@ use sp_runtime::{ }; #[cfg(test)] -pub mod tests; +mod tests; #[cfg(test)] pub mod mock_ext; diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index bda5d2e65135f..5a46c3cfdc9f7 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -204,6 +204,7 @@ impl PrecompileExt for MockExt { fn copy_code_slice(&mut self, _buf: &mut [u8], _address: &H160, _code_offset: usize) { panic!("MockExt::copy_code_slice") + } fn convert_native_to_evm(&self, _value: crate::BalanceOf) -> U256 { diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index 18580e51c6a4e..6500076a5d5a9 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -43,7 +43,7 @@ use std::{cell::RefCell, collections::hash_map::HashMap, rc::Rc}; type System = frame_system::Pallet; -pub type MockStack<'a> = Stack<'a, Test, MockExecutable>; +type MockStack<'a> = Stack<'a, Test, MockExecutable>; parameter_types! { static Loader: MockLoader = MockLoader::default(); @@ -59,13 +59,13 @@ fn events() -> Vec> { .collect() } -pub struct MockCtx<'a> { - pub ext: &'a mut MockStack<'a>, +struct MockCtx<'a> { + ext: &'a mut MockStack<'a>, input_data: Vec, } #[derive(Clone)] -pub struct MockExecutable { +struct MockExecutable { func: Rc Fn(MockCtx<'a>, &Self) -> ExecResult + 'static>, constructor: Rc Fn(MockCtx<'a>, &Self) -> ExecResult + 'static>, code_hash: H256, @@ -83,7 +83,7 @@ impl MockLoader { Loader::get().map.keys().copied().collect() } - pub fn insert( + fn insert( func_type: ExportedFunction, f: impl Fn(MockCtx, &MockExecutable) -> ExecResult + 'static, ) -> H256 { @@ -192,11 +192,11 @@ impl Executable for MockExecutable { } } -pub fn exec_success() -> ExecResult { +fn exec_success() -> ExecResult { Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }) } -pub fn exec_trapped() -> ExecResult { +fn exec_trapped() -> ExecResult { Err(ExecError { error: >::ContractTrapped.into(), origin: ErrorOrigin::Callee }) } @@ -253,7 +253,7 @@ fn transfer_works() { Pallet::::convert_native_to_evm(value), &mut storage_meter, ) - .unwrap(); + .unwrap(); let min_balance = ::Currency::minimum_balance(); assert!(min_balance > 0); @@ -350,7 +350,7 @@ fn correct_transfer_on_call() { vec![], false, ) - .unwrap(); + .unwrap(); assert_eq!(get_balance(&ALICE), 100 - value); assert_eq!(get_balance(&BOB_FALLBACK), balance + value); @@ -464,7 +464,7 @@ fn changes_are_reverted_on_failing_call() { vec![], false, ) - .unwrap(); + .unwrap(); assert!(output.did_revert()); assert_eq!(get_balance(&ALICE), 100); @@ -1512,7 +1512,7 @@ fn cannot_send_more_balance_than_available_to_self() { vec![], false, ) - .unwrap(); + .unwrap(); }); } @@ -1693,7 +1693,7 @@ fn nonce() { false, BumpNonce::Yes, ) - .ok(); + .ok(); assert_eq!(System::account_nonce(&ALICE), 0); assert_ok!(MockStack::run_instantiate( @@ -2445,7 +2445,7 @@ fn last_frame_output_works_on_instantiate() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2630,7 +2630,7 @@ fn immutable_data_access_checks_work() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2699,7 +2699,7 @@ fn correct_immutable_data_in_delegate_call() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2739,8 +2739,8 @@ fn immutable_data_set_overrides() { false, BumpNonce::Yes, ) - .unwrap() - .0; + .unwrap() + .0; MockStack::run_call( origin, @@ -2751,7 +2751,7 @@ fn immutable_data_set_overrides() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2797,7 +2797,7 @@ fn immutable_data_set_errors_with_empty_data() { vec![], false, ) - .unwrap() + .unwrap() }); } diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index 4f8efbd5384dd..605650813d5f8 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -105,12 +105,31 @@ impl BuiltinPrecompile for System { }, ISystemCalls::callerIsOrigin(ISystem::callerIsOriginCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::CallerIsOrigin)?; - let is_origin = env.caller_is_origin(); + let is_origin = match env.origin() { + Origin::Root => { + // `Root` does not have an address + false + }, + Origin::Signed(origin_account_id) => { + let origin_address = T::AddressMapper::to_address(&origin_account_id).0; + match env.caller() { + Origin::Signed(caller_account_id) => { + let caller_address = + T::AddressMapper::to_address(&caller_account_id).0; + origin_address == caller_address + }, + Origin::Root => false, + } + }, + }; Ok(is_origin.abi_encode()) }, ISystemCalls::callerIsRoot(ISystem::callerIsRootCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::CallerIsRoot)?; - let is_root = env.caller_is_root(); + let is_root = match env.caller() { + Origin::Root => true, + Origin::Signed(_) => false, + }; Ok(is_root.abi_encode()) }, ISystemCalls::ownCodeHash(ISystem::ownCodeHashCall {}) => { @@ -141,20 +160,14 @@ mod tests { use crate::{ address::AddressMapper, call_builder::{caller_funding, CallSetup}, - exec::ExportedFunction::Call, - gas::GasMeter, pallet, precompiles::{ alloy::sol_types::{sol_data::Bytes, SolType}, tests::run_test_vectors, BuiltinPrecompile, }, - storage, - test_utils::{BOB, BOB_ADDR, GAS_LIMIT}, - tests::{test_utils::place_contract, ExtBuilder, Test}, - U256, + tests::{ExtBuilder, Test}, }; - use assert_matches::assert_matches; use codec::Decode; use frame_support::traits::fungible::Mutate; @@ -227,73 +240,4 @@ mod tests { ); }) } - - /* - use crate::Weight; - use alloy_core::sol_types::{sol_data::Bool}; - use crate::exec::Ext; - use crate::exec::PrecompileExt; - - #[test] - fn root_caller_succeeds() { - let code_bob = crate::exec::tests::MockLoader::insert(Call, |ctx, _| { - let ret = ctx.ext - .delegate_call( - Weight::MAX, - U256::zero(), - H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), - ) - .map(|_| ctx.ext.last_frame_output().clone()); - let caller_is_root = Bool::abi_decode(&ret.unwrap().data).expect("decoding to bool failed"); - assert!(caller_is_root); - crate::exec::tests::exec_success() - }); - - ExtBuilder::default().build().execute_with(|| { - place_contract(&BOB, code_bob); - let result = crate::exec::tests::MockStack::run_call( - Origin::Root, - BOB_ADDR, - &mut GasMeter::::new(GAS_LIMIT), - &mut storage::meter::Meter::new(0), - U256::zero(), - vec![0], - false, - ); - assert_matches!(result, Ok(_)); - }); - } - - #[test] - fn root_caller_fails() { - let code_bob = crate::exec::tests::MockLoader::insert(Call, |ctx, _| { - let ret = ctx.ext - .delegate_call( - Weight::MAX, - U256::zero(), - H160::from(pallet_revive_uapi::SYSTEM_PRECOMPILE_ADDR), - pallet_revive_uapi::solidity_selector("callerIsRoot()").to_vec(), - ) - .map(|_| ctx.ext.last_frame_output().clone()); - let caller_is_root = Bool::abi_decode(&ret.unwrap().data).expect("decoding to bool failed"); - assert!(!caller_is_root); - crate::exec::tests::exec_success() - }); - - ExtBuilder::default().build().execute_with(|| { - place_contract(&BOB, code_bob); - let result = crate::exec::tests::MockStack::run_call( - Origin::Signed(BOB), - BOB_ADDR, - &mut GasMeter::::new(GAS_LIMIT), - &mut storage::meter::Meter::new(0), - U256::zero(), - vec![0], - false, - ); - assert_matches!(result, Ok(_)); - }); - } - */ } From ebf036569bd5361ac1c7a1dc36af7bee6ffd6ebc Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 10 Sep 2025 19:50:37 +0200 Subject: [PATCH 36/63] Move `ISystem` to `pallet-revive-uapi` --- Cargo.lock | 1 + substrate/frame/revive/Cargo.toml | 2 +- substrate/frame/revive/src/benchmarking.rs | 4 +- substrate/frame/revive/src/exec/mock_ext.rs | 3 +- substrate/frame/revive/src/exec/tests.rs | 24 +++---- substrate/frame/revive/src/precompiles.rs | 2 +- .../frame/revive/src/precompiles/builtin.rs | 2 +- .../revive/src/precompiles/builtin/system.rs | 50 +------------ substrate/frame/revive/uapi/Cargo.toml | 2 + substrate/frame/revive/uapi/src/lib.rs | 5 +- .../frame/revive/uapi/src/precompiles/mod.rs | 16 +++++ .../revive/uapi/src/precompiles/system.rs | 70 +++++++++++++++++++ .../utils.rs} | 4 -- 13 files changed, 114 insertions(+), 71 deletions(-) create mode 100644 substrate/frame/revive/uapi/src/precompiles/mod.rs create mode 100644 substrate/frame/revive/uapi/src/precompiles/system.rs rename substrate/frame/revive/uapi/src/{precompile_utils.rs => precompiles/utils.rs} (88%) diff --git a/Cargo.lock b/Cargo.lock index 85b9926be6c36..bbe3c784182cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13151,6 +13151,7 @@ dependencies = [ name = "pallet-revive-uapi" version = "0.1.0" dependencies = [ + "alloy-core", "bitflags 1.3.2", "const-crypto", "hex-literal", diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index 6a2078dd50c43..8963fc97b343f 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -47,7 +47,7 @@ frame-support = { workspace = true } frame-system = { workspace = true } pallet-revive-fixtures = { workspace = true, optional = true } pallet-revive-proc-macro = { workspace = true } -pallet-revive-uapi = { workspace = true, features = ["scale"] } +pallet-revive-uapi = { workspace = true, features = ["scale", "precompiles"] } pallet-transaction-payment = { workspace = true } ripemd = { workspace = true } sp-api = { workspace = true } diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index 810366ec0d184..fcb7264bd8ee4 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -30,7 +30,7 @@ use crate::{ SolType, }, run::builtin as run_builtin_precompile, - BenchmarkSystem, BuiltinPrecompile, ISystem, + BenchmarkSystem, BuiltinPrecompile, }, storage::WriteOutcome, vm::{ @@ -52,6 +52,8 @@ use frame_support::{ weights::{Weight, WeightMeter}, }; use frame_system::RawOrigin; +#[cfg(feature = "runtime-benchmarks")] +use pallet_revive_uapi::precompiles::system::ISystem; use pallet_revive_uapi::{pack_hi_lo, CallFlags, ReturnErrorCode, StorageFlags}; use revm::{ bytecode::{opcode::EXTCODECOPY, Bytecode}, diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index 5a46c3cfdc9f7..c629971909840 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -204,14 +204,13 @@ impl PrecompileExt for MockExt { fn copy_code_slice(&mut self, _buf: &mut [u8], _address: &H160, _code_offset: usize) { panic!("MockExt::copy_code_slice") - } fn convert_native_to_evm(&self, _value: crate::BalanceOf) -> U256 { panic!("MockExt::convert_native_to_evm") } - fn to_account_id(&self, address: &H160) -> AccountIdOf { + fn to_account_id(&self, _address: &H160) -> AccountIdOf { panic!("MockExt::to_account_id") } } diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index 6500076a5d5a9..e54ee36354f1c 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -253,7 +253,7 @@ fn transfer_works() { Pallet::::convert_native_to_evm(value), &mut storage_meter, ) - .unwrap(); + .unwrap(); let min_balance = ::Currency::minimum_balance(); assert!(min_balance > 0); @@ -350,7 +350,7 @@ fn correct_transfer_on_call() { vec![], false, ) - .unwrap(); + .unwrap(); assert_eq!(get_balance(&ALICE), 100 - value); assert_eq!(get_balance(&BOB_FALLBACK), balance + value); @@ -464,7 +464,7 @@ fn changes_are_reverted_on_failing_call() { vec![], false, ) - .unwrap(); + .unwrap(); assert!(output.did_revert()); assert_eq!(get_balance(&ALICE), 100); @@ -1512,7 +1512,7 @@ fn cannot_send_more_balance_than_available_to_self() { vec![], false, ) - .unwrap(); + .unwrap(); }); } @@ -1693,7 +1693,7 @@ fn nonce() { false, BumpNonce::Yes, ) - .ok(); + .ok(); assert_eq!(System::account_nonce(&ALICE), 0); assert_ok!(MockStack::run_instantiate( @@ -2445,7 +2445,7 @@ fn last_frame_output_works_on_instantiate() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2630,7 +2630,7 @@ fn immutable_data_access_checks_work() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2699,7 +2699,7 @@ fn correct_immutable_data_in_delegate_call() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2739,8 +2739,8 @@ fn immutable_data_set_overrides() { false, BumpNonce::Yes, ) - .unwrap() - .0; + .unwrap() + .0; MockStack::run_call( origin, @@ -2751,7 +2751,7 @@ fn immutable_data_set_overrides() { vec![], false, ) - .unwrap() + .unwrap() }); } @@ -2797,7 +2797,7 @@ fn immutable_data_set_errors_with_empty_data() { vec![], false, ) - .unwrap() + .unwrap() }); } diff --git a/substrate/frame/revive/src/precompiles.rs b/substrate/frame/revive/src/precompiles.rs index 0968a7d927c58..83b8b760e16a1 100644 --- a/substrate/frame/revive/src/precompiles.rs +++ b/substrate/frame/revive/src/precompiles.rs @@ -51,7 +51,7 @@ use sp_runtime::DispatchError; #[cfg(feature = "runtime-benchmarks")] pub(crate) use builtin::{ - IBenchmarking, ISystem, NoInfo as BenchmarkNoInfo, System as BenchmarkSystem, + IBenchmarking, NoInfo as BenchmarkNoInfo, System as BenchmarkSystem, WithInfo as BenchmarkWithInfo, }; diff --git a/substrate/frame/revive/src/precompiles/builtin.rs b/substrate/frame/revive/src/precompiles/builtin.rs index 34fab30802096..abec334768e8b 100644 --- a/substrate/frame/revive/src/precompiles/builtin.rs +++ b/substrate/frame/revive/src/precompiles/builtin.rs @@ -37,7 +37,7 @@ use crate::{ #[cfg(feature = "runtime-benchmarks")] pub use self::{ benchmarking::{IBenchmarking, NoInfo, WithInfo}, - system::{ISystem, System}, + system::System, }; #[cfg(not(feature = "runtime-benchmarks"))] diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index 605650813d5f8..fcd7a4e668b8d 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -22,58 +22,14 @@ use crate::{ Config, Origin, H160, }; use alloc::vec::Vec; -use alloy_core::{sol, sol_types::SolValue}; +use alloy_core::sol_types::SolValue; use codec::Encode; use core::{marker::PhantomData, num::NonZero}; -use frame_support::traits::fungible::Inspect; +use pallet_revive_uapi::precompiles::system::ISystem; use sp_core::hexdisplay::AsBytesRef; pub struct System(PhantomData); -sol! { - interface ISystem { - /// Computes the BLAKE2 256-bit hash on the given input. - function hashBlake256(bytes memory input) external pure returns (bytes32 digest); - - /// Computes the BLAKE2 128-bit hash on the given input. - function hashBlake128(bytes memory input) external pure returns (bytes32 digest); - - /// Retrieve the account id for a specified `H160` address. - /// - /// Calling this function on a native `H160` chain (`type AccountId = H160`) - /// does not make sense, as it would just return the `address` that it was - /// called with. - /// - /// # Note - /// - /// If no mapping exists for `addr`, the fallback account id will be returned. - function toAccountId(address input) external view returns (bytes memory account_id); - - /// Checks whether the contract caller is the origin of the whole call stack. - function callerIsOrigin() external view returns (bool); - - /// Checks whether the caller of the current contract is root. - /// - /// Note that only the origin of the call stack can be root. Hence this - /// function returning `true` implies that the contract is being called by the origin. - /// - /// A return value of `true` indicates that this contract is being called by a root origin, - /// and `false` indicates that the caller is a signed origin. - function callerIsRoot() external view returns (bool); - - /// Returns the minimum balance that is required for creating an account - /// (the existential deposit). - function minimumBalance() external view returns (uint); - - /// Returns the code hash of the currently executing contract. - function ownCodeHash() external view returns (bytes32); - - /// Returns the amount of weight left. - /// The data is encoded as `Weight`. - function weightLeft() external view returns (uint64 refTime, uint64 proofSize); - } -} - impl BuiltinPrecompile for System { type T = T; type Interface = ISystem::ISystemCalls; @@ -156,7 +112,7 @@ impl BuiltinPrecompile for System { #[cfg(test)] mod tests { - use super::{ISystem, *}; + use super::*; use crate::{ address::AddressMapper, call_builder::{caller_funding, CallSetup}, diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml index 6c527918dadfb..136d6dc006c74 100644 --- a/substrate/frame/revive/uapi/Cargo.toml +++ b/substrate/frame/revive/uapi/Cargo.toml @@ -22,6 +22,7 @@ const-crypto = { version = "0.3.0", default-features = false } hex-literal = { version = "0.4.1", default-features = false } pallet-revive-proc-macro = { workspace = true } scale-info = { features = ["derive"], optional = true, workspace = true } +alloy-core = { workspace = true, features = ["sol-types"], optional = true } [target.'cfg(target_arch = "riscv64")'.dependencies] polkavm-derive = { version = "0.27.0" } @@ -30,3 +31,4 @@ polkavm-derive = { version = "0.27.0" } default = ["scale"] scale = ["dep:codec", "scale-info"] unstable-hostfn = [] +precompiles = ["alloy-core"] diff --git a/substrate/frame/revive/uapi/src/lib.rs b/substrate/frame/revive/uapi/src/lib.rs index 18c308228e367..c2a98c5410add 100644 --- a/substrate/frame/revive/uapi/src/lib.rs +++ b/substrate/frame/revive/uapi/src/lib.rs @@ -23,8 +23,9 @@ mod flags; pub use flags::*; mod host; mod macros; -mod precompile_utils; -pub use precompile_utils::*; + +pub mod precompiles; +pub use precompiles::{system::SYSTEM_PRECOMPILE_ADDR, utils::solidity_selector}; pub use host::{HostFn, HostFnImpl}; diff --git a/substrate/frame/revive/uapi/src/precompiles/mod.rs b/substrate/frame/revive/uapi/src/precompiles/mod.rs new file mode 100644 index 0000000000000..0df51720ad9a4 --- /dev/null +++ b/substrate/frame/revive/uapi/src/precompiles/mod.rs @@ -0,0 +1,16 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// +// 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. + +pub mod system; +pub mod utils; diff --git a/substrate/frame/revive/uapi/src/precompiles/system.rs b/substrate/frame/revive/uapi/src/precompiles/system.rs new file mode 100644 index 0000000000000..1dcd944980b5f --- /dev/null +++ b/substrate/frame/revive/uapi/src/precompiles/system.rs @@ -0,0 +1,70 @@ +// 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. + +//! Information around the `System` pre-compile. + +#[cfg(feature = "precompiles")] +use alloy_core::sol; + +/// The contract address for the System pre-compile. +pub const SYSTEM_PRECOMPILE_ADDR: [u8; 20] = + hex_literal::hex!("0000000000000000000000000000000000000900"); + +#[cfg(feature = "precompiles")] +sol! { + interface ISystem { + /// Computes the BLAKE2 256-bit hash on the given input. + function hashBlake256(bytes memory input) external pure returns (bytes32 digest); + + /// Computes the BLAKE2 128-bit hash on the given input. + function hashBlake128(bytes memory input) external pure returns (bytes32 digest); + + /// Retrieve the account id for a specified `H160` address. + /// + /// Calling this function on a native `H160` chain (`type AccountId = H160`) + /// does not make sense, as it would just return the `address` that it was + /// called with. + /// + /// # Note + /// + /// If no mapping exists for `addr`, the fallback account id will be returned. + function toAccountId(address input) external view returns (bytes memory account_id); + + /// Checks whether the contract caller is the origin of the whole call stack. + function callerIsOrigin() external view returns (bool); + + /// Checks whether the caller of the current contract is root. + /// + /// Note that only the origin of the call stack can be root. Hence this + /// function returning `true` implies that the contract is being called by the origin. + /// + /// A return value of `true` indicates that this contract is being called by a root origin, + /// and `false` indicates that the caller is a signed origin. + function callerIsRoot() external view returns (bool); + + /// Returns the minimum balance that is required for creating an account + /// (the existential deposit). + function minimumBalance() external view returns (uint); + + /// Returns the code hash of the currently executing contract. + function ownCodeHash() external view returns (bytes32); + + /// Returns the amount of weight left. + /// The data is encoded as `Weight`. + function weightLeft() external view returns (uint64 refTime, uint64 proofSize); + } +} diff --git a/substrate/frame/revive/uapi/src/precompile_utils.rs b/substrate/frame/revive/uapi/src/precompiles/utils.rs similarity index 88% rename from substrate/frame/revive/uapi/src/precompile_utils.rs rename to substrate/frame/revive/uapi/src/precompiles/utils.rs index a2c6d498b9786..95ae966db0a2d 100644 --- a/substrate/frame/revive/uapi/src/precompile_utils.rs +++ b/substrate/frame/revive/uapi/src/precompiles/utils.rs @@ -17,10 +17,6 @@ //! Helper utilities around pre-compiles. -/// The contract address for the System pre-compile. -pub const SYSTEM_PRECOMPILE_ADDR: [u8; 20] = - hex_literal::hex!("0000000000000000000000000000000000000900"); - /// Returns the Solidity selector for `fn_sig`. /// /// Note that this is a const function, it is evaluated at compile time. From b7d75dce1fc746f193ccf415171e18c5c0b14fbd Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 10 Sep 2025 21:07:01 +0200 Subject: [PATCH 37/63] Rename feature `precompiles` to `precompiles-sol-interfaces` --- substrate/frame/revive/Cargo.toml | 2 +- substrate/frame/revive/uapi/Cargo.toml | 2 +- substrate/frame/revive/uapi/src/precompiles/system.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index 8963fc97b343f..43b9cf05e9caa 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -47,7 +47,7 @@ frame-support = { workspace = true } frame-system = { workspace = true } pallet-revive-fixtures = { workspace = true, optional = true } pallet-revive-proc-macro = { workspace = true } -pallet-revive-uapi = { workspace = true, features = ["scale", "precompiles"] } +pallet-revive-uapi = { workspace = true, features = ["scale", "precompile-sol-interfaces"] } pallet-transaction-payment = { workspace = true } ripemd = { workspace = true } sp-api = { workspace = true } diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml index 136d6dc006c74..bf994a487d3d0 100644 --- a/substrate/frame/revive/uapi/Cargo.toml +++ b/substrate/frame/revive/uapi/Cargo.toml @@ -31,4 +31,4 @@ polkavm-derive = { version = "0.27.0" } default = ["scale"] scale = ["dep:codec", "scale-info"] unstable-hostfn = [] -precompiles = ["alloy-core"] +precompile-sol-interfaces = ["alloy-core"] diff --git a/substrate/frame/revive/uapi/src/precompiles/system.rs b/substrate/frame/revive/uapi/src/precompiles/system.rs index 1dcd944980b5f..4558487ab21aa 100644 --- a/substrate/frame/revive/uapi/src/precompiles/system.rs +++ b/substrate/frame/revive/uapi/src/precompiles/system.rs @@ -17,14 +17,14 @@ //! Information around the `System` pre-compile. -#[cfg(feature = "precompiles")] +#[cfg(feature = "precompile-sol-interfaces")] use alloy_core::sol; /// The contract address for the System pre-compile. pub const SYSTEM_PRECOMPILE_ADDR: [u8; 20] = hex_literal::hex!("0000000000000000000000000000000000000900"); -#[cfg(feature = "precompiles")] +#[cfg(feature = "precompile-sol-interfaces")] sol! { interface ISystem { /// Computes the BLAKE2 256-bit hash on the given input. From b865371363007c2c657c72e2542304113cdb3a78 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 10 Sep 2025 21:16:42 +0200 Subject: [PATCH 38/63] Improve comment --- substrate/frame/revive/uapi/src/precompiles/system.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrate/frame/revive/uapi/src/precompiles/system.rs b/substrate/frame/revive/uapi/src/precompiles/system.rs index 4558487ab21aa..d3e2fff511905 100644 --- a/substrate/frame/revive/uapi/src/precompiles/system.rs +++ b/substrate/frame/revive/uapi/src/precompiles/system.rs @@ -63,8 +63,7 @@ sol! { /// Returns the code hash of the currently executing contract. function ownCodeHash() external view returns (bytes32); - /// Returns the amount of weight left. - /// The data is encoded as `Weight`. + /// Returns the amount of `Weight` left. function weightLeft() external view returns (uint64 refTime, uint64 proofSize); } } From 10420b8183c81971907f5ea44369dc1f99e7184e Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 10 Sep 2025 21:17:44 +0200 Subject: [PATCH 39/63] Revert introduction of `convert_native_to_evm` --- substrate/frame/revive/src/exec.rs | 8 -------- substrate/frame/revive/src/exec/mock_ext.rs | 12 ++++-------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index b78b96863e881..487e720f80952 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -440,9 +440,6 @@ pub trait PrecompileExt: sealing::Sealed { /// - If `code_offset + buf.len()` extends beyond code: Available code copied, remaining bytes /// are filled with zeros fn copy_code_slice(&mut self, buf: &mut [u8], address: &H160, code_offset: usize); - - /// Convert a native balance to EVM balance. - fn convert_native_to_evm(&self, value: BalanceOf) -> U256; } /// Describes the different functions that can be exported by an [`Executable`]. @@ -2170,11 +2167,6 @@ where buf[len..].fill(0); } - - /// Convert a native balance to EVM balance. - fn convert_native_to_evm(&self, value: BalanceOf) -> U256 { - crate::Pallet::::convert_native_to_evm(value) - } } mod sealing { diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index c629971909840..2ff9e81b82df6 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -206,10 +206,6 @@ impl PrecompileExt for MockExt { panic!("MockExt::copy_code_slice") } - fn convert_native_to_evm(&self, _value: crate::BalanceOf) -> U256 { - panic!("MockExt::convert_native_to_evm") - } - fn to_account_id(&self, _address: &H160) -> AccountIdOf { panic!("MockExt::to_account_id") } @@ -259,14 +255,14 @@ impl Ext for MockExt { panic!("MockExt::delegate_call") } - fn own_code_hash(&mut self) -> &H256 { - panic!("MockExt::own_code_hash") - } - fn terminate(&mut self, _beneficiary: &H160) -> Result { panic!("MockExt::terminate") } + fn own_code_hash(&mut self) -> &H256 { + panic!("MockExt::own_code_hash") + } + fn set_code_hash(&mut self, _hash: H256) -> Result { panic!("MockExt::set_code_hash") } From 6ba7f58d447afce38885ebd1d0151b4b6bacd71d Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 10 Sep 2025 21:25:07 +0200 Subject: [PATCH 40/63] Use `call` over `delegate_call` --- .../frame/revive/fixtures/contracts/call_caller_is_origin.rs | 3 ++- .../frame/revive/fixtures/contracts/call_caller_is_root.rs | 3 ++- .../frame/revive/fixtures/contracts/call_own_code_hash.rs | 3 ++- .../frame/revive/fixtures/contracts/caller_is_origin_n.rs | 3 ++- substrate/frame/revive/fixtures/contracts/drain.rs | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs index e68349e4d2115..cc301691de3d2 100644 --- a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs @@ -32,12 +32,13 @@ pub extern "C" fn deploy() {} #[polkavm_derive::polkavm_export] pub extern "C" fn call() { let mut output = [0u8; 32]; - let _ = api::delegate_call( + let _ = api::call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. + &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("callerIsOrigin()"), Some(&mut &mut output[..]), ).unwrap(); diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs index fdd968e4deeed..00412bd84895f 100644 --- a/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs @@ -32,12 +32,13 @@ pub extern "C" fn deploy() {} #[polkavm_derive::polkavm_export] pub extern "C" fn call() { let mut output = [0u8; 32]; - let _ = api::delegate_call( + let _ = api::call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. + &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("callerIsRoot()"), Some(&mut &mut output[..]), ).unwrap(); diff --git a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs index bf0b5cd6293cc..91f4fa69e27f6 100644 --- a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs +++ b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs @@ -36,12 +36,13 @@ pub extern "C" fn deploy() { } pub extern "C" fn call() { let mut output_buf = [0u8; 32]; let output = &mut &mut output_buf[..]; - let _ = api::delegate_call( + let _ = api::call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. + &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("ownCodeHash()"), Some(output), ).unwrap(); diff --git a/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs b/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs index 8553b61336890..6f47ca7a95925 100644 --- a/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs +++ b/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs @@ -33,12 +33,13 @@ pub extern "C" fn call() { input!(n: u32, ); for _ in 0..n { - let _ = api::delegate_call( + let _ = api::call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. + &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("callerIsOrigin()"), None, ).unwrap(); diff --git a/substrate/frame/revive/fixtures/contracts/drain.rs b/substrate/frame/revive/fixtures/contracts/drain.rs index 303072a0bb1a2..4d9b1ca6f4a63 100644 --- a/substrate/frame/revive/fixtures/contracts/drain.rs +++ b/substrate/frame/revive/fixtures/contracts/drain.rs @@ -32,12 +32,13 @@ pub extern "C" fn call() { let mut output_buf = [0u8; 32]; let output = &mut &mut output_buf[..]; - let _ = api::delegate_call( + let _ = api::call( uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. + &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("minimumBalance()"), Some(output), ).unwrap(); From bf48062cbb22e79130a0e0a67ce06845694622bb Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 10 Sep 2025 21:29:40 +0200 Subject: [PATCH 41/63] Rename `precompile-sol-interfaces` to `precompiles-sol-interfaces` --- substrate/frame/revive/Cargo.toml | 2 +- substrate/frame/revive/uapi/Cargo.toml | 2 +- substrate/frame/revive/uapi/src/precompiles/system.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index 43b9cf05e9caa..da5d1ce7f3097 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -47,7 +47,7 @@ frame-support = { workspace = true } frame-system = { workspace = true } pallet-revive-fixtures = { workspace = true, optional = true } pallet-revive-proc-macro = { workspace = true } -pallet-revive-uapi = { workspace = true, features = ["scale", "precompile-sol-interfaces"] } +pallet-revive-uapi = { workspace = true, features = ["scale", "precompiles-sol-interfaces"] } pallet-transaction-payment = { workspace = true } ripemd = { workspace = true } sp-api = { workspace = true } diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml index bf994a487d3d0..b17965753ff4a 100644 --- a/substrate/frame/revive/uapi/Cargo.toml +++ b/substrate/frame/revive/uapi/Cargo.toml @@ -31,4 +31,4 @@ polkavm-derive = { version = "0.27.0" } default = ["scale"] scale = ["dep:codec", "scale-info"] unstable-hostfn = [] -precompile-sol-interfaces = ["alloy-core"] +precompiles-sol-interfaces = ["alloy-core"] diff --git a/substrate/frame/revive/uapi/src/precompiles/system.rs b/substrate/frame/revive/uapi/src/precompiles/system.rs index d3e2fff511905..adb53f8a9d70a 100644 --- a/substrate/frame/revive/uapi/src/precompiles/system.rs +++ b/substrate/frame/revive/uapi/src/precompiles/system.rs @@ -17,14 +17,14 @@ //! Information around the `System` pre-compile. -#[cfg(feature = "precompile-sol-interfaces")] +#[cfg(feature = "precompiles-sol-interfaces")] use alloy_core::sol; /// The contract address for the System pre-compile. pub const SYSTEM_PRECOMPILE_ADDR: [u8; 20] = hex_literal::hex!("0000000000000000000000000000000000000900"); -#[cfg(feature = "precompile-sol-interfaces")] +#[cfg(feature = "precompiles-sol-interfaces")] sol! { interface ISystem { /// Computes the BLAKE2 256-bit hash on the given input. From 6fc1398be380cf99bdd1e0eaf9b4c63641ca28a7 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 10 Sep 2025 21:36:27 +0200 Subject: [PATCH 42/63] Use `READ_ONLY` for calling getters on pre-compile --- .../frame/revive/fixtures/contracts/call_caller_is_origin.rs | 2 +- .../frame/revive/fixtures/contracts/call_caller_is_root.rs | 2 +- substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs | 2 +- substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs | 2 +- substrate/frame/revive/fixtures/contracts/drain.rs | 2 +- substrate/frame/revive/uapi/src/precompiles/system.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs index cc301691de3d2..b8fc11b4a3463 100644 --- a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs @@ -33,7 +33,7 @@ pub extern "C" fn deploy() {} pub extern "C" fn call() { let mut output = [0u8; 32]; let _ = api::call( - uapi::CallFlags::empty(), + uapi::CallFlags::READ_ONLY, &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs index 00412bd84895f..5a50abaac13fc 100644 --- a/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs @@ -33,7 +33,7 @@ pub extern "C" fn deploy() {} pub extern "C" fn call() { let mut output = [0u8; 32]; let _ = api::call( - uapi::CallFlags::empty(), + uapi::CallFlags::READ_ONLY, &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. diff --git a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs index 91f4fa69e27f6..7d215b0c19ba2 100644 --- a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs +++ b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs @@ -37,7 +37,7 @@ pub extern "C" fn call() { let mut output_buf = [0u8; 32]; let output = &mut &mut output_buf[..]; let _ = api::call( - uapi::CallFlags::empty(), + uapi::CallFlags::READ_ONLY, &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. diff --git a/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs b/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs index 6f47ca7a95925..e9f124de2eafe 100644 --- a/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs +++ b/substrate/frame/revive/fixtures/contracts/caller_is_origin_n.rs @@ -34,7 +34,7 @@ pub extern "C" fn call() { for _ in 0..n { let _ = api::call( - uapi::CallFlags::empty(), + uapi::CallFlags::READ_ONLY, &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. diff --git a/substrate/frame/revive/fixtures/contracts/drain.rs b/substrate/frame/revive/fixtures/contracts/drain.rs index 4d9b1ca6f4a63..df86587eb6aa1 100644 --- a/substrate/frame/revive/fixtures/contracts/drain.rs +++ b/substrate/frame/revive/fixtures/contracts/drain.rs @@ -33,7 +33,7 @@ pub extern "C" fn call() { let mut output_buf = [0u8; 32]; let output = &mut &mut output_buf[..]; let _ = api::call( - uapi::CallFlags::empty(), + uapi::CallFlags::READ_ONLY, &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. diff --git a/substrate/frame/revive/uapi/src/precompiles/system.rs b/substrate/frame/revive/uapi/src/precompiles/system.rs index adb53f8a9d70a..1e4bb728e8f70 100644 --- a/substrate/frame/revive/uapi/src/precompiles/system.rs +++ b/substrate/frame/revive/uapi/src/precompiles/system.rs @@ -20,7 +20,7 @@ #[cfg(feature = "precompiles-sol-interfaces")] use alloy_core::sol; -/// The contract address for the System pre-compile. +/// Address for the System pre-compile. pub const SYSTEM_PRECOMPILE_ADDR: [u8; 20] = hex_literal::hex!("0000000000000000000000000000000000000900"); From ab717db1e8577ea3878f467f021d6f8883326cb4 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Wed, 10 Sep 2025 21:38:35 +0200 Subject: [PATCH 43/63] Fix `call_diverging_out_len` --- .../revive/fixtures/contracts/call_diverging_out_len.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs index fdcf99a8f9b5c..6b9c7af292dd7 100644 --- a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs +++ b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs @@ -60,12 +60,13 @@ fn assert_call(callee_address: &[u8; 20], expected_output: [u8; fn assert_instantiate(expected_output: [u8; BUF_SIZE]) { let mut output_buf1 = [0u8; 32]; let output1 = &mut &mut output_buf1[..]; - let _ = api::delegate_call( - uapi::CallFlags::empty(), + let _ = api::call( + uapi::CallFlags::READ_ONLY, &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. + &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("ownCodeHash()"), Some(output1), ).unwrap(); From 118aea730cc530e93c08012f583f44face5cab56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Fri, 12 Sep 2025 13:51:10 +0200 Subject: [PATCH 44/63] Update substrate/frame/revive/src/benchmarking.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexander Theißen --- substrate/frame/revive/src/benchmarking.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index fcb7264bd8ee4..f2a8bd3bf58b3 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -52,7 +52,6 @@ use frame_support::{ weights::{Weight, WeightMeter}, }; use frame_system::RawOrigin; -#[cfg(feature = "runtime-benchmarks")] use pallet_revive_uapi::precompiles::system::ISystem; use pallet_revive_uapi::{pack_hi_lo, CallFlags, ReturnErrorCode, StorageFlags}; use revm::{ From fc94affb10f734a227fa2ce23c376e8e84601205 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 12 Sep 2025 13:53:58 +0200 Subject: [PATCH 45/63] Remove unused dep --- substrate/frame/revive/fixtures/build/_Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/revive/fixtures/build/_Cargo.toml b/substrate/frame/revive/fixtures/build/_Cargo.toml index 67cc31e870f75..af898cec525ef 100644 --- a/substrate/frame/revive/fixtures/build/_Cargo.toml +++ b/substrate/frame/revive/fixtures/build/_Cargo.toml @@ -13,7 +13,6 @@ edition = "2021" # All paths are injected dynamically by the build script. [dependencies] uapi = { package = 'pallet-revive-uapi', features = ["unstable-hostfn"], default-features = false } -const-crypto = { version = "0.3.0", default-features = false } hex-literal = { version = "0.4.1", default-features = false } polkavm-derive = { version = "0.27.0" } From 41ebb98c4300a4b88a2b9aa9c50340ac81e6b256 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 12 Sep 2025 15:10:15 +0200 Subject: [PATCH 46/63] Use `delegate_call` for `own_code_hash` + `caller_is_root` --- .../frame/revive/fixtures/contracts/call_caller_is_root.rs | 5 ++--- .../revive/fixtures/contracts/call_diverging_out_len.rs | 5 ++--- .../frame/revive/fixtures/contracts/call_own_code_hash.rs | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs index 5a50abaac13fc..fdd968e4deeed 100644 --- a/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs @@ -32,13 +32,12 @@ pub extern "C" fn deploy() {} #[polkavm_derive::polkavm_export] pub extern "C" fn call() { let mut output = [0u8; 32]; - let _ = api::call( - uapi::CallFlags::READ_ONLY, + let _ = api::delegate_call( + uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. - &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("callerIsRoot()"), Some(&mut &mut output[..]), ).unwrap(); diff --git a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs index 6b9c7af292dd7..fdcf99a8f9b5c 100644 --- a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs +++ b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs @@ -60,13 +60,12 @@ fn assert_call(callee_address: &[u8; 20], expected_output: [u8; fn assert_instantiate(expected_output: [u8; BUF_SIZE]) { let mut output_buf1 = [0u8; 32]; let output1 = &mut &mut output_buf1[..]; - let _ = api::call( - uapi::CallFlags::READ_ONLY, + let _ = api::delegate_call( + uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. - &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("ownCodeHash()"), Some(output1), ).unwrap(); diff --git a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs index 7d215b0c19ba2..bf0b5cd6293cc 100644 --- a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs +++ b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs @@ -36,13 +36,12 @@ pub extern "C" fn deploy() { } pub extern "C" fn call() { let mut output_buf = [0u8; 32]; let output = &mut &mut output_buf[..]; - let _ = api::call( - uapi::CallFlags::READ_ONLY, + let _ = api::delegate_call( + uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. - &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("ownCodeHash()"), Some(output), ).unwrap(); From ddf9d08ed2bf0d7dd189703b2bb7acce15782fe4 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 12 Sep 2025 15:34:39 +0200 Subject: [PATCH 47/63] Use `delegate_call` for `caller_is_origin` --- .../frame/revive/fixtures/contracts/call_caller_is_origin.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs index b8fc11b4a3463..e68349e4d2115 100644 --- a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs @@ -32,13 +32,12 @@ pub extern "C" fn deploy() {} #[polkavm_derive::polkavm_export] pub extern "C" fn call() { let mut output = [0u8; 32]; - let _ = api::call( - uapi::CallFlags::READ_ONLY, + let _ = api::delegate_call( + uapi::CallFlags::empty(), &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. - &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("callerIsOrigin()"), Some(&mut &mut output[..]), ).unwrap(); From 76361a8c38e1e55a38ad349832e43f4119f88639 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 12 Sep 2025 15:35:10 +0200 Subject: [PATCH 48/63] Simplify `System` precompile --- substrate/frame/revive/src/benchmarking.rs | 5 ++-- .../revive/src/precompiles/builtin/system.rs | 23 ++----------------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index f2a8bd3bf58b3..0be2d706ab1c0 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -52,8 +52,9 @@ use frame_support::{ weights::{Weight, WeightMeter}, }; use frame_system::RawOrigin; -use pallet_revive_uapi::precompiles::system::ISystem; -use pallet_revive_uapi::{pack_hi_lo, CallFlags, ReturnErrorCode, StorageFlags}; +use pallet_revive_uapi::{ + pack_hi_lo, precompiles::system::ISystem, CallFlags, ReturnErrorCode, StorageFlags, +}; use revm::{ bytecode::{opcode::EXTCODECOPY, Bytecode}, interpreter::{ diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index fcd7a4e668b8d..f65e5199fc8ee 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -61,31 +61,12 @@ impl BuiltinPrecompile for System { }, ISystemCalls::callerIsOrigin(ISystem::callerIsOriginCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::CallerIsOrigin)?; - let is_origin = match env.origin() { - Origin::Root => { - // `Root` does not have an address - false - }, - Origin::Signed(origin_account_id) => { - let origin_address = T::AddressMapper::to_address(&origin_account_id).0; - match env.caller() { - Origin::Signed(caller_account_id) => { - let caller_address = - T::AddressMapper::to_address(&caller_account_id).0; - origin_address == caller_address - }, - Origin::Root => false, - } - }, - }; + let is_origin = env.caller_is_origin(); Ok(is_origin.abi_encode()) }, ISystemCalls::callerIsRoot(ISystem::callerIsRootCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::CallerIsRoot)?; - let is_root = match env.caller() { - Origin::Root => true, - Origin::Signed(_) => false, - }; + let is_root = env.caller_is_root(); Ok(is_root.abi_encode()) }, ISystemCalls::ownCodeHash(ISystem::ownCodeHashCall {}) => { From 45f106c83429844db7a92fd959483d2b996a7a25 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 12 Sep 2025 15:35:34 +0200 Subject: [PATCH 49/63] Use Solidity ABI encoding for `own_code_hash` return value --- substrate/frame/revive/src/precompiles/builtin/system.rs | 2 +- substrate/frame/revive/src/tests/pvm.rs | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index f65e5199fc8ee..9244ad1d58ce0 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -72,7 +72,7 @@ impl BuiltinPrecompile for System { ISystemCalls::ownCodeHash(ISystem::ownCodeHashCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::OwnCodeHash)?; let address = env.address(); - let output = env.code_hash(&address).encode(); + let output = env.code_hash(&address).0.abi_encode(); Ok(output) }, ISystemCalls::minimumBalance(ISystem::minimumBalanceCall {}) => { diff --git a/substrate/frame/revive/src/tests/pvm.rs b/substrate/frame/revive/src/tests/pvm.rs index 8325eb70e9d93..8108956d82203 100644 --- a/substrate/frame/revive/src/tests/pvm.rs +++ b/substrate/frame/revive/src/tests/pvm.rs @@ -27,7 +27,10 @@ use crate::{ evm::{runtime::GAS_PRICE, CallTrace, CallTracer, CallType, GenericTransaction}, exec::Key, limits, - precompiles::alloy::sol_types::{sol_data::Bool, SolType}, + precompiles::alloy::sol_types::{ + sol_data::{Bool, FixedBytes}, + SolType, + }, storage::DeletionQueueManager, test_utils::builder::Contract, tests::{ @@ -3482,7 +3485,8 @@ fn call_own_code_hash_works() { builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); let ret = builder::bare_call(addr).build_and_unwrap_result(); - assert_eq!(H256::from_slice(&ret.data[..]), code_hash); + let ret_hash = FixedBytes::<32>::abi_decode(&ret.data).unwrap(); + assert_eq!(ret_hash, code_hash.0); }); } From 869f6905eba0afb75bf4cd2de0111cfb0c0e0bb4 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 12 Sep 2025 16:21:24 +0200 Subject: [PATCH 50/63] Allow dead code for `ExtInfo::own_code_hash` We can't use it in the `System` precompile, that one is only `Ext`. --- substrate/frame/revive/src/exec.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index d859246b80cf8..259e7e96788d3 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -208,6 +208,7 @@ pub trait Ext: PrecompileWithInfoExt { fn terminate(&mut self, beneficiary: &H160) -> Result; /// Returns the code hash of the contract being executed. + #[allow(dead_code)] fn own_code_hash(&mut self) -> &H256; /// Sets new code hash and immutable data for an existing contract. From 55a30fe67db931f6514e40d8025d49e6e5c9213e Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 12 Sep 2025 16:22:07 +0200 Subject: [PATCH 51/63] Remove unused imports --- substrate/frame/revive/src/precompiles/builtin/system.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index 9244ad1d58ce0..0dbd64c8e0bce 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -16,10 +16,9 @@ // limitations under the License. use crate::{ - address::AddressMapper, precompiles::{BuiltinAddressMatcher, BuiltinPrecompile, Error, Ext}, vm::RuntimeCosts, - Config, Origin, H160, + Config, H160, }; use alloc::vec::Vec; use alloy_core::sol_types::SolValue; From 5923c69a42e8014273d44ef36be6039b1d2e09c2 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 12 Sep 2025 16:28:06 +0200 Subject: [PATCH 52/63] Drive-by fix: ink! URL --- substrate/frame/contracts/src/chain_extension.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/contracts/src/chain_extension.rs b/substrate/frame/contracts/src/chain_extension.rs index b9bb451fd734a..b2f7408917c97 100644 --- a/substrate/frame/contracts/src/chain_extension.rs +++ b/substrate/frame/contracts/src/chain_extension.rs @@ -67,7 +67,7 @@ //! # Example //! //! The ink-examples repository maintains an -//! [end-to-end example](https://github.com/paritytech/ink-examples/tree/main/rand-extension) +//! [end-to-end example](https://github.com/use-ink/ink-examples/tree/v5.x.x/rand-extension) //! on how to use a chain extension in order to provide new features to ink! contracts. use crate::{ From 2ac798ae12079103689c8dcadbb8043434e5b5c9 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 12 Sep 2025 23:19:30 +0200 Subject: [PATCH 53/63] Apply `taplo` toml format --- substrate/frame/revive/uapi/Cargo.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml index b17965753ff4a..7d4ce0c04d574 100644 --- a/substrate/frame/revive/uapi/Cargo.toml +++ b/substrate/frame/revive/uapi/Cargo.toml @@ -16,13 +16,16 @@ features = ["unstable-hostfn"] targets = ["riscv64imac-unknown-none-elf"] [dependencies] +alloy-core = { workspace = true, features = ["sol-types"], optional = true } bitflags = { workspace = true } -codec = { features = ["derive", "max-encoded-len"], optional = true, workspace = true } +codec = { features = [ + "derive", + "max-encoded-len", +], optional = true, workspace = true } const-crypto = { version = "0.3.0", default-features = false } hex-literal = { version = "0.4.1", default-features = false } pallet-revive-proc-macro = { workspace = true } scale-info = { features = ["derive"], optional = true, workspace = true } -alloy-core = { workspace = true, features = ["sol-types"], optional = true } [target.'cfg(target_arch = "riscv64")'.dependencies] polkavm-derive = { version = "0.27.0" } From 6d92b7024a6c566f950bff560bbbec6610cd720c Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 12 Sep 2025 23:28:40 +0200 Subject: [PATCH 54/63] Revert unrelated `taplo` change --- substrate/frame/revive/uapi/Cargo.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml index 7d4ce0c04d574..9fb935cab2fd1 100644 --- a/substrate/frame/revive/uapi/Cargo.toml +++ b/substrate/frame/revive/uapi/Cargo.toml @@ -18,10 +18,7 @@ targets = ["riscv64imac-unknown-none-elf"] [dependencies] alloy-core = { workspace = true, features = ["sol-types"], optional = true } bitflags = { workspace = true } -codec = { features = [ - "derive", - "max-encoded-len", -], optional = true, workspace = true } +codec = { features = [ "derive", "max-encoded-len" ], optional = true, workspace = true } const-crypto = { version = "0.3.0", default-features = false } hex-literal = { version = "0.4.1", default-features = false } pallet-revive-proc-macro = { workspace = true } From cbfd780b042a759b97cca520da4d53750bb0e153 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Mon, 15 Sep 2025 12:00:35 +0200 Subject: [PATCH 55/63] Make `own_code_hash` callable via `call` --- .../revive/fixtures/contracts/call_diverging_out_len.rs | 5 +++-- .../frame/revive/fixtures/contracts/call_own_code_hash.rs | 5 +++-- substrate/frame/revive/src/benchmarking.rs | 7 +++++-- substrate/frame/revive/src/precompiles/builtin/system.rs | 6 ++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs index fdcf99a8f9b5c..6b9c7af292dd7 100644 --- a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs +++ b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs @@ -60,12 +60,13 @@ fn assert_call(callee_address: &[u8; 20], expected_output: [u8; fn assert_instantiate(expected_output: [u8; BUF_SIZE]) { let mut output_buf1 = [0u8; 32]; let output1 = &mut &mut output_buf1[..]; - let _ = api::delegate_call( - uapi::CallFlags::empty(), + let _ = api::call( + uapi::CallFlags::READ_ONLY, &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. + &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("ownCodeHash()"), Some(output1), ).unwrap(); diff --git a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs index bf0b5cd6293cc..7d215b0c19ba2 100644 --- a/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs +++ b/substrate/frame/revive/fixtures/contracts/call_own_code_hash.rs @@ -36,12 +36,13 @@ pub extern "C" fn deploy() { } pub extern "C" fn call() { let mut output_buf = [0u8; 32]; let output = &mut &mut output_buf[..]; - let _ = api::delegate_call( - uapi::CallFlags::empty(), + let _ = api::call( + uapi::CallFlags::READ_ONLY, &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. + &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("ownCodeHash()"), Some(output), ).unwrap(); diff --git a/substrate/frame/revive/src/benchmarking.rs b/substrate/frame/revive/src/benchmarking.rs index 0be2d706ab1c0..691477539f181 100644 --- a/substrate/frame/revive/src/benchmarking.rs +++ b/substrate/frame/revive/src/benchmarking.rs @@ -676,6 +676,9 @@ mod benchmarks { let input_bytes = ISystem::ISystemCalls::ownCodeHash(ISystem::ownCodeHashCall {}).abi_encode(); let mut call_setup = CallSetup::::default(); + let contract_acc = call_setup.contract().account_id.clone(); + let caller = call_setup.contract().address; + call_setup.set_origin(Origin::from_account_id(contract_acc)); let (mut ext, _) = call_setup.ext(); let result; @@ -688,8 +691,8 @@ mod benchmarks { ); } assert!(result.is_ok()); - let pre_compile_code_hash = VmBinaryModule::dummy().hash; - assert_eq!(pre_compile_code_hash.0.to_vec(), result.unwrap().data); + let caller_code_hash = ext.code_hash(&caller); + assert_eq!(caller_code_hash.0.to_vec(), result.unwrap().data); } #[benchmark(pov_mode = Measured)] diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index 0dbd64c8e0bce..2a566b2367bd6 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -16,6 +16,7 @@ // limitations under the License. use crate::{ + address::AddressMapper, precompiles::{BuiltinAddressMatcher, BuiltinPrecompile, Error, Ext}, vm::RuntimeCosts, Config, H160, @@ -70,8 +71,9 @@ impl BuiltinPrecompile for System { }, ISystemCalls::ownCodeHash(ISystem::ownCodeHashCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::OwnCodeHash)?; - let address = env.address(); - let output = env.code_hash(&address).0.abi_encode(); + let caller = env.caller(); + let addr = T::AddressMapper::to_address(caller.account_id()?); + let output = env.code_hash(&addr.into()).0.abi_encode(); Ok(output) }, ISystemCalls::minimumBalance(ISystem::minimumBalanceCall {}) => { From 5d39e844205cbaf88afa098fd55af9ca41e4e752 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Mon, 15 Sep 2025 12:00:57 +0200 Subject: [PATCH 56/63] Reflect calling convention in comments --- .../revive/uapi/src/precompiles/system.rs | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/substrate/frame/revive/uapi/src/precompiles/system.rs b/substrate/frame/revive/uapi/src/precompiles/system.rs index 1e4bb728e8f70..99c1ada896c6d 100644 --- a/substrate/frame/revive/uapi/src/precompiles/system.rs +++ b/substrate/frame/revive/uapi/src/precompiles/system.rs @@ -45,6 +45,14 @@ sol! { function toAccountId(address input) external view returns (bytes memory account_id); /// Checks whether the contract caller is the origin of the whole call stack. + /// + /// # Important + /// + /// Call this function via [`crate::HostFn::delegate_call`]. + /// + /// `delegate_call` is necessary because if `call` were to be used, the call would + /// be executed in the context of the pre-compile and examine if the calling contract + /// (i.e. your contract) is the origin. function callerIsOrigin() external view returns (bool); /// Checks whether the caller of the current contract is root. @@ -54,13 +62,29 @@ sol! { /// /// A return value of `true` indicates that this contract is being called by a root origin, /// and `false` indicates that the caller is a signed origin. + /// + /// # Important + /// + /// Call this function via [`crate::HostFn::delegate_call`]. + /// + /// `delegate_call` is necessary because if `call` were to be used, the call would + /// be executed in the context of the pre-compile and examine if the calling contract + /// (i.e. your contract) is `Root`. function callerIsRoot() external view returns (bool); /// Returns the minimum balance that is required for creating an account /// (the existential deposit). function minimumBalance() external view returns (uint); - /// Returns the code hash of the currently executing contract. + /// Returns the code hash of the caller. + /// + /// # Important + /// + /// Call this function via [`crate::HostFn::call`] with [`crate::flags::CallFlags`] + /// set to [`crate::flags::CallFlags::READ_ONLY`]. + /// + /// `READONLY` minimizes the security scope of the call. `call` is necessary + /// as the function returns the code hash of the caller. function ownCodeHash() external view returns (bytes32); /// Returns the amount of `Weight` left. From 78131c8afafabfba3ab62014bae732cf3160d760 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Mon, 15 Sep 2025 15:05:12 +0200 Subject: [PATCH 57/63] Use caller of caller for `System::caller_is_origin` + `System::caller_is_root` --- .../contracts/call_caller_is_origin.rs | 5 +-- .../fixtures/contracts/call_caller_is_root.rs | 5 +-- substrate/frame/revive/src/exec.rs | 33 +++++++++++++++---- substrate/frame/revive/src/exec/mock_ext.rs | 8 +++-- substrate/frame/revive/src/exec/tests.rs | 12 +++---- .../revive/src/precompiles/builtin/system.rs | 4 +-- .../revive/uapi/src/precompiles/system.rs | 29 ++-------------- 7 files changed, 50 insertions(+), 46 deletions(-) diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs index e68349e4d2115..b8fc11b4a3463 100644 --- a/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_origin.rs @@ -32,12 +32,13 @@ pub extern "C" fn deploy() {} #[polkavm_derive::polkavm_export] pub extern "C" fn call() { let mut output = [0u8; 32]; - let _ = api::delegate_call( - uapi::CallFlags::empty(), + let _ = api::call( + uapi::CallFlags::READ_ONLY, &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. + &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("callerIsOrigin()"), Some(&mut &mut output[..]), ).unwrap(); diff --git a/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs index fdd968e4deeed..5a50abaac13fc 100644 --- a/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs +++ b/substrate/frame/revive/fixtures/contracts/call_caller_is_root.rs @@ -32,12 +32,13 @@ pub extern "C" fn deploy() {} #[polkavm_derive::polkavm_export] pub extern "C" fn call() { let mut output = [0u8; 32]; - let _ = api::delegate_call( - uapi::CallFlags::empty(), + let _ = api::call( + uapi::CallFlags::READ_ONLY, &uapi::SYSTEM_PRECOMPILE_ADDR, u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. &[u8::MAX; 32], // No deposit limit. + &[0u8; 32], // Value transferred to the contract. &uapi::solidity_selector("callerIsRoot()"), Some(&mut &mut output[..]), ).unwrap(); diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 259e7e96788d3..0c299cd94ed30 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -326,6 +326,9 @@ pub trait PrecompileExt: sealing::Sealed { /// Returns the caller. fn caller(&self) -> Origin; + /// Returns the caller of the caller. + fn caller_of_caller(&self) -> Origin; + /// Return the origin of the whole call stack. fn origin(&self) -> &Origin; @@ -340,10 +343,10 @@ pub trait PrecompileExt: sealing::Sealed { fn code_size(&self, address: &H160) -> u64; /// Check if the caller of the current contract is the origin of the whole call stack. - fn caller_is_origin(&self) -> bool; + fn caller_is_origin(&self, use_caller_of_caller: bool) -> bool; /// Check if the caller is origin, and this origin is root. - fn caller_is_root(&self) -> bool; + fn caller_is_root(&self, use_caller_of_caller: bool) -> bool; /// Returns a reference to the account id of the current contract. fn account_id(&self) -> &AccountIdOf; @@ -2002,6 +2005,19 @@ where } } + fn caller_of_caller(&self) -> Origin { + // fetch top frame of top frame + let caller_of_caller_frame = match self.frames().nth(2) { + None => return self.origin.clone(), + Some(frame) => frame, + }; + if let Some(DelegateInfo { caller, .. }) = &caller_of_caller_frame.delegate { + caller.to_owned() + } else { + Origin::from_account_id(caller_of_caller_frame.account_id.clone()) + } + } + fn origin(&self) -> &Origin { &self.origin } @@ -2036,13 +2052,18 @@ where .unwrap_or_default() } - fn caller_is_origin(&self) -> bool { - self.origin == self.caller() + fn caller_is_origin(&self, use_caller_of_caller: bool) -> bool { + let caller = if use_caller_of_caller { + self.caller_of_caller() + } else { + self.caller() + }; + self.origin == caller } - fn caller_is_root(&self) -> bool { + fn caller_is_root(&self, use_caller_of_caller: bool) -> bool { // if the caller isn't origin, then it can't be root. - self.caller_is_origin() && self.origin == Origin::Root + self.caller_is_origin(use_caller_of_caller) && self.origin == Origin::Root } fn balance(&self) -> U256 { diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index 2ff9e81b82df6..ea12a0eb4ef70 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -80,6 +80,10 @@ impl PrecompileExt for MockExt { panic!("MockExt::caller") } + fn caller_of_caller(&self) -> Origin { + panic!("MockExt::caller_of_caller") + } + fn origin(&self) -> &Origin { panic!("MockExt::origin") } @@ -92,11 +96,11 @@ impl PrecompileExt for MockExt { panic!("MockExt::code_size") } - fn caller_is_origin(&self) -> bool { + fn caller_is_origin(&self, use_caller_of_caller: bool) -> bool { panic!("MockExt::caller_is_origin") } - fn caller_is_root(&self) -> bool { + fn caller_is_root(&self, use_caller_of_caller: bool) -> bool { panic!("MockExt::caller_is_root") } diff --git a/substrate/frame/revive/src/exec/tests.rs b/substrate/frame/revive/src/exec/tests.rs index e09ef5e9e6bcf..3be69bc619cc6 100644 --- a/substrate/frame/revive/src/exec/tests.rs +++ b/substrate/frame/revive/src/exec/tests.rs @@ -901,13 +901,13 @@ fn own_code_hash_returns_proper_values() { fn caller_is_origin_returns_proper_values() { let code_charlie = MockLoader::insert(Call, |ctx, _| { // BOB is not the origin of the stack call - assert!(!ctx.ext.caller_is_origin()); + assert!(!ctx.ext.caller_is_origin(false)); exec_success() }); let code_bob = MockLoader::insert(Call, |ctx, _| { // ALICE is the origin of the call stack - assert!(ctx.ext.caller_is_origin()); + assert!(ctx.ext.caller_is_origin(false)); // BOB calls CHARLIE ctx.ext .call(Weight::zero(), U256::zero(), &CHARLIE_ADDR, U256::zero(), vec![], true, false) @@ -937,7 +937,7 @@ fn caller_is_origin_returns_proper_values() { fn root_caller_succeeds() { let code_bob = MockLoader::insert(Call, |ctx, _| { // root is the origin of the call stack. - assert!(ctx.ext.caller_is_root()); + assert!(ctx.ext.caller_is_root(false)); exec_success() }); @@ -963,7 +963,7 @@ fn root_caller_succeeds() { fn root_caller_does_not_succeed_when_value_not_zero() { let code_bob = MockLoader::insert(Call, |ctx, _| { // root is the origin of the call stack. - assert!(ctx.ext.caller_is_root()); + assert!(ctx.ext.caller_is_root(false)); exec_success() }); @@ -989,13 +989,13 @@ fn root_caller_does_not_succeed_when_value_not_zero() { fn root_caller_succeeds_with_consecutive_calls() { let code_charlie = MockLoader::insert(Call, |ctx, _| { // BOB is not root, even though the origin is root. - assert!(!ctx.ext.caller_is_root()); + assert!(!ctx.ext.caller_is_root(false)); exec_success() }); let code_bob = MockLoader::insert(Call, |ctx, _| { // root is the origin of the call stack. - assert!(ctx.ext.caller_is_root()); + assert!(ctx.ext.caller_is_root(false)); // BOB calls CHARLIE. ctx.ext .call(Weight::zero(), U256::zero(), &CHARLIE_ADDR, U256::zero(), vec![], true, false) diff --git a/substrate/frame/revive/src/precompiles/builtin/system.rs b/substrate/frame/revive/src/precompiles/builtin/system.rs index 2a566b2367bd6..9fce7a54a849d 100644 --- a/substrate/frame/revive/src/precompiles/builtin/system.rs +++ b/substrate/frame/revive/src/precompiles/builtin/system.rs @@ -61,12 +61,12 @@ impl BuiltinPrecompile for System { }, ISystemCalls::callerIsOrigin(ISystem::callerIsOriginCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::CallerIsOrigin)?; - let is_origin = env.caller_is_origin(); + let is_origin = env.caller_is_origin(true); Ok(is_origin.abi_encode()) }, ISystemCalls::callerIsRoot(ISystem::callerIsRootCall {}) => { env.gas_meter_mut().charge(RuntimeCosts::CallerIsRoot)?; - let is_root = env.caller_is_root(); + let is_root = env.caller_is_root(true); Ok(is_root.abi_encode()) }, ISystemCalls::ownCodeHash(ISystem::ownCodeHashCall {}) => { diff --git a/substrate/frame/revive/uapi/src/precompiles/system.rs b/substrate/frame/revive/uapi/src/precompiles/system.rs index 99c1ada896c6d..e73c9ca05fa29 100644 --- a/substrate/frame/revive/uapi/src/precompiles/system.rs +++ b/substrate/frame/revive/uapi/src/precompiles/system.rs @@ -44,32 +44,17 @@ sol! { /// If no mapping exists for `addr`, the fallback account id will be returned. function toAccountId(address input) external view returns (bytes memory account_id); - /// Checks whether the contract caller is the origin of the whole call stack. - /// - /// # Important - /// - /// Call this function via [`crate::HostFn::delegate_call`]. - /// - /// `delegate_call` is necessary because if `call` were to be used, the call would - /// be executed in the context of the pre-compile and examine if the calling contract - /// (i.e. your contract) is the origin. + /// Checks whether the caller of the contract calling this function is the origin + /// of the whole call stack. function callerIsOrigin() external view returns (bool); - /// Checks whether the caller of the current contract is root. + /// Checks whether the caller of the contract calling this function is root. /// /// Note that only the origin of the call stack can be root. Hence this /// function returning `true` implies that the contract is being called by the origin. /// /// A return value of `true` indicates that this contract is being called by a root origin, /// and `false` indicates that the caller is a signed origin. - /// - /// # Important - /// - /// Call this function via [`crate::HostFn::delegate_call`]. - /// - /// `delegate_call` is necessary because if `call` were to be used, the call would - /// be executed in the context of the pre-compile and examine if the calling contract - /// (i.e. your contract) is `Root`. function callerIsRoot() external view returns (bool); /// Returns the minimum balance that is required for creating an account @@ -77,14 +62,6 @@ sol! { function minimumBalance() external view returns (uint); /// Returns the code hash of the caller. - /// - /// # Important - /// - /// Call this function via [`crate::HostFn::call`] with [`crate::flags::CallFlags`] - /// set to [`crate::flags::CallFlags::READ_ONLY`]. - /// - /// `READONLY` minimizes the security scope of the call. `call` is necessary - /// as the function returns the code hash of the caller. function ownCodeHash() external view returns (bytes32); /// Returns the amount of `Weight` left. From 1793c1d4e4c2368beb8e9dbf2fa7e4d6885e15b4 Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Mon, 15 Sep 2025 18:30:07 +0200 Subject: [PATCH 58/63] Use `clone()` over `to_owned()` --- substrate/frame/revive/src/exec.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 0c299cd94ed30..18622e527b1a1 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -2012,7 +2012,7 @@ where Some(frame) => frame, }; if let Some(DelegateInfo { caller, .. }) = &caller_of_caller_frame.delegate { - caller.to_owned() + caller.clone() } else { Origin::from_account_id(caller_of_caller_frame.account_id.clone()) } @@ -2053,11 +2053,7 @@ where } fn caller_is_origin(&self, use_caller_of_caller: bool) -> bool { - let caller = if use_caller_of_caller { - self.caller_of_caller() - } else { - self.caller() - }; + let caller = if use_caller_of_caller { self.caller_of_caller() } else { self.caller() }; self.origin == caller } From 1862e0d5aa42a6f4e21dc7a964a66ea1f2deba3f Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Mon, 15 Sep 2025 19:22:39 +0200 Subject: [PATCH 59/63] Name unused variable --- substrate/frame/revive/src/exec/mock_ext.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index ea12a0eb4ef70..b2c92b50c840f 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -100,7 +100,7 @@ impl PrecompileExt for MockExt { panic!("MockExt::caller_is_origin") } - fn caller_is_root(&self, use_caller_of_caller: bool) -> bool { + fn caller_is_root(&self, _use_caller_of_caller: bool) -> bool { panic!("MockExt::caller_is_root") } From 6922bc71954b6f370a26402307667f176100027b Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 16 Sep 2025 17:09:11 +0200 Subject: [PATCH 60/63] Make CI happy --- substrate/frame/revive/Cargo.toml | 2 +- substrate/frame/revive/src/exec/mock_ext.rs | 2 +- substrate/frame/revive/uapi/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml index da5d1ce7f3097..15b929e043287 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -47,7 +47,7 @@ frame-support = { workspace = true } frame-system = { workspace = true } pallet-revive-fixtures = { workspace = true, optional = true } pallet-revive-proc-macro = { workspace = true } -pallet-revive-uapi = { workspace = true, features = ["scale", "precompiles-sol-interfaces"] } +pallet-revive-uapi = { workspace = true, features = ["precompiles-sol-interfaces", "scale"] } pallet-transaction-payment = { workspace = true } ripemd = { workspace = true } sp-api = { workspace = true } diff --git a/substrate/frame/revive/src/exec/mock_ext.rs b/substrate/frame/revive/src/exec/mock_ext.rs index b2c92b50c840f..91a3e1c1c43f5 100644 --- a/substrate/frame/revive/src/exec/mock_ext.rs +++ b/substrate/frame/revive/src/exec/mock_ext.rs @@ -96,7 +96,7 @@ impl PrecompileExt for MockExt { panic!("MockExt::code_size") } - fn caller_is_origin(&self, use_caller_of_caller: bool) -> bool { + fn caller_is_origin(&self, _use_caller_of_caller: bool) -> bool { panic!("MockExt::caller_is_origin") } diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml index 9fb935cab2fd1..c2ee75eef05bd 100644 --- a/substrate/frame/revive/uapi/Cargo.toml +++ b/substrate/frame/revive/uapi/Cargo.toml @@ -16,7 +16,7 @@ features = ["unstable-hostfn"] targets = ["riscv64imac-unknown-none-elf"] [dependencies] -alloy-core = { workspace = true, features = ["sol-types"], optional = true } +alloy-core = { workspace = true, optional = true, features = ["sol-types"] } bitflags = { workspace = true } codec = { features = [ "derive", "max-encoded-len" ], optional = true, workspace = true } const-crypto = { version = "0.3.0", default-features = false } From a89bf309895802dbe0e3f7f5ac368af21a9f8e4a Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 16 Sep 2025 17:11:24 +0200 Subject: [PATCH 61/63] Make CI happy --- substrate/frame/revive/uapi/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml index c2ee75eef05bd..fae01668c831d 100644 --- a/substrate/frame/revive/uapi/Cargo.toml +++ b/substrate/frame/revive/uapi/Cargo.toml @@ -30,5 +30,5 @@ polkavm-derive = { version = "0.27.0" } [features] default = ["scale"] scale = ["dep:codec", "scale-info"] -unstable-hostfn = [] precompiles-sol-interfaces = ["alloy-core"] +unstable-hostfn = [] From 77786322656f51ed0d6ed98a5940f87b2ac1f8af Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 16 Sep 2025 19:12:53 +0200 Subject: [PATCH 62/63] Apply CI recommended changes to toml files --- substrate/frame/revive/uapi/Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml index fae01668c831d..2c35b8fc8df26 100644 --- a/substrate/frame/revive/uapi/Cargo.toml +++ b/substrate/frame/revive/uapi/Cargo.toml @@ -18,7 +18,10 @@ targets = ["riscv64imac-unknown-none-elf"] [dependencies] alloy-core = { workspace = true, optional = true, features = ["sol-types"] } bitflags = { workspace = true } -codec = { features = [ "derive", "max-encoded-len" ], optional = true, workspace = true } +codec = { features = [ + "derive", + "max-encoded-len", +], optional = true, workspace = true } const-crypto = { version = "0.3.0", default-features = false } hex-literal = { version = "0.4.1", default-features = false } pallet-revive-proc-macro = { workspace = true } From 23124e4aae0fb7be541921cd62e417019f0b3dde Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Tue, 16 Sep 2025 19:29:24 +0200 Subject: [PATCH 63/63] Apply CI recommended changes to toml files --- substrate/frame/revive/uapi/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml index 2c35b8fc8df26..dafbd96642621 100644 --- a/substrate/frame/revive/uapi/Cargo.toml +++ b/substrate/frame/revive/uapi/Cargo.toml @@ -19,8 +19,8 @@ targets = ["riscv64imac-unknown-none-elf"] alloy-core = { workspace = true, optional = true, features = ["sol-types"] } bitflags = { workspace = true } codec = { features = [ - "derive", - "max-encoded-len", + "derive", + "max-encoded-len", ], optional = true, workspace = true } const-crypto = { version = "0.3.0", default-features = false } hex-literal = { version = "0.4.1", default-features = false }