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

Bump reth version #29

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
2,160 changes: 1,117 additions & 1,043 deletions Cargo.lock

Large diffs are not rendered by default.

15 changes: 12 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,31 @@ path = "src/main.rs"
inherits = "release"
debug = true

[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1

[dependencies]
async-trait = "0.1.73"
clap = "4.4.5"
derivative = "2.2.0"
eyre = "0.6.8"
hex = "0.4.3"
jsonrpsee = "0.20.1"
reth = { git = "https://github.com/paradigmxyz/reth", rev = "5a623a9c1285d986fc46f1091d58d7a388323457" }
reth-db = { features = ["test-utils"], git = "https://github.com/paradigmxyz/reth", rev = "5a623a9c1285d986fc46f1091d58d7a388323457"}
reth-tracing = { git = "https://github.com/paradigmxyz/reth", rev = "5a623a9c1285d986fc46f1091d58d7a388323457"}
reth = { git = "https://github.com/paradigmxyz/reth", tag = "v0.2.0-beta.3" }
reth-db = { features = ["test-utils"], git = "https://github.com/paradigmxyz/reth", tag = "v0.2.0-beta.3"}
reth-provider = { git = "https://github.com/paradigmxyz/reth", tag = "v0.2.0-beta.3", features=["test-utils"]}
reth-tracing = { git = "https://github.com/paradigmxyz/reth", tag = "v0.2.0-beta.3"}
reth-interfaces = { git = "https://github.com/paradigmxyz/reth", tag = "v0.2.0-beta.3"}
reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v0.2.0-beta.3"}
secp256k1 = { version = "0.28.0", features = ["rand-std"] }
serde = "1.0.188"
serde_json = "1.0.107"
serde_with = "3.3.0"
tokio = "1.35"
uuid = "1.6.1"
ruint = "1.12.1"

[dev-dependencies]
tokio = "1.32.0"
46 changes: 1 addition & 45 deletions src/cli_ext.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,7 @@
use crate::rpc::ValidationApiServer;
use crate::ValidationApi;
use reth::cli::components::{RethNodeComponents, RethRpcComponents};
use reth::cli::{
config::RethRpcConfig,
ext::{RethCliExt, RethNodeCommandConfig},
};

/// The type that tells the reth CLI what extensions to use
pub struct ValidationCliExt;

impl RethCliExt for ValidationCliExt {
/// This tells the reth CLI to install the `validation` rpc namespace via `RethCliValidationApi`
type Node = RethCliValidationApi;
}

/// Our custom cli args extension that adds one flag to reth default CLI.
#[derive(Debug, Clone, Copy, Default, clap::Args)]
pub struct RethCliValidationApi {
pub struct ValidationCliExt {
/// CLI flag to enable the validation extension namespace
#[clap(long)]
pub enable_ext: bool,
}

impl RethNodeCommandConfig for RethCliValidationApi {
// This is the entrypoint for the CLI to extend the RPC server with custom rpc namespaces.
fn extend_rpc_modules<Conf, Reth>(
&mut self,
_config: &Conf,
components: &Reth,
rpc_components: RethRpcComponents<'_, Reth>,
) -> eyre::Result<()>
where
Conf: RethRpcConfig,
Reth: RethNodeComponents,
{
if !self.enable_ext {
return Ok(());
}

// here we get the configured pool type from the CLI.
let provider = components.provider();
let ext = ValidationApi::new(provider);

// now we merge our extension namespace into all configured transports
rpc_components.modules.merge_configured(ext.into_rpc())?;

println!("validation extension enabled");
Ok(())
}
}
25 changes: 23 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,29 @@
//! ```
use clap::Parser;
use reth::cli::Cli;
use reth_payload_validator::ValidationCliExt;
use reth_node_ethereum::EthereumNode;
use reth_payload_validator::{rpc::ValidationApiServer, ValidationApi, ValidationCliExt};

fn main() {
Cli::<ValidationCliExt>::parse().run().unwrap();
Cli::<ValidationCliExt>::parse()
.run(|builder, _args| async move {
let handle = builder
.node(EthereumNode::default())
.extend_rpc_modules(move |ctx| {
// here we get the configured pool.
let provider = ctx.provider().clone();

let ext = ValidationApi::new(provider);

// now we merge our extension namespace into all configured transports
ctx.modules.merge_configured(ext.into_rpc())?;

println!("txpool extension enabled");
Ok(())
})
.launch()
.await?;
handle.wait_for_node_exit().await
})
.unwrap();
}
2 changes: 1 addition & 1 deletion src/rpc/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use jsonrpsee::proc_macros::rpc;
/// trait interface for a custom rpc namespace: `validation`
///
/// This defines an additional namespace where all methods are configured as trait functions.
#[rpc(client, server, namespace = "flashbots")]
#[rpc(server, client, namespace = "flashbots")]
pub trait ValidationApi {
/// Validates a block submitted to the relay
#[method(name = "validateBuilderSubmissionV3")]
Expand Down
55 changes: 18 additions & 37 deletions src/rpc/utils.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use crate::rpc::result::internal_rpc_err;
use jsonrpsee::core::RpcResult;
use reth_tracing::tracing;
use std::cmp::Ordering;

pub fn compare_values<T: std::cmp::PartialEq + std::fmt::Display>(
name: &str,
Expand All @@ -28,44 +26,27 @@ const MIN_GAS_LIMIT: u64 = 5000;
// the target if the baseline gas is lower.
// Ported from: https://github.com/flashbots/builder/blob/03ee71cf0a344397204f65ff6d3a917ee8e06724/core/utils/gas_limit.go#L8
// Reference implementation: https://eips.ethereum.org/EIPS/eip-1559#specification
pub fn calc_gas_limit(parent_gas_limit: u64, desired_limit: u64) -> u64 {
pub fn calc_gas_limit(parent_gas_limit: u64, mut desired_limit: u64) -> u64 {
// TODO: Understand why 1 is subtracted here
let delta = parent_gas_limit / GAS_LIMIT_BOUND_DIVISOR - 1;
let desired_or_min_limit = std::cmp::max(desired_limit, MIN_GAS_LIMIT);
match parent_gas_limit.cmp(&desired_or_min_limit) {
Ordering::Less => {
let max_acceptable_limit = parent_gas_limit + delta;
tracing::debug!(
parent_gas_limit,
delta,
desired_limit,
desired_or_min_limit,
max_acceptable_limit,
"Parent gas limit is less than desired/min limit"
);
std::cmp::min(max_acceptable_limit, desired_or_min_limit)
}
Ordering::Greater => {
let min_acceptable_limit = parent_gas_limit - delta;
tracing::debug!(
parent_gas_limit,
delta,
desired_limit,
desired_or_min_limit,
min_acceptable_limit,
"Parent gas limit is greater than desired/min limit"
);
std::cmp::max(min_acceptable_limit, desired_or_min_limit)
let mut limit = parent_gas_limit;

if desired_limit < MIN_GAS_LIMIT {
desired_limit = MIN_GAS_LIMIT;
}

// If we're outside our allowed gas range, we try to hone towards them
if limit < desired_limit {
limit = parent_gas_limit + delta;
if limit > desired_limit {
limit = desired_limit;
}
Ordering::Equal => {
tracing::debug!(
parent_gas_limit,
delta,
desired_limit,
desired_or_min_limit,
"Parent gas limit is equal to desired/min limit"
);
parent_gas_limit
} else if limit > desired_limit {
limit = parent_gas_limit - delta;
if limit < desired_limit {
limit = desired_limit;
}
}

limit
}
77 changes: 57 additions & 20 deletions src/rpc/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ use crate::rpc::result::internal_rpc_err;
use crate::rpc::types::*;
use crate::rpc::utils::*;
use jsonrpsee::core::RpcResult;
use reth::consensus_common::validation::full_validation;
use reth::consensus_common::validation::{
validate_all_transaction_regarding_block_and_nonces, validate_block_regarding_chain,
validate_block_standalone, validate_header_standalone,
};
use reth::primitives::SealedHeader;
use reth::primitives::{
revm_primitives::AccountInfo, Address, Receipts, SealedBlock, TransactionSigned, U256,
revm_primitives::AccountInfo, Address, BlockId, ChainSpec, Receipts, SealedBlock,
TransactionSigned, U256,
};
use reth::providers::{
AccountReader, BlockExecutor, BlockReaderIdExt, BundleStateWithReceipts, ChainSpecProvider,
Expand All @@ -13,6 +18,8 @@ use reth::providers::{
use reth::revm::{database::StateProviderDatabase, db::BundleState, processor::EVMProcessor};
use reth::rpc::compat::engine::payload::try_into_sealed_block;
use reth::rpc::result::ToRpcResult;
use reth_interfaces::{consensus::ConsensusError, RethResult};
use reth_node_ethereum::EthEvmConfig;
use reth_tracing::tracing;
use std::time::Instant;
use uuid::Uuid;
Expand Down Expand Up @@ -71,16 +78,16 @@ where
}

fn validate_inner(&self) -> RpcResult<()> {
self.trace_validation_step(self.check_gas_limit(), "Check Gas Limit")?;

self.trace_validation_step(
self.compare_message_execution_payload(),
"Message / Payload comparison",
)?;

let block = self.trace_validation_step(self.parse_block(), "Block parsing")?;

self.trace_validation_step(self.validate_header(&block), "Full validation")?;
let parent = self.trace_validation_step(self.validate_header(&block), "Full validation")?;

self.trace_validation_step(self.check_gas_limit(parent), "Check Gas Limit")?;

let state = self.trace_validation_step(
self.execute_and_verify_block(&block),
Expand Down Expand Up @@ -146,16 +153,19 @@ where
.to_rpc_result()
}

fn validate_header(&self, block: &SealedBlock) -> RpcResult<()> {
fn validate_header(&self, block: &SealedBlock) -> RpcResult<SealedHeader> {
full_validation(block, &self.provider, &self.provider.chain_spec()).to_rpc_result()
}

fn execute_and_verify_block(&self, block: &SealedBlock) -> RpcResult<BundleStateWithReceipts> {
let chain_spec = self.provider.chain_spec();
let state_provider = self.provider.latest().to_rpc_result()?;

let mut executor =
EVMProcessor::new_with_db(chain_spec, StateProviderDatabase::new(&state_provider));
let mut executor = EVMProcessor::new_with_db(
chain_spec,
StateProviderDatabase::new(&state_provider),
EthEvmConfig::default(),
);

let unsealed_block =
block
Expand All @@ -179,7 +189,10 @@ where
block: &SealedBlock,
state: &BundleStateWithReceipts,
) -> RpcResult<()> {
let state_provider = self.provider.latest().to_rpc_result()?;
let state_provider = self
.provider
.state_by_block_id(BlockId::Hash(block.parent_hash.into()))
.to_rpc_result()?;
let state_root = state_provider
.state_root(state)
.map_err(|e| internal_rpc_err(format!("Error computing state root: {e:?}")))?;
Expand Down Expand Up @@ -211,21 +224,11 @@ where
)
}

fn check_gas_limit(&self) -> RpcResult<()> {
fn check_gas_limit(&self, parent: SealedHeader) -> RpcResult<()> {
let parent_hash = &self.request_body.execution_payload.parent_hash;
let registered_gas_limit = self.request_body.registered_gas_limit;
let block_gas_limit = self.request_body.execution_payload.gas_limit;

let parent = self
.provider
.header(parent_hash)
.to_rpc_result()?
.ok_or(internal_rpc_err(format!(
"Parent block with hash {} not found",
parent_hash
)))?;
tracing::debug!(request_id=self.request_id.to_string(), parent_hash = %parent_hash, parent_gas_limit = parent.gas_limit, registered_gas_limit = registered_gas_limit, block_gas_limit = block_gas_limit, "Checking gas limit");

// Prysm has a bug where it registers validators with a desired gas limit
// of 0. Some builders treat these as desiring gas limit 30_000_000. As a
// workaround, whenever the desired gas limit is 0, we accept both the
Expand Down Expand Up @@ -328,3 +331,37 @@ fn check_proposer_balance_change(

fee_receiver_account_after.balance >= (fee_receiver_account_before.balance + expected_payment)
}

/// Full validation of block before execution.
pub fn full_validation<Provider: HeaderProvider + AccountReader + WithdrawalsProvider>(
block: &SealedBlock,
provider: Provider,
chain_spec: &ChainSpec,
) -> RethResult<SealedHeader> {
validate_header_standalone(&block.header, chain_spec)?;
validate_block_standalone(block, chain_spec)?;
let parent = validate_block_regarding_chain(block, &provider)?;

let header = &block.header;
header
.validate_against_parent(&parent, chain_spec)
.map_err(ConsensusError::from)?;

// NOTE: depending on the need of the stages, recovery could be done in different place.
let transactions = block
.body
.iter()
.map(|tx| {
tx.try_ecrecovered()
.ok_or(ConsensusError::TransactionSignerRecoveryError)
})
.collect::<Result<Vec<_>, _>>()?;

validate_all_transaction_regarding_block_and_nonces(
transactions.iter(),
&block.header,
provider,
chain_spec,
)?;
Ok(parent)
}
Loading
Loading