diff --git a/Cargo.lock b/Cargo.lock index 1741b55968..97c40b4340 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2293,7 +2293,6 @@ dependencies = [ "fc-mapping-sync", "fc-rpc-core", "fc-storage", - "fp-ethereum", "fp-evm", "fp-rpc", "fp-storage", @@ -2571,7 +2570,6 @@ dependencies = [ "ethereum-types", "fp-evm", "frame-support", - "num_enum", "parity-scale-codec", "sp-std", ] @@ -2582,6 +2580,7 @@ version = "3.0.0-dev" dependencies = [ "evm", "frame-support", + "num_enum", "parity-scale-codec", "scale-info", "serde", diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 11ff7510bf..34d10f7a6a 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -52,7 +52,6 @@ fc-api = { workspace = true } fc-mapping-sync = { workspace = true } fc-rpc-core = { workspace = true } fc-storage = { workspace = true } -fp-ethereum = { workspace = true, features = ["default"] } fp-evm = { workspace = true } fp-rpc = { workspace = true, features = ["default"] } fp-storage = { workspace = true, features = ["default"] } diff --git a/client/rpc/src/eth/format.rs b/client/rpc/src/eth/format.rs index 4d110196dd..70b2439b45 100644 --- a/client/rpc/src/eth/format.rs +++ b/client/rpc/src/eth/format.rs @@ -20,7 +20,7 @@ use sc_transaction_pool_api::error::{Error as PError, IntoPoolError}; use sp_runtime::transaction_validity::InvalidTransaction; // Frontier -use fp_ethereum::TransactionValidationError as VError; +use fp_evm::TransactionValidationError as VError; // Formats the same way Geth node formats responses. pub struct Geth; @@ -43,9 +43,12 @@ impl Geth { VError::InvalidSignature => "invalid sender".into(), VError::GasLimitTooLow => "intrinsic gas too low".into(), VError::GasLimitTooHigh => "exceeds block gas limit".into(), - VError::MaxFeePerGasTooLow => { + VError::GasPriceTooLow => "gas price less than block base fee".into(), + VError::PriorityFeeTooHigh => { "max priority fee per gas higher than max fee per gas".into() } + VError::InvalidFeeInput => "invalid fee input".into(), + _ => "transaction validation error".into(), }, _ => "unknown error".into(), }, diff --git a/frame/ethereum/src/lib.rs b/frame/ethereum/src/lib.rs index cbbdaab434..d2cb517fd8 100644 --- a/frame/ethereum/src/lib.rs +++ b/frame/ethereum/src/lib.rs @@ -33,9 +33,9 @@ mod tests; use ethereum_types::{Bloom, BloomInput, H160, H256, H64, U256}; use evm::ExitReason; use fp_consensus::{PostLog, PreLog, FRONTIER_ENGINE_ID}; -use fp_ethereum::{TransactionValidationError, ValidatedTransaction as ValidatedTransactionT}; +use fp_ethereum::ValidatedTransaction as ValidatedTransactionT; use fp_evm::{ - CallOrCreateInfo, CheckEvmTransaction, CheckEvmTransactionConfig, InvalidEvmTransactionError, + CallOrCreateInfo, CheckEvmTransaction, CheckEvmTransactionConfig, TransactionValidationError, }; use fp_storage::{EthereumStorageSchema, PALLET_ETHEREUM_SCHEMA}; use frame_support::{ @@ -979,36 +979,42 @@ impl BlockHashMapping for EthereumBlockHashMapping { pub struct InvalidTransactionWrapper(InvalidTransaction); -impl From for InvalidTransactionWrapper { - fn from(validation_error: InvalidEvmTransactionError) -> Self { +impl From for InvalidTransactionWrapper { + fn from(validation_error: TransactionValidationError) -> Self { match validation_error { - InvalidEvmTransactionError::GasLimitTooLow => InvalidTransactionWrapper( + TransactionValidationError::GasLimitTooLow => InvalidTransactionWrapper( InvalidTransaction::Custom(TransactionValidationError::GasLimitTooLow as u8), ), - InvalidEvmTransactionError::GasLimitTooHigh => InvalidTransactionWrapper( + TransactionValidationError::GasLimitTooHigh => InvalidTransactionWrapper( InvalidTransaction::Custom(TransactionValidationError::GasLimitTooHigh as u8), ), - InvalidEvmTransactionError::GasPriceTooLow => { - InvalidTransactionWrapper(InvalidTransaction::Payment) - } - InvalidEvmTransactionError::PriorityFeeTooHigh => InvalidTransactionWrapper( - InvalidTransaction::Custom(TransactionValidationError::MaxFeePerGasTooLow as u8), + TransactionValidationError::PriorityFeeTooHigh => InvalidTransactionWrapper( + InvalidTransaction::Custom(TransactionValidationError::PriorityFeeTooHigh as u8), ), - InvalidEvmTransactionError::BalanceTooLow => { + TransactionValidationError::BalanceTooLow => { InvalidTransactionWrapper(InvalidTransaction::Payment) } - InvalidEvmTransactionError::TxNonceTooLow => { + TransactionValidationError::TxNonceTooLow => { InvalidTransactionWrapper(InvalidTransaction::Stale) } - InvalidEvmTransactionError::TxNonceTooHigh => { + TransactionValidationError::TxNonceTooHigh => { InvalidTransactionWrapper(InvalidTransaction::Future) } - InvalidEvmTransactionError::InvalidPaymentInput => { - InvalidTransactionWrapper(InvalidTransaction::Payment) - } - InvalidEvmTransactionError::InvalidChainId => InvalidTransactionWrapper( + TransactionValidationError::InvalidFeeInput => InvalidTransactionWrapper( + InvalidTransaction::Custom(TransactionValidationError::InvalidFeeInput as u8), + ), + TransactionValidationError::InvalidChainId => InvalidTransactionWrapper( InvalidTransaction::Custom(TransactionValidationError::InvalidChainId as u8), ), + TransactionValidationError::InvalidSignature => InvalidTransactionWrapper( + InvalidTransaction::Custom(TransactionValidationError::InvalidSignature as u8), + ), + TransactionValidationError::GasPriceTooLow => InvalidTransactionWrapper( + InvalidTransaction::Custom(TransactionValidationError::GasPriceTooLow as u8), + ), + TransactionValidationError::UnknownError => InvalidTransactionWrapper( + InvalidTransaction::Custom(TransactionValidationError::UnknownError as u8), + ), } } } diff --git a/frame/ethereum/src/tests/eip1559.rs b/frame/ethereum/src/tests/eip1559.rs index d0091d6ab0..6187d42a52 100644 --- a/frame/ethereum/src/tests/eip1559.rs +++ b/frame/ethereum/src/tests/eip1559.rs @@ -256,7 +256,7 @@ fn transaction_with_invalid_chain_id_should_fail_in_block() { assert_err!( extrinsic.apply::(&dispatch_info, 0), TransactionValidityError::Invalid(InvalidTransaction::Custom( - fp_ethereum::TransactionValidationError::InvalidChainId as u8, + fp_evm::TransactionValidationError::InvalidChainId as u8, )) ); }); diff --git a/frame/ethereum/src/tests/eip2930.rs b/frame/ethereum/src/tests/eip2930.rs index 6b3a6cd34d..1b425106c3 100644 --- a/frame/ethereum/src/tests/eip2930.rs +++ b/frame/ethereum/src/tests/eip2930.rs @@ -188,7 +188,7 @@ fn transaction_with_invalid_chain_id_should_fail_in_block() { assert_err!( extrinsic.apply::(&dispatch_info, 0), TransactionValidityError::Invalid(InvalidTransaction::Custom( - fp_ethereum::TransactionValidationError::InvalidChainId as u8, + fp_evm::TransactionValidationError::InvalidChainId as u8, )) ); }); diff --git a/frame/ethereum/src/tests/legacy.rs b/frame/ethereum/src/tests/legacy.rs index c119da3700..c7500c17d2 100644 --- a/frame/ethereum/src/tests/legacy.rs +++ b/frame/ethereum/src/tests/legacy.rs @@ -188,7 +188,7 @@ fn transaction_with_invalid_chain_id_should_fail_in_block() { assert_err!( extrinsic.apply::(&dispatch_info, 0), TransactionValidityError::Invalid(InvalidTransaction::Custom( - fp_ethereum::TransactionValidationError::InvalidChainId as u8, + fp_evm::TransactionValidationError::InvalidChainId as u8, )) ); }); diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index fb3a0388f8..25f6dac4fd 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -96,9 +96,8 @@ use fp_account::AccountId20; use fp_evm::GenesisAccount; pub use fp_evm::{ Account, CallInfo, CreateInfo, ExecutionInfoV2 as ExecutionInfo, FeeCalculator, - InvalidEvmTransactionError, IsPrecompileResult, LinearCostPrecompile, Log, Precompile, - PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet, - Vicinity, + IsPrecompileResult, LinearCostPrecompile, Log, Precompile, PrecompileFailure, PrecompileHandle, + PrecompileOutput, PrecompileResult, PrecompileSet, TransactionValidationError, Vicinity, }; pub use self::{ @@ -495,17 +494,17 @@ pub mod pallet { TransactionMustComeFromEOA, } - impl From for Error { - fn from(validation_error: InvalidEvmTransactionError) -> Self { + impl From for Error { + fn from(validation_error: TransactionValidationError) -> Self { match validation_error { - InvalidEvmTransactionError::GasLimitTooLow => Error::::GasLimitTooLow, - InvalidEvmTransactionError::GasLimitTooHigh => Error::::GasLimitTooHigh, - InvalidEvmTransactionError::GasPriceTooLow => Error::::GasPriceTooLow, - InvalidEvmTransactionError::PriorityFeeTooHigh => Error::::GasPriceTooLow, - InvalidEvmTransactionError::BalanceTooLow => Error::::BalanceLow, - InvalidEvmTransactionError::TxNonceTooLow => Error::::InvalidNonce, - InvalidEvmTransactionError::TxNonceTooHigh => Error::::InvalidNonce, - InvalidEvmTransactionError::InvalidPaymentInput => Error::::GasPriceTooLow, + TransactionValidationError::GasLimitTooLow => Error::::GasLimitTooLow, + TransactionValidationError::GasLimitTooHigh => Error::::GasLimitTooHigh, + TransactionValidationError::BalanceTooLow => Error::::BalanceLow, + TransactionValidationError::TxNonceTooLow => Error::::InvalidNonce, + TransactionValidationError::TxNonceTooHigh => Error::::InvalidNonce, + TransactionValidationError::GasPriceTooLow => Error::::GasPriceTooLow, + TransactionValidationError::PriorityFeeTooHigh => Error::::GasPriceTooLow, + TransactionValidationError::InvalidFeeInput => Error::::GasPriceTooLow, _ => Error::::Undefined, } } diff --git a/primitives/ethereum/Cargo.toml b/primitives/ethereum/Cargo.toml index 3b1fbfb3a2..9761ac232e 100644 --- a/primitives/ethereum/Cargo.toml +++ b/primitives/ethereum/Cargo.toml @@ -13,7 +13,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ethereum = { workspace = true, features = ["with-codec"] } ethereum-types = { workspace = true } -num_enum = { version = "0.6.1", default-features = false } scale-codec = { package = "parity-scale-codec", workspace = true } # Substrate frame-support = { workspace = true } @@ -26,7 +25,6 @@ default = ["std"] std = [ "ethereum/std", "ethereum-types/std", - "num_enum/std", "scale-codec/std", # Substrate "frame-support/std", diff --git a/primitives/ethereum/src/lib.rs b/primitives/ethereum/src/lib.rs index 3a15999d1c..2aeee6cbff 100644 --- a/primitives/ethereum/src/lib.rs +++ b/primitives/ethereum/src/lib.rs @@ -28,19 +28,6 @@ use frame_support::dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}; use scale_codec::{Decode, Encode}; use sp_std::{result::Result, vec::Vec}; -#[repr(u8)] -#[derive(num_enum::FromPrimitive, num_enum::IntoPrimitive)] -pub enum TransactionValidationError { - #[allow(dead_code)] - #[num_enum(default)] - UnknownError, - InvalidChainId, - InvalidSignature, - GasLimitTooLow, - GasLimitTooHigh, - MaxFeePerGasTooLow, -} - pub trait ValidatedTransaction { fn apply( source: H160, diff --git a/primitives/evm/Cargo.toml b/primitives/evm/Cargo.toml index b5bd222d7e..9e9f8d41ea 100644 --- a/primitives/evm/Cargo.toml +++ b/primitives/evm/Cargo.toml @@ -12,6 +12,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] evm = { workspace = true, features = ["with-codec"] } +num_enum = { version = "0.6.1", default-features = false } scale-codec = { package = "parity-scale-codec", workspace = true } scale-info = { workspace = true } serde = { workspace = true, optional = true } @@ -26,6 +27,7 @@ default = ["std"] std = [ "evm/std", "evm/with-serde", + "num_enum/std", "serde/std", "scale-codec/std", # Substrate diff --git a/primitives/evm/src/lib.rs b/primitives/evm/src/lib.rs index 4a4902ba27..bdbb2792f0 100644 --- a/primitives/evm/src/lib.rs +++ b/primitives/evm/src/lib.rs @@ -43,7 +43,7 @@ pub use self::{ }, validation::{ CheckEvmTransaction, CheckEvmTransactionConfig, CheckEvmTransactionInput, - InvalidEvmTransactionError, + TransactionValidationError, }, }; diff --git a/primitives/evm/src/validation.rs b/primitives/evm/src/validation.rs index a9ea6963d1..5faccd458d 100644 --- a/primitives/evm/src/validation.rs +++ b/primitives/evm/src/validation.rs @@ -45,7 +45,7 @@ pub struct CheckEvmTransactionConfig<'config> { } #[derive(Debug)] -pub struct CheckEvmTransaction<'config, E: From> { +pub struct CheckEvmTransaction<'config, E: From> { pub config: CheckEvmTransactionConfig<'config>, pub transaction: CheckEvmTransactionInput, pub weight_limit: Option, @@ -53,20 +53,36 @@ pub struct CheckEvmTransaction<'config, E: From> { _marker: sp_std::marker::PhantomData, } -#[derive(Debug)] -pub enum InvalidEvmTransactionError { +/// Transaction validation errors +#[repr(u8)] +#[derive(num_enum::FromPrimitive, num_enum::IntoPrimitive, Debug)] +pub enum TransactionValidationError { + /// The transaction gas limit is too low GasLimitTooLow, + /// The transaction gas limit is too hign GasLimitTooHigh, + /// The transaction gas price is too low GasPriceTooLow, + /// The transaction priority fee is too high PriorityFeeTooHigh, + /// The transaction balance is too low BalanceTooLow, + /// The transaction nonce is too low TxNonceTooLow, + /// The transaction nonce is too high TxNonceTooHigh, - InvalidPaymentInput, + /// The transaction fee input is invalid + InvalidFeeInput, + /// The chain id is incorrect InvalidChainId, + /// The transaction signature is invalid + InvalidSignature, + /// Unknown error + #[num_enum(default)] + UnknownError, } -impl<'config, E: From> CheckEvmTransaction<'config, E> { +impl<'config, E: From> CheckEvmTransaction<'config, E> { pub fn new( config: CheckEvmTransactionConfig<'config>, transaction: CheckEvmTransactionInput, @@ -84,16 +100,16 @@ impl<'config, E: From> CheckEvmTransaction<'config, pub fn validate_in_pool_for(&self, who: &Account) -> Result<&Self, E> { if self.transaction.nonce < who.nonce { - return Err(InvalidEvmTransactionError::TxNonceTooLow.into()); + return Err(TransactionValidationError::TxNonceTooLow.into()); } self.validate_common() } pub fn validate_in_block_for(&self, who: &Account) -> Result<&Self, E> { if self.transaction.nonce > who.nonce { - return Err(InvalidEvmTransactionError::TxNonceTooHigh.into()); + return Err(TransactionValidationError::TxNonceTooHigh.into()); } else if self.transaction.nonce < who.nonce { - return Err(InvalidEvmTransactionError::TxNonceTooLow.into()); + return Err(TransactionValidationError::TxNonceTooLow.into()); } self.validate_common() } @@ -102,7 +118,7 @@ impl<'config, E: From> CheckEvmTransaction<'config, // Chain id matches the one in the signature. if let Some(chain_id) = self.transaction.chain_id { if chain_id != self.config.chain_id { - return Err(InvalidEvmTransactionError::InvalidChainId.into()); + return Err(TransactionValidationError::InvalidChainId.into()); } } Ok(self) @@ -114,7 +130,7 @@ impl<'config, E: From> CheckEvmTransaction<'config, if self.config.is_transactional || gas_price > U256::zero() { // Transaction max fee is at least the current base fee. if gas_price < self.config.base_fee { - return Err(InvalidEvmTransactionError::GasPriceTooLow.into()); + return Err(TransactionValidationError::GasPriceTooLow.into()); } } Ok(self) @@ -137,7 +153,7 @@ impl<'config, E: From> CheckEvmTransaction<'config, if self.config.is_transactional || fee > U256::zero() { let total_payment = self.transaction.value.saturating_add(fee); if who.balance < total_payment { - return Err(InvalidEvmTransactionError::BalanceTooLow.into()); + return Err(TransactionValidationError::BalanceTooLow.into()); } } Ok(self) @@ -161,7 +177,7 @@ impl<'config, E: From> CheckEvmTransaction<'config, // EIP-1559 tip. (None, Some(max_fee_per_gas), Some(max_priority_fee_per_gas)) => { if max_priority_fee_per_gas > max_fee_per_gas { - return Err(InvalidEvmTransactionError::PriorityFeeTooHigh.into()); + return Err(TransactionValidationError::PriorityFeeTooHigh.into()); } let effective_gas_price = self .config @@ -173,7 +189,7 @@ impl<'config, E: From> CheckEvmTransaction<'config, } _ => { if self.config.is_transactional { - Err(InvalidEvmTransactionError::InvalidPaymentInput.into()) + Err(TransactionValidationError::InvalidFeeInput.into()) } else { // Allow non-set fee input for non-transactional calls. Ok((U256::zero(), None)) @@ -192,7 +208,7 @@ impl<'config, E: From> CheckEvmTransaction<'config, let _ = weight_limit .proof_size() .checked_sub(proof_size_base_cost) - .ok_or(InvalidEvmTransactionError::GasLimitTooLow)?; + .ok_or(TransactionValidationError::GasLimitTooLow)?; } // We must ensure a transaction can pay the cost of its data bytes. @@ -214,12 +230,12 @@ impl<'config, E: From> CheckEvmTransaction<'config, }; if gasometer.record_transaction(transaction_cost).is_err() { - return Err(InvalidEvmTransactionError::GasLimitTooLow.into()); + return Err(TransactionValidationError::GasLimitTooLow.into()); } // Transaction gas limit is within the upper bound block gas limit. if self.transaction.gas_limit > self.config.block_gas_limit { - return Err(InvalidEvmTransactionError::GasLimitTooHigh.into()); + return Err(TransactionValidationError::GasLimitTooHigh.into()); } } @@ -240,24 +256,28 @@ mod tests { BalanceTooLow, TxNonceTooLow, TxNonceTooHigh, - InvalidPaymentInput, + InvalidFeeInput, InvalidChainId, + InvalidSignature, + UnknownError, } static SHANGHAI_CONFIG: evm::Config = evm::Config::shanghai(); - impl From for TestError { - fn from(e: InvalidEvmTransactionError) -> Self { + impl From for TestError { + fn from(e: TransactionValidationError) -> Self { match e { - InvalidEvmTransactionError::GasLimitTooLow => TestError::GasLimitTooLow, - InvalidEvmTransactionError::GasLimitTooHigh => TestError::GasLimitTooHigh, - InvalidEvmTransactionError::GasPriceTooLow => TestError::GasPriceTooLow, - InvalidEvmTransactionError::PriorityFeeTooHigh => TestError::PriorityFeeTooHigh, - InvalidEvmTransactionError::BalanceTooLow => TestError::BalanceTooLow, - InvalidEvmTransactionError::TxNonceTooLow => TestError::TxNonceTooLow, - InvalidEvmTransactionError::TxNonceTooHigh => TestError::TxNonceTooHigh, - InvalidEvmTransactionError::InvalidPaymentInput => TestError::InvalidPaymentInput, - InvalidEvmTransactionError::InvalidChainId => TestError::InvalidChainId, + TransactionValidationError::GasLimitTooLow => TestError::GasLimitTooLow, + TransactionValidationError::GasLimitTooHigh => TestError::GasLimitTooHigh, + TransactionValidationError::GasPriceTooLow => TestError::GasPriceTooLow, + TransactionValidationError::PriorityFeeTooHigh => TestError::PriorityFeeTooHigh, + TransactionValidationError::BalanceTooLow => TestError::BalanceTooLow, + TransactionValidationError::TxNonceTooLow => TestError::TxNonceTooLow, + TransactionValidationError::TxNonceTooHigh => TestError::TxNonceTooHigh, + TransactionValidationError::InvalidFeeInput => TestError::InvalidFeeInput, + TransactionValidationError::InvalidChainId => TestError::InvalidChainId, + TransactionValidationError::InvalidSignature => TestError::InvalidSignature, + TransactionValidationError::UnknownError => TestError::UnknownError, } } } @@ -625,7 +645,7 @@ mod tests { let test = transaction_none_fee(true); let res = test.with_base_fee(); assert!(res.is_err()); - assert_eq!(res.unwrap_err(), TestError::InvalidPaymentInput); + assert_eq!(res.unwrap_err(), TestError::InvalidFeeInput); } #[test] @@ -712,7 +732,7 @@ mod tests { let test = transaction_none_fee(true); let res = test.with_balance_for(&who); assert!(res.is_err()); - assert_eq!(res.unwrap_err(), TestError::InvalidPaymentInput); + assert_eq!(res.unwrap_err(), TestError::InvalidFeeInput); } #[test] @@ -792,7 +812,7 @@ mod tests { let test = invalid_transaction_mixed_fees(is_transactional); let res = test.with_balance_for(&who); assert!(res.is_err()); - assert_eq!(res.unwrap_err(), TestError::InvalidPaymentInput); + assert_eq!(res.unwrap_err(), TestError::InvalidFeeInput); // Succeeds for non-transactional. let is_transactional = false; let test = invalid_transaction_mixed_fees(is_transactional); @@ -808,7 +828,7 @@ mod tests { let test = invalid_transaction_mixed_fees(is_transactional); let res = test.with_base_fee(); assert!(res.is_err()); - assert_eq!(res.unwrap_err(), TestError::InvalidPaymentInput); + assert_eq!(res.unwrap_err(), TestError::InvalidFeeInput); // Succeeds for non-transactional. let is_transactional = false; let test = invalid_transaction_mixed_fees(is_transactional); diff --git a/ts-tests/tests/test-balance.ts b/ts-tests/tests/test-balance.ts index 4afd52eb82..a2faff274d 100644 --- a/ts-tests/tests/test-balance.ts +++ b/ts-tests/tests/test-balance.ts @@ -5,7 +5,11 @@ import { GENESIS_ACCOUNT, GENESIS_ACCOUNT_PRIVATE_KEY, GENESIS_ACCOUNT_BALANCE, import { createAndFinalizeBlock, describeWithFrontier, customRequest } from "./util"; describeWithFrontier("Frontier RPC (Balance)", (context) => { - const TEST_ACCOUNT = "0x1111111111111111111111111111111111111111"; + const TEST_ACCOUNT = "0xdd33Af49c851553841E94066B54Fd28612522901"; + const TEST_ACCOUNT_PRIVATE_KEY = "0x4ca933bffe83185dda76e7913fc96e5c97cdb7ca1fbfcc085d6376e6f564ef71"; + const TRANFER_VALUE = "0x200"; // 512, must be higher than ExistentialDeposit + const GAS_PRICE = "0x3B9ACA00"; // 1000000000 + var nonce = 0; step("genesis balance is setup correctly", async function () { expect(await context.web3.eth.getBalance(GENESIS_ACCOUNT)).to.equal(GENESIS_ACCOUNT_BALANCE); @@ -15,15 +19,14 @@ describeWithFrontier("Frontier RPC (Balance)", (context) => { await createAndFinalizeBlock(context.web3); this.timeout(15000); - const value = "0x200"; // 512, must be higher than ExistentialDeposit - const gasPrice = "0x3B9ACA00"; // 1000000000 const tx = await context.web3.eth.accounts.signTransaction( { from: GENESIS_ACCOUNT, to: TEST_ACCOUNT, - value: value, - gasPrice: gasPrice, + value: TRANFER_VALUE, + gasPrice: GAS_PRICE, gas: "0x100000", + nonce: nonce, }, GENESIS_ACCOUNT_PRIVATE_KEY ); @@ -32,10 +35,10 @@ describeWithFrontier("Frontier RPC (Balance)", (context) => { // GENESIS_ACCOUNT_BALANCE - (21000 * gasPrice) - value; const expectedGenesisBalance = ( BigInt(GENESIS_ACCOUNT_BALANCE) - - BigInt(21000) * BigInt(gasPrice) - - BigInt(value) + BigInt(21000) * BigInt(GAS_PRICE) - + BigInt(TRANFER_VALUE) ).toString(); - const expectedTestBalance = (Number(value) - EXISTENTIAL_DEPOSIT).toString(); + const expectedTestBalance = (Number(TRANFER_VALUE) - EXISTENTIAL_DEPOSIT).toString(); expect(await context.web3.eth.getBalance(GENESIS_ACCOUNT, "pending")).to.equal(expectedGenesisBalance); expect(await context.web3.eth.getBalance(TEST_ACCOUNT, "pending")).to.equal(expectedTestBalance); @@ -44,4 +47,41 @@ describeWithFrontier("Frontier RPC (Balance)", (context) => { expect(await context.web3.eth.getBalance(GENESIS_ACCOUNT)).to.equal(expectedGenesisBalance); expect(await context.web3.eth.getBalance(TEST_ACCOUNT)).to.equal(expectedTestBalance); }); + + step("gas price too low", async function () { + nonce += 1; + + let gas_price = await context.web3.eth.getGasPrice(); + const tx = await context.web3.eth.accounts.signTransaction( + { + from: GENESIS_ACCOUNT, + to: TEST_ACCOUNT, + value: TRANFER_VALUE, + gasPrice: Number(gas_price) - 1, + gas: "0x100000", + nonce: nonce, + }, + GENESIS_ACCOUNT_PRIVATE_KEY + ); + let result = await customRequest(context.web3, "eth_sendRawTransaction", [tx.rawTransaction]); + expect(result.error.message).to.be.equal("gas price less than block base fee"); + }); + + step("balance insufficient", async function () { + nonce += 1; + let test_account_balance = await context.web3.eth.getBalance(TEST_ACCOUNT); + const tx = await context.web3.eth.accounts.signTransaction( + { + from: TEST_ACCOUNT, + to: GENESIS_ACCOUNT, + value: test_account_balance + 1, + gasPrice: GAS_PRICE, + gas: "0x100000", + nonce: nonce, + }, + TEST_ACCOUNT_PRIVATE_KEY + ); + let result = await customRequest(context.web3, "eth_sendRawTransaction", [tx.rawTransaction]); + expect(result.error.message).to.be.equal("insufficient funds for gas * price + value"); + }); }); diff --git a/ts-tests/tests/test-nonce.ts b/ts-tests/tests/test-nonce.ts index 7d3b5c9ab9..00e2a33714 100644 --- a/ts-tests/tests/test-nonce.ts +++ b/ts-tests/tests/test-nonce.ts @@ -33,4 +33,24 @@ describeWithFrontier("Frontier RPC (Nonce)", (context) => { expect(await context.web3.eth.getTransactionCount(GENESIS_ACCOUNT, "pending")).to.eq(1); expect(await context.web3.eth.getTransactionCount(GENESIS_ACCOUNT, "earliest")).to.eq(0); }); + + step("staled nonce", async function () { + await createAndFinalizeBlock(context.web3); + expect(await context.web3.eth.getTransactionCount(GENESIS_ACCOUNT, "latest")).to.eq(1); + + const tx = await context.web3.eth.accounts.signTransaction( + { + from: GENESIS_ACCOUNT, + to: TEST_ACCOUNT, + value: "0x400", // Must be higher than ExistentialDeposit + gasPrice: "0x3B9ACA00", + gas: "0x100000", + nonce: 0, + }, + GENESIS_ACCOUNT_PRIVATE_KEY + ); + + let result = await customRequest(context.web3, "eth_sendRawTransaction", [tx.rawTransaction]); + expect(result.error.message).to.be.equal("nonce too low"); + }); });