-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e68b051
commit 7845ccd
Showing
24 changed files
with
1,912 additions
and
13 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ panic = "unwind" | |
members = [ | ||
"core/*", | ||
"node", | ||
"pallets/*", | ||
"precompiles/*", | ||
"runtime/*", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
[package] | ||
authors = ["Darwinia Network <[email protected]>"] | ||
description = "State storage precompiles for EVM pallet." | ||
edition = "2021" | ||
homepage = "https://darwinia.network" | ||
license = "GPL-3.0" | ||
name = "darwinia-message-transact" | ||
readme = "README.md" | ||
repository = "https://github.com/darwinia-network/darwinia" | ||
version = "6.0.0" | ||
|
||
[dependencies] | ||
# crates.io | ||
codec = { default-features = false, package = "parity-scale-codec", version = "3.2.1", features = ["derive"] } | ||
ethereum = { default-features = false, version = "0.12.0", features = ["with-codec"] } | ||
scale-info = { default-features = false, version = "2.3.0", features = ["derive"] } | ||
|
||
# frontier | ||
fp-ethereum = { default-features = false, git = "https://github.com/paritytech/frontier", branch = "polkadot-v0.9.30" } | ||
fp-evm = { default-features = false, git = "https://github.com/paritytech/frontier", branch = "polkadot-v0.9.30" } | ||
pallet-evm = { default-features = false, git = "https://github.com/paritytech/frontier", branch = "polkadot-v0.9.30" } | ||
|
||
# paritytech | ||
frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } | ||
frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } | ||
sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } | ||
sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } | ||
sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } | ||
|
||
[dev-dependencies] | ||
array-bytes = { version = "4.1" } | ||
libsecp256k1 = { version = "0.5", features = ["static-context", "hmac"] } | ||
rlp = { version = "0.5" } | ||
sha3 = { version = "0.9" } | ||
|
||
# darwinia | ||
pallet-bridge-dispatch = { git = "https://github.com/darwinia-network/darwinia-messages-substrate", branch = "polkadot-v0.9.30" } | ||
bp-message-dispatch = { git = "https://github.com/darwinia-network/darwinia-messages-substrate", branch = "polkadot-v0.9.30" } | ||
bp-runtime = { git = "https://github.com/darwinia-network/darwinia-messages-substrate", branch = "polkadot-v0.9.30" } | ||
|
||
# frontier | ||
fp-self-contained = { git = "https://github.com/paritytech/frontier", branch = "polkadot-v0.9.30" } | ||
|
||
# moonbeam | ||
precompile-utils = { git = "https://github.com/darwinia-network/moonbeam.git", branch = "polkadot-v0.9.30", features = ["testing"] } | ||
|
||
# substrate | ||
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } | ||
pallet-ethereum = { git = "https://github.com/paritytech/frontier", branch = "polkadot-v0.9.30" } | ||
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } | ||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } | ||
|
||
[features] | ||
default = ["std"] | ||
std = [ | ||
# crates.io | ||
"codec/std", | ||
"ethereum/std", | ||
"scale-info/std", | ||
|
||
# frontier | ||
"fp-evm/std", | ||
"fp-ethereum/std", | ||
"pallet-evm/std", | ||
"pallet-ethereum/std", | ||
|
||
# paritytech | ||
"frame-support/std", | ||
"frame-system/std", | ||
"sp-core/std", | ||
"sp-runtime/std", | ||
"sp-std/std", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
// This file is part of Darwinia. | ||
// | ||
// Copyright (C) 2018-2022 Darwinia Network | ||
// SPDX-License-Identifier: GPL-3.0 | ||
// | ||
// Darwinia 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. | ||
// | ||
// Darwinia 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 Darwinia. If not, see <https://www.gnu.org/licenses/>. | ||
|
||
#![cfg_attr(not(feature = "std"), no_std)] | ||
|
||
#[cfg(test)] | ||
mod mock; | ||
#[cfg(test)] | ||
mod tests; | ||
|
||
// crates.io | ||
use codec::{Decode, Encode, MaxEncodedLen}; | ||
use ethereum::TransactionV2 as Transaction; | ||
use frame_support::sp_runtime::traits::UniqueSaturatedInto; | ||
use scale_info::TypeInfo; | ||
// frontier | ||
use fp_ethereum::{TransactionData, ValidatedTransaction}; | ||
use fp_evm::{CheckEvmTransaction, CheckEvmTransactionConfig, InvalidEvmTransactionError}; | ||
use pallet_evm::{FeeCalculator, GasWeightMapping}; | ||
// substrate | ||
use frame_support::{traits::EnsureOrigin, PalletError, RuntimeDebug}; | ||
use sp_core::{H160, U256}; | ||
|
||
pub use pallet::*; | ||
|
||
#[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] | ||
pub enum LcmpEthOrigin { | ||
MessageTransact(H160), | ||
} | ||
|
||
pub fn ensure_message_transact<OuterOrigin>(o: OuterOrigin) -> Result<H160, &'static str> | ||
where | ||
OuterOrigin: Into<Result<LcmpEthOrigin, OuterOrigin>>, | ||
{ | ||
match o.into() { | ||
Ok(LcmpEthOrigin::MessageTransact(n)) => Ok(n), | ||
_ => Err("bad origin: expected to be an Lcmp Ethereum transaction"), | ||
} | ||
} | ||
|
||
pub struct EnsureLcmpEthOrigin; | ||
impl<O: Into<Result<LcmpEthOrigin, O>> + From<LcmpEthOrigin>> EnsureOrigin<O> | ||
for EnsureLcmpEthOrigin | ||
{ | ||
type Success = H160; | ||
|
||
fn try_origin(o: O) -> Result<Self::Success, O> { | ||
o.into().map(|o| match o { | ||
LcmpEthOrigin::MessageTransact(id) => id, | ||
}) | ||
} | ||
|
||
#[cfg(feature = "runtime-benchmarks")] | ||
fn successful_origin() -> O { | ||
O::from(LcmpEthOrigin::MessageTransact(Default::default())) | ||
} | ||
} | ||
|
||
#[frame_support::pallet] | ||
pub mod pallet { | ||
use super::*; | ||
use frame_support::pallet_prelude::*; | ||
use frame_system::pallet_prelude::*; | ||
|
||
#[pallet::pallet] | ||
pub struct Pallet<T>(PhantomData<T>); | ||
|
||
#[pallet::origin] | ||
pub type Origin = LcmpEthOrigin; | ||
|
||
#[pallet::config] | ||
pub trait Config: frame_system::Config + pallet_evm::Config { | ||
/// Handler for applying an already validated transaction | ||
type ValidatedTransaction: ValidatedTransaction; | ||
/// Origin for message transact | ||
type LcmpEthOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = H160>; | ||
} | ||
|
||
#[pallet::error] | ||
pub enum Error<T> { | ||
/// Evm validation errors. | ||
MessageTransactError(EvmTxErrorWrapper), | ||
} | ||
|
||
#[pallet::call] | ||
impl<T: Config> Pallet<T> | ||
where | ||
OriginFor<T>: Into<Result<LcmpEthOrigin, OriginFor<T>>>, | ||
{ | ||
/// This call can only be called by the lcmp message layer and is not available to normal | ||
/// users. | ||
#[pallet::weight({ | ||
let without_base_extrinsic_weight = true; | ||
<T as pallet_evm::Config>::GasWeightMapping::gas_to_weight({ | ||
let transaction_data: TransactionData = transaction.into(); | ||
transaction_data.gas_limit.unique_saturated_into() | ||
}, without_base_extrinsic_weight) | ||
})] | ||
pub fn message_transact( | ||
origin: OriginFor<T>, | ||
transaction: Transaction, | ||
) -> DispatchResultWithPostInfo { | ||
let source = ensure_message_transact(origin)?; | ||
let (who, _) = pallet_evm::Pallet::<T>::account_basic(&source); | ||
let base_fee = T::FeeCalculator::min_gas_price().0; | ||
|
||
let mut transaction_mut = transaction; | ||
match transaction_mut { | ||
Transaction::Legacy(ref mut tx) => { | ||
tx.nonce = who.nonce; | ||
tx.gas_price = base_fee; | ||
}, | ||
Transaction::EIP2930(ref mut tx) => { | ||
tx.nonce = who.nonce; | ||
tx.gas_price = base_fee; | ||
}, | ||
Transaction::EIP1559(ref mut tx) => { | ||
tx.nonce = who.nonce; | ||
tx.max_fee_per_gas = base_fee; | ||
tx.max_priority_fee_per_gas = U256::zero(); | ||
}, | ||
}; | ||
|
||
let transaction_data: TransactionData = (&transaction_mut).into(); | ||
let _ = CheckEvmTransaction::<EvmTxErrorWrapper>::new( | ||
CheckEvmTransactionConfig { | ||
evm_config: T::config(), | ||
block_gas_limit: T::BlockGasLimit::get(), | ||
base_fee, | ||
chain_id: T::ChainId::get(), | ||
is_transactional: true, | ||
}, | ||
transaction_data.clone().into(), | ||
) | ||
.validate_in_block_for(&who) | ||
.and_then(|v| v.with_chain_id()) | ||
.and_then(|v| v.with_base_fee()) | ||
.and_then(|v| v.with_balance_for(&who)) | ||
.map_err(|e| <Error<T>>::MessageTransactError(e))?; | ||
|
||
T::ValidatedTransaction::apply(source, transaction_mut) | ||
} | ||
} | ||
} | ||
|
||
#[derive(Encode, Decode, TypeInfo, PalletError)] | ||
pub enum EvmTxErrorWrapper { | ||
GasLimitTooLow, | ||
GasLimitTooHigh, | ||
GasPriceTooLow, | ||
PriorityFeeTooHigh, | ||
BalanceTooLow, | ||
TxNonceTooLow, | ||
TxNonceTooHigh, | ||
InvalidPaymentInput, | ||
InvalidChainId, | ||
} | ||
|
||
impl From<InvalidEvmTransactionError> for EvmTxErrorWrapper { | ||
fn from(validation_error: InvalidEvmTransactionError) -> Self { | ||
match validation_error { | ||
InvalidEvmTransactionError::GasLimitTooLow => EvmTxErrorWrapper::GasLimitTooLow, | ||
InvalidEvmTransactionError::GasLimitTooHigh => EvmTxErrorWrapper::GasLimitTooHigh, | ||
InvalidEvmTransactionError::GasPriceTooLow => EvmTxErrorWrapper::GasPriceTooLow, | ||
InvalidEvmTransactionError::PriorityFeeTooHigh => EvmTxErrorWrapper::PriorityFeeTooHigh, | ||
InvalidEvmTransactionError::BalanceTooLow => EvmTxErrorWrapper::BalanceTooLow, | ||
InvalidEvmTransactionError::TxNonceTooLow => EvmTxErrorWrapper::TxNonceTooLow, | ||
InvalidEvmTransactionError::TxNonceTooHigh => EvmTxErrorWrapper::TxNonceTooHigh, | ||
InvalidEvmTransactionError::InvalidPaymentInput => | ||
EvmTxErrorWrapper::InvalidPaymentInput, | ||
InvalidEvmTransactionError::InvalidChainId => EvmTxErrorWrapper::InvalidChainId, | ||
} | ||
} | ||
} | ||
|
||
/// Calculates the fee for a relayer to submit an LCMP Evm transaction. | ||
/// | ||
/// The gas_price of an LCMP Evm transaction is always the min_gas_price(), which is a fixed value. | ||
/// Therefore, only the gas_limit and value of the transaction should be considered in the | ||
/// calculation of the fee, and the gas_price of the transaction itself can be ignored. | ||
pub fn total_payment<T: pallet_evm::Config>(tx_data: TransactionData) -> U256 { | ||
let base_fee = <T as pallet_evm::Config>::FeeCalculator::min_gas_price().0; | ||
let fee = base_fee.saturating_mul(tx_data.gas_limit); | ||
|
||
tx_data.value.saturating_add(fee) | ||
} |
Oops, something went wrong.