mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 04:41:02 +00:00
pallet-evm: add support for transaction-level create2 (#4907)
* pallet-evm: add support for transaction-level create2 * Bump runtime version * Switch to FunctionOf for weights
This commit is contained in:
@@ -25,7 +25,7 @@ pub use crate::backend::{Account, Log, Vicinity, Backend};
|
||||
|
||||
use sp_std::{vec::Vec, marker::PhantomData};
|
||||
use frame_support::{ensure, decl_module, decl_storage, decl_event, decl_error};
|
||||
use frame_support::weights::{Weight, WeighData, ClassifyDispatch, DispatchClass, PaysFee};
|
||||
use frame_support::weights::{Weight, DispatchClass, FunctionOf};
|
||||
use frame_support::traits::{Currency, WithdrawReason, ExistenceRequirement};
|
||||
use frame_system::{self as system, ensure_signed};
|
||||
use sp_runtime::ModuleId;
|
||||
@@ -34,6 +34,7 @@ use sp_core::{U256, H256, H160, Hasher};
|
||||
use sp_runtime::{
|
||||
DispatchResult, traits::{UniqueSaturatedInto, AccountIdConversion, SaturatedConversion},
|
||||
};
|
||||
use sha3::{Digest, Keccak256};
|
||||
use evm::{ExitReason, ExitSucceed, ExitError};
|
||||
use evm::executor::StackExecutor;
|
||||
use evm::backend::ApplyBackend;
|
||||
@@ -115,38 +116,6 @@ impl Precompiles for () {
|
||||
}
|
||||
}
|
||||
|
||||
struct WeightForCallCreate;
|
||||
|
||||
impl WeighData<(&H160, &Vec<u8>, &U256, &u32, &U256, &Option<U256>)> for WeightForCallCreate {
|
||||
fn weigh_data(
|
||||
&self,
|
||||
(_, _, _, gas_provided, gas_price, _): (&H160, &Vec<u8>, &U256, &u32, &U256, &Option<U256>)
|
||||
) -> Weight {
|
||||
(*gas_price).saturated_into::<Weight>().saturating_mul(*gas_provided)
|
||||
}
|
||||
}
|
||||
|
||||
impl WeighData<(&Vec<u8>, &U256, &u32, &U256, &Option<U256>)> for WeightForCallCreate {
|
||||
fn weigh_data(
|
||||
&self,
|
||||
(_, _, gas_provided, gas_price, _): (&Vec<u8>, &U256, &u32, &U256, &Option<U256>)
|
||||
) -> Weight {
|
||||
(*gas_price).saturated_into::<Weight>().saturating_mul(*gas_provided)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ClassifyDispatch<T> for WeightForCallCreate {
|
||||
fn classify_dispatch(&self, _: T) -> DispatchClass {
|
||||
DispatchClass::Normal
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PaysFee<T> for WeightForCallCreate {
|
||||
fn pays_fee(&self, _: T) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// EVM module trait
|
||||
pub trait Trait: frame_system::Trait + pallet_timestamp::Trait {
|
||||
/// Calculator for current gas price.
|
||||
@@ -252,7 +221,7 @@ decl_module! {
|
||||
}
|
||||
|
||||
/// Issue an EVM call operation. This is similar to a message call transaction in Ethereum.
|
||||
#[weight = WeightForCallCreate]
|
||||
#[weight = FunctionOf(|(_, _, _, gas_limit, gas_price, _): (&H160, &Vec<u8>, &U256, &u32, &U256, &Option<U256>)| (*gas_price).saturated_into::<Weight>().saturating_mul(*gas_limit), DispatchClass::Normal, true)]
|
||||
fn call(
|
||||
origin,
|
||||
target: H160,
|
||||
@@ -315,7 +284,7 @@ decl_module! {
|
||||
|
||||
/// Issue an EVM create operation. This is similar to a contract creation transaction in
|
||||
/// Ethereum.
|
||||
#[weight = WeightForCallCreate]
|
||||
#[weight = FunctionOf(|(_, _, gas_limit, gas_price, _): (&Vec<u8>, &U256, &u32, &U256, &Option<U256>)| (*gas_price).saturated_into::<Weight>().saturating_mul(*gas_limit), DispatchClass::Normal, true)]
|
||||
fn create(
|
||||
origin,
|
||||
init: Vec<u8>,
|
||||
@@ -353,7 +322,9 @@ decl_module! {
|
||||
ensure!(source_account.nonce == nonce, Error::<T>::InvalidNonce);
|
||||
}
|
||||
|
||||
let create_address = executor.create_address(source, evm::CreateScheme::Dynamic);
|
||||
let create_address = executor.create_address(
|
||||
evm::CreateScheme::Legacy { caller: source }
|
||||
);
|
||||
let reason = executor.transact_create(
|
||||
source,
|
||||
value,
|
||||
@@ -378,6 +349,76 @@ decl_module! {
|
||||
|
||||
ret.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Issue an EVM create2 operation.
|
||||
#[weight = FunctionOf(|(_, _, _, gas_limit, gas_price, _): (&Vec<u8>, &H256, &U256, &u32, &U256, &Option<U256>)| (*gas_price).saturated_into::<Weight>().saturating_mul(*gas_limit), DispatchClass::Normal, true)]
|
||||
fn create2(
|
||||
origin,
|
||||
init: Vec<u8>,
|
||||
salt: H256,
|
||||
value: U256,
|
||||
gas_limit: u32,
|
||||
gas_price: U256,
|
||||
nonce: Option<U256>,
|
||||
) -> DispatchResult {
|
||||
let sender = ensure_signed(origin)?;
|
||||
ensure!(gas_price >= T::FeeCalculator::min_gas_price(), Error::<T>::GasPriceTooLow);
|
||||
|
||||
let source = T::ConvertAccountId::convert_account_id(&sender);
|
||||
|
||||
let vicinity = Vicinity {
|
||||
gas_price,
|
||||
origin: source,
|
||||
};
|
||||
|
||||
let mut backend = Backend::<T>::new(&vicinity);
|
||||
let mut executor = StackExecutor::new_with_precompile(
|
||||
&backend,
|
||||
gas_limit as usize,
|
||||
&backend::GASOMETER_CONFIG,
|
||||
T::Precompiles::execute,
|
||||
);
|
||||
|
||||
let total_fee = gas_price.checked_mul(U256::from(gas_limit))
|
||||
.ok_or(Error::<T>::FeeOverflow)?;
|
||||
let total_payment = value.checked_add(total_fee).ok_or(Error::<T>::PaymentOverflow)?;
|
||||
let source_account = Accounts::get(&source);
|
||||
ensure!(source_account.balance >= total_payment, Error::<T>::BalanceLow);
|
||||
executor.withdraw(source, total_fee).map_err(|_| Error::<T>::WithdrawFailed)?;
|
||||
|
||||
if let Some(nonce) = nonce {
|
||||
ensure!(source_account.nonce == nonce, Error::<T>::InvalidNonce);
|
||||
}
|
||||
|
||||
let code_hash = H256::from_slice(Keccak256::digest(&init).as_slice());
|
||||
let create_address = executor.create_address(
|
||||
evm::CreateScheme::Create2 { caller: source, code_hash, salt }
|
||||
);
|
||||
let reason = executor.transact_create2(
|
||||
source,
|
||||
value,
|
||||
init,
|
||||
salt,
|
||||
gas_limit as usize,
|
||||
);
|
||||
|
||||
let ret = match reason {
|
||||
ExitReason::Succeed(_) => {
|
||||
Module::<T>::deposit_event(Event::Created(create_address));
|
||||
Ok(())
|
||||
},
|
||||
ExitReason::Error(_) => Err(Error::<T>::ExitReasonFailed),
|
||||
ExitReason::Revert(_) => Err(Error::<T>::ExitReasonRevert),
|
||||
ExitReason::Fatal(_) => Err(Error::<T>::ExitReasonFatal),
|
||||
};
|
||||
let actual_fee = executor.fee(gas_price);
|
||||
executor.deposit(source, total_fee.saturating_sub(actual_fee));
|
||||
|
||||
let (values, logs) = executor.deconstruct();
|
||||
backend.apply(values, logs, true);
|
||||
|
||||
ret.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user