difftreelog
CORE-302 Add Rc for SubstrateRecorder
in: master
7 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6089,7 +6089,7 @@
"pallet-evm",
"pallet-evm-coder-substrate",
"pallet-nonfungible",
- "parity-scale-codec",
+ "parity-scale-codec 3.1.2",
"scale-info",
"sp-core",
"sp-runtime",
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -20,7 +20,7 @@
use core::ops::{Deref, DerefMut};
use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
-use sp_std::vec::Vec;
+use sp_std::{vec::Vec, rc::Rc};
use pallet_evm::account::CrossAccountId;
use frame_support::{
dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},
pallets/evm-coder-substrate/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![cfg_attr(not(feature = "std"), no_std)]1819#[cfg(not(feature = "std"))]20extern crate alloc;21#[cfg(not(feature = "std"))]22use alloc::format;23use frame_support::dispatch::Weight;2425use core::marker::PhantomData;26use sp_std::cell::RefCell;2728use codec::Decode;29use frame_support::pallet_prelude::DispatchError;30use frame_support::traits::PalletInfo;31use frame_support::{ensure, sp_runtime::ModuleError};32use up_data_structs::budget;33use pallet_evm::{34 ExitError, ExitRevert, ExitSucceed, GasWeightMapping, PrecompileFailure, PrecompileOutput,35 PrecompileResult,36};37use sp_core::H160;38// #[cfg(feature = "runtime-benchmarks")]39// pub mod benchmarking;4041use evm_coder::{42 abi::{AbiReader, AbiWrite, AbiWriter},43 execution::{self, Result},44 types::{Msg, value},45};4647pub use pallet::*;4849#[frame_support::pallet]50pub mod pallet {51 use super::*;5253 use frame_system::ensure_signed;54 pub use frame_support::dispatch::DispatchResult;55 use frame_system::pallet_prelude::*;5657 /// DispatchError is opaque, but we need to somehow extract correct error in case of OutOfGas failure58 /// So we have this pallet, which defines OutOfGas error, and knews its own id to check if DispatchError59 /// is thrown because of it60 ///61 /// These errors shouldn't end in extrinsic results, as they only used in evm execution path62 #[pallet::error]63 pub enum Error<T> {64 OutOfGas,65 OutOfFund,66 }6768 #[pallet::config]69 pub trait Config: frame_system::Config {70 type GasWeightMapping: pallet_evm::GasWeightMapping;71 }7273 #[pallet::pallet]74 pub struct Pallet<T>(_);7576 #[pallet::call]77 impl<T: Config> Pallet<T> {78 #[pallet::weight(0)]79 pub fn empty_call(origin: OriginFor<T>) -> DispatchResult {80 let _sender = ensure_signed(origin)?;81 Ok(())82 }83 }84}8586// From instabul hardfork configuration: https://github.com/rust-blockchain/evm/blob/fd4fd6acc0ca3208d6770fdb3ba407c94cdf97c6/runtime/src/lib.rs#L28487pub const G_SLOAD_WORD: u64 = 800;88pub const G_SSTORE_WORD: u64 = 20000;8990pub struct GasCallsBudget<'r, T: Config> {91 recorder: &'r SubstrateRecorder<T>,92 gas_per_call: u64,93}94impl<T: Config> budget::Budget for GasCallsBudget<'_, T> {95 fn consume_custom(&self, calls: u32) -> bool {96 let (gas, overflown) = (calls as u64).overflowing_add(self.gas_per_call);97 if overflown {98 return false;99 }100 self.recorder.consume_gas(gas).is_ok()101 }102}103104#[derive(Default)]105pub struct SubstrateRecorder<T: Config> {106 initial_gas: u64,107 gas_limit: RefCell<u64>,108 _phantom: PhantomData<*const T>,109}110111impl<T: Config> SubstrateRecorder<T> {112 pub fn new(gas_limit: u64) -> Self {113 Self {114 initial_gas: gas_limit,115 gas_limit: RefCell::new(gas_limit),116 _phantom: PhantomData,117 }118 }119120 pub fn gas_left(&self) -> u64 {121 *self.gas_limit.borrow()122 }123 pub fn gas_calls_budget(&self, gas_per_call: u64) -> GasCallsBudget<T> {124 GasCallsBudget {125 recorder: self,126 gas_per_call,127 }128 }129 pub fn weight_calls_budget(&self, weight_per_call: Weight) -> GasCallsBudget<T> {130 GasCallsBudget {131 recorder: self,132 gas_per_call: T::GasWeightMapping::weight_to_gas(weight_per_call),133 }134 }135 pub fn consume_sload_sub(&self) -> DispatchResult {136 self.consume_gas_sub(G_SLOAD_WORD)137 }138 pub fn consume_sstores_sub(&self, amount: usize) -> DispatchResult {139 self.consume_gas_sub(G_SSTORE_WORD.saturating_mul(amount as u64))140 }141 pub fn consume_sstore_sub(&self) -> DispatchResult {142 self.consume_gas_sub(G_SSTORE_WORD)143 }144 pub fn consume_gas_sub(&self, gas: u64) -> DispatchResult {145 ensure!(gas != u64::MAX, Error::<T>::OutOfGas);146 let mut gas_limit = self.gas_limit.borrow_mut();147 ensure!(gas <= *gas_limit, Error::<T>::OutOfGas);148 *gas_limit -= gas;149 Ok(())150 }151152 pub fn consume_sload(&self) -> Result<()> {153 self.consume_gas(G_SLOAD_WORD)154 }155 pub fn consume_sstore(&self) -> Result<()> {156 self.consume_gas(G_SSTORE_WORD)157 }158 pub fn consume_gas(&self, gas: u64) -> Result<()> {159 if gas == u64::MAX {160 return Err(execution::Error::Error(ExitError::OutOfGas));161 }162 let mut gas_limit = self.gas_limit.borrow_mut();163 if gas > *gas_limit {164 return Err(execution::Error::Error(ExitError::OutOfGas));165 }166 *gas_limit -= gas;167 Ok(())168 }169 pub fn return_gas(&self, gas: u64) {170 let mut gas_limit = self.gas_limit.borrow_mut();171 *gas_limit += gas;172 }173174 pub fn evm_to_precompile_output(175 self,176 result: evm_coder::execution::Result<Option<AbiWriter>>,177 ) -> Option<PrecompileResult> {178 use evm_coder::execution::Error;179 Some(match result {180 Ok(Some(v)) => Ok(PrecompileOutput {181 exit_status: ExitSucceed::Returned,182 cost: self.initial_gas - self.gas_left(),183 // We don't use this interface184 logs: sp_std::vec![],185 output: v.finish(),186 }),187 Ok(None) => return None,188 Err(Error::Revert(e)) => {189 let mut writer = AbiWriter::new_call(evm_coder::fn_selector!(Error(string)));190 (&e as &str).abi_write(&mut writer);191192 Err(PrecompileFailure::Revert {193 exit_status: ExitRevert::Reverted,194 cost: self.initial_gas - self.gas_left(),195 output: writer.finish(),196 })197 }198 Err(Error::Fatal(f)) => Err(f.into()),199 Err(Error::Error(e)) => Err(e.into()),200 })201 }202}203204pub fn dispatch_to_evm<T: Config>(err: DispatchError) -> evm_coder::execution::Error {205 use evm_coder::execution::Error as ExError;206 match err {207 DispatchError::Module(ModuleError { index, error, .. })208 if index209 == T::PalletInfo::index::<Pallet<T>>()210 .expect("evm-coder-substrate is a pallet, which should be added to runtime")211 as u8 =>212 {213 let mut read = &error as &[u8];214 match Error::<T>::decode(&mut read) {215 Ok(Error::<T>::OutOfGas) => ExError::Error(ExitError::OutOfGas),216 Ok(Error::<T>::OutOfFund) => ExError::Error(ExitError::OutOfFund),217 _ => unreachable!("this pallet only defines two possible errors"),218 }219 }220 DispatchError::Module(ModuleError {221 message: Some(msg), ..222 }) => ExError::Revert(msg.into()),223 DispatchError::Module(ModuleError { index, error, .. }) => {224 ExError::Revert(format!("error {:?} in pallet {}", error, index))225 }226 e => ExError::Revert(format!("substrate error: {:?}", e)),227 }228}229230pub trait WithRecorder<T: Config> {231 fn recorder(&self) -> &SubstrateRecorder<T>;232 fn into_recorder(self) -> SubstrateRecorder<T>;233}234235/// Helper to simplify implementing bridge between evm-coder definitions and pallet-evm236pub fn call<237 T: Config,238 C: evm_coder::Call + evm_coder::Weighted,239 E: evm_coder::Callable<C> + WithRecorder<T>,240>(241 caller: H160,242 mut e: E,243 value: value,244 input: &[u8],245) -> Option<PrecompileResult> {246 let result = call_internal(caller, &mut e, value, input);247 e.into_recorder().evm_to_precompile_output(result)248}249250fn call_internal<251 T: Config,252 C: evm_coder::Call + evm_coder::Weighted,253 E: evm_coder::Callable<C> + WithRecorder<T>,254>(255 caller: H160,256 e: &mut E,257 value: value,258 input: &[u8],259) -> evm_coder::execution::Result<Option<AbiWriter>> {260 let (selector, mut reader) = AbiReader::new_call(input)?;261 let call = C::parse(selector, &mut reader)?;262 if call.is_none() {263 return Ok(None);264 }265 let call = call.unwrap();266267 let dispatch_info = call.weight();268 e.recorder()269 .consume_gas(T::GasWeightMapping::weight_to_gas(dispatch_info.weight))?;270271 match e.call(Msg {272 call,273 caller,274 value,275 }) {276 Ok(v) => {277 let unspent = v.post_info.calc_unspent(&dispatch_info);278 e.recorder()279 .return_gas(T::GasWeightMapping::weight_to_gas(unspent));280 Ok(Some(v.data))281 }282 Err(v) => {283 let unspent = v.post_info.calc_unspent(&dispatch_info);284 e.recorder()285 .return_gas(T::GasWeightMapping::weight_to_gas(unspent));286 Err(v.data)287 }288 }289}pallets/evm-collection/src/eth.rsdiffbeforeafterboth--- a/pallets/evm-collection/src/eth.rs
+++ b/pallets/evm-collection/src/eth.rs
@@ -31,7 +31,7 @@
use crate::{Config, Pallet};
use frame_support::traits::Get;
-use sp_std::vec::Vec;
+use sp_std::{vec::Vec, rc::Rc};
use alloc::format;
struct EvmCollection<T: Config>(SubstrateRecorder<T>);
pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -28,7 +28,7 @@
};
use frame_support::traits::Get;
use up_sponsorship::SponsorshipHandler;
-use sp_std::vec::Vec;
+use sp_std::{vec::Vec, rc::Rc};
struct ContractHelpers<T: Config>(SubstrateRecorder<T>);
impl<T: Config> WithRecorder<T> for ContractHelpers<T> {
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -33,7 +33,7 @@
use pallet_evm_coder_substrate::WithRecorder;
use sp_core::H160;
use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
-use sp_std::collections::btree_map::BTreeMap;
+use sp_std::{collections::btree_map::BTreeMap, rc::Rc};
pub use pallet::*;
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -33,9 +33,8 @@
use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
use sp_core::H160;
use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};
-use sp_std::{vec::Vec, vec, collections::btree_set::BTreeSet};
+use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
use core::ops::Deref;
-use sp_std::collections::btree_map::BTreeMap;
use codec::{Encode, Decode, MaxEncodedLen};
use scale_info::TypeInfo;