CVE-2021-41138: Improper Input Validation (CWE-20)
value: Frontier is Substrate's Ethereum compatibility layer. In the newly introduced signed Frontier-specific extrinsic for `pallet-ethereum`, a large part of transaction validation logic was only called in transaction pool validation, but not in block execution. Malicious validators can take advantage of this to put invalid transactions into a block. The attack is limited in that the signature is always validated, and the majority of the validation is done again in the subsequent `pallet-evm` execution logic. However, do note that a chain ID replay attack was possible. In addition, spamming attacks are of main concerns, while they are limited by Substrate block size limits and other factors. The issue is patched in commit `146bb48849e5393004be5c88beefe76fdf009aba`.
CWE description: The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
CVSS v3 base score: 5.3
Published: 2021-10-13T16:15Z
Repository: https://github.com/paritytech/frontier
Language: Rust
Files changed: frame/ethereum/src/lib.rs, frame/ethereum/src/mock.rs, frame/ethereum/src/tests.rs, primitives/self-contained/src/checked_extrinsic.rs, primitives/self-contained/src/lib.rs, template/runtime/src/lib.rs
Commit date: 2021-10-13 14:48:35 +0200
Commit message: Fix security issue: transaction validity controls must be executed in STF (#495)

* add security tests

* add pre_dispatch phase to fiy security issues

* Revert frame-evm changes

* keeping *_self_contained aligned

* remove unused default impl
Diff: diff --git a/frame/ethereum/src/lib.rs b/frame/ethereum/src/lib.rs
index 5c96f9a..82f4727 100644
--- a/frame/ethereum/src/lib.rs
+++ b/frame/ethereum/src/lib.rs
@@ -116,82 +116,30 @@ where
 		} else {
 			None
 		}
 	}
 
-	pub fn validate_self_contained(&self, origin: &H160) -> Option<TransactionValidity> {
+	pub fn pre_dispatch_self_contained(
+		&self,
+		origin: &H160,
+	) -> Option<Result<(), TransactionValidityError>> {
 		if let Call::transact(transaction) = self {
-			let validate = || {
-				// We must ensure a transaction can pay the cost of its data bytes.
-				// If it can't it should not be included in a block.
-				let mut gasometer = evm::gasometer::Gasometer::new(
-					transaction.gas_limit.low_u64(),
-					<T as pallet_evm::Config>::config(),
-				);
-				let transaction_cost = match transaction.action {
-					TransactionAction::Call(_) => {
-						evm::gasometer::call_transaction_cost(&transaction.input)
-					}
-					TransactionAction::Create => {
-						evm::gasometer::create_transaction_cost(&transaction.input)
-					}
-				};
-				if gasometer.record_transaction(transaction_cost).is_err() {
-					return InvalidTransaction::Custom(
-						TransactionValidationError::InvalidGasLimit as u8,
-					)
-					.into();
-				}
-
-				if let Some(chain_id) = transaction.signature.chain_id() {
-					if chain_id != T::ChainId::get() {
-						return InvalidTransaction::Custom(
-							TransactionValidationError::InvalidChainId as u8,
-						)
-						.into();
-					}
-				}
-
-				if transaction.gas_limit >= T::BlockGasLimit::get() {
-					return InvalidTransaction::Custom(
-						TransactionValidationError::InvalidGasLimit as u8,
-					)
-					.into();
-				}
-
-				let account_data = pallet_evm::Pallet::<T>::account_basic(&origin);
-
-				if transaction.nonce < account_data.nonce {
-					return InvalidTransaction::Stale.into();
-				}
-
-				let fee = transaction.gas_price.saturating_mul(transaction.gas_limit);
-				let total_payment = transaction.value.saturating_add(fee);
-				if account_data.balance < total_payment {
-					return InvalidTransaction::Payment.into();
-				}
-
-				let min_gas_price = T::FeeCalculator::min_gas_price();
-
-				if transaction.gas_price < min_gas_price {
-					return InvalidTransaction::Payment.into();
-				}
-
-				let mut builder = ValidTransactionBuilder::default()
-					.and_provides((origin, transaction.nonce))
-					.priority(transaction.gas_price.unique_saturated_into());
-
-				if transaction.nonce > account_data.nonce {
-					if let Some(prev_nonce) = transaction.nonce.checked_sub(1.into()) {
-						builder = builder.and_requires((origin, prev_nonce))
-					}
-				}
-
-				builder.build()
-			};
+			Some(Pallet::<T>::validate_transaction_in_block(
+				*origin,
+				&transaction,
+			))
+		} else {
+			None
+		}
+	}
 
-			Some(validate())
+	pub fn validate_self_contained(&self, origin: &H160) -> Option<TransactionValidity> {
+		if let Call::transact(transaction) = self {
+			Some(Pallet::<T>::validate_transaction_in_pool(
+				*origin,
+				transaction,
+			))
 		} else {
 			None
 		}
 	}
 }
@@ -257,13 +205,16 @@ pub mod pallet {
 				for transaction in block.transactions {
 					let source = Self::recover_signer(&transaction).expect(
 						"pre-block transaction signature invalid; the block cannot be built",
 					);
 
-					Self::do_transact(source, transaction).expect(
+					Self::validate_transaction_in_block(source, &transaction).expect(
 						"pre-block transaction verification failed; the block cannot be built",
 					);
+					Self::apply_validated_transaction(source, transaction).expect(
+						"pre-block transaction execution failed; the block cannot be built",
+					);
 				}
 			}
 
 			0
 		}
@@ -285,11 +236,11 @@ pub mod pallet {
 			ensure!(
 				fp_consensus::find_pre_log(&frame_system::Pallet::<T>::digest()).is_err(),
 				Error::<T>::PreLogExists,
 			);
 
-			Self::do_transact(source, transaction)
+			Self::apply_validated_transaction(source, transaction)
 		}
 	}
 
 	#[pallet::event]
 	#[pallet::generate_deposit(pub(super) fn deposit_event)]
@@ -416,11 +367,102 @@ impl<T: Config> Pallet<T> {
 				bloom.accrue(BloomInput::Raw(&topic[..]));
 			}
 		}
 	}
 
-	fn do_transact(source: H160, transaction: Transaction) -> DispatchResultWithPostInfo {
+	// Common controls to be performed in the same way by the pool and the
+	// State Transition Function (STF).
+	// This is the case for all controls except those concerning the nonce.
+	fn validate_transaction_common(
+		origin: H160,
+		transaction: &Transaction,
+	) -> Result<U256, TransactionValidityError> {
+		// We must ensure a transaction can pay the cost of its data bytes.
+		// If it can't it should not be included in a block.
+		let mut gasometer = evm::gasometer::Gasometer::new(
+			transaction.gas_limit.low_u64(),
+			<T as pallet_evm::Config>::config(),
+		);
+		let transaction_cost = match transaction.action {
+			TransactionAction::Call(_) => evm::gasometer::call_transaction_cost(&transaction.input),
+			TransactionAction::Create => {
+				evm::gasometer::create_transaction_cost(&transaction.input)
+			}
+		};
+		if gasometer.record_transaction(transaction_cost).is_err() {
+			return Err(InvalidTransaction::Custom(
+				TransactionValidationError::InvalidGasLimit as u8,
+			)
+			.into());
+		}
+
+		if let Some(chain_id) = transaction.signature.chain_id() {
+			if chain_id != T::ChainId::get() {
+				return Err(InvalidTransaction::Custom(
+					TransactionValidationError::InvalidChainId as u8,
+				)
+				.into());
+			}
+		}
+
+		if transaction.gas_limit >= T::BlockGasLimit::get() {
+			return Err(InvalidTransaction::Custom(
+				TransactionValidationError::InvalidGasLimit as u8,
+			)
+			.into());
+		}
+
+		let account_data = pallet_evm::Pallet::<T>::account_basic(&origin);
+
+		let fee = transaction.gas_price.saturating_mul(transaction.gas_limit);
+		let total_payment = transaction.value.saturating_add(fee);
+		if account_data.balance < total_payment {
+			return Err(InvalidTransaction::Payment.into());
+		}
+
+		let min_gas_price = T::FeeCalculator::min_gas_price();
+
+		if transaction.gas_price < min_gas_price {
+			return Err(InvalidTransaction::Payment.into());
+		}
+
+		Ok(account_data.nonce)
+	}
+
+	// Controls that must be performed by the pool.
+	// The controls common with the State Transition Function (STF) are in
+	// the function `validate_transaction_common`.
+	fn validate_transaction_in_pool(
+		origin: H160,
+		transaction: &Transaction,
+	) -> TransactionValidity {
+		let account_nonce = Self::validate_transaction_common(origin, transaction)?;
+
+		if transaction.nonce < account_nonce {
+			return Err(InvalidTransaction::Stale.into());
+		}
+
+		// The tag provides and requires must be filled correctly according to the nonce.
+		let mut builder = ValidTransactionBuilder::default()
+			.and_provides((origin, transaction.nonce))
+			.priority(transaction.gas_price.unique_saturated_into());
+
+		// In the context of the pool, a transaction with
+		// too high a nonce is still considered valid
+		if transaction.nonce > account_nonce {
+			if let Some(prev_nonce) = transaction.nonce.checked_sub(1.into()) {
+				builder = builder.and_requires((origin, prev_nonce))
+			}
+		}
+
+		builder.build()
+	}
+
+	fn apply_validated_transaction(
+		source: H160,
+		transaction: Transaction,
+	) -> DispatchResultWithPostInfo {
 		let transaction_hash =
 			H256::from_slice(Keccak256::digest(&rlp::encode(&transaction)).as_slice());
 		let transaction_index = Pending::<T>::get().len() as u32;
 
 		let (to, _, info) = Self::execute(
@@ -563,10 +605,33 @@ impl<T: Config> Pallet<T> {
 
 				Ok((None, Some(res.value), CallOrCreateInfo::Create(res)))
 			}
 		}
 	}
+
+	/// Validate an Ethereum transaction already in block
+	///
+	/// This function must be called during the pre-dispatch phase
+	/// (just before applying the extrinsic).
+	pub fn validate_transaction_in_block(
+		origin: H160,
+		transaction: &ethereum::TransactionV0,
+	) -> Result<(), TransactionValidityError> {
+		let account_nonce = Self::validate_transaction_common(origin, transaction)?;
+
+		// In the context of the block, a transaction with a nonce that is
+		// too high should be considered invalid and make the whole block invalid.
+		if transaction.nonce > account_nonce {
+			Err(TransactionValidityError::Invalid(
+				InvalidTransaction::Future,
+			))
+		} else if transaction.nonce < account_nonce {
+			Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))
+		} else {
+			Ok(())
+		}
+	}
 }
 
 #[derive(Eq, PartialEq, Clone, sp_runtime::RuntimeDebug)]
 pub enum ReturnValue {
 	Bytes(Vec<u8>),
diff --git a/frame/ethereum/src/mock.rs b/frame/ethereum/src/mock.rs
index 5956762..5a8a385 100644
--- a/frame/ethereum/src/mock.rs
+++ b/frame/ethereum/src/mock.rs
@@ -17,23 +17,26 @@
 
 //! Test utilities
 
 use super::*;
 use crate::IntermediateStateRoot;
+use codec::{WrapperTypeDecode, WrapperTypeEncode};
 use ethereum::{TransactionAction, TransactionSignature};
 use frame_support::{parameter_types, traits::FindAuthor, ConsensusEngineId, PalletId};
 use pallet_evm::{AddressMapping, EnsureAddressTruncated, FeeCalculator};
 use rlp::*;
 use sha3::Digest;
 use sp_core::{H160, H256, U256};
 use sp_runtime::{
 	testing::Header,
-	traits::{BlakeTwo256, IdentityLookup},
+	traits::{BlakeTwo256, IdentityLookup, SignedExtension},
 	AccountId32,
 };
 
-type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
+pub type SignedExtra = (frame_system::CheckSpecVersion<Test>,);
+
+type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test, (), SignedExtra>;
 type Block = frame_system::mocking::MockBlock<Test>;
 
 frame_support::construct_runtime! {
 	pub enum Test where
 		Block = Block,
@@ -164,10 +167,58 @@ impl pallet_evm::Config for Test {
 impl crate::Config for Test {
 	type Event = Event;
 	type StateRoot = IntermediateStateRoot;
 }
 
+impl fp_self_contained::SelfContainedCall for Call {
+	type SignedInfo = H160;
+
+	fn is_self_contained(&self) -> bool {
+		match self {
+			Call::Ethereum(call) => call.is_self_contained(),
+			_ => false,
+		}
+	}
+
+	fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
+		match self {
+			Call::Ethereum(call) => call.check_self_contained(),
+			_ => None,
+		}
+	}
+
+	fn validate_self_contained(&self, info: &Self::SignedInfo) -> Option<TransactionValidity> {
+		match self {
+			Call::Ethereum(call) => call.validate_self_contained(info),
+			_ => None,
+		}
+	}
+
+	fn pre_dispatch_self_contained(
+		&self,
+		info: &Self::SignedInfo,
+	) -> Option<Result<(), TransactionValidityError>> {
+		match self {
+			Call::Ethereum(call) => call.pre_dispatch_self_contained(info),
+			_ => None,
+		}
+	}
+
+	fn apply_self_contained(
+		self,
+		info: Self::SignedInfo,
+	) -> Option<sp_runtime::DispatchResultWithInfo<sp_runtime::traits::PostDispatchInfoOf<Self>>> {
+		use sp_runtime::traits::Dispatchable as _;
+		match self {
+			call @ Call::Ethereum(crate::Call::transact(_)) => {
+				Some(call.dispatch(Origin::from(crate::RawOrigin::EthereumTransaction(info))))
+			}
+			_ => None,
+		}
+	}
+}
+
 pub struct AccountInfo {
 	pub address: H160,
 	pub account_id: AccountId32,
 	pub private_key: H256,
 }
@@ -253,20 +304,24 @@ impl UnsignedTransaction {
 		self.signing_rlp_append(&mut stream);
 		H256::from_slice(&Keccak256::digest(&stream.out()).as_slice())
 	}
 
 	pub fn sign(&self, key: &H256) -> Transaction {
+		self.sign_with_chain_id(key, ChainId::get())
+	}
+
+	pub fn sign_with_chain_id(&self, key: &H256, chain_id: u64) -> Transaction {
 		let hash = self.signing_hash();
 		let msg = libsecp256k1::Message::parse(hash.as_fixed_bytes());
 		let s = libsecp256k1::sign(
 			&msg,
 			&libsecp256k1::SecretKey::parse_slice(&key[..]).unwrap(),
 		);
 		let sig = s.0.serialize();
 
 		let sig = TransactionSignature::new(
-			s.1.serialize() as u64 % 2 + ChainId::get() * 2 + 35,
+			s.1.serialize() as u64 % 2 + chain_id * 2 + 35,
 			H256::from_slice(&sig[0..32]),
 			H256::from_slice(&sig[32..64]),
 		)
 		.unwrap();
 
diff --git a/frame/ethereum/src/tests.rs b/frame/ethereum/src/tests.rs
index b1aafcd..b793c7e 100644
--- a/frame/ethereum/src/tests.rs
+++ b/frame/ethereum/src/tests.rs
@@ -16,17 +16,22 @@
 // limitations under the License.
 
 //! Consensus extension module tests for BABE consensus.
 
 use crate::{
-	mock::*, CallOrCreateInfo, Error, RawOrigin, Transaction, TransactionAction,
-	ValidTransactionBuilder, H160, H256, U256,
+	mock::*, CallOrCreateInfo, Error, RawOrigin, Transaction, TransactionAction, H160, H256, U256,
 };
 use ethereum::TransactionSignature;
-use frame_support::{assert_err, assert_noop, assert_ok, unsigned::ValidateUnsigned};
+use frame_support::{
+	assert_err, assert_noop, assert_ok,
+	unsigned::{TransactionValidityError, ValidateUnsigned},
+};
 use rustc_hex::{FromHex, ToHex};
-use sp_runtime::transaction_validity::{InvalidTransaction, TransactionSource};
+use sp_runtime::traits::Applyable;
+use sp_runtime::transaction_validity::{
+	InvalidTransaction, TransactionSource, ValidTransactionBuilder,
+};
 use std::str::FromStr;
 
 // This ERC-20 contract mints the maximum amount of tokens to the contract creator.
 // pragma solidity ^0.5.0;`
 // import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/token/ERC20/ERC20.sol";
@@ -89,11 +94,11 @@ fn transaction_without_enough_gas_should_not_work() {
 		);
 	});
 }
 
 #[test]
-fn transaction_with_invalid_nonce_should_not_work() {
+fn transaction_with_to_low_nonce_should_not_work() {
 	let (pairs, mut ext) = new_test_ext(1);
 	let alice = &pairs[0];
 
 	ext.execute_with(|| {
 		// nonce is 0
@@ -138,10 +143,61 @@ fn transaction_with_invalid_nonce_should_not_work() {
 			InvalidTransaction::Stale
 		);
 	});
 }
 
+#[test]
+fn transaction_with_to_hight_nonce_should_fail_in_block() {
+	let (pairs, mut ext) = new_test_ext(1);
+	let alice = &pairs[0];
+
+	ext.execute_with(|| {
+		let mut transaction = default_erc20_creation_unsigned_transaction();
+		transaction.nonce = U256::one();
+
+		let signed = transaction.sign(&alice.private_key);
+		let call = crate::Call::<Test>::transact(signed);
+		let source = call.check_self_contained().unwrap().unwrap();
+		let extrinsic = fp_self_contained::CheckedExtrinsic::<_, _, SignedExtra, _> {
+			signed: fp_self_contained::CheckedSignature::SelfContained(source),
+			function: Call::Ethereum(call),
+		};
+		use frame_support::weights::GetDispatchInfo as _;
+		let dispatch_info = extrinsic.get_dispatch_info();
+		assert_err!(
+			extrinsic.apply::<Test>(&dispatch_info, 0),
+			TransactionValidityError::Invalid(InvalidTransaction::Future)
+		);
+	});
+}
+
+#[test]
+fn transaction_with_invalid_chain_id_should_fail_in_block() {
+	let (pairs, mut ext) = new_test_ext(1);
+	let alice = &pairs[0];
+
+	ext.execute_with(|| {
+		let transaction =
+			default_erc20_creation_unsigned_transaction().sign_with_chain_id(&alice.private_key, 1);
+
+		let call = crate::Call::<Test>::transact(transaction);
+		let source = call.check_self_contained().unwrap().unwrap();
+		let extrinsic = fp_self_contained::CheckedExtrinsic::<_, _, SignedExtra, _> {
+			signed: fp_self_contained::CheckedSignature::SelfContained(source),
+			function: Call::Ethereum(call),
+		};
+		use frame_support::weights::GetDispatchInfo as _;
+		let dispatch_info = extrinsic.get_dispatch_info();
+		assert_err!(
+			extrinsic.apply::<Test>(&dispatch_info, 0),
+			TransactionValidityError::Invalid(InvalidTransaction::Custom(
+				crate::TransactionValidationError::InvalidChainId as u8,
+			))
+		);
+	});
+}
+
 #[test]
 fn contract_constructor_should_get_executed() {
 	let (pairs, mut ext) = new_test_ext(1);
 	let alice = &pairs[0];
 	let erc20_address = contract_address(alice.address, 0);
diff --git a/primitives/self-contained/src/checked_extrinsic.rs b/primitives/self-contained/src/checked_extrinsic.rs
index e0ecebf..41a66c6 100644
--- a/primitives/self-contained/src/checked_extrinsic.rs
+++ b/primitives/self-contained/src/checked_extrinsic.rs
@@ -133,10 +133,16 @@ where
 					&res.map(|_| ()).map_err(|e| e.error),
 				)?;
 				Ok(res)
 			}
 			CheckedSignature::SelfContained(signed_info) => {
+				// If pre-dispatch fail, the block must be considered invalid
+				self.function
+					.pre_dispatch_self_contained(&signed_info)
+					.ok_or(TransactionValidityError::Invalid(
+						InvalidTransaction::BadProof,
+					))??;
 				Ok(self.function.apply_self_contained(signed_info).ok_or(
 					TransactionValidityError::Invalid(InvalidTransaction::BadProof),
 				)?)
 			}
 		}
diff --git a/primitives/self-contained/src/lib.rs b/primitives/self-contained/src/lib.rs
index 82aebb7..62cca45 100644
--- a/primitives/self-contained/src/lib.rs
+++ b/primitives/self-contained/src/lib.rs
@@ -42,10 +42,24 @@ pub trait SelfContainedCall: Dispatchable {
 	/// if the function is not a self-contained.
 	fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>>;
 	/// Validate a self-contained function. Returns `None` if the
 	/// function is not a self-contained.
 	fn validate_self_contained(&self, info: &Self::SignedInfo) -> Option<TransactionValidity>;
+	/// Do any pre-flight stuff for a self-contained call.
+	///
+	/// Note this function by default delegates to `validate_self_contained`, so that
+	/// all checks performed for the transaction queue are also performed during
+	/// the dispatch phase (applying the extrinsic).
+	///
+	/// If you ever override this function, you need to make sure to always
+	/// perform the same validation as in `validate_self_contained`.
+	///
+	/// Returns `None` if the function is not a self-contained.
+	fn pre_dispatch_self_contained(
+		&self,
+		info: &Self::SignedInfo,
+	) -> Option<Result<(), TransactionValidityError>>;
 	/// Apply a self-contained function. Returns `None` if the
 	/// function is not a self-contained.
 	fn apply_self_contained(
 		self,
 		info: Self::SignedInfo,
diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs
index 2d8d9b0..209a35c 100644
--- a/template/runtime/src/lib.rs
+++ b/template/runtime/src/lib.rs
@@ -438,10 +438,20 @@ impl fp_self_contained::SelfContainedCall for Call {
 			Call::Ethereum(call) => call.validate_self_contained(info),
 			_ => None,
 		}
 	}
 
+	fn pre_dispatch_self_contained(
+		&self,
+		info: &Self::SignedInfo,
+	) -> Option<Result<(), TransactionValidityError>> {
+		match self {
+			Call::Ethereum(call) => call.pre_dispatch_self_contained(info),
+			_ => None,
+		}
+	}
+
 	fn apply_self_contained(
 		self,
 		info: Self::SignedInfo,
 	) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
 		match self {

Vulnerable code: 	pub fn validate_self_contained(&self, origin: &H160) -> Option<TransactionValidity> {
			let validate = || {
				// We must ensure a transaction can pay the cost of its data bytes.
				// If it can't it should not be included in a block.
				let mut gasometer = evm::gasometer::Gasometer::new(
					transaction.gas_limit.low_u64(),
					<T as pallet_evm::Config>::config(),
				);
				let transaction_cost = match transaction.action {
					TransactionAction::Call(_) => {
						evm::gasometer::call_transaction_cost(&transaction.input)
					}
					TransactionAction::Create => {
						evm::gasometer::create_transaction_cost(&transaction.input)
					}
				};
				if gasometer.record_transaction(transaction_cost).is_err() {
					return InvalidTransaction::Custom(
						TransactionValidationError::InvalidGasLimit as u8,
					)
					.into();
				}

				if let Some(chain_id) = transaction.signature.chain_id() {
					if chain_id != T::ChainId::get() {
						return InvalidTransaction::Custom(
							TransactionValidationError::InvalidChainId as u8,
						)
						.into();
					}
				}

				if transaction.gas_limit >= T::BlockGasLimit::get() {
					return InvalidTransaction::Custom(
						TransactionValidationError::InvalidGasLimit as u8,
					)
					.into();
				}

				let account_data = pallet_evm::Pallet::<T>::account_basic(&origin);

				if transaction.nonce < account_data.nonce {
					return InvalidTransaction::Stale.into();
				}

				let fee = transaction.gas_price.saturating_mul(transaction.gas_limit);
				let total_payment = transaction.value.saturating_add(fee);
				if account_data.balance < total_payment {
					return InvalidTransaction::Payment.into();
				}

				let min_gas_price = T::FeeCalculator::min_gas_price();

				if transaction.gas_price < min_gas_price {
					return InvalidTransaction::Payment.into();
				}

				let mut builder = ValidTransactionBuilder::default()
					.and_provides((origin, transaction.nonce))
					.priority(transaction.gas_price.unique_saturated_into());

				if transaction.nonce > account_data.nonce {
					if let Some(prev_nonce) = transaction.nonce.checked_sub(1.into()) {
						builder = builder.and_requires((origin, prev_nonce))
					}
				}

				builder.build()
			};
			Some(validate())
					Self::do_transact(source, transaction).expect(
			Self::do_transact(source, transaction)
	fn do_transact(source: H160, transaction: Transaction) -> DispatchResultWithPostInfo {
	traits::{BlakeTwo256, IdentityLookup},
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
			s.1.serialize() as u64 % 2 + ChainId::get() * 2 + 35,
	mock::*, CallOrCreateInfo, Error, RawOrigin, Transaction, TransactionAction,
	ValidTransactionBuilder, H160, H256, U256,
use frame_support::{assert_err, assert_noop, assert_ok, unsigned::ValidateUnsigned};
use sp_runtime::transaction_validity::{InvalidTransaction, TransactionSource};
fn transaction_with_invalid_nonce_should_not_work() {
Fixed code: 	pub fn pre_dispatch_self_contained(
		&self,
		origin: &H160,
	) -> Option<Result<(), TransactionValidityError>> {
			Some(Pallet::<T>::validate_transaction_in_block(
				*origin,
				&transaction,
			))
		} else {
			None
		}
	}
	pub fn validate_self_contained(&self, origin: &H160) -> Option<TransactionValidity> {
		if let Call::transact(transaction) = self {
			Some(Pallet::<T>::validate_transaction_in_pool(
				*origin,
				transaction,
			))
					Self::validate_transaction_in_block(source, &transaction).expect(
					Self::apply_validated_transaction(source, transaction).expect(
						"pre-block transaction execution failed; the block cannot be built",
					);
			Self::apply_validated_transaction(source, transaction)
	// Common controls to be performed in the same way by the pool and the
	// State Transition Function (STF).
	// This is the case for all controls except those concerning the nonce.
	fn validate_transaction_common(
		origin: H160,
		transaction: &Transaction,
	) -> Result<U256, TransactionValidityError> {
		// We must ensure a transaction can pay the cost of its data bytes.
		// If it can't it should not be included in a block.
		let mut gasometer = evm::gasometer::Gasometer::new(
			transaction.gas_limit.low_u64(),
			<T as pallet_evm::Config>::config(),
		);
		let transaction_cost = match transaction.action {
			TransactionAction::Call(_) => evm::gasometer::call_transaction_cost(&transaction.input),
			TransactionAction::Create => {
				evm::gasometer::create_transaction_cost(&transaction.input)
			}
		};
		if gasometer.record_transaction(transaction_cost).is_err() {
			return Err(InvalidTransaction::Custom(
				TransactionValidationError::InvalidGasLimit as u8,
			)
			.into());
		}

		if let Some(chain_id) = transaction.signature.chain_id() {
			if chain_id != T::ChainId::get() {
				return Err(InvalidTransaction::Custom(
					TransactionValidationError::InvalidChainId as u8,
				)
				.into());
			}
		}

		if transaction.gas_limit >= T::BlockGasLimit::get() {
			return Err(InvalidTransaction::Custom(
				TransactionValidationError::InvalidGasLimit as u8,
			)
			.into());
		}

		let account_data = pallet_evm::Pallet::<T>::account_basic(&origin);

		let fee = transaction.gas_price.saturating_mul(transaction.gas_limit);
		let total_payment = transaction.value.saturating_add(fee);
		if account_data.balance < total_payment {
			return Err(InvalidTransaction::Payment.into());
		}

		let min_gas_price = T::FeeCalculator::min_gas_price();

		if transaction.gas_price < min_gas_price {
			return Err(InvalidTransaction::Payment.into());
		}

		Ok(account_data.nonce)
	}

	// Controls that must be performed by the pool.
	// The controls common with the State Transition Function (STF) are in
	// the function `validate_transaction_common`.
	fn validate_transaction_in_pool(
		origin: H160,
		transaction: &Transaction,
	) -> TransactionValidity {
		let account_nonce = Self::validate_transaction_common(origin, transaction)?;

		if transaction.nonce < account_nonce {
			return Err(InvalidTransaction::Stale.into());
		}

		// The tag provides and requires must be filled correctly according to the nonce.
		let mut builder = ValidTransactionBuilder::default()
			.and_provides((origin, transaction.nonce))
			.priority(transaction.gas_price.unique_saturated_into());

		// In the context of the pool, a transaction with
		// too high a nonce is still considered valid
		if transaction.nonce > account_nonce {
			if let Some(prev_nonce) = transaction.nonce.checked_sub(1.into()) {
				builder = builder.and_requires((origin, prev_nonce))
			}
		}

		builder.build()
	}

	fn apply_validated_transaction(
		source: H160,
		transaction: Transaction,
	) -> DispatchResultWithPostInfo {

	/// Validate an Ethereum transaction already in block
	///
	/// This function must be called during the pre-dispatch phase
	/// (just before applying the extrinsic).
	pub fn validate_transaction_in_block(
		origin: H160,
		transaction: &ethereum::TransactionV0,
	) -> Result<(), TransactionValidityError> {
		let account_nonce = Self::validate_transaction_common(origin, transaction)?;

		// In the context of the block, a transaction with a nonce that is
		// too high should be considered invalid and make the whole block invalid.
		if transaction.nonce > account_nonce {
			Err(TransactionValidityError::Invalid(
				InvalidTransaction::Future,
			))
		} else if transaction.nonce < account_nonce {
			Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))
		} else {
			Ok(())
		}
	}
use codec::{WrapperTypeDecode, WrapperTypeEncode};
	traits::{BlakeTwo256, IdentityLookup, SignedExtension},
pub type SignedExtra = (frame_system::CheckSpecVersion<Test>,);

type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test, (), SignedExtra>;
impl fp_self_contained::SelfContainedCall for Call {
	type SignedInfo = H160;

	fn is_self_contained(&self) -> bool {
		match self {
			Call::Ethereum(call) => call.is_self_contained(),
			_ => false,
		}
	}

	fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
		match self {
			Call::Ethereum(call) => call.check_self_contained(),
			_ => None,
		}
	}

	fn validate_self_contained(&self, info: &Self::SignedInfo) -> Option<TransactionValidity> {
		match self {
			Call::Ethereum(call) => call.validate_self_contained(info),
			_ => None,
		}
	}

	fn pre_dispatch_self_contained(
		&self,
		info: &Self::SignedInfo,
	) -> Option<Result<(), TransactionValidityError>> {
		match self {
			Call::Ethereum(call) => call.pre_dispatch_self_contained(info),
			_ => None,
		}
	}

	fn apply_self_contained(
		self,
		info: Self::SignedInfo,
	) -> Option<sp_runtime::DispatchResultWithInfo<sp_runtime::traits::PostDispatchInfoOf<Self>>> {
		use sp_runtime::traits::Dispatchable as _;
		match self {
			call @ Call::Ethereum(crate::Call::transact(_)) => {
				Some(call.dispatch(Origin::from(crate::RawOrigin::EthereumTransaction(info))))
			}
			_ => None,
		}
	}
}

		self.sign_with_chain_id(key, ChainId::get())
	}

	pub fn sign_with_chain_id(&self, key: &H256, chain_id: u64) -> Transaction {
			s.1.serialize() as u64 % 2 + chain_id * 2 + 35,
	mock::*, CallOrCreateInfo, Error, RawOrigin, Transaction, TransactionAction, H160, H256, U256,
use frame_support::{
	assert_err, assert_noop, assert_ok,
	unsigned::{TransactionValidityError, ValidateUnsigned},
};
use sp_runtime::traits::Applyable;
use sp_runtime::transaction_validity::{
	InvalidTransaction, TransactionSource, ValidTransactionBuilder,
};
fn transaction_with_to_low_nonce_should_not_work() {
#[test]
fn transaction_with_to_hight_nonce_should_fail_in_block() {
	let (pairs, mut ext) = new_test_ext(1);
	let alice = &pairs[0];

	ext.execute_with(|| {
		let mut transaction = default_erc20_creation_unsigned_transaction();
		transaction.nonce = U256::one();

		let signed = transaction.sign(&alice.private_key);
		let call = crate::Call::<Test>::transact(signed);
		let source = call.check_self_contained().unwrap().unwrap();
		let extrinsic = fp_self_contained::CheckedExtrinsic::<_, _, SignedExtra, _> {
			signed: fp_self_contained::CheckedSignature::SelfContained(source),
			function: Call::Ethereum(call),
		};
		use frame_support::weights::GetDispatchInfo as _;
		let dispatch_info = extrinsic.get_dispatch_info();
		assert_err!(
			extrinsic.apply::<Test>(&dispatch_info, 0),
			TransactionValidityError::Invalid(InvalidTransaction::Future)
		);
	});
}

#[test]
fn transaction_with_invalid_chain_id_should_fail_in_block() {
	let (pairs, mut ext) = new_test_ext(1);
	let alice = &pairs[0];

	ext.execute_with(|| {
		let transaction =
			default_erc20_creation_unsigned_transaction().sign_with_chain_id(&alice.private_key, 1);

		let call = crate::Call::<Test>::transact(transaction);
		let source = call.check_self_contained().unwrap().unwrap();
		let extrinsic = fp_self_contained::CheckedExtrinsic::<_, _, SignedExtra, _> {
			signed: fp_self_contained::CheckedSignature::SelfContained(source),
			function: Call::Ethereum(call),
		};
		use frame_support::weights::GetDispatchInfo as _;
		let dispatch_info = extrinsic.get_dispatch_info();
		assert_err!(
			extrinsic.apply::<Test>(&dispatch_info, 0),
			TransactionValidityError::Invalid(InvalidTransaction::Custom(
				crate::TransactionValidationError::InvalidChainId as u8,
			))
		);
	});
}

				// If pre-dispatch fail, the block must be considered invalid
				self.function
					.pre_dispatch_self_contained(&signed_info)
					.ok_or(TransactionValidityError::Invalid(
						InvalidTransaction::BadProof,
					))??;
	/// Do any pre-flight stuff for a self-contained call.
	///
	/// Note this function by default delegates to `validate_self_contained`, so that
	/// all checks performed for the transaction queue are also performed during
	/// the dispatch phase (applying the extrinsic).
	///
	/// If you ever override this function, you need to make sure to always
	/// perform the same validation as in `validate_self_contained`.
	///
	/// Returns `None` if the function is not a self-contained.
	fn pre_dispatch_self_contained(
		&self,
		info: &Self::SignedInfo,
	) -> Option<Result<(), TransactionValidityError>>;
	fn pre_dispatch_self_contained(
		&self,
		info: &Self::SignedInfo,
	) -> Option<Result<(), TransactionValidityError>> {
		match self {
			Call::Ethereum(call) => call.pre_dispatch_self_contained(info),
			_ => None,
		}
	}