mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 07:41:08 +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:
Generated
+8
-8
@@ -1235,9 +1235,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "evm"
|
||||
version = "0.14.2"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73f887b371f9999682ccc5b1cb771e7d4408ae61e93fc0343ceaeb761fca42d1"
|
||||
checksum = "272f65e18a2b6449b682bfcdf6c3ccc63db0b93898d89c0fb237548bbfc764a5"
|
||||
dependencies = [
|
||||
"evm-core",
|
||||
"evm-gasometer",
|
||||
@@ -1250,18 +1250,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "evm-core"
|
||||
version = "0.14.0"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3bcde5af3d542874ddeb53de0919302d57586ea04b3f76f54d865f8a6cdc70ae"
|
||||
checksum = "66534d42e13d50f9101bed87cb568fd5aa929c600c3c13f8dadbbf39f5635945"
|
||||
dependencies = [
|
||||
"primitive-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "evm-gasometer"
|
||||
version = "0.14.0"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b82bc9f275cb59d2bcc05d85c98736ddfaba003a7ef7b73893fa7c1c1fab29dc"
|
||||
checksum = "39bc5b592803ca644781fe2290b7305ea5182f7c9516d615ddfb2308c2cab639"
|
||||
dependencies = [
|
||||
"evm-core",
|
||||
"evm-runtime",
|
||||
@@ -1270,9 +1270,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "evm-runtime"
|
||||
version = "0.14.1"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dbbc89d29618c3722c17ba78ddf432d40ace8ee27e3f8b28b52a85921112e4b"
|
||||
checksum = "389e4b447fb26971a9c76c8aa49c0ab435f8e46e8fc46e1bc4ebf01f3c2b428f"
|
||||
dependencies = [
|
||||
"evm-core",
|
||||
"primitive-types",
|
||||
|
||||
@@ -82,8 +82,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
// and set impl_version to 0. If only runtime
|
||||
// implementation changes and behavior does not, then leave spec_version as
|
||||
// is and increment impl_version.
|
||||
spec_version: 216,
|
||||
impl_version: 3,
|
||||
spec_version: 217,
|
||||
impl_version: 0,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ sp-std = { version = "2.0.0", default-features = false, path = "../../primitives
|
||||
sp-io = { version = "2.0.0", default-features = false, path = "../../primitives/io" }
|
||||
primitive-types = { version = "0.6.2", default-features = false, features = ["rlp"] }
|
||||
rlp = { version = "0.4", default-features = false }
|
||||
evm = { version = "0.14", default-features = false }
|
||||
evm = { version = "0.15", default-features = false }
|
||||
sha3 = { version = "0.8", default-features = false }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -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