Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(rpc): EthTransactions default trait methods using pending block #8659

Merged
merged 37 commits into from
Jun 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
cab888f
Make on_blocking_task method accessible in default trait method impls
emhane Jun 1, 2024
b902f35
Minimise thread interface eth api
emhane Jun 1, 2024
c35b40e
Update docs and symbol name
emhane Jun 1, 2024
8ccddd3
Add missing reth primitives to op feature
emhane Jun 1, 2024
257dc5d
Remove feature gate to fix broken test
emhane Jun 1, 2024
40194d6
Fix flaky test
emhane Jun 1, 2024
68e64b4
fixup! Fix flaky test
emhane Jun 1, 2024
30b63cc
fixup! Fix flaky test
emhane Jun 1, 2024
fcc64ea
Update lock file
emhane Jun 1, 2024
734ac99
Reinsert functions for spawning blocking threads into EthTransactions
emhane Jun 4, 2024
c000f43
Drive-by, update docs
emhane Jun 4, 2024
d1b91ad
Move spawn cpu heavy to trait
emhane Jun 4, 2024
eec99b8
Fix lint
emhane Jun 4, 2024
924024f
Revert impl for spawning blocking io
emhane Jun 4, 2024
ea6cbd3
Make impl of spawn blocking default trait methods
emhane Jun 4, 2024
ecb6771
Update docs
emhane Jun 5, 2024
fe494dc
Revert unrelated changes
emhane Jun 5, 2024
ba6f403
Merge branch 'main' into emhane/blocking-read
emhane Jun 5, 2024
55d2649
Merge branch 'matt/scaffold-ethapi' into emhane/blocking-read
emhane Jun 5, 2024
139f97f
Merge branch 'matt/scaffold-ethapi' into emhane/blocking-read
emhane Jun 5, 2024
8b8ed16
Fix lint
emhane Jun 5, 2024
f3ed6bd
Add super traits to spawn blocking
emhane Jun 5, 2024
16334cd
Move impl of methods using evm config to default trait methods
emhane Jun 5, 2024
20d2489
Move EthApi state access methods into trait
emhane Jun 5, 2024
4a40032
Move EthTransaction impls to default trait methods
emhane Jun 5, 2024
f2df915
Move state rpc methods into new trait default impl
emhane Jun 5, 2024
ca19811
fixup! Move state rpc methods into new trait default impl
emhane Jun 5, 2024
8ee373c
Move EthTransactions impl to default trait methods
emhane Jun 6, 2024
6dfac1a
Add trait for pending block
emhane Jun 6, 2024
90f67b6
Merge branch 'matt/scaffold-ethapi' into emhane/ethapi-txns
emhane Jun 6, 2024
0db764e
Merge branch 'matt/scaffold-ethapi' into emhane/ethapi-txns
emhane Jun 6, 2024
2340e87
Merge branch 'emhane/ethapi-txns' into emhane/ethapi-pending-block
emhane Jun 6, 2024
3c0b7ab
Fix lint
emhane Jun 6, 2024
6634723
Merge branch 'emhane/ethapi-txns' into emhane/ethapi-pending-block
emhane Jun 6, 2024
5e27f32
Move impl to get evm env at block to EthTransactions default trait me…
emhane Jun 6, 2024
e69b697
Move EthTransactions impl using evm_env_at into default trait methods
emhane Jun 6, 2024
7b1a566
Merge branch 'matt/scaffold-ethapi' into emhane/ethapi-txns-pending-b…
emhane Jun 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/rpc/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ tracing.workspace = true
tracing-futures = "0.2"
schnellru.workspace = true
futures.workspace = true
derive_more = { workspace = true, default-features = false, features = ["deref", "deref_mut", "constructor"] }
derive_more.workspace = true
dyn-clone.workspace = true
auto_impl.workspace = true

Expand Down
6 changes: 3 additions & 3 deletions crates/rpc/rpc/src/debug.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
eth::{
api::{EthTransactions, LoadState, SpawnBlocking},
api::{EthTransactions, LoadPendingBlock, LoadState, SpawnBlocking},
error::{EthApiError, EthResult},
revm_utils::{prepare_call_env, EvmOverrides},
},
Expand Down Expand Up @@ -65,7 +65,7 @@ impl<Provider, Eth> DebugApi<Provider, Eth> {
impl<Provider, Eth> DebugApi<Provider, Eth>
where
Provider: BlockReaderIdExt + HeaderProvider + ChainSpecProvider + 'static,
Eth: EthTransactions + LoadState + SpawnBlocking + 'static,
Eth: EthTransactions + LoadState + SpawnBlocking + LoadPendingBlock + 'static,
{
/// Acquires a permit to execute a tracing call.
async fn acquire_trace_permit(&self) -> Result<OwnedSemaphorePermit, AcquireError> {
Expand Down Expand Up @@ -614,7 +614,7 @@ where
impl<Provider, Eth> DebugApiServer for DebugApi<Provider, Eth>
where
Provider: BlockReaderIdExt + HeaderProvider + ChainSpecProvider + 'static,
Eth: EthApiSpec + SpawnBlocking + LoadState + 'static,
Eth: EthApiSpec + SpawnBlocking + LoadState + LoadPendingBlock + 'static,
{
/// Handler for `debug_getRawHeader`
async fn raw_header(&self, block_id: BlockId) -> RpcResult<Bytes> {
Expand Down
171 changes: 146 additions & 25 deletions crates/rpc/rpc/src/eth/api/traits/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ use std::{fmt, sync::Arc};

use reth_evm::ConfigureEvm;
use reth_primitives::{
revm::env::fill_block_env_with_coinbase, BlockId, Bytes, FromRecoveredPooledTransaction,
Header, IntoRecoveredTransaction, Receipt, SealedBlock, SealedBlockWithSenders,
TransactionMeta, TransactionSigned, TxHash, B256,
revm::env::{fill_block_env_with_coinbase, tx_env_with_recovered},
BlockId, Bytes, FromRecoveredPooledTransaction, Header, IntoRecoveredTransaction, Receipt,
SealedBlock, SealedBlockWithSenders, TransactionMeta, TransactionSigned, TxHash, B256,
};
use reth_provider::{
BlockIdReader, BlockReaderIdExt, ReceiptProvider, StateProviderBox, TransactionsProvider,
};
use reth_provider::{BlockReaderIdExt, ReceiptProvider, StateProviderBox, TransactionsProvider};
use reth_revm::database::StateProviderDatabase;
use reth_rpc_types::{AnyTransactionReceipt, TransactionInfo, TransactionRequest};
use reth_transaction_pool::{TransactionOrigin, TransactionPool};
Expand All @@ -29,10 +31,13 @@ use revm_primitives::{

use crate::{
eth::{
api::{BuildReceipt, EthState, LoadState, SpawnBlocking},
api::{
pending_block::PendingBlockEnv, BuildReceipt, EthState, LoadPendingBlock, LoadState,
SpawnBlocking,
},
cache::EthStateCache,
error::{EthApiError, EthResult},
revm_utils::{EvmOverrides, FillableTransaction},
revm_utils::{prepare_call_env, EvmOverrides, FillableTransaction},
utils::recover_raw_transaction,
TransactionSource,
},
Expand Down Expand Up @@ -191,7 +196,7 @@ pub trait EthTransactions: Send + Sync {
/// Returns default gas limit to use for `eth_call` and tracing RPC methods.
fn call_gas_limit(&self) -> u64;

/// Executes the closure with the state that corresponds to the given [BlockId].
/// Executes the closure with the state that corresponds to the given [`BlockId`].
fn with_state_at_block<F, T>(&self, at: BlockId, f: F) -> EthResult<T>
where
Self: LoadState,
Expand All @@ -201,7 +206,7 @@ pub trait EthTransactions: Send + Sync {
f(state)
}

/// Executes the closure with the state that corresponds to the given [BlockId] on a new task
/// Executes the closure with the state that corresponds to the given [`BlockId`] on a new task
async fn spawn_with_state_at_block<F, T>(&self, at: BlockId, f: F) -> EthResult<T>
where
Self: LoadState + SpawnBlocking,
Expand All @@ -215,15 +220,28 @@ pub trait EthTransactions: Send + Sync {
.await
}

/// Returns the revm evm env for the requested [BlockId]
/// Returns the revm evm env for the requested [`BlockId`]
///
/// If the [BlockId] this will return the [BlockId] of the block the env was configured
/// If the [`BlockId`] this will return the [`BlockId`] of the block the env was configured
/// for.
/// If the [BlockId] is pending, this will return the "Pending" tag, otherwise this returns the
/// hash of the exact block.
/// If the [`BlockId`] is pending, this will return the "Pending" tag, otherwise this returns
/// the hash of the exact block.
async fn evm_env_at(&self, at: BlockId) -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv, BlockId)>
where
Self: LoadState;
Self: LoadState + LoadPendingBlock,
{
if at.is_pending() {
let PendingBlockEnv { cfg, block_env, origin } = self.pending_block_env_and_cfg()?;
Ok((cfg, block_env, origin.state_block_id()))
} else {
// Use cached values if there is no pending block
let block_hash = EthTransactions::provider(self)
.block_hash_for_id(at)?
.ok_or_else(|| EthApiError::UnknownBlockNumber)?;
let (cfg, env) = self.cache().get_evm_env(block_hash).await?;
Ok((cfg, env, block_hash.into()))
}
}

/// Returns the revm evm env for the raw block header
///
Expand All @@ -233,7 +251,7 @@ pub trait EthTransactions: Send + Sync {
header: &Header,
) -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv)>
where
Self: LoadState,
Self: LoadState + LoadPendingBlock,
{
// get the parent config first
let (cfg, mut block_env, _) = self.evm_env_at(header.parent_hash.into()).await?;
Expand Down Expand Up @@ -483,9 +501,29 @@ pub trait EthTransactions: Send + Sync {
f: F,
) -> EthResult<R>
where
Self: LoadState,
Self: LoadState + SpawnBlocking + LoadPendingBlock,
F: FnOnce(&mut StateCacheDB, EnvWithHandlerCfg) -> EthResult<R> + Send + 'static,
R: Send + 'static;
R: Send + 'static,
{
let (cfg, block_env, at) = self.evm_env_at(at).await?;
let this = self.clone();
self.spawn_tracing(move |_| {
let state = this.state_at_block_id(at)?;
let mut db = CacheDB::new(StateProviderDatabase::new(state));

let env = prepare_call_env(
cfg,
block_env,
request,
this.call_gas_limit(),
&mut db,
overrides,
)?;
f(&mut db, env)
})
.await
.map_err(|_| EthApiError::InternalBlockingTaskError)
}

/// Executes the call request at the given [BlockId].
async fn transact_call_at(
Expand All @@ -495,7 +533,11 @@ pub trait EthTransactions: Send + Sync {
overrides: EvmOverrides,
) -> EthResult<(ResultAndState, EnvWithHandlerCfg)>
where
Self: LoadState;
Self: LoadState + LoadPendingBlock,
{
let this = self.clone();
self.spawn_with_call_at(request, at, overrides, move |db, env| this.transact(db, env)).await
}

/// Executes the call request at the given [BlockId] on a new task and returns the result of the
/// inspect call.
Expand All @@ -507,8 +549,15 @@ pub trait EthTransactions: Send + Sync {
inspector: I,
) -> EthResult<(ResultAndState, EnvWithHandlerCfg)>
where
Self: LoadState,
I: for<'a> Inspector<&'a mut StateCacheDB> + Send + 'static;
Self: LoadState + LoadPendingBlock,
I: for<'a> Inspector<&'a mut StateCacheDB> + Send + 'static,
{
let this = self.clone();
self.spawn_with_call_at(request, at, overrides, move |db, env| {
this.inspect(db, env, inspector)
})
.await
}

/// Executes the transaction on top of the given [BlockId] with a tracer configured by the
/// config.
Expand Down Expand Up @@ -603,7 +652,7 @@ pub trait EthTransactions: Send + Sync {
f: F,
) -> EthResult<Option<R>>
where
Self: LoadState,
Self: LoadState + LoadPendingBlock,
F: FnOnce(TransactionInfo, TracingInspector, ResultAndState, StateCacheDB) -> EthResult<R>
+ Send
+ 'static,
Expand All @@ -624,9 +673,45 @@ pub trait EthTransactions: Send + Sync {
/// [BlockingTaskPool](reth_tasks::pool::BlockingTaskPool).
async fn spawn_replay_transaction<F, R>(&self, hash: B256, f: F) -> EthResult<Option<R>>
where
Self: LoadState,
Self: LoadState + LoadPendingBlock,
F: FnOnce(TransactionInfo, ResultAndState, StateCacheDB) -> EthResult<R> + Send + 'static,
R: Send + 'static;
R: Send + 'static,
{
let (transaction, block) = match self.transaction_and_block(hash).await? {
None => return Ok(None),
Some(res) => res,
};
let (tx, tx_info) = transaction.split();

let (cfg, block_env, _) = self.evm_env_at(block.hash().into()).await?;

// we need to get the state of the parent block because we're essentially replaying the
// block the transaction is included in
let parent_block = block.parent_hash;
let block_txs = block.into_transactions_ecrecovered();

let this = self.clone();
self.spawn_with_state_at_block(parent_block.into(), move |state| {
let mut db = CacheDB::new(StateProviderDatabase::new(state));

// replay all transactions prior to the targeted transaction
this.replay_transactions_until(
&mut db,
cfg.clone(),
block_env.clone(),
block_txs,
tx.hash,
)?;

let env =
EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, tx_env_with_recovered(&tx));

let (res, _) = this.transact(&mut db, env)?;
f(tx_info, res, db)
})
.await
.map(Some)
}

/// Retrieves the transaction if it exists and returns its trace.
///
Expand All @@ -640,16 +725,52 @@ pub trait EthTransactions: Send + Sync {
async fn spawn_trace_transaction_in_block_with_inspector<Insp, F, R>(
&self,
hash: B256,
inspector: Insp,
mut inspector: Insp,
f: F,
) -> EthResult<Option<R>>
where
Self: LoadState,
Self: LoadState + LoadPendingBlock,
F: FnOnce(TransactionInfo, Insp, ResultAndState, StateCacheDB) -> EthResult<R>
+ Send
+ 'static,
Insp: for<'a> Inspector<&'a mut StateCacheDB> + Send + 'static,
R: Send + 'static;
R: Send + 'static,
{
let (transaction, block) = match self.transaction_and_block(hash).await? {
None => return Ok(None),
Some(res) => res,
};
let (tx, tx_info) = transaction.split();

let (cfg, block_env, _) = self.evm_env_at(block.hash().into()).await?;

// we need to get the state of the parent block because we're essentially replaying the
// block the transaction is included in
let parent_block = block.parent_hash;
let block_txs = block.into_transactions_ecrecovered();

let this = self.clone();
self.spawn_with_state_at_block(parent_block.into(), move |state| {
let mut db = CacheDB::new(StateProviderDatabase::new(state));

// replay all transactions prior to the targeted transaction
this.replay_transactions_until(
&mut db,
cfg.clone(),
block_env.clone(),
block_txs,
tx.hash,
)?;

let env =
EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, tx_env_with_recovered(&tx));

let (res, _) = this.inspect(&mut db, env, &mut inspector)?;
f(tx_info, inspector, res, db)
})
.await
.map(Some)
}

/// Executes all transactions of a block and returns a list of callback results invoked for each
/// transaction in the block.
Expand Down
Loading
Loading