diff --git a/Cargo.lock b/Cargo.lock index 85b0107bcb..7914c6350b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9590,7 +9590,7 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "precompile-utils" -version = "0.4.3" +version = "0.4.4" dependencies = [ "assert_matches", "derive_more", diff --git a/precompiles/dapps-staking/Cargo.toml b/precompiles/dapps-staking/Cargo.toml index dfd46ac32a..76f9483fc2 100644 --- a/precompiles/dapps-staking/Cargo.toml +++ b/precompiles/dapps-staking/Cargo.toml @@ -31,7 +31,7 @@ pallet-evm = { workspace = true } [dev-dependencies] derive_more = { workspace = true } -pallet-balances = { workspace = true } +pallet-balances = { workspace = true, features = ["std"] } pallet-timestamp = { workspace = true } precompile-utils = { workspace = true, features = ["testing"] } serde = { workspace = true } diff --git a/precompiles/utils/Cargo.toml b/precompiles/utils/Cargo.toml index 8874ea1976..6102900fd6 100644 --- a/precompiles/utils/Cargo.toml +++ b/precompiles/utils/Cargo.toml @@ -2,7 +2,7 @@ name = "precompile-utils" authors = ["StakeTechnologies", "PureStake"] description = "Utils to write EVM precompiles." -version = "0.4.3" +version = "0.4.4" edition.workspace = true homepage.workspace = true repository.workspace = true diff --git a/precompiles/utils/src/evm/costs.rs b/precompiles/utils/src/evm/costs.rs deleted file mode 100644 index 82f90bbe7b..0000000000 --- a/precompiles/utils/src/evm/costs.rs +++ /dev/null @@ -1,119 +0,0 @@ -// This file is part of Astar. - -// Copyright 2019-2022 PureStake Inc. -// Copyright (C) 2022-2023 Stake Technologies Pte.Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later -// -// This file is part of Utils package, originally developed by Purestake Inc. -// Utils package used in Astar Network in terms of GPLv3. -// -// Utils is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Utils is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Utils. If not, see . -use { - crate::EvmResult, - fp_evm::{ExitError, PrecompileFailure}, - sp_core::U256, -}; - -pub fn log_costs(topics: usize, data_len: usize) -> EvmResult { - // Cost calculation is copied from EVM code that is not publicly exposed by the crates. - // https://github.com/rust-blockchain/evm/blob/master/gasometer/src/costs.rs#L148 - - const G_LOG: u64 = 375; - const G_LOGDATA: u64 = 8; - const G_LOGTOPIC: u64 = 375; - - let topic_cost = G_LOGTOPIC - .checked_mul(topics as u64) - .ok_or(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - })?; - - let data_cost = G_LOGDATA - .checked_mul(data_len as u64) - .ok_or(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - })?; - - G_LOG - .checked_add(topic_cost) - .ok_or(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - })? - .checked_add(data_cost) - .ok_or(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }) -} - -// Compute the cost of doing a subcall. -// Some parameters cannot be known in advance, so we estimate the worst possible cost. -pub fn call_cost(value: U256, config: &evm::Config) -> u64 { - // Copied from EVM code since not public. - pub const G_CALLVALUE: u64 = 9000; - pub const G_NEWACCOUNT: u64 = 25000; - - fn address_access_cost(is_cold: bool, regular_value: u64, config: &evm::Config) -> u64 { - if config.increase_state_access_gas { - if is_cold { - config.gas_account_access_cold - } else { - config.gas_storage_read_warm - } - } else { - regular_value - } - } - - fn xfer_cost(is_call_or_callcode: bool, transfers_value: bool) -> u64 { - if is_call_or_callcode && transfers_value { - G_CALLVALUE - } else { - 0 - } - } - - fn new_cost( - is_call_or_staticcall: bool, - new_account: bool, - transfers_value: bool, - config: &evm::Config, - ) -> u64 { - let eip161 = !config.empty_considered_exists; - if is_call_or_staticcall { - if eip161 { - if transfers_value && new_account { - G_NEWACCOUNT - } else { - 0 - } - } else if new_account { - G_NEWACCOUNT - } else { - 0 - } - } else { - 0 - } - } - - let transfers_value = value != U256::default(); - let is_cold = true; - let is_call_or_callcode = true; - let is_call_or_staticcall = true; - let new_account = true; - - address_access_cost(is_cold, config.gas_call, config) - + xfer_cost(is_call_or_callcode, transfers_value) - + new_cost(is_call_or_staticcall, new_account, transfers_value, config) -} diff --git a/precompiles/utils/src/evm/handle.rs b/precompiles/utils/src/evm/handle.rs deleted file mode 100644 index f0c30dfdbf..0000000000 --- a/precompiles/utils/src/evm/handle.rs +++ /dev/null @@ -1,183 +0,0 @@ -// This file is part of Astar. - -// Copyright 2019-2022 PureStake Inc. -// Copyright (C) 2022-2023 Stake Technologies Pte.Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later -// -// This file is part of Utils package, originally developed by Purestake Inc. -// Utils package used in Astar Network in terms of GPLv3. -// -// Utils is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Utils is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Utils. If not, see . - -use { - crate::{check_function_modifier, data::EvmDataReader, EvmResult, FunctionModifier}, - fp_evm::{Log, PrecompileHandle}, -}; - -pub trait PrecompileHandleExt: PrecompileHandle { - /// Record cost of a log manually. - /// This can be useful to record log costs early when their content have static size. - #[must_use] - fn record_log_costs_manual(&mut self, topics: usize, data_len: usize) -> EvmResult; - - /// Record cost of logs. - #[must_use] - fn record_log_costs(&mut self, logs: &[&Log]) -> EvmResult; - - #[must_use] - /// Check that a function call is compatible with the context it is - /// called into. - fn check_function_modifier(&self, modifier: FunctionModifier) -> EvmResult; - - #[must_use] - /// Returns a reader of the input, skipping the selector. - fn read_after_selector(&self) -> EvmResult; -} - -impl PrecompileHandleExt for T { - /// Record cost of a log manualy. - /// This can be useful to record log costs early when their content have static size. - #[must_use] - fn record_log_costs_manual(&mut self, topics: usize, data_len: usize) -> EvmResult { - self.record_cost(crate::evm::costs::log_costs(topics, data_len)?)?; - - Ok(()) - } - - /// Record cost of logs. - #[must_use] - fn record_log_costs(&mut self, logs: &[&Log]) -> EvmResult { - for log in logs { - self.record_log_costs_manual(log.topics.len(), log.data.len())?; - } - - Ok(()) - } - - #[must_use] - /// Check that a function call is compatible with the context it is - /// called into. - fn check_function_modifier(&self, modifier: FunctionModifier) -> EvmResult { - check_function_modifier(self.context(), self.is_static(), modifier) - } - - #[must_use] - /// Returns a reader of the input, skipping the selector. - fn read_after_selector(&self) -> EvmResult { - EvmDataReader::new_skip_selector(self.input()) - } -} - -environmental::environmental!(EVM_CONTEXT: trait PrecompileHandle); - -pub fn using_precompile_handle<'a, R, F: FnOnce() -> R>( - precompile_handle: &'a mut dyn PrecompileHandle, - mutator: F, -) -> R { - // # Safety - // - // unsafe rust does not mean unsafe, but "the compiler cannot guarantee the safety of the - // memory". - // - // The only risk here is that the lifetime 'a comes to its end while the global variable - // `EVM_CONTEXT` still contains the reference to the precompile handle. - // The `using` method guarantee that it can't happen because the global variable is freed right - // after the execution of the `mutator` closure (whatever the result of the execution). - unsafe { - EVM_CONTEXT::using( - core::mem::transmute::<&'a mut dyn PrecompileHandle, &'static mut dyn PrecompileHandle>( - precompile_handle, - ), - mutator, - ) - } -} - -pub fn with_precompile_handle R>(f: F) -> Option { - EVM_CONTEXT::with(|precompile_handle| f(precompile_handle)) -} - -#[cfg(test)] -mod tests { - use super::*; - - struct MockPrecompileHandle; - impl PrecompileHandle for MockPrecompileHandle { - fn call( - &mut self, - _: sp_core::H160, - _: Option, - _: Vec, - _: Option, - _: bool, - _: &evm::Context, - ) -> (evm::ExitReason, Vec) { - unimplemented!() - } - - fn record_cost(&mut self, _: u64) -> Result<(), evm::ExitError> { - unimplemented!() - } - - fn remaining_gas(&self) -> u64 { - unimplemented!() - } - - fn log( - &mut self, - _: sp_core::H160, - _: Vec, - _: Vec, - ) -> Result<(), evm::ExitError> { - unimplemented!() - } - - fn code_address(&self) -> sp_core::H160 { - unimplemented!() - } - - fn input(&self) -> &[u8] { - unimplemented!() - } - - fn context(&self) -> &evm::Context { - unimplemented!() - } - - fn is_static(&self) -> bool { - true - } - - fn gas_limit(&self) -> Option { - unimplemented!() - } - } - - #[test] - fn with_precompile_handle_without_context() { - assert_eq!(with_precompile_handle(|_| {}), None); - } - - #[test] - fn with_precompile_handle_with_context() { - let mut precompile_handle = MockPrecompileHandle; - - assert_eq!( - using_precompile_handle(&mut precompile_handle, || with_precompile_handle( - |handle| handle.is_static() - )), - Some(true) - ); - } -} diff --git a/precompiles/utils/src/evm/logs.rs b/precompiles/utils/src/evm/logs.rs deleted file mode 100644 index 8a322b7832..0000000000 --- a/precompiles/utils/src/evm/logs.rs +++ /dev/null @@ -1,114 +0,0 @@ -// This file is part of Astar. - -// Copyright 2019-2022 PureStake Inc. -// Copyright (C) 2022-2023 Stake Technologies Pte.Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later -// -// This file is part of Utils package, originally developed by Purestake Inc. -// Utils package used in Astar Network in terms of GPLv3. -// -// Utils is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Utils is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Utils. If not, see . - -use { - crate::EvmResult, - pallet_evm::{Log, PrecompileHandle}, - sp_core::{H160, H256}, - sp_std::{vec, vec::Vec}, -}; - -/// Create a 0-topic log. -#[must_use] -pub fn log0(address: impl Into, data: impl Into>) -> Log { - Log { - address: address.into(), - topics: vec![], - data: data.into(), - } -} - -/// Create a 1-topic log. -#[must_use] -pub fn log1(address: impl Into, topic0: impl Into, data: impl Into>) -> Log { - Log { - address: address.into(), - topics: vec![topic0.into()], - data: data.into(), - } -} - -/// Create a 2-topics log. -#[must_use] -pub fn log2( - address: impl Into, - topic0: impl Into, - topic1: impl Into, - data: impl Into>, -) -> Log { - Log { - address: address.into(), - topics: vec![topic0.into(), topic1.into()], - data: data.into(), - } -} - -/// Create a 3-topics log. -#[must_use] -pub fn log3( - address: impl Into, - topic0: impl Into, - topic1: impl Into, - topic2: impl Into, - data: impl Into>, -) -> Log { - Log { - address: address.into(), - topics: vec![topic0.into(), topic1.into(), topic2.into()], - data: data.into(), - } -} - -/// Create a 4-topics log. -#[must_use] -pub fn log4( - address: impl Into, - topic0: impl Into, - topic1: impl Into, - topic2: impl Into, - topic3: impl Into, - data: impl Into>, -) -> Log { - Log { - address: address.into(), - topics: vec![topic0.into(), topic1.into(), topic2.into(), topic3.into()], - data: data.into(), - } -} - -/// Extension trait allowing to record logs into a PrecompileHandle. -pub trait LogExt { - fn record(self, handle: &mut impl PrecompileHandle) -> EvmResult; - - fn compute_cost(&self) -> EvmResult; -} - -impl LogExt for Log { - fn record(self, handle: &mut impl PrecompileHandle) -> EvmResult { - handle.log(self.address, self.topics, self.data)?; - Ok(()) - } - - fn compute_cost(&self) -> EvmResult { - crate::evm::costs::log_costs(self.topics.len(), self.data.len()) - } -} diff --git a/precompiles/utils/src/evm/mod.rs b/precompiles/utils/src/evm/mod.rs deleted file mode 100644 index d4182d44cc..0000000000 --- a/precompiles/utils/src/evm/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -// This file is part of Astar. - -// Copyright 2019-2022 PureStake Inc. -// Copyright (C) 2022-2023 Stake Technologies Pte.Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later -// -// This file is part of Utils package, originally developed by Purestake Inc. -// Utils package used in Astar Network in terms of GPLv3. -// -// Utils is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Utils is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Utils. If not, see . - -pub mod costs; -pub mod handle; -pub mod logs;