mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: flashbots_validateBuilderSubmissionV3 (#12168)
This commit is contained in:
@ -24,6 +24,7 @@ eyre.workspace = true
|
||||
rand.workspace = true
|
||||
secp256k1 = { workspace = true, features = ["rand"] }
|
||||
thiserror.workspace = true
|
||||
serde.workspace = true
|
||||
|
||||
tracy-client = { workspace = true, optional = true, features = ["demangle"] }
|
||||
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
use alloy_eips::BlockHashOrNumber;
|
||||
use alloy_primitives::B256;
|
||||
use reth_fs_util::FsPathError;
|
||||
use std::{
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs},
|
||||
path::Path,
|
||||
str::FromStr,
|
||||
time::Duration,
|
||||
};
|
||||
@ -82,6 +84,11 @@ pub fn parse_socket_address(value: &str) -> eyre::Result<SocketAddr, SocketAddre
|
||||
.ok_or_else(|| SocketAddressParsingError::Parse(value.to_string()))
|
||||
}
|
||||
|
||||
/// Wrapper around [`reth_fs_util::read_json_file`] which can be used as a clap value parser.
|
||||
pub fn read_json_from_file<T: serde::de::DeserializeOwned>(path: &str) -> Result<T, FsPathError> {
|
||||
reth_fs_util::read_json_file(Path::new(path))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@ -7,6 +7,7 @@ use reth::{
|
||||
args::{DiscoveryArgs, NetworkArgs, RpcServerArgs},
|
||||
builder::{NodeBuilder, NodeConfig, NodeHandle},
|
||||
network::PeersHandleProvider,
|
||||
rpc::server_types::RpcModuleSelection,
|
||||
tasks::TaskManager,
|
||||
};
|
||||
use reth_chainspec::{EthChainSpec, EthereumHardforks};
|
||||
@ -147,7 +148,12 @@ where
|
||||
let node_config = NodeConfig::new(chain_spec.clone())
|
||||
.with_network(network_config.clone())
|
||||
.with_unused_ports()
|
||||
.with_rpc(RpcServerArgs::default().with_unused_ports().with_http())
|
||||
.with_rpc(
|
||||
RpcServerArgs::default()
|
||||
.with_unused_ports()
|
||||
.with_http()
|
||||
.with_http_api(RpcModuleSelection::All),
|
||||
)
|
||||
.set_dev(is_dev);
|
||||
|
||||
let span = span!(Level::INFO, "node", idx);
|
||||
|
||||
@ -24,7 +24,7 @@ use reth_primitives::{
|
||||
use std::{fmt::Debug, sync::Arc, time::SystemTime};
|
||||
|
||||
/// The bound divisor of the gas limit, used in update calculations.
|
||||
const GAS_LIMIT_BOUND_DIVISOR: u64 = 1024;
|
||||
pub const GAS_LIMIT_BOUND_DIVISOR: u64 = 1024;
|
||||
|
||||
mod validation;
|
||||
pub use validation::validate_block_post_execution;
|
||||
@ -32,7 +32,7 @@ pub use validation::validate_block_post_execution;
|
||||
/// Ethereum beacon consensus
|
||||
///
|
||||
/// This consensus engine does basic checks as outlined in the execution specs.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EthBeaconConsensus<ChainSpec> {
|
||||
/// Configuration
|
||||
chain_spec: Arc<ChainSpec>,
|
||||
|
||||
@ -59,6 +59,7 @@ alloy-signer.workspace = true
|
||||
alloy-eips.workspace = true
|
||||
alloy-sol-types.workspace = true
|
||||
alloy-contract.workspace = true
|
||||
alloy-rpc-types-beacon.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
use crate::utils::eth_payload_attributes;
|
||||
use alloy_eips::calc_next_block_base_fee;
|
||||
use alloy_primitives::U256;
|
||||
use alloy_provider::{network::EthereumWallet, Provider, ProviderBuilder};
|
||||
use alloy_eips::{calc_next_block_base_fee, eip2718::Encodable2718};
|
||||
use alloy_primitives::{Address, B256, U256};
|
||||
use alloy_provider::{network::EthereumWallet, Provider, ProviderBuilder, SendableTx};
|
||||
use alloy_rpc_types_beacon::relay::{BidTrace, SignedBidSubmissionV3};
|
||||
use rand::{rngs::StdRng, Rng, SeedableRng};
|
||||
use reth::rpc::{
|
||||
api::BuilderBlockValidationRequestV3,
|
||||
compat::engine::payload::block_to_payload_v3,
|
||||
types::{engine::BlobsBundleV1, TransactionRequest},
|
||||
};
|
||||
use reth_chainspec::{ChainSpecBuilder, MAINNET};
|
||||
use reth_e2e_test_utils::setup_engine;
|
||||
use reth_node_ethereum::EthereumNode;
|
||||
@ -107,3 +113,77 @@ async fn test_fee_history() -> eyre::Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_flashbots_validate() -> eyre::Result<()> {
|
||||
reth_tracing::init_test_tracing();
|
||||
|
||||
let chain_spec = Arc::new(
|
||||
ChainSpecBuilder::default()
|
||||
.chain(MAINNET.chain)
|
||||
.genesis(serde_json::from_str(include_str!("../assets/genesis.json")).unwrap())
|
||||
.cancun_activated()
|
||||
.build(),
|
||||
);
|
||||
|
||||
let (mut nodes, _tasks, wallet) =
|
||||
setup_engine::<EthereumNode>(1, chain_spec.clone(), false, eth_payload_attributes).await?;
|
||||
let mut node = nodes.pop().unwrap();
|
||||
let provider = ProviderBuilder::new()
|
||||
.with_recommended_fillers()
|
||||
.wallet(EthereumWallet::new(wallet.gen().swap_remove(0)))
|
||||
.on_http(node.rpc_url());
|
||||
|
||||
node.advance(100, |_| {
|
||||
let provider = provider.clone();
|
||||
Box::pin(async move {
|
||||
let SendableTx::Envelope(tx) =
|
||||
provider.fill(TransactionRequest::default().to(Address::ZERO)).await.unwrap()
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
tx.encoded_2718().into()
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
|
||||
let _ = provider.send_transaction(TransactionRequest::default().to(Address::ZERO)).await?;
|
||||
let (payload, attrs) = node.new_payload().await?;
|
||||
|
||||
let mut request = BuilderBlockValidationRequestV3 {
|
||||
request: SignedBidSubmissionV3 {
|
||||
message: BidTrace {
|
||||
parent_hash: payload.block().parent_hash,
|
||||
block_hash: payload.block().hash(),
|
||||
gas_used: payload.block().gas_used,
|
||||
gas_limit: payload.block().gas_limit,
|
||||
..Default::default()
|
||||
},
|
||||
execution_payload: block_to_payload_v3(payload.block().clone()),
|
||||
blobs_bundle: BlobsBundleV1::new([]),
|
||||
signature: Default::default(),
|
||||
},
|
||||
parent_beacon_block_root: attrs.parent_beacon_block_root.unwrap(),
|
||||
registered_gas_limit: payload.block().gas_limit,
|
||||
};
|
||||
|
||||
assert!(provider
|
||||
.raw_request::<_, ()>("flashbots_validateBuilderSubmissionV3".into(), (&request,))
|
||||
.await
|
||||
.is_ok());
|
||||
|
||||
request.registered_gas_limit -= 1;
|
||||
assert!(provider
|
||||
.raw_request::<_, ()>("flashbots_validateBuilderSubmissionV3".into(), (&request,))
|
||||
.await
|
||||
.is_err());
|
||||
request.registered_gas_limit += 1;
|
||||
|
||||
request.request.execution_payload.payload_inner.payload_inner.state_root = B256::ZERO;
|
||||
assert!(provider
|
||||
.raw_request::<_, ()>("flashbots_validateBuilderSubmissionV3".into(), (&request,))
|
||||
.await
|
||||
.is_err());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -198,6 +198,7 @@ pub struct RpcRegistry<Node: FullNodeComponents, EthApi: EthApiTypes> {
|
||||
Node::Provider,
|
||||
EthApi,
|
||||
Node::Executor,
|
||||
Node::Consensus,
|
||||
>,
|
||||
}
|
||||
|
||||
@ -214,6 +215,7 @@ where
|
||||
Node::Provider,
|
||||
EthApi,
|
||||
Node::Executor,
|
||||
Node::Consensus,
|
||||
>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
@ -442,6 +444,7 @@ where
|
||||
.with_executor(node.task_executor().clone())
|
||||
.with_evm_config(node.evm_config().clone())
|
||||
.with_block_executor(node.block_executor().clone())
|
||||
.with_consensus(node.consensus().clone())
|
||||
.build_with_auth_server(module_config, engine_api, eth_api_builder);
|
||||
|
||||
// in dev mode we generate 20 random dev-signer accounts
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
//! clap [Args](clap::Args) for RPC related arguments.
|
||||
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
ffi::OsStr,
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use alloy_primitives::Address;
|
||||
use alloy_rpc_types_engine::JwtSecret;
|
||||
use clap::{
|
||||
builder::{PossibleValue, RangedU64ValueParser, TypedValueParser},
|
||||
@ -183,6 +185,11 @@ pub struct RpcServerArgs {
|
||||
#[arg(long = "rpc.proof-permits", alias = "rpc-proof-permits", value_name = "COUNT", default_value_t = constants::DEFAULT_PROOF_PERMITS)]
|
||||
pub rpc_proof_permits: usize,
|
||||
|
||||
/// Path to file containing disallowed addresses, json-encoded list of strings. Block
|
||||
/// validation API will reject blocks containing transactions from these addresses.
|
||||
#[arg(long = "builder.disallow", value_name = "PATH", value_parser = reth_cli_util::parsers::read_json_from_file::<HashSet<Address>>)]
|
||||
pub builder_disallow: Option<HashSet<Address>>,
|
||||
|
||||
/// State cache configuration.
|
||||
#[command(flatten)]
|
||||
pub rpc_state_cache: RpcStateCacheArgs,
|
||||
@ -199,6 +206,12 @@ impl RpcServerArgs {
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures modules for the HTTP-RPC server.
|
||||
pub fn with_http_api(mut self, http_api: RpcModuleSelection) -> Self {
|
||||
self.http_api = Some(http_api);
|
||||
self
|
||||
}
|
||||
|
||||
/// Enables the WS-RPC server.
|
||||
pub const fn with_ws(mut self) -> Self {
|
||||
self.ws = true;
|
||||
@ -318,6 +331,7 @@ impl Default for RpcServerArgs {
|
||||
gas_price_oracle: GasPriceOracleArgs::default(),
|
||||
rpc_state_cache: RpcStateCacheArgs::default(),
|
||||
rpc_proof_permits: constants::DEFAULT_PROOF_PERMITS,
|
||||
builder_disallow: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ pub struct ExecutionPayloadValidator<ChainSpec> {
|
||||
chain_spec: Arc<ChainSpec>,
|
||||
}
|
||||
|
||||
impl<ChainSpec: EthereumHardforks> ExecutionPayloadValidator<ChainSpec> {
|
||||
impl<ChainSpec> ExecutionPayloadValidator<ChainSpec> {
|
||||
/// Create a new validator.
|
||||
pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
|
||||
Self { chain_spec }
|
||||
@ -34,7 +34,9 @@ impl<ChainSpec: EthereumHardforks> ExecutionPayloadValidator<ChainSpec> {
|
||||
pub fn chain_spec(&self) -> &ChainSpec {
|
||||
&self.chain_spec
|
||||
}
|
||||
}
|
||||
|
||||
impl<ChainSpec: EthereumHardforks> ExecutionPayloadValidator<ChainSpec> {
|
||||
/// Returns true if the Cancun hardfork is active at the given timestamp.
|
||||
#[inline]
|
||||
fn is_cancun_active_at_timestamp(&self, timestamp: u64) -> bool {
|
||||
|
||||
@ -36,6 +36,8 @@ alloy-rpc-types-engine.workspace = true
|
||||
|
||||
# misc
|
||||
jsonrpsee = { workspace = true, features = ["server", "macros"] }
|
||||
serde.workspace = true
|
||||
serde_with.workspace = true
|
||||
|
||||
[features]
|
||||
client = [
|
||||
|
||||
@ -46,7 +46,7 @@ pub mod servers {
|
||||
rpc::RpcApiServer,
|
||||
trace::TraceApiServer,
|
||||
txpool::TxPoolApiServer,
|
||||
validation::BlockSubmissionValidationApiServer,
|
||||
validation::{BlockSubmissionValidationApiServer, BuilderBlockValidationRequestV3},
|
||||
web3::Web3ApiServer,
|
||||
};
|
||||
pub use reth_rpc_eth_api::{
|
||||
|
||||
@ -1,9 +1,28 @@
|
||||
//! API for block submission validation.
|
||||
|
||||
use alloy_primitives::B256;
|
||||
use alloy_rpc_types_beacon::relay::{
|
||||
BuilderBlockValidationRequest, BuilderBlockValidationRequestV2, BuilderBlockValidationRequestV3,
|
||||
BuilderBlockValidationRequest, BuilderBlockValidationRequestV2, SignedBidSubmissionV3,
|
||||
};
|
||||
use jsonrpsee::proc_macros::rpc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::{serde_as, DisplayFromStr};
|
||||
|
||||
/// A Request to validate a [`SignedBidSubmissionV3`]
|
||||
///
|
||||
/// <https://github.com/flashbots/builder/blob/7577ac81da21e760ec6693637ce2a81fe58ac9f8/eth/block-validation/api.go#L198-L202>
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct BuilderBlockValidationRequestV3 {
|
||||
/// The request to be validated.
|
||||
#[serde(flatten)]
|
||||
pub request: SignedBidSubmissionV3,
|
||||
/// The registered gas limit for the validation request.
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
pub registered_gas_limit: u64,
|
||||
/// The parent beacon block root for the validation request.
|
||||
pub parent_beacon_block_root: B256,
|
||||
}
|
||||
|
||||
/// Block validation rpc interface.
|
||||
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "flashbots"))]
|
||||
|
||||
@ -15,6 +15,7 @@ workspace = true
|
||||
# reth
|
||||
reth-ipc.workspace = true
|
||||
reth-chainspec.workspace = true
|
||||
reth-consensus.workspace = true
|
||||
reth-network-api.workspace = true
|
||||
reth-node-core.workspace = true
|
||||
reth-provider.workspace = true
|
||||
|
||||
@ -2,6 +2,7 @@ use std::{net::SocketAddr, path::PathBuf};
|
||||
|
||||
use jsonrpsee::server::ServerBuilder;
|
||||
use reth_node_core::{args::RpcServerArgs, utils::get_or_create_jwt_secret_from_path};
|
||||
use reth_rpc::ValidationApiConfig;
|
||||
use reth_rpc_eth_types::{EthConfig, EthStateCacheConfig, GasPriceOracleConfig};
|
||||
use reth_rpc_layer::{JwtError, JwtSecret};
|
||||
use reth_rpc_server_types::RpcModuleSelection;
|
||||
@ -27,6 +28,9 @@ pub trait RethRpcServerConfig {
|
||||
/// The configured ethereum RPC settings.
|
||||
fn eth_config(&self) -> EthConfig;
|
||||
|
||||
/// The configured ethereum RPC settings.
|
||||
fn flashbots_config(&self) -> ValidationApiConfig;
|
||||
|
||||
/// Returns state cache configuration.
|
||||
fn state_cache_config(&self) -> EthStateCacheConfig;
|
||||
|
||||
@ -101,6 +105,10 @@ impl RethRpcServerConfig for RpcServerArgs {
|
||||
.proof_permits(self.rpc_proof_permits)
|
||||
}
|
||||
|
||||
fn flashbots_config(&self) -> ValidationApiConfig {
|
||||
ValidationApiConfig { disallow: self.builder_disallow.clone().unwrap_or_default() }
|
||||
}
|
||||
|
||||
fn state_cache_config(&self) -> EthStateCacheConfig {
|
||||
EthStateCacheConfig {
|
||||
max_blocks: self.rpc_state_cache.max_blocks,
|
||||
@ -124,7 +132,7 @@ impl RethRpcServerConfig for RpcServerArgs {
|
||||
|
||||
fn transport_rpc_module_config(&self) -> TransportRpcModuleConfig {
|
||||
let mut config = TransportRpcModuleConfig::default()
|
||||
.with_config(RpcModuleConfig::new(self.eth_config()));
|
||||
.with_config(RpcModuleConfig::new(self.eth_config(), self.flashbots_config()));
|
||||
|
||||
if self.http {
|
||||
config = config.with_http(
|
||||
|
||||
@ -27,13 +27,14 @@
|
||||
//! use reth_tasks::TokioTaskExecutor;
|
||||
//! use reth_transaction_pool::TransactionPool;
|
||||
//!
|
||||
//! pub async fn launch<Provider, Pool, Network, Events, EvmConfig, BlockExecutor>(
|
||||
//! pub async fn launch<Provider, Pool, Network, Events, EvmConfig, BlockExecutor, Consensus>(
|
||||
//! provider: Provider,
|
||||
//! pool: Pool,
|
||||
//! network: Network,
|
||||
//! events: Events,
|
||||
//! evm_config: EvmConfig,
|
||||
//! block_executor: BlockExecutor,
|
||||
//! consensus: Consensus,
|
||||
//! ) where
|
||||
//! Provider: FullRpcProvider + AccountReader + ChangeSetReader,
|
||||
//! Pool: TransactionPool + Unpin + 'static,
|
||||
@ -41,6 +42,7 @@
|
||||
//! Events: CanonStateSubscriptions + Clone + 'static,
|
||||
//! EvmConfig: ConfigureEvm<Header = Header>,
|
||||
//! BlockExecutor: BlockExecutorProvider,
|
||||
//! Consensus: reth_consensus::Consensus + Clone + 'static,
|
||||
//! {
|
||||
//! // configure the rpc module per transport
|
||||
//! let transports = TransportRpcModuleConfig::default().with_http(vec![
|
||||
@ -57,6 +59,7 @@
|
||||
//! events,
|
||||
//! evm_config,
|
||||
//! block_executor,
|
||||
//! consensus,
|
||||
//! )
|
||||
//! .build(transports, Box::new(EthApi::with_spawner));
|
||||
//! let handle = RpcServerConfig::default()
|
||||
@ -95,6 +98,7 @@
|
||||
//! EngineT,
|
||||
//! EvmConfig,
|
||||
//! BlockExecutor,
|
||||
//! Consensus,
|
||||
//! >(
|
||||
//! provider: Provider,
|
||||
//! pool: Pool,
|
||||
@ -103,6 +107,7 @@
|
||||
//! engine_api: EngineApi,
|
||||
//! evm_config: EvmConfig,
|
||||
//! block_executor: BlockExecutor,
|
||||
//! consensus: Consensus,
|
||||
//! ) where
|
||||
//! Provider: FullRpcProvider + AccountReader + ChangeSetReader,
|
||||
//! Pool: TransactionPool + Unpin + 'static,
|
||||
@ -112,6 +117,7 @@
|
||||
//! EngineT: EngineTypes,
|
||||
//! EvmConfig: ConfigureEvm<Header = Header>,
|
||||
//! BlockExecutor: BlockExecutorProvider,
|
||||
//! Consensus: reth_consensus::Consensus + Clone + 'static,
|
||||
//! {
|
||||
//! // configure the rpc module per transport
|
||||
//! let transports = TransportRpcModuleConfig::default().with_http(vec![
|
||||
@ -128,6 +134,7 @@
|
||||
//! events,
|
||||
//! evm_config,
|
||||
//! block_executor,
|
||||
//! consensus,
|
||||
//! );
|
||||
//!
|
||||
//! // configure the server modules
|
||||
@ -155,6 +162,7 @@ use std::{
|
||||
collections::HashMap,
|
||||
fmt::Debug,
|
||||
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||
sync::Arc,
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
@ -170,6 +178,7 @@ use jsonrpsee::{
|
||||
Methods, RpcModule,
|
||||
};
|
||||
use reth_chainspec::EthereumHardforks;
|
||||
use reth_consensus::Consensus;
|
||||
use reth_engine_primitives::EngineTypes;
|
||||
use reth_evm::{execute::BlockExecutorProvider, ConfigureEvm};
|
||||
use reth_network_api::{noop::NoopNetwork, NetworkInfo, Peers};
|
||||
@ -180,7 +189,7 @@ use reth_provider::{
|
||||
};
|
||||
use reth_rpc::{
|
||||
AdminApi, DebugApi, EngineEthApi, EthBundle, NetApi, OtterscanApi, RPCApi, RethApi, TraceApi,
|
||||
TxPoolApi, ValidationApi, Web3Api,
|
||||
TxPoolApi, ValidationApi, ValidationApiConfig, Web3Api,
|
||||
};
|
||||
use reth_rpc_api::servers::*;
|
||||
use reth_rpc_eth_api::{
|
||||
@ -243,6 +252,7 @@ pub async fn launch<Provider, Pool, Network, Tasks, Events, EvmConfig, EthApi, B
|
||||
evm_config: EvmConfig,
|
||||
eth: DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>,
|
||||
block_executor: BlockExecutor,
|
||||
consensus: Arc<dyn Consensus>,
|
||||
) -> Result<RpcServerHandle, RpcError>
|
||||
where
|
||||
Provider: FullRpcProvider + AccountReader + ChangeSetReader,
|
||||
@ -266,6 +276,7 @@ where
|
||||
events,
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
)
|
||||
.build(module_config, eth),
|
||||
)
|
||||
@ -276,7 +287,16 @@ where
|
||||
///
|
||||
/// This is the main entrypoint and the easiest way to configure an RPC server.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RpcModuleBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor> {
|
||||
pub struct RpcModuleBuilder<
|
||||
Provider,
|
||||
Pool,
|
||||
Network,
|
||||
Tasks,
|
||||
Events,
|
||||
EvmConfig,
|
||||
BlockExecutor,
|
||||
Consensus,
|
||||
> {
|
||||
/// The Provider type to when creating all rpc handlers
|
||||
provider: Provider,
|
||||
/// The Pool type to when creating all rpc handlers
|
||||
@ -291,14 +311,17 @@ pub struct RpcModuleBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig, B
|
||||
evm_config: EvmConfig,
|
||||
/// The provider for getting a block executor that executes blocks
|
||||
block_executor: BlockExecutor,
|
||||
/// The consensus implementation.
|
||||
consensus: Consensus,
|
||||
}
|
||||
|
||||
// === impl RpcBuilder ===
|
||||
|
||||
impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
RpcModuleBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor, Consensus>
|
||||
RpcModuleBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor, Consensus>
|
||||
{
|
||||
/// Create a new instance of the builder
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub const fn new(
|
||||
provider: Provider,
|
||||
pool: Pool,
|
||||
@ -307,32 +330,54 @@ impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
events: Events,
|
||||
evm_config: EvmConfig,
|
||||
block_executor: BlockExecutor,
|
||||
consensus: Consensus,
|
||||
) -> Self {
|
||||
Self { provider, pool, network, executor, events, evm_config, block_executor }
|
||||
Self { provider, pool, network, executor, events, evm_config, block_executor, consensus }
|
||||
}
|
||||
|
||||
/// Configure the provider instance.
|
||||
pub fn with_provider<P>(
|
||||
self,
|
||||
provider: P,
|
||||
) -> RpcModuleBuilder<P, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
) -> RpcModuleBuilder<P, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor, Consensus>
|
||||
where
|
||||
P: BlockReader + StateProviderFactory + EvmEnvProvider + 'static,
|
||||
{
|
||||
let Self { pool, network, executor, events, evm_config, block_executor, .. } = self;
|
||||
RpcModuleBuilder { provider, network, pool, executor, events, evm_config, block_executor }
|
||||
let Self { pool, network, executor, events, evm_config, block_executor, consensus, .. } =
|
||||
self;
|
||||
RpcModuleBuilder {
|
||||
provider,
|
||||
network,
|
||||
pool,
|
||||
executor,
|
||||
events,
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure the transaction pool instance.
|
||||
pub fn with_pool<P>(
|
||||
self,
|
||||
pool: P,
|
||||
) -> RpcModuleBuilder<Provider, P, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
) -> RpcModuleBuilder<Provider, P, Network, Tasks, Events, EvmConfig, BlockExecutor, Consensus>
|
||||
where
|
||||
P: TransactionPool + 'static,
|
||||
{
|
||||
let Self { provider, network, executor, events, evm_config, block_executor, .. } = self;
|
||||
RpcModuleBuilder { provider, network, pool, executor, events, evm_config, block_executor }
|
||||
let Self {
|
||||
provider, network, executor, events, evm_config, block_executor, consensus, ..
|
||||
} = self;
|
||||
RpcModuleBuilder {
|
||||
provider,
|
||||
network,
|
||||
pool,
|
||||
executor,
|
||||
events,
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure a [`NoopTransactionPool`] instance.
|
||||
@ -350,8 +395,11 @@ impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
Events,
|
||||
EvmConfig,
|
||||
BlockExecutor,
|
||||
Consensus,
|
||||
> {
|
||||
let Self { provider, executor, events, network, evm_config, block_executor, .. } = self;
|
||||
let Self {
|
||||
provider, executor, events, network, evm_config, block_executor, consensus, ..
|
||||
} = self;
|
||||
RpcModuleBuilder {
|
||||
provider,
|
||||
executor,
|
||||
@ -360,6 +408,7 @@ impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
evm_config,
|
||||
block_executor,
|
||||
pool: NoopTransactionPool::default(),
|
||||
consensus,
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,12 +416,23 @@ impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
pub fn with_network<N>(
|
||||
self,
|
||||
network: N,
|
||||
) -> RpcModuleBuilder<Provider, Pool, N, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
) -> RpcModuleBuilder<Provider, Pool, N, Tasks, Events, EvmConfig, BlockExecutor, Consensus>
|
||||
where
|
||||
N: NetworkInfo + Peers + 'static,
|
||||
{
|
||||
let Self { provider, pool, executor, events, evm_config, block_executor, .. } = self;
|
||||
RpcModuleBuilder { provider, network, pool, executor, events, evm_config, block_executor }
|
||||
let Self {
|
||||
provider, pool, executor, events, evm_config, block_executor, consensus, ..
|
||||
} = self;
|
||||
RpcModuleBuilder {
|
||||
provider,
|
||||
network,
|
||||
pool,
|
||||
executor,
|
||||
events,
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure a [`NoopNetwork`] instance.
|
||||
@ -382,9 +442,19 @@ impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
/// [`EthApi`](reth_rpc::eth::EthApi) which requires a [`NetworkInfo`] implementation.
|
||||
pub fn with_noop_network(
|
||||
self,
|
||||
) -> RpcModuleBuilder<Provider, Pool, NoopNetwork, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
{
|
||||
let Self { provider, pool, executor, events, evm_config, block_executor, .. } = self;
|
||||
) -> RpcModuleBuilder<
|
||||
Provider,
|
||||
Pool,
|
||||
NoopNetwork,
|
||||
Tasks,
|
||||
Events,
|
||||
EvmConfig,
|
||||
BlockExecutor,
|
||||
Consensus,
|
||||
> {
|
||||
let Self {
|
||||
provider, pool, executor, events, evm_config, block_executor, consensus, ..
|
||||
} = self;
|
||||
RpcModuleBuilder {
|
||||
provider,
|
||||
pool,
|
||||
@ -393,6 +463,7 @@ impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
network: NoopNetwork::default(),
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,12 +471,22 @@ impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
pub fn with_executor<T>(
|
||||
self,
|
||||
executor: T,
|
||||
) -> RpcModuleBuilder<Provider, Pool, Network, T, Events, EvmConfig, BlockExecutor>
|
||||
) -> RpcModuleBuilder<Provider, Pool, Network, T, Events, EvmConfig, BlockExecutor, Consensus>
|
||||
where
|
||||
T: TaskSpawner + 'static,
|
||||
{
|
||||
let Self { pool, network, provider, events, evm_config, block_executor, .. } = self;
|
||||
RpcModuleBuilder { provider, network, pool, executor, events, evm_config, block_executor }
|
||||
let Self { pool, network, provider, events, evm_config, block_executor, consensus, .. } =
|
||||
self;
|
||||
RpcModuleBuilder {
|
||||
provider,
|
||||
network,
|
||||
pool,
|
||||
executor,
|
||||
events,
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure [`TokioTaskExecutor`] as the task executor to use for additional tasks.
|
||||
@ -422,8 +503,10 @@ impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
Events,
|
||||
EvmConfig,
|
||||
BlockExecutor,
|
||||
Consensus,
|
||||
> {
|
||||
let Self { pool, network, provider, events, evm_config, block_executor, .. } = self;
|
||||
let Self { pool, network, provider, events, evm_config, block_executor, consensus, .. } =
|
||||
self;
|
||||
RpcModuleBuilder {
|
||||
provider,
|
||||
network,
|
||||
@ -432,6 +515,7 @@ impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
executor: TokioTaskExecutor::default(),
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
}
|
||||
}
|
||||
|
||||
@ -439,41 +523,90 @@ impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
pub fn with_events<E>(
|
||||
self,
|
||||
events: E,
|
||||
) -> RpcModuleBuilder<Provider, Pool, Network, Tasks, E, EvmConfig, BlockExecutor>
|
||||
) -> RpcModuleBuilder<Provider, Pool, Network, Tasks, E, EvmConfig, BlockExecutor, Consensus>
|
||||
where
|
||||
E: CanonStateSubscriptions + 'static,
|
||||
{
|
||||
let Self { provider, pool, executor, network, evm_config, block_executor, .. } = self;
|
||||
RpcModuleBuilder { provider, network, pool, executor, events, evm_config, block_executor }
|
||||
let Self {
|
||||
provider, pool, executor, network, evm_config, block_executor, consensus, ..
|
||||
} = self;
|
||||
RpcModuleBuilder {
|
||||
provider,
|
||||
network,
|
||||
pool,
|
||||
executor,
|
||||
events,
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure the evm configuration type
|
||||
pub fn with_evm_config<E>(
|
||||
self,
|
||||
evm_config: E,
|
||||
) -> RpcModuleBuilder<Provider, Pool, Network, Tasks, Events, E, BlockExecutor>
|
||||
) -> RpcModuleBuilder<Provider, Pool, Network, Tasks, Events, E, BlockExecutor, Consensus>
|
||||
where
|
||||
E: ConfigureEvm + 'static,
|
||||
{
|
||||
let Self { provider, pool, executor, network, events, block_executor, .. } = self;
|
||||
RpcModuleBuilder { provider, network, pool, executor, events, evm_config, block_executor }
|
||||
let Self { provider, pool, executor, network, events, block_executor, consensus, .. } =
|
||||
self;
|
||||
RpcModuleBuilder {
|
||||
provider,
|
||||
network,
|
||||
pool,
|
||||
executor,
|
||||
events,
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure the block executor provider
|
||||
pub fn with_block_executor<BE>(
|
||||
self,
|
||||
block_executor: BE,
|
||||
) -> RpcModuleBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig, BE>
|
||||
) -> RpcModuleBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig, BE, Consensus>
|
||||
where
|
||||
BE: BlockExecutorProvider,
|
||||
{
|
||||
let Self { provider, network, pool, executor, events, evm_config, .. } = self;
|
||||
RpcModuleBuilder { provider, network, pool, executor, events, evm_config, block_executor }
|
||||
let Self { provider, network, pool, executor, events, evm_config, consensus, .. } = self;
|
||||
RpcModuleBuilder {
|
||||
provider,
|
||||
network,
|
||||
pool,
|
||||
executor,
|
||||
events,
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure the consensus implementation.
|
||||
pub fn with_consensus<C>(
|
||||
self,
|
||||
consensus: C,
|
||||
) -> RpcModuleBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor, C> {
|
||||
let Self { provider, network, pool, executor, events, evm_config, block_executor, .. } =
|
||||
self;
|
||||
RpcModuleBuilder {
|
||||
provider,
|
||||
network,
|
||||
pool,
|
||||
executor,
|
||||
events,
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
RpcModuleBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor>
|
||||
impl<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor, Consensus>
|
||||
RpcModuleBuilder<Provider, Pool, Network, Tasks, Events, EvmConfig, BlockExecutor, Consensus>
|
||||
where
|
||||
Provider: FullRpcProvider + AccountReader + ChangeSetReader,
|
||||
Pool: TransactionPool + 'static,
|
||||
@ -482,6 +615,7 @@ where
|
||||
Events: CanonStateSubscriptions + Clone + 'static,
|
||||
EvmConfig: ConfigureEvm<Header = Header>,
|
||||
BlockExecutor: BlockExecutorProvider,
|
||||
Consensus: reth_consensus::Consensus + Clone + 'static,
|
||||
{
|
||||
/// Configures all [`RpcModule`]s specific to the given [`TransportRpcModuleConfig`] which can
|
||||
/// be used to start the transport server(s).
|
||||
@ -498,14 +632,23 @@ where
|
||||
) -> (
|
||||
TransportRpcModules,
|
||||
AuthRpcModule,
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>,
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>,
|
||||
)
|
||||
where
|
||||
EngineT: EngineTypes,
|
||||
EngineApi: EngineApiServer<EngineT>,
|
||||
EthApi: FullEthApiServer,
|
||||
{
|
||||
let Self { provider, pool, network, executor, events, evm_config, block_executor } = self;
|
||||
let Self {
|
||||
provider,
|
||||
pool,
|
||||
network,
|
||||
executor,
|
||||
events,
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
} = self;
|
||||
|
||||
let config = module_config.config.clone().unwrap_or_default();
|
||||
|
||||
@ -515,6 +658,7 @@ where
|
||||
network,
|
||||
executor,
|
||||
events,
|
||||
consensus,
|
||||
config,
|
||||
evm_config,
|
||||
eth,
|
||||
@ -536,6 +680,7 @@ where
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use reth_consensus::noop::NoopConsensus;
|
||||
/// use reth_evm::ConfigureEvm;
|
||||
/// use reth_evm_ethereum::execute::EthExecutorProvider;
|
||||
/// use reth_network_api::noop::NoopNetwork;
|
||||
@ -555,6 +700,7 @@ where
|
||||
/// .with_events(TestCanonStateSubscriptions::default())
|
||||
/// .with_evm_config(evm)
|
||||
/// .with_block_executor(EthExecutorProvider::mainnet())
|
||||
/// .with_consensus(NoopConsensus::default())
|
||||
/// .into_registry(Default::default(), Box::new(EthApi::with_spawner));
|
||||
///
|
||||
/// let eth_api = registry.eth_api();
|
||||
@ -564,17 +710,27 @@ where
|
||||
self,
|
||||
config: RpcModuleConfig,
|
||||
eth: DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>,
|
||||
) -> RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>
|
||||
) -> RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>
|
||||
where
|
||||
EthApi: EthApiTypes + 'static,
|
||||
{
|
||||
let Self { provider, pool, network, executor, events, evm_config, block_executor } = self;
|
||||
let Self {
|
||||
provider,
|
||||
pool,
|
||||
network,
|
||||
executor,
|
||||
events,
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
} = self;
|
||||
RpcRegistryInner::new(
|
||||
provider,
|
||||
pool,
|
||||
network,
|
||||
executor,
|
||||
events,
|
||||
consensus,
|
||||
config,
|
||||
evm_config,
|
||||
eth,
|
||||
@ -594,7 +750,16 @@ where
|
||||
{
|
||||
let mut modules = TransportRpcModules::default();
|
||||
|
||||
let Self { provider, pool, network, executor, events, evm_config, block_executor } = self;
|
||||
let Self {
|
||||
provider,
|
||||
pool,
|
||||
network,
|
||||
executor,
|
||||
events,
|
||||
evm_config,
|
||||
block_executor,
|
||||
consensus,
|
||||
} = self;
|
||||
|
||||
if !module_config.is_empty() {
|
||||
let TransportRpcModuleConfig { http, ws, ipc, config } = module_config.clone();
|
||||
@ -605,6 +770,7 @@ where
|
||||
network,
|
||||
executor,
|
||||
events,
|
||||
consensus,
|
||||
config.unwrap_or_default(),
|
||||
evm_config,
|
||||
eth,
|
||||
@ -621,9 +787,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RpcModuleBuilder<(), (), (), (), (), (), ()> {
|
||||
impl Default for RpcModuleBuilder<(), (), (), (), (), (), (), ()> {
|
||||
fn default() -> Self {
|
||||
Self::new((), (), (), (), (), (), ())
|
||||
Self::new((), (), (), (), (), (), (), ())
|
||||
}
|
||||
}
|
||||
|
||||
@ -632,6 +798,8 @@ impl Default for RpcModuleBuilder<(), (), (), (), (), (), ()> {
|
||||
pub struct RpcModuleConfig {
|
||||
/// `eth` namespace settings
|
||||
eth: EthConfig,
|
||||
/// `flashbots` namespace settings
|
||||
flashbots: ValidationApiConfig,
|
||||
}
|
||||
|
||||
// === impl RpcModuleConfig ===
|
||||
@ -643,8 +811,8 @@ impl RpcModuleConfig {
|
||||
}
|
||||
|
||||
/// Returns a new RPC module config given the eth namespace config
|
||||
pub const fn new(eth: EthConfig) -> Self {
|
||||
Self { eth }
|
||||
pub const fn new(eth: EthConfig, flashbots: ValidationApiConfig) -> Self {
|
||||
Self { eth, flashbots }
|
||||
}
|
||||
|
||||
/// Get a reference to the eth namespace config
|
||||
@ -662,6 +830,7 @@ impl RpcModuleConfig {
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct RpcModuleConfigBuilder {
|
||||
eth: Option<EthConfig>,
|
||||
flashbots: Option<ValidationApiConfig>,
|
||||
}
|
||||
|
||||
// === impl RpcModuleConfigBuilder ===
|
||||
@ -673,10 +842,16 @@ impl RpcModuleConfigBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures a custom flashbots namespace config
|
||||
pub fn flashbots(mut self, flashbots: ValidationApiConfig) -> Self {
|
||||
self.flashbots = Some(flashbots);
|
||||
self
|
||||
}
|
||||
|
||||
/// Consumes the type and creates the [`RpcModuleConfig`]
|
||||
pub fn build(self) -> RpcModuleConfig {
|
||||
let Self { eth } = self;
|
||||
RpcModuleConfig { eth: eth.unwrap_or_default() }
|
||||
let Self { eth, flashbots } = self;
|
||||
RpcModuleConfig { eth: eth.unwrap_or_default(), flashbots: flashbots.unwrap_or_default() }
|
||||
}
|
||||
|
||||
/// Get a reference to the eth namespace config, if any
|
||||
@ -705,6 +880,7 @@ pub struct RpcRegistryInner<
|
||||
Events,
|
||||
EthApi: EthApiTypes,
|
||||
BlockExecutor,
|
||||
Consensus,
|
||||
> {
|
||||
provider: Provider,
|
||||
pool: Pool,
|
||||
@ -712,6 +888,9 @@ pub struct RpcRegistryInner<
|
||||
executor: Tasks,
|
||||
events: Events,
|
||||
block_executor: BlockExecutor,
|
||||
consensus: Consensus,
|
||||
/// Holds the configuration for the RPC modules
|
||||
config: RpcModuleConfig,
|
||||
/// Holds a all `eth_` namespace handlers
|
||||
eth: EthHandlers<Provider, Pool, Network, Events, EthApi>,
|
||||
/// to put trace calls behind semaphore
|
||||
@ -722,8 +901,8 @@ pub struct RpcRegistryInner<
|
||||
|
||||
// === impl RpcRegistryInner ===
|
||||
|
||||
impl<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>
|
||||
impl<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>
|
||||
where
|
||||
Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static,
|
||||
Pool: Send + Sync + Clone + 'static,
|
||||
@ -741,6 +920,7 @@ where
|
||||
network: Network,
|
||||
executor: Tasks,
|
||||
events: Events,
|
||||
consensus: Consensus,
|
||||
config: RpcModuleConfig,
|
||||
evm_config: EvmConfig,
|
||||
eth_api_builder: DynEthApiBuilder<
|
||||
@ -776,6 +956,8 @@ where
|
||||
network,
|
||||
eth,
|
||||
executor,
|
||||
consensus,
|
||||
config,
|
||||
modules: Default::default(),
|
||||
blocking_pool_guard,
|
||||
events,
|
||||
@ -784,8 +966,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>
|
||||
impl<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>
|
||||
where
|
||||
EthApi: EthApiTypes,
|
||||
{
|
||||
@ -842,8 +1024,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>
|
||||
impl<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>
|
||||
where
|
||||
Network: NetworkInfo + Clone + 'static,
|
||||
EthApi: EthApiTypes,
|
||||
@ -881,8 +1063,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>
|
||||
impl<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>
|
||||
where
|
||||
Provider: FullRpcProvider + AccountReader + ChangeSetReader,
|
||||
Network: NetworkInfo + Peers + Clone + 'static,
|
||||
@ -994,8 +1176,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>
|
||||
impl<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>
|
||||
where
|
||||
Provider: FullRpcProvider + AccountReader + ChangeSetReader,
|
||||
Network: NetworkInfo + Peers + Clone + 'static,
|
||||
@ -1069,13 +1251,21 @@ where
|
||||
}
|
||||
|
||||
/// Instantiates `ValidationApi`
|
||||
pub fn validation_api(&self) -> ValidationApi<Provider> {
|
||||
ValidationApi::new(self.provider.clone())
|
||||
pub fn validation_api(&self) -> ValidationApi<Provider, BlockExecutor>
|
||||
where
|
||||
Consensus: reth_consensus::Consensus + Clone + 'static,
|
||||
{
|
||||
ValidationApi::new(
|
||||
self.provider.clone(),
|
||||
Arc::new(self.consensus.clone()),
|
||||
self.block_executor.clone(),
|
||||
self.config.flashbots.clone(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor>
|
||||
impl<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>
|
||||
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi, BlockExecutor, Consensus>
|
||||
where
|
||||
Provider: FullRpcProvider + AccountReader + ChangeSetReader,
|
||||
Pool: TransactionPool + 'static,
|
||||
@ -1084,6 +1274,7 @@ where
|
||||
Events: CanonStateSubscriptions + Clone + 'static,
|
||||
EthApi: FullEthApiServer,
|
||||
BlockExecutor: BlockExecutorProvider,
|
||||
Consensus: reth_consensus::Consensus + Clone + 'static,
|
||||
{
|
||||
/// Configures the auth module that includes the
|
||||
/// * `engine_` namespace
|
||||
@ -1228,9 +1419,14 @@ where
|
||||
.into_rpc()
|
||||
.into()
|
||||
}
|
||||
RethRpcModule::Flashbots => {
|
||||
ValidationApi::new(self.provider.clone()).into_rpc().into()
|
||||
}
|
||||
RethRpcModule::Flashbots => ValidationApi::new(
|
||||
self.provider.clone(),
|
||||
Arc::new(self.consensus.clone()),
|
||||
self.block_executor.clone(),
|
||||
self.config.flashbots.clone(),
|
||||
)
|
||||
.into_rpc()
|
||||
.into(),
|
||||
})
|
||||
.clone()
|
||||
})
|
||||
@ -1688,7 +1884,7 @@ impl TransportRpcModuleConfig {
|
||||
}
|
||||
|
||||
/// Sets a custom [`RpcModuleConfig`] for the configured modules.
|
||||
pub const fn with_config(mut self, config: RpcModuleConfig) -> Self {
|
||||
pub fn with_config(mut self, config: RpcModuleConfig) -> Self {
|
||||
self.config = Some(config);
|
||||
self
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use alloy_rpc_types_engine::{ClientCode, ClientVersionV1};
|
||||
use reth_beacon_consensus::BeaconConsensusEngineHandle;
|
||||
use reth_chainspec::MAINNET;
|
||||
use reth_consensus::noop::NoopConsensus;
|
||||
use reth_ethereum_engine_primitives::{EthEngineTypes, EthereumEngineValidator};
|
||||
use reth_evm::execute::BasicBlockExecutorProvider;
|
||||
use reth_evm_ethereum::{execute::EthExecutionStrategyFactory, EthEvmConfig};
|
||||
@ -126,6 +127,7 @@ pub fn test_rpc_builder() -> RpcModuleBuilder<
|
||||
TestCanonStateSubscriptions,
|
||||
EthEvmConfig,
|
||||
BasicBlockExecutorProvider<EthExecutionStrategyFactory>,
|
||||
NoopConsensus,
|
||||
> {
|
||||
RpcModuleBuilder::default()
|
||||
.with_provider(NoopProvider::default())
|
||||
@ -137,4 +139,5 @@ pub fn test_rpc_builder() -> RpcModuleBuilder<
|
||||
.with_block_executor(
|
||||
BasicBlockExecutorProvider::new(EthExecutionStrategyFactory::mainnet()),
|
||||
)
|
||||
.with_consensus(NoopConsensus::default())
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize};
|
||||
pub const DEFAULT_STALE_FILTER_TTL: Duration = Duration::from_secs(5 * 60);
|
||||
|
||||
/// Additional config values for the eth namespace.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct EthConfig {
|
||||
/// Settings for the caching layer
|
||||
pub cache: EthStateCacheConfig,
|
||||
|
||||
@ -4,6 +4,7 @@ use std::fmt;
|
||||
|
||||
use alloy_rpc_types_engine::PayloadError;
|
||||
use jsonrpsee_core::RpcResult;
|
||||
use reth_errors::ConsensusError;
|
||||
use reth_primitives::BlockId;
|
||||
|
||||
/// Helper trait to easily convert various `Result` types into [`RpcResult`]
|
||||
@ -102,6 +103,7 @@ macro_rules! impl_to_rpc_result {
|
||||
}
|
||||
|
||||
impl_to_rpc_result!(PayloadError);
|
||||
impl_to_rpc_result!(ConsensusError);
|
||||
impl_to_rpc_result!(reth_errors::RethError);
|
||||
impl_to_rpc_result!(reth_errors::ProviderError);
|
||||
impl_to_rpc_result!(reth_network_api::NetworkError);
|
||||
|
||||
@ -18,6 +18,7 @@ reth-primitives = { workspace = true, features = ["secp256k1"] }
|
||||
reth-rpc-api.workspace = true
|
||||
reth-rpc-eth-api.workspace = true
|
||||
reth-errors.workspace = true
|
||||
reth-ethereum-consensus.workspace = true
|
||||
reth-provider.workspace = true
|
||||
reth-transaction-pool.workspace = true
|
||||
reth-network-api.workspace = true
|
||||
@ -33,12 +34,14 @@ reth-rpc-eth-types.workspace = true
|
||||
reth-rpc-server-types.workspace = true
|
||||
reth-network-types.workspace = true
|
||||
reth-trie.workspace = true
|
||||
reth-consensus.workspace = true
|
||||
reth-payload-validator.workspace = true
|
||||
|
||||
# ethereum
|
||||
alloy-consensus.workspace = true
|
||||
alloy-signer.workspace = true
|
||||
alloy-signer-local.workspace = true
|
||||
alloy-eips.workspace = true
|
||||
alloy-eips = { workspace = true, features = ["kzg"] }
|
||||
alloy-dyn-abi.workspace = true
|
||||
alloy-genesis.workspace = true
|
||||
alloy-network.workspace = true
|
||||
|
||||
@ -55,5 +55,5 @@ pub use reth::RethApi;
|
||||
pub use rpc::RPCApi;
|
||||
pub use trace::TraceApi;
|
||||
pub use txpool::TxPoolApi;
|
||||
pub use validation::ValidationApi;
|
||||
pub use validation::{ValidationApi, ValidationApiConfig};
|
||||
pub use web3::Web3Api;
|
||||
|
||||
@ -1,56 +1,376 @@
|
||||
use alloy_consensus::{BlobTransactionValidationError, EnvKzgSettings, Transaction};
|
||||
use alloy_eips::eip4844::kzg_to_versioned_hash;
|
||||
use alloy_rpc_types::engine::{
|
||||
BlobsBundleV1, CancunPayloadFields, ExecutionPayload, ExecutionPayloadSidecar,
|
||||
};
|
||||
use alloy_rpc_types_beacon::relay::{
|
||||
BuilderBlockValidationRequest, BuilderBlockValidationRequestV2, BuilderBlockValidationRequestV3,
|
||||
BidTrace, BuilderBlockValidationRequest, BuilderBlockValidationRequestV2,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use jsonrpsee::core::RpcResult;
|
||||
use reth_chainspec::ChainSpecProvider;
|
||||
use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
|
||||
use reth_consensus::{Consensus, PostExecutionInput};
|
||||
use reth_errors::{BlockExecutionError, ConsensusError, ProviderError, RethError};
|
||||
use reth_ethereum_consensus::GAS_LIMIT_BOUND_DIVISOR;
|
||||
use reth_evm::execute::{BlockExecutorProvider, Executor};
|
||||
use reth_payload_validator::ExecutionPayloadValidator;
|
||||
use reth_primitives::{Block, GotExpected, Receipt, SealedBlockWithSenders, SealedHeader};
|
||||
use reth_provider::{
|
||||
AccountReader, BlockReaderIdExt, HeaderProvider, StateProviderFactory, WithdrawalsProvider,
|
||||
AccountReader, BlockExecutionInput, BlockExecutionOutput, BlockReaderIdExt, HeaderProvider,
|
||||
StateProviderFactory, WithdrawalsProvider,
|
||||
};
|
||||
use reth_rpc_api::BlockSubmissionValidationApiServer;
|
||||
use reth_rpc_server_types::result::internal_rpc_err;
|
||||
use std::sync::Arc;
|
||||
use tracing::warn;
|
||||
use reth_revm::database::StateProviderDatabase;
|
||||
use reth_rpc_api::{BlockSubmissionValidationApiServer, BuilderBlockValidationRequestV3};
|
||||
use reth_rpc_eth_types::EthApiError;
|
||||
use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
|
||||
use reth_trie::HashedPostState;
|
||||
use revm_primitives::{Address, B256, U256};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashSet, sync::Arc};
|
||||
|
||||
/// The type that implements the `validation` rpc namespace trait
|
||||
pub struct ValidationApi<Provider> {
|
||||
inner: Arc<ValidationApiInner<Provider>>,
|
||||
/// Configuration for validation API.
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ValidationApiConfig {
|
||||
/// Disallowed addresses.
|
||||
pub disallow: HashSet<Address>,
|
||||
}
|
||||
|
||||
impl<Provider> ValidationApi<Provider>
|
||||
where
|
||||
Provider: BlockReaderIdExt
|
||||
+ ChainSpecProvider
|
||||
+ StateProviderFactory
|
||||
+ HeaderProvider
|
||||
+ AccountReader
|
||||
+ WithdrawalsProvider
|
||||
+ Clone
|
||||
+ 'static,
|
||||
{
|
||||
/// The provider that can interact with the chain.
|
||||
pub fn provider(&self) -> Provider {
|
||||
self.inner.provider.clone()
|
||||
}
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ValidationApiError {
|
||||
#[error("block gas limit mismatch: {_0}")]
|
||||
GasLimitMismatch(GotExpected<u64>),
|
||||
#[error("block gas used mismatch: {_0}")]
|
||||
GasUsedMismatch(GotExpected<u64>),
|
||||
#[error("block parent hash mismatch: {_0}")]
|
||||
ParentHashMismatch(GotExpected<B256>),
|
||||
#[error("block hash mismatch: {_0}")]
|
||||
BlockHashMismatch(GotExpected<B256>),
|
||||
#[error("missing latest block in database")]
|
||||
MissingLatestBlock,
|
||||
#[error("could not verify proposer payment")]
|
||||
ProposerPayment,
|
||||
#[error("invalid blobs bundle")]
|
||||
InvalidBlobsBundle,
|
||||
#[error("block accesses blacklisted address: {_0}")]
|
||||
Blacklist(Address),
|
||||
#[error(transparent)]
|
||||
Blob(#[from] BlobTransactionValidationError),
|
||||
#[error(transparent)]
|
||||
Consensus(#[from] ConsensusError),
|
||||
#[error(transparent)]
|
||||
Provider(#[from] ProviderError),
|
||||
#[error(transparent)]
|
||||
Execution(#[from] BlockExecutionError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ValidationApiInner<Provider: ChainSpecProvider, E> {
|
||||
/// The provider that can interact with the chain.
|
||||
provider: Provider,
|
||||
/// Consensus implementation.
|
||||
consensus: Arc<dyn Consensus>,
|
||||
/// Execution payload validator.
|
||||
payload_validator: ExecutionPayloadValidator<Provider::ChainSpec>,
|
||||
/// Block executor factory.
|
||||
executor_provider: E,
|
||||
/// Set of disallowed addresses
|
||||
disallow: HashSet<Address>,
|
||||
}
|
||||
|
||||
/// The type that implements the `validation` rpc namespace trait
|
||||
#[derive(Clone, Debug, derive_more::Deref)]
|
||||
pub struct ValidationApi<Provider: ChainSpecProvider, E> {
|
||||
#[deref]
|
||||
inner: Arc<ValidationApiInner<Provider, E>>,
|
||||
}
|
||||
|
||||
impl<Provider, E> ValidationApi<Provider, E>
|
||||
where
|
||||
Provider: ChainSpecProvider,
|
||||
{
|
||||
/// Create a new instance of the [`ValidationApi`]
|
||||
pub fn new(provider: Provider) -> Self {
|
||||
let inner = Arc::new(ValidationApiInner { provider });
|
||||
pub fn new(
|
||||
provider: Provider,
|
||||
consensus: Arc<dyn Consensus>,
|
||||
executor_provider: E,
|
||||
config: ValidationApiConfig,
|
||||
) -> Self {
|
||||
let ValidationApiConfig { disallow } = config;
|
||||
|
||||
let payload_validator = ExecutionPayloadValidator::new(provider.chain_spec());
|
||||
let inner = Arc::new(ValidationApiInner {
|
||||
provider,
|
||||
consensus,
|
||||
payload_validator,
|
||||
executor_provider,
|
||||
disallow,
|
||||
});
|
||||
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<Provider> BlockSubmissionValidationApiServer for ValidationApi<Provider>
|
||||
impl<Provider, E> ValidationApi<Provider, E>
|
||||
where
|
||||
Provider: BlockReaderIdExt
|
||||
+ ChainSpecProvider
|
||||
+ ChainSpecProvider<ChainSpec: EthereumHardforks>
|
||||
+ StateProviderFactory
|
||||
+ HeaderProvider
|
||||
+ AccountReader
|
||||
+ WithdrawalsProvider
|
||||
+ Clone
|
||||
+ 'static,
|
||||
E: BlockExecutorProvider,
|
||||
{
|
||||
/// Validates the given block and a [`BidTrace`] against it.
|
||||
pub fn validate_message_against_block(
|
||||
&self,
|
||||
block: SealedBlockWithSenders,
|
||||
message: BidTrace,
|
||||
registered_gas_limit: u64,
|
||||
) -> Result<(), ValidationApiError> {
|
||||
self.validate_message_against_header(&block.header, &message)?;
|
||||
|
||||
self.consensus.validate_header_with_total_difficulty(&block.header, U256::MAX)?;
|
||||
self.consensus.validate_header(&block.header)?;
|
||||
self.consensus.validate_block_pre_execution(&block)?;
|
||||
|
||||
if !self.disallow.is_empty() {
|
||||
if self.disallow.contains(&block.beneficiary) {
|
||||
return Err(ValidationApiError::Blacklist(block.beneficiary))
|
||||
}
|
||||
if self.disallow.contains(&message.proposer_fee_recipient) {
|
||||
return Err(ValidationApiError::Blacklist(message.proposer_fee_recipient))
|
||||
}
|
||||
for (sender, tx) in block.senders.iter().zip(block.transactions()) {
|
||||
if self.disallow.contains(sender) {
|
||||
return Err(ValidationApiError::Blacklist(*sender))
|
||||
}
|
||||
if let Some(to) = tx.to() {
|
||||
if self.disallow.contains(&to) {
|
||||
return Err(ValidationApiError::Blacklist(to))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let latest_header =
|
||||
self.provider.latest_header()?.ok_or_else(|| ValidationApiError::MissingLatestBlock)?;
|
||||
|
||||
if latest_header.hash() != block.header.parent_hash {
|
||||
return Err(ConsensusError::ParentHashMismatch(
|
||||
GotExpected { got: block.header.parent_hash, expected: latest_header.hash() }
|
||||
.into(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
self.consensus.validate_header_against_parent(&block.header, &latest_header)?;
|
||||
self.validate_gas_limit(registered_gas_limit, &latest_header, &block.header)?;
|
||||
|
||||
let state_provider = self.provider.state_by_block_hash(latest_header.hash())?;
|
||||
let executor = self.executor_provider.executor(StateProviderDatabase::new(&state_provider));
|
||||
|
||||
let block = block.unseal();
|
||||
let mut accessed_blacklisted = None;
|
||||
let output = executor.execute_with_state_closure(
|
||||
BlockExecutionInput::new(&block, U256::MAX),
|
||||
|state| {
|
||||
if !self.disallow.is_empty() {
|
||||
for account in state.cache.accounts.keys() {
|
||||
if self.disallow.contains(account) {
|
||||
accessed_blacklisted = Some(*account);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)?;
|
||||
|
||||
if let Some(account) = accessed_blacklisted {
|
||||
return Err(ValidationApiError::Blacklist(account))
|
||||
}
|
||||
|
||||
self.consensus.validate_block_post_execution(
|
||||
&block,
|
||||
PostExecutionInput::new(&output.receipts, &output.requests),
|
||||
)?;
|
||||
|
||||
self.ensure_payment(&block, &output, &message)?;
|
||||
|
||||
let state_root =
|
||||
state_provider.state_root(HashedPostState::from_bundle_state(&output.state.state))?;
|
||||
|
||||
if state_root != block.state_root {
|
||||
return Err(ConsensusError::BodyStateRootDiff(
|
||||
GotExpected { got: state_root, expected: block.state_root }.into(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ensures that fields of [`BidTrace`] match the fields of the [`SealedHeader`].
|
||||
fn validate_message_against_header(
|
||||
&self,
|
||||
header: &SealedHeader,
|
||||
message: &BidTrace,
|
||||
) -> Result<(), ValidationApiError> {
|
||||
if header.hash() != message.block_hash {
|
||||
Err(ValidationApiError::BlockHashMismatch(GotExpected {
|
||||
got: message.block_hash,
|
||||
expected: header.hash(),
|
||||
}))
|
||||
} else if header.parent_hash != message.parent_hash {
|
||||
Err(ValidationApiError::ParentHashMismatch(GotExpected {
|
||||
got: message.parent_hash,
|
||||
expected: header.parent_hash,
|
||||
}))
|
||||
} else if header.gas_limit != message.gas_limit {
|
||||
Err(ValidationApiError::GasLimitMismatch(GotExpected {
|
||||
got: message.gas_limit,
|
||||
expected: header.gas_limit,
|
||||
}))
|
||||
} else if header.gas_used != message.gas_used {
|
||||
return Err(ValidationApiError::GasUsedMismatch(GotExpected {
|
||||
got: message.gas_used,
|
||||
expected: header.gas_used,
|
||||
}))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures that the chosen gas limit is the closest possible value for the validator's
|
||||
/// registered gas limit.
|
||||
///
|
||||
/// Ref: <https://github.com/flashbots/builder/blob/a742641e24df68bc2fc476199b012b0abce40ffe/core/blockchain.go#L2474-L2477>
|
||||
fn validate_gas_limit(
|
||||
&self,
|
||||
registered_gas_limit: u64,
|
||||
parent_header: &SealedHeader,
|
||||
header: &SealedHeader,
|
||||
) -> Result<(), ValidationApiError> {
|
||||
let max_gas_limit =
|
||||
parent_header.gas_limit + parent_header.gas_limit / GAS_LIMIT_BOUND_DIVISOR - 1;
|
||||
let min_gas_limit =
|
||||
parent_header.gas_limit - parent_header.gas_limit / GAS_LIMIT_BOUND_DIVISOR + 1;
|
||||
|
||||
let best_gas_limit =
|
||||
std::cmp::max(min_gas_limit, std::cmp::min(max_gas_limit, registered_gas_limit));
|
||||
|
||||
if best_gas_limit != header.gas_limit {
|
||||
return Err(ValidationApiError::GasLimitMismatch(GotExpected {
|
||||
got: header.gas_limit,
|
||||
expected: best_gas_limit,
|
||||
}))
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ensures that the proposer has received [`BidTrace::value`] for this block.
|
||||
///
|
||||
/// Firstly attempts to verify the payment by checking the state changes, otherwise falls back
|
||||
/// to checking the latest block transaction.
|
||||
fn ensure_payment(
|
||||
&self,
|
||||
block: &Block,
|
||||
output: &BlockExecutionOutput<Receipt>,
|
||||
message: &BidTrace,
|
||||
) -> Result<(), ValidationApiError> {
|
||||
let (mut balance_before, balance_after) = if let Some(acc) =
|
||||
output.state.state.get(&message.proposer_fee_recipient)
|
||||
{
|
||||
let balance_before = acc.original_info.as_ref().map(|i| i.balance).unwrap_or_default();
|
||||
let balance_after = acc.info.as_ref().map(|i| i.balance).unwrap_or_default();
|
||||
|
||||
(balance_before, balance_after)
|
||||
} else {
|
||||
// account might have balance but considering it zero is fine as long as we know
|
||||
// that balance have not changed
|
||||
(U256::ZERO, U256::ZERO)
|
||||
};
|
||||
|
||||
if let Some(withdrawals) = &block.body.withdrawals {
|
||||
for withdrawal in withdrawals {
|
||||
if withdrawal.address == message.proposer_fee_recipient {
|
||||
balance_before += withdrawal.amount_wei();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if balance_after >= balance_before + message.value {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let (receipt, tx) = output
|
||||
.receipts
|
||||
.last()
|
||||
.zip(block.body.transactions.last())
|
||||
.ok_or(ValidationApiError::ProposerPayment)?;
|
||||
|
||||
if !receipt.success {
|
||||
return Err(ValidationApiError::ProposerPayment)
|
||||
}
|
||||
|
||||
if tx.to() != Some(message.proposer_fee_recipient) {
|
||||
return Err(ValidationApiError::ProposerPayment)
|
||||
}
|
||||
|
||||
if tx.value() != message.value {
|
||||
return Err(ValidationApiError::ProposerPayment)
|
||||
}
|
||||
|
||||
if !tx.input().is_empty() {
|
||||
return Err(ValidationApiError::ProposerPayment)
|
||||
}
|
||||
|
||||
if let Some(block_base_fee) = block.base_fee_per_gas {
|
||||
if tx.effective_tip_per_gas(block_base_fee).unwrap_or_default() != 0 {
|
||||
return Err(ValidationApiError::ProposerPayment)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validates the given [`BlobsBundleV1`] and returns versioned hashes for blobs.
|
||||
pub fn validate_blobs_bundle(
|
||||
&self,
|
||||
mut blobs_bundle: BlobsBundleV1,
|
||||
) -> Result<Vec<B256>, ValidationApiError> {
|
||||
if blobs_bundle.commitments.len() != blobs_bundle.proofs.len() ||
|
||||
blobs_bundle.commitments.len() != blobs_bundle.blobs.len()
|
||||
{
|
||||
return Err(ValidationApiError::InvalidBlobsBundle)
|
||||
}
|
||||
|
||||
let versioned_hashes = blobs_bundle
|
||||
.commitments
|
||||
.iter()
|
||||
.map(|c| kzg_to_versioned_hash(c.as_slice()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let sidecar = blobs_bundle.pop_sidecar(blobs_bundle.blobs.len());
|
||||
|
||||
sidecar.validate(&versioned_hashes, EnvKzgSettings::default().get())?;
|
||||
|
||||
Ok(versioned_hashes)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<Provider, E> BlockSubmissionValidationApiServer for ValidationApi<Provider, E>
|
||||
where
|
||||
Provider: BlockReaderIdExt
|
||||
+ ChainSpecProvider<ChainSpec: EthereumHardforks>
|
||||
+ StateProviderFactory
|
||||
+ HeaderProvider
|
||||
+ AccountReader
|
||||
+ WithdrawalsProvider
|
||||
+ Clone
|
||||
+ 'static,
|
||||
E: BlockExecutorProvider,
|
||||
{
|
||||
async fn validate_builder_submission_v1(
|
||||
&self,
|
||||
@ -71,24 +391,28 @@ where
|
||||
&self,
|
||||
request: BuilderBlockValidationRequestV3,
|
||||
) -> RpcResult<()> {
|
||||
warn!("flashbots_validateBuilderSubmissionV3: blindly accepting request without validation {:?}", request);
|
||||
Ok(())
|
||||
let block = self
|
||||
.payload_validator
|
||||
.ensure_well_formed_payload(
|
||||
ExecutionPayload::V3(request.request.execution_payload),
|
||||
ExecutionPayloadSidecar::v3(CancunPayloadFields {
|
||||
parent_beacon_block_root: request.parent_beacon_block_root,
|
||||
versioned_hashes: self
|
||||
.validate_blobs_bundle(request.request.blobs_bundle)
|
||||
.map_err(|e| RethError::Other(e.into()))
|
||||
.to_rpc_result()?,
|
||||
}),
|
||||
)
|
||||
.to_rpc_result()?
|
||||
.try_seal_with_senders()
|
||||
.map_err(|_| EthApiError::InvalidTransactionSignature)?;
|
||||
|
||||
self.validate_message_against_block(
|
||||
block,
|
||||
request.request.message,
|
||||
request.registered_gas_limit,
|
||||
)
|
||||
.map_err(|e| RethError::Other(e.into()))
|
||||
.to_rpc_result()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider> std::fmt::Debug for ValidationApi<Provider> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ValidationApi").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider> Clone for ValidationApi<Provider> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { inner: Arc::clone(&self.inner) }
|
||||
}
|
||||
}
|
||||
|
||||
struct ValidationApiInner<Provider> {
|
||||
/// The provider that can interact with the chain.
|
||||
provider: Provider,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user