diff --git a/crates/rpc/rpc-eth-api/src/helpers/call.rs b/crates/rpc/rpc-eth-api/src/helpers/call.rs index d37f0b5bb4..836ba3c495 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/call.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/call.rs @@ -97,8 +97,9 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA let mut blocks: Vec>> = Vec::with_capacity(block_state_calls.len()); - // Track previous block number for validation + // Track previous block number and timestamp for validation let mut prev_block_number = parent.number(); + let mut prev_timestamp = parent.timestamp(); for block in block_state_calls { // Validate block number ordering if overridden @@ -112,6 +113,19 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA .into()); } } + // Validate timestamp ordering if overridden + if let Some(time) = block + .block_overrides + .as_ref() + .and_then(|o| o.time) + .filter(|&t| t <= prev_timestamp) + { + return Err(EthApiError::other(EthSimulateError::BlockTimestampInvalid { + got: time, + parent: prev_timestamp, + }) + .into()); + } let mut evm_env = this .evm_config() @@ -252,6 +266,7 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA // Update tracking for next iteration's validation prev_block_number = parent.number(); + prev_timestamp = parent.timestamp(); let block = simulate::build_simulated_block::( result.block, diff --git a/crates/rpc/rpc-eth-types/src/simulate.rs b/crates/rpc/rpc-eth-types/src/simulate.rs index 25b87bd1b2..c54e31d8a7 100644 --- a/crates/rpc/rpc-eth-types/src/simulate.rs +++ b/crates/rpc/rpc-eth-types/src/simulate.rs @@ -56,9 +56,14 @@ pub enum EthSimulateError { /// The parent block number. parent: u64, }, - /// Block timestamp in sequence did not increase or stay the same. - #[error("Block timestamp in sequence did not increase")] - BlockTimestampInvalid, + /// Block timestamp in sequence did not increase. + #[error("block timestamps must be in order: {got} <= {parent}")] + BlockTimestampInvalid { + /// The block timestamp that was provided. + got: u64, + /// The parent block timestamp. + parent: u64, + }, /// Transaction nonce is too low. #[error("nonce too low: next nonce {state}, tx nonce {tx}")] NonceTooLow { @@ -112,7 +117,7 @@ impl EthSimulateError { Self::InsufficientFunds { .. } => -38014, Self::BlockGasLimitExceeded => -38015, Self::BlockNumberInvalid { .. } => -38020, - Self::BlockTimestampInvalid => -38021, + Self::BlockTimestampInvalid { .. } => -38021, Self::PrecompileSelfReference => -38022, Self::PrecompileDuplicateAddress => -38023, Self::SenderNotEOA => -38024,