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): pending block helper trait #8640

Merged
merged 44 commits into from
Jun 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 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
e93cb32
Nitpick
emhane Jun 8, 2024
b1a3160
Return impl types without ref
emhane Jun 8, 2024
9ec16f0
Move RawTransactionForwarder into traits mod
emhane Jun 8, 2024
34eac96
Merge branch 'matt/scaffold-ethapi' into emhane/ethapi-txns
emhane Jun 8, 2024
13edf49
Fix merge conflicts
emhane Jun 8, 2024
42f7d74
Merge branch 'emhane/ethapi-txns' of github.com:paradigmxyz/reth into…
emhane Jun 8, 2024
a355c26
Merge branch 'emhane/ethapi-txns' into emhane/ethapi-pending-block
emhane Jun 8, 2024
4b81978
Fix lint
emhane Jun 8, 2024
4efb2e8
Merge branch 'matt/scaffold-ethapi' into emhane/ethapi-pending-block
emhane Jun 8, 2024
008f939
Fix lint
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
derive_more = { workspace = true, default-features = false, features = ["deref", "deref_mut", "constructor"] }
dyn-clone.workspace = true
auto_impl.workspace = true

Expand Down
33 changes: 23 additions & 10 deletions crates/rpc/rpc/src/eth/api/block.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
//! Contains RPC handler implementations specific to blocks.

use crate::{
eth::error::{EthApiError, EthResult},
EthApi,
};

use reth_evm::ConfigureEvm;
use reth_network_api::NetworkInfo;
use reth_primitives::BlockId;
Expand All @@ -16,7 +11,13 @@ use reth_rpc_types::{Header, Index, RichBlock};
use reth_rpc_types_compat::block::{from_block, uncle_block_from_header};
use reth_transaction_pool::TransactionPool;

use crate::eth::api::EthBlocks;
use crate::{
eth::{
api::{EthBlocks, LoadPendingBlock},
error::{EthApiError, EthResult},
},
EthApi,
};

impl<Provider, Pool, Network, EvmConfig> EthBlocks for EthApi<Provider, Pool, Network, EvmConfig>
where
Expand Down Expand Up @@ -94,7 +95,10 @@ where
pub(crate) async fn block(
&self,
block_id: impl Into<BlockId>,
) -> EthResult<Option<reth_primitives::SealedBlock>> {
) -> EthResult<Option<reth_primitives::SealedBlock>>
where
Self: LoadPendingBlock,
{
self.block_with_senders(block_id)
.await
.map(|maybe_block| maybe_block.map(|block| block.block))
Expand All @@ -104,7 +108,10 @@ where
pub(crate) async fn block_with_senders(
&self,
block_id: impl Into<BlockId>,
) -> EthResult<Option<reth_primitives::SealedBlockWithSenders>> {
) -> EthResult<Option<reth_primitives::SealedBlockWithSenders>>
where
Self: LoadPendingBlock,
{
let block_id = block_id.into();

if block_id.is_pending() {
Expand Down Expand Up @@ -133,7 +140,10 @@ where
&self,
block_id: impl Into<BlockId>,
full: bool,
) -> EthResult<Option<RichBlock>> {
) -> EthResult<Option<RichBlock>>
where
Self: LoadPendingBlock,
{
let block = match self.block_with_senders(block_id).await? {
Some(block) => block,
None => return Ok(None),
Expand All @@ -151,7 +161,10 @@ where
pub(crate) async fn rpc_block_header(
&self,
block_id: impl Into<BlockId>,
) -> EthResult<Option<Header>> {
) -> EthResult<Option<Header>>
where
Self: LoadPendingBlock,
{
let header = self.rpc_block(block_id, false).await?.map(|block| block.inner.header);
Ok(header)
}
Expand Down
30 changes: 16 additions & 14 deletions crates/rpc/rpc/src/eth/api/call.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
//! Contains RPC handler implementations specific to endpoints that call/execute within evm.

use crate::{
eth::{
api::{EthTransactions, SpawnBlocking},
error::{ensure_success, EthApiError, EthResult, RevertError, RpcInvalidTransactionError},
revm_utils::{
apply_state_overrides, build_call_evm_env, caller_gas_allowance,
cap_tx_gas_limit_with_caller_allowance, get_precompiles, prepare_call_env,
EvmOverrides,
},
},
EthApi,
};
use reth_evm::ConfigureEvm;
use reth_network_api::NetworkInfo;
use reth_primitives::{revm::env::tx_env_with_recovered, BlockId, Bytes, TxKind, U256};
Expand All @@ -34,7 +22,18 @@ use revm::{
use revm_inspectors::access_list::AccessListInspector;
use tracing::trace;

use super::LoadState;
use crate::{
eth::{
api::{EthTransactions, LoadPendingBlock, LoadState, SpawnBlocking},
error::{ensure_success, EthApiError, EthResult, RevertError, RpcInvalidTransactionError},
revm_utils::{
apply_state_overrides, build_call_evm_env, caller_gas_allowance,
cap_tx_gas_limit_with_caller_allowance, get_precompiles, prepare_call_env,
EvmOverrides,
},
},
EthApi,
};

// Gas per transaction not creating a contract.
const MIN_TRANSACTION_GAS: u64 = 21_000u64;
Expand Down Expand Up @@ -88,7 +87,10 @@ where
bundle: Bundle,
state_context: Option<StateContext>,
mut state_override: Option<StateOverride>,
) -> EthResult<Vec<EthCallResponse>> {
) -> EthResult<Vec<EthCallResponse>>
where
Self: LoadPendingBlock,
{
let Bundle { transactions, block_override } = bundle;
if transactions.is_empty() {
return Err(EthApiError::InvalidParams(String::from("transactions are empty.")))
Expand Down
19 changes: 12 additions & 7 deletions crates/rpc/rpc/src/eth/api/fees.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
//! Contains RPC handler implementations for fee history.

use crate::{
eth::{
api::fee_history::{calculate_reward_percentiles_for_block, FeeHistoryEntry},
error::{EthApiError, EthResult},
},
EthApi,
};
use reth_evm::ConfigureEvm;
use reth_network_api::NetworkInfo;
use reth_primitives::{BlockNumberOrTag, U256};
Expand All @@ -15,8 +8,20 @@ use reth_rpc_types::FeeHistory;
use reth_transaction_pool::TransactionPool;
use tracing::debug;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use crate::{
eth::{
api::{
fee_history::{calculate_reward_percentiles_for_block, FeeHistoryEntry},
LoadPendingBlock,
},
error::{EthApiError, EthResult},
},
EthApi,
};

impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig>
where
Self: LoadPendingBlock,
Pool: TransactionPool + Clone + 'static,
Provider:
BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static,
Expand Down
146 changes: 17 additions & 129 deletions crates/rpc/rpc/src/eth/api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,41 @@
//! The entire implementation of the namespace is quite large, hence it is divided across several
//! files.

use std::{fmt::Debug, sync::Arc};

use async_trait::async_trait;
use reth_errors::{RethError, RethResult};
use reth_evm::ConfigureEvm;
use reth_network_api::NetworkInfo;
use reth_primitives::{
revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg},
Address, BlockNumberOrTag, ChainInfo, SealedBlockWithSenders, SealedHeader, U256, U64,
};
use reth_primitives::{Address, BlockNumberOrTag, ChainInfo, U256, U64};
use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory};
use reth_rpc_types::{SyncInfo, SyncStatus};
use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor};
use reth_transaction_pool::TransactionPool;
use revm_primitives::{CfgEnv, SpecId};
use std::{
fmt::Debug,
sync::Arc,
time::{Duration, Instant},
};
use tokio::sync::Mutex;

use crate::eth::{
api::{
fee_history::FeeHistoryCache,
pending_block::{PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin},
},
cache::EthStateCache,
error::{EthApiError, EthResult},
gas_oracle::GasPriceOracle,
api::fee_history::FeeHistoryCache, cache::EthStateCache, gas_oracle::GasPriceOracle,
signer::EthSigner,
};

pub mod block;
mod call;
pub(crate) mod fee_history;

mod fees;
mod pending_block;
pub mod pending_block;
pub mod receipt;
mod server;
mod sign;
mod state;
pub mod traits;
pub mod transactions;

pub use pending_block::PendingBlock;
pub use receipt::ReceiptBuilder;
pub use traits::{
BuildReceipt, EthBlocks, EthState, EthTransactions, LoadState, RawTransactionForwarder,
SpawnBlocking, StateCacheDB,
BuildReceipt, EthBlocks, EthState, EthTransactions, LoadPendingBlock, LoadState,
RawTransactionForwarder, SpawnBlocking, StateCacheDB,
};
pub use transactions::TransactionSource;

Expand Down Expand Up @@ -211,120 +198,15 @@ where
}
}

impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig>
where
Provider:
BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static,
Pool: TransactionPool + 'static,
Network: NetworkInfo + 'static,
EvmConfig: ConfigureEvm,
{
/// Configures the [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the pending block
///
/// If no pending block is available, this will derive it from the `latest` block
pub(crate) fn pending_block_env_and_cfg(&self) -> EthResult<PendingBlockEnv> {
let origin: PendingBlockEnvOrigin = if let Some(pending) =
self.provider().pending_block_with_senders()?
{
PendingBlockEnvOrigin::ActualPending(pending)
} else {
// no pending block from the CL yet, so we use the latest block and modify the env
// values that we can
let latest =
self.provider().latest_header()?.ok_or_else(|| EthApiError::UnknownBlockNumber)?;

let (mut latest_header, block_hash) = latest.split();
// child block
latest_header.number += 1;
// assumed child block is in the next slot: 12s
latest_header.timestamp += 12;
// base fee of the child block
let chain_spec = self.provider().chain_spec();

latest_header.base_fee_per_gas = latest_header.next_block_base_fee(
chain_spec.base_fee_params_at_timestamp(latest_header.timestamp),
);

// update excess blob gas consumed above target
latest_header.excess_blob_gas = latest_header.next_block_excess_blob_gas();

// we're reusing the same block hash because we need this to lookup the block's state
let latest = SealedHeader::new(latest_header, block_hash);

PendingBlockEnvOrigin::DerivedFromLatest(latest)
};

let mut cfg = CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), SpecId::LATEST);

let mut block_env = BlockEnv::default();
// Note: for the PENDING block we assume it is past the known merge block and thus this will
// not fail when looking up the total difficulty value for the blockenv.
self.provider().fill_env_with_header(
&mut cfg,
&mut block_env,
origin.header(),
self.inner.evm_config.clone(),
)?;

Ok(PendingBlockEnv { cfg, block_env, origin })
}

/// Returns the locally built pending block
pub(crate) async fn local_pending_block(&self) -> EthResult<Option<SealedBlockWithSenders>> {
let pending = self.pending_block_env_and_cfg()?;
if pending.origin.is_actual_pending() {
return Ok(pending.origin.into_actual_pending())
}

let mut lock = self.inner.pending_block.lock().await;

let now = Instant::now();

// check if the block is still good
if let Some(pending_block) = lock.as_ref() {
// this is guaranteed to be the `latest` header
if pending.block_env.number.to::<u64>() == pending_block.block.number &&
pending.origin.header().hash() == pending_block.block.parent_hash &&
now <= pending_block.expires_at
{
return Ok(Some(pending_block.block.clone()))
}
}

// no pending block from the CL yet, so we need to build it ourselves via txpool
let pending_block = match self
.spawn_blocking_io(move |this| {
// we rebuild the block
pending.build_block(this.provider(), this.pool())
})
.await
{
Ok(block) => block,
Err(err) => {
tracing::debug!(target: "rpc", "Failed to build pending block: {:?}", err);
return Ok(None)
}
};

let now = Instant::now();
*lock = Some(PendingBlock {
block: pending_block.clone(),
expires_at: now + Duration::from_secs(1),
});

Ok(Some(pending_block))
}
}

impl<Provider, Pool, Events, EvmConfig> std::fmt::Debug
for EthApi<Provider, Pool, Events, EvmConfig>
impl<Provider, Pool, Network, EvmConfig> std::fmt::Debug
for EthApi<Provider, Pool, Network, EvmConfig>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EthApi").finish_non_exhaustive()
}
}

impl<Provider, Pool, Events, EvmConfig> Clone for EthApi<Provider, Pool, Events, EvmConfig> {
impl<Provider, Pool, Network, EvmConfig> Clone for EthApi<Provider, Pool, Network, EvmConfig> {
fn clone(&self) -> Self {
Self { inner: Arc::clone(&self.inner) }
}
Expand Down Expand Up @@ -474,6 +356,12 @@ impl<Provider, Pool, Network, EvmConfig> EthApiInner<Provider, Pool, Network, Ev
&self.eth_cache
}

/// Returns a handle to the pending block.
#[inline]
pub const fn pending_block(&self) -> &Mutex<Option<PendingBlock>> {
&self.pending_block
}

/// Returns a handle to the task spawner.
#[inline]
pub const fn task_spawner(&self) -> &dyn TaskSpawner {
Expand Down
Loading
Loading