diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index 6c8cd2f852..130231d968 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -329,15 +329,11 @@ where F: FnOnce(StateProviderBox<'_>) -> EthResult + Send + 'static, T: Send + 'static, { - let this = self.clone(); - self.inner - .blocking_task_pool - .spawn(move || { - let state = this.state_at(at)?; - f(state) - }) - .await - .map_err(|_| EthApiError::InternalBlockingTaskError)? + self.spawn_tracing_task_with(move |this| { + let state = this.state_at(at)?; + f(state) + }) + .await } async fn evm_env_at(&self, at: BlockId) -> EthResult<(CfgEnv, BlockEnv, BlockId)> { @@ -803,34 +799,48 @@ where None => return Ok(None), }; - // we need to get the state of the parent block because we're replaying this block on top of - // its parent block's state - let state_at = block.parent_hash; - - let block_hash = block.hash; - let transactions = block.body; - // replay all transactions of the block - self.spawn_with_state_at_block(state_at.into(), move |state| { + self.spawn_tracing_task_with(move |this| { + // we need to get the state of the parent block because we're replaying this block on + // top of its parent block's state + let state_at = block.parent_hash; + let block_hash = block.hash; + + let block_number = block_env.number.saturating_to::(); + let base_fee = block_env.basefee.saturating_to::(); + + // prepare transactions, we do everything upfront to reduce time spent with open state + let max_transactions = + highest_index.map_or(block.body.len(), |highest| highest as usize); + let transactions = block + .body + .into_iter() + .take(max_transactions) + .enumerate() + .map(|(idx, tx)| -> EthResult<_> { + let tx = tx.into_ecrecovered().ok_or(BlockError::InvalidSignature)?; + let tx_info = TransactionInfo { + hash: Some(tx.hash()), + index: Some(idx as u64), + block_hash: Some(block_hash), + block_number: Some(block_number), + base_fee: Some(base_fee), + }; + let tx_env = tx_env_with_recovered(&tx); + + Ok((tx_info, tx_env)) + }) + .collect::, _>>()?; + let mut results = Vec::with_capacity(transactions.len()); + + // now get the state + let state = this.state_at(state_at.into())?; let mut db = CacheDB::new(StateProviderDatabase::new(state)); - let max_transactions = - highest_index.map_or(transactions.len(), |highest| highest as usize); - let mut transactions = - transactions.into_iter().take(max_transactions).enumerate().peekable(); + let mut transactions = transactions.into_iter().peekable(); - while let Some((idx, tx)) = transactions.next() { - let tx = tx.into_ecrecovered().ok_or(BlockError::InvalidSignature)?; - let tx_info = TransactionInfo { - hash: Some(tx.hash()), - index: Some(idx as u64), - block_hash: Some(block_hash), - block_number: Some(block_env.number.try_into().unwrap_or(u64::MAX)), - base_fee: Some(block_env.basefee.try_into().unwrap_or(u64::MAX)), - }; - - let tx = tx_env_with_recovered(&tx); + while let Some((tx_info, tx)) = transactions.next() { let env = Env { cfg: cfg.clone(), block: block_env.clone(), tx }; let mut inspector = TracingInspector::new(config); @@ -856,6 +866,28 @@ where // === impl EthApi === +impl EthApi +where + Pool: TransactionPool + Clone + 'static, + Provider: + BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, + Network: NetworkInfo + Send + Sync + 'static, +{ + /// Spawns the given closure on a new blocking tracing task + async fn spawn_tracing_task_with(&self, f: F) -> EthResult + where + F: FnOnce(Self) -> EthResult + Send + 'static, + T: Send + 'static, + { + let this = self.clone(); + self.inner + .blocking_task_pool + .spawn(move || f(this)) + .await + .map_err(|_| EthApiError::InternalBlockingTaskError)? + } +} + impl EthApi where Provider: