Skip to content

Commit

Permalink
move check_nonce to pallet-evm-nonce-tracker
Browse files Browse the repository at this point in the history
  • Loading branch information
vedhavyas committed Apr 30, 2024
1 parent 1bad28c commit 65d6a64
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 166 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions domains/pallets/evm_nonce_tracker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ frame-support = { default-features = false, git = "https://github.com/subspace/p
frame-system = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "44d742b90e7852aed1f08ab5299d5d88cfa1c6ed" }
scale-info = { version = "2.11.1", default-features = false, features = ["derive"] }
sp-core = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "44d742b90e7852aed1f08ab5299d5d88cfa1c6ed" }
sp-runtime = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "44d742b90e7852aed1f08ab5299d5d88cfa1c6ed" }

[features]
default = ["std"]
Expand All @@ -27,4 +28,5 @@ std = [
"frame-system/std",
"scale-info/std",
"sp-core/std",
"sp-runtime/std",
]
Original file line number Diff line number Diff line change
@@ -1,44 +1,53 @@
use crate::{AccountId, EVMNoncetracker, Runtime, RuntimeCall};
use crate::Config;
#[cfg(not(feature = "std"))]
use alloc::fmt;
#[cfg(not(feature = "std"))]
use alloc::vec;
use codec::{Decode, Encode};
use domain_runtime_primitives::Nonce;
use core::cmp::max;
use core::result::Result;
use frame_support::dispatch::DispatchInfo;
use frame_support::pallet_prelude::{
InvalidTransaction, TransactionLongevity, TransactionValidity, TransactionValidityError,
TypeInfo, ValidTransaction,
};
use frame_support::sp_runtime::traits::{DispatchInfoOf, One, SignedExtension, Zero};
use sp_core::{H160, U256};
use sp_std::cmp::max;
use sp_std::vec;
use frame_support::sp_runtime::traits::{DispatchInfoOf, One, SignedExtension};
use sp_runtime::traits::{Dispatchable, Zero};
#[cfg(feature = "std")]
use std::fmt;
#[cfg(feature = "std")]
use std::vec;

/// Check nonce is a fork of frame_system::CheckNonce with change to pre_dispatch function
/// where this fork uses EVMNonceTracker to track the nonce since EVM pre_dispatch does not
/// increment the nonce unlike the Substrate pre_dispatch
#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub struct CheckNonce(#[codec(compact)] pub Nonce);
#[scale_info(skip_type_params(T))]
pub struct CheckNonce<T: Config>(#[codec(compact)] pub T::Nonce);

impl CheckNonce {
impl<T: Config> CheckNonce<T> {
/// utility constructor. Used only in client/factory code.
pub fn from(nonce: Nonce) -> Self {
pub fn from(nonce: T::Nonce) -> Self {
Self(nonce)
}
}

impl sp_std::fmt::Debug for CheckNonce {
impl<T: Config> fmt::Debug for CheckNonce<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "CheckNonce({})", self.0)
}

#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}

impl SignedExtension for CheckNonce {
impl<T: Config> SignedExtension for CheckNonce<T>
where
T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
{
const IDENTIFIER: &'static str = "CheckNonce";
type AccountId = AccountId;
type Call = RuntimeCall;
type AccountId = T::AccountId;
type Call = T::RuntimeCall;
type AdditionalSigned = ();
type Pre = ();

Expand All @@ -53,7 +62,7 @@ impl SignedExtension for CheckNonce {
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> TransactionValidity {
let account = frame_system::Account::<Runtime>::get(who);
let account = frame_system::Account::<T>::get(who);
if account.providers.is_zero() && account.sufficients.is_zero() {
// Nonce storage not paid for
return InvalidTransaction::Payment.into();
Expand All @@ -64,7 +73,7 @@ impl SignedExtension for CheckNonce {

let provides = vec![Encode::encode(&(who, self.0))];
let requires = if account.nonce < self.0 {
vec![Encode::encode(&(who, self.0 - Nonce::one()))]
vec![Encode::encode(&(who, self.0 - One::one()))]
} else {
vec![]
};
Expand All @@ -85,24 +94,21 @@ impl SignedExtension for CheckNonce {
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> Result<(), TransactionValidityError> {
let mut account = frame_system::Account::<Runtime>::get(who);
let mut account = frame_system::Account::<T>::get(who);
if account.providers.is_zero() && account.sufficients.is_zero() {
// Nonce storage not paid for
return Err(InvalidTransaction::Payment.into());
}

// if a sender sends an evm transaction first and substrate transaction
// after with same nonce, then reject the second transaction
// if sender reverse the transaction types, substrate first and evm second,
// evm transaction will be rejected, since substrate updates nonce in pre_dispatch.
let account_nonce =
if let Some(tracked_nonce) = EVMNoncetracker::account_nonce(H160::from(*who)) {
let account_nonce = U256::from(account.nonce);
let current_nonce = max(tracked_nonce, account_nonce);
current_nonce.as_u32()
} else {
account.nonce
};
let account_nonce = if let Some(tracked_nonce) = crate::AccountNonce::<T>::get(who.clone())
{
max(tracked_nonce.as_u32().into(), account.nonce)
} else {
account.nonce
};

if self.0 != account_nonce {
return Err(if self.0 < account.nonce {
Expand All @@ -112,8 +118,8 @@ impl SignedExtension for CheckNonce {
}
.into());
}
account.nonce += Nonce::one();
frame_system::Account::<Runtime>::insert(who, account);
account.nonce += T::Nonce::one();
frame_system::Account::<T>::insert(who, account);
Ok(())
}
}
16 changes: 11 additions & 5 deletions domains/pallets/evm_nonce_tracker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,19 @@
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(not(feature = "std"))]
extern crate alloc;

mod check_nonce;
pub use check_nonce::CheckNonce;
pub use pallet::*;
use sp_core::{H160, U256};
use sp_core::U256;

#[frame_support::pallet]
mod pallet {
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::BlockNumberFor;
use sp_core::{H160, U256};
use sp_core::U256;

#[pallet::config]
pub trait Config: frame_system::Config {}
Expand All @@ -33,7 +38,8 @@ mod pallet {
/// This is only used for pre_dispatch since EVM pre_dispatch does not
/// increment account nonce.
#[pallet::storage]
pub(super) type AccountNonce<T> = StorageMap<_, Identity, H160, U256, OptionQuery>;
pub(super) type AccountNonce<T: Config> =
StorageMap<_, Identity, T::AccountId, U256, OptionQuery>;

/// Pallet EVM account nonce tracker.
#[pallet::pallet]
Expand All @@ -52,12 +58,12 @@ mod pallet {

impl<T: Config> Pallet<T> {
/// Returns current nonce for the given account.
pub fn account_nonce(account: H160) -> Option<U256> {
pub fn account_nonce(account: T::AccountId) -> Option<U256> {
AccountNonce::<T>::get(account)
}

/// Set nonce to the account.
pub fn set_account_nonce(account: H160, nonce: U256) {
pub fn set_account_nonce(account: T::AccountId, nonce: U256) {
AccountNonce::<T>::set(account, Some(nonce))
}
}
10 changes: 5 additions & 5 deletions domains/runtime/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit = "256"]

mod check_nonce;
mod precompiles;

// Make the WASM binary available.
Expand Down Expand Up @@ -127,7 +126,7 @@ type CustomSignedExtra = (
frame_system::CheckTxVersion<Runtime>,
frame_system::CheckGenesis<Runtime>,
frame_system::CheckMortality<Runtime>,
check_nonce::CheckNonce,
pallet_evm_nonce_tracker::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
);
Expand Down Expand Up @@ -887,7 +886,8 @@ fn pre_dispatch_evm_transaction(
// pick the highest nonce
let account_nonce = {
let tracked_nonce =
EVMNoncetracker::account_nonce(account_id).unwrap_or(U256::zero());
EVMNoncetracker::account_nonce(AccountId::from(account_id))
.unwrap_or(U256::zero());
let account_nonce = EVM::account_basic(&account_id).0.nonce;
max(tracked_nonce, account_nonce)
};
Expand All @@ -902,7 +902,7 @@ fn pre_dispatch_evm_transaction(
.checked_add(U256::one())
.ok_or(InvalidTransaction::Custom(ERR_NONCE_OVERFLOW))?;

EVMNoncetracker::set_account_nonce(account_id, next_nonce);
EVMNoncetracker::set_account_nonce(AccountId::from(account_id), next_nonce);
}
}

Expand Down Expand Up @@ -939,7 +939,7 @@ fn check_transaction_and_do_pre_dispatch_inner(
extra.2,
extra.3,
extra.4,
check_nonce::CheckNonce::from(extra.5 .0),
pallet_evm_nonce_tracker::CheckNonce::from(extra.5 .0),
extra.6,
extra.7,
);
Expand Down
119 changes: 0 additions & 119 deletions domains/test/runtime/evm/src/check_nonce.rs

This file was deleted.

Loading

0 comments on commit 65d6a64

Please sign in to comment.