Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
210323b
added-feature
rose2221 Jun 8, 2025
33469e1
Update crates/rpc/rpc-eth-api/src/helpers/fee.rs
rose2221 Jun 8, 2025
6395eb0
Merge branch 'paradigmxyz:main' into feature/minimum_base
rose2221 Jun 10, 2025
3868f41
files changed
rose2221 Jun 10, 2025
1b7e21d
Merge branch 'paradigmxyz:main' into feature/minimum_base
rose2221 Jun 15, 2025
3a4deff
fixed errors
rose2221 Jun 15, 2025
626525b
Merge branch 'main' into basefee/centralize-with-rose
rezzmah Jun 18, 2025
d726bb6
fix: correct timestamp usage in centralized base fee calculation
rezzmah Jun 18, 2025
c389d02
fix: address clippy warnings in base fee centralization
rezzmah Jun 18, 2025
4066c5b
refactor: minimize diff and follow reth patterns
rezzmah Jun 18, 2025
96e35f7
fix: remove commented code and restore proper test logic
rezzmah Jun 18, 2025
3581cb7
fix: restore Self: Sized constraint for trait object compatibility
rezzmah Jun 18, 2025
974466a
Update api.rs
rezzmah Jun 18, 2025
7046d8c
revert
rezzmah Jun 18, 2025
ff89a49
Remove excessive trait bound
rezzmah Jun 18, 2025
87740a3
Update lib.rs
rezzmah Jun 18, 2025
9c03672
revert change
rezzmah Jun 18, 2025
58f2ae9
refactor: simplify fee history base fee calculation
rezzmah Jun 18, 2025
b8f0046
refactor: use chainspec.next_block_base_fee directly
rezzmah Jun 18, 2025
26c66d5
lint
rezzmah Jun 18, 2025
cb1a741
lint
rezzmah Jun 18, 2025
329f907
Update fee.rs
rezzmah Jun 18, 2025
e9d8b78
Update fee_history.rs
rezzmah Jun 18, 2025
4e0332d
perf: optimize chain_spec access in fee history
rezzmah Jun 18, 2025
c83d2dc
Update core.rs
rezzmah Jun 18, 2025
7a2f43f
Update maintain.rs
rezzmah Jun 18, 2025
8e4c8e4
Update fee_history.rs
rezzmah Jun 18, 2025
9630cdd
style: improve code formatting and remove excessive comments
rezzmah Jun 18, 2025
1128f98
docs: clarify header field limitations for next_block_base_fee
rezzmah Jun 18, 2025
97d69d1
lint
rezzmah Jun 18, 2025
171e60a
refactor: update Optimism tests to use centralized base fee calculation
rezzmah Jun 18, 2025
8d07fb2
fix: add backticks to code items in documentation
rezzmah Jun 19, 2025
709861f
lint
rezzmah Jun 19, 2025
3abe2f4
Update api.rs
rezzmah Jun 19, 2025
464a097
Update fee.rs
rezzmah Jun 19, 2025
456b674
Merge remote-tracking branch 'upstream/main' into basefee/centralize-…
rezzmah Jun 20, 2025
893122d
docs: simplify next_block_base_fee documentation
rezzmah Jun 20, 2025
bafe103
refactor: change next_block_base_fee to take individual gas fields
rezzmah Jun 20, 2025
992996e
fix: improve error handling and clean up imports
rezzmah Jun 20, 2025
3cf3618
docs: add clarifying comment about BaseFeeMissing error
rezzmah Jun 20, 2025
3bc1c01
test: use unwrap() instead of unwrap_or_default() for base fee
rezzmah Jun 20, 2025
92795dd
revert: use original next_block_base_fee function for optimism
rezzmah Jun 20, 2025
7beacfc
style: clean up imports and formatting
rezzmah Jun 20, 2025
da53137
docs: fix broken documentation link
rezzmah Jun 20, 2025
d35816a
feat: add parent_timestamp parameter to next_block_base_fee
rezzmah Jun 21, 2025
e76da1c
feat: adopt alloy-consensus pattern for next_block_base_fee
rezzmah Jun 22, 2025
9e94ca2
feat: store full headers in FeeHistoryEntry to eliminate database loo…
rezzmah Jun 23, 2025
e44ef72
feat: make FeeHistoryCache and FeeHistoryEntry generic over header type
rezzmah Jun 23, 2025
ad8fec4
Merge remote-tracking branch 'upstream/main' into basefee/centralize-…
rezzmah Jun 25, 2025
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
18 changes: 16 additions & 2 deletions crates/chainspec/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{ChainSpec, DepositContract};
use alloc::{boxed::Box, vec::Vec};
use alloy_chains::Chain;
use alloy_consensus::Header;
use alloy_eips::{eip1559::BaseFeeParams, eip7840::BlobParams};
use alloy_consensus::{BlockHeader, Header};
use alloy_eips::{calc_next_block_base_fee, eip1559::BaseFeeParams, eip7840::BlobParams};
use alloy_genesis::Genesis;
use alloy_primitives::{B256, U256};
use core::fmt::{Debug, Display};
Expand Down Expand Up @@ -65,6 +65,20 @@ pub trait EthChainSpec: Send + Sync + Unpin + Debug {

/// Returns the final total difficulty if the Paris hardfork is known.
fn final_paris_total_difficulty(&self) -> Option<U256>;

/// See [`calc_next_block_base_fee`].
fn next_block_base_fee<H>(&self, parent: &H, target_timestamp: u64) -> Option<u64>
where
Self: Sized,
H: BlockHeader,
{
Some(calc_next_block_base_fee(
parent.gas_used(),
parent.gas_limit(),
parent.base_fee_per_gas()?,
self.base_fee_params_at_timestamp(target_timestamp),
))
}
}

impl EthChainSpec for ChainSpec {
Expand Down
30 changes: 30 additions & 0 deletions crates/chainspec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,34 @@ mod tests {
let chain: Chain = NamedChain::Holesky.into();
assert_eq!(s, chain.public_dns_network_protocol().unwrap().as_str());
}

#[test]
fn test_centralized_base_fee_calculation() {
use crate::{ChainSpec, EthChainSpec};
use alloy_consensus::Header;
use alloy_eips::eip1559::INITIAL_BASE_FEE;

fn parent_header() -> Header {
Header {
gas_used: 15_000_000,
gas_limit: 30_000_000,
base_fee_per_gas: Some(INITIAL_BASE_FEE),
timestamp: 1_000,
..Default::default()
}
}

let spec = ChainSpec::default();
let parent = parent_header();

// For testing, assume next block has timestamp 12 seconds later
let next_timestamp = parent.timestamp + 12;

let expected = parent
.next_block_base_fee(spec.base_fee_params_at_timestamp(next_timestamp))
.unwrap_or_default();

let got = spec.next_block_base_fee(&parent, next_timestamp).unwrap_or_default();
assert_eq!(expected, got, "Base fee calculation does not match expected value");
}
}
14 changes: 4 additions & 10 deletions crates/consensus/common/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use alloy_consensus::{
constants::MAXIMUM_EXTRA_DATA_SIZE, BlockHeader as _, EMPTY_OMMER_ROOT_HASH,
};
use alloy_eips::{calc_next_block_base_fee, eip4844::DATA_GAS_PER_BLOB, eip7840::BlobParams};
use alloy_eips::{eip4844::DATA_GAS_PER_BLOB, eip7840::BlobParams};
use reth_chainspec::{EthChainSpec, EthereumHardfork, EthereumHardforks};
use reth_consensus::ConsensusError;
use reth_primitives_traits::{
Expand Down Expand Up @@ -266,15 +266,9 @@ pub fn validate_against_parent_eip1559_base_fee<
{
alloy_eips::eip1559::INITIAL_BASE_FEE
} else {
// This BaseFeeMissing will not happen as previous blocks are checked to have
// them.
let base_fee = parent.base_fee_per_gas().ok_or(ConsensusError::BaseFeeMissing)?;
calc_next_block_base_fee(
parent.gas_used(),
parent.gas_limit(),
base_fee,
chain_spec.base_fee_params_at_timestamp(header.timestamp()),
)
chain_spec
.next_block_base_fee(parent, header.timestamp())
.ok_or(ConsensusError::BaseFeeMissing)?
};
if expected_base_fee != base_fee {
return Err(ConsensusError::BaseFeeDiff(GotExpected {
Expand Down
4 changes: 1 addition & 3 deletions crates/ethereum/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,7 @@ where
BlobExcessGasAndPrice { excess_blob_gas, blob_gasprice }
});

let mut basefee = parent.next_block_base_fee(
self.chain_spec().base_fee_params_at_timestamp(attributes.timestamp),
);
let mut basefee = chain_spec.next_block_base_fee(parent, attributes.timestamp);

let mut gas_limit = attributes.gas_limit;

Expand Down
13 changes: 4 additions & 9 deletions crates/ethereum/node/tests/e2e/rpc.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::utils::eth_payload_attributes;
use alloy_eips::{calc_next_block_base_fee, eip2718::Encodable2718};
use alloy_eips::eip2718::Encodable2718;
use alloy_primitives::{Address, B256, U256};
use alloy_provider::{network::EthereumWallet, Provider, ProviderBuilder, SendableTx};
use alloy_rpc_types_beacon::relay::{
Expand All @@ -9,7 +9,7 @@ use alloy_rpc_types_beacon::relay::{
use alloy_rpc_types_engine::{BlobsBundleV1, ExecutionPayloadV3};
use alloy_rpc_types_eth::TransactionRequest;
use rand::{rngs::StdRng, Rng, SeedableRng};
use reth_chainspec::{ChainSpecBuilder, MAINNET};
use reth_chainspec::{ChainSpecBuilder, EthChainSpec, MAINNET};
use reth_e2e_test_utils::setup_engine;
use reth_node_ethereum::EthereumNode;
use reth_payload_primitives::BuiltPayload;
Expand Down Expand Up @@ -98,14 +98,9 @@ async fn test_fee_history() -> eyre::Result<()> {
.unwrap()
.header;
for block in (latest_block + 2 - block_count)..=latest_block {
let expected_base_fee = calc_next_block_base_fee(
prev_header.gas_used,
prev_header.gas_limit,
prev_header.base_fee_per_gas.unwrap(),
chain_spec.base_fee_params_at_block(block),
);

let header = provider.get_block_by_number(block.into()).await?.unwrap().header;
let expected_base_fee =
chain_spec.next_block_base_fee(&prev_header, header.timestamp).unwrap();

assert_eq!(header.base_fee_per_gas.unwrap(), expected_base_fee);
assert_eq!(
Expand Down
12 changes: 3 additions & 9 deletions crates/optimism/chainspec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -736,9 +736,7 @@ mod tests {
genesis.hash_slow(),
b256!("0xf712aa9241cc24369b143cf6dce85f0902a9731e70d66818a3a5845b296c73dd")
);
let base_fee = genesis
.next_block_base_fee(BASE_MAINNET.base_fee_params_at_timestamp(genesis.timestamp))
.unwrap();
let base_fee = BASE_MAINNET.next_block_base_fee(genesis, genesis.timestamp).unwrap();
// <https://base.blockscout.com/block/1>
assert_eq!(base_fee, 980000000);
}
Expand All @@ -750,9 +748,7 @@ mod tests {
genesis.hash_slow(),
b256!("0x0dcc9e089e30b90ddfc55be9a37dd15bc551aeee999d2e2b51414c54eaf934e4")
);
let base_fee = genesis
.next_block_base_fee(BASE_SEPOLIA.base_fee_params_at_timestamp(genesis.timestamp))
.unwrap();
let base_fee = BASE_SEPOLIA.next_block_base_fee(genesis, genesis.timestamp).unwrap();
// <https://base-sepolia.blockscout.com/block/1>
assert_eq!(base_fee, 980000000);
}
Expand All @@ -764,9 +760,7 @@ mod tests {
genesis.hash_slow(),
b256!("0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d")
);
let base_fee = genesis
.next_block_base_fee(OP_SEPOLIA.base_fee_params_at_timestamp(genesis.timestamp))
.unwrap();
let base_fee = OP_SEPOLIA.next_block_base_fee(genesis, genesis.timestamp).unwrap();
// <https://optimism-sepolia.blockscout.com/block/1>
assert_eq!(base_fee, 980000000);
}
Expand Down
12 changes: 3 additions & 9 deletions crates/optimism/consensus/src/validation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,7 @@ pub fn next_block_base_fee(
if chain_spec.is_holocene_active_at_timestamp(parent.timestamp()) {
Ok(decode_holocene_base_fee(chain_spec, parent, timestamp)?)
} else {
Ok(parent
.next_block_base_fee(chain_spec.base_fee_params_at_timestamp(timestamp))
.unwrap_or_default())
Ok(chain_spec.next_block_base_fee(&parent, timestamp).unwrap_or_default())
}
}

Expand Down Expand Up @@ -255,9 +253,7 @@ mod tests {
let base_fee = next_block_base_fee(&op_chain_spec, &parent, 0);
assert_eq!(
base_fee.unwrap(),
parent
.next_block_base_fee(op_chain_spec.base_fee_params_at_timestamp(0))
.unwrap_or_default()
op_chain_spec.next_block_base_fee(&parent, 0).unwrap_or_default()
);
}

Expand All @@ -275,9 +271,7 @@ mod tests {
let base_fee = next_block_base_fee(&op_chain_spec, &parent, 1800000005);
assert_eq!(
base_fee.unwrap(),
parent
.next_block_base_fee(op_chain_spec.base_fee_params_at_timestamp(0))
.unwrap_or_default()
op_chain_spec.next_block_base_fee(&parent, 0).unwrap_or_default()
);
}

Expand Down
2 changes: 1 addition & 1 deletion crates/optimism/rpc/src/eth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ where
}

#[inline]
fn fee_history_cache(&self) -> &FeeHistoryCache {
fn fee_history_cache(&self) -> &FeeHistoryCache<ProviderHeader<N::Provider>> {
self.inner.eth_api.fee_history_cache()
}

Expand Down
36 changes: 21 additions & 15 deletions crates/rpc/rpc-eth-api/src/helpers/fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use reth_rpc_eth_types::{
fee_history::calculate_reward_percentiles_for_block, EthApiError, FeeHistoryCache,
FeeHistoryEntry, GasPriceOracle, RpcInvalidTransactionError,
};
use reth_storage_api::{BlockIdReader, BlockReaderIdExt, HeaderProvider};
use reth_storage_api::{BlockIdReader, BlockReaderIdExt, HeaderProvider, ProviderHeader};
use tracing::debug;

/// Fee related functions for the [`EthApiServer`](crate::EthApiServer) trait in the
Expand Down Expand Up @@ -136,7 +136,8 @@ pub trait EthFees: LoadFee {
}

for entry in &fee_entries {
base_fee_per_gas.push(entry.base_fee_per_gas as u128);
base_fee_per_gas
.push(entry.header.base_fee_per_gas().unwrap_or_default() as u128);
gas_used_ratio.push(entry.gas_used_ratio);
base_fee_per_blob_gas.push(entry.base_fee_per_blob_gas.unwrap_or_default());
blob_gas_used_ratio.push(entry.blob_gas_used_ratio);
Expand All @@ -153,8 +154,12 @@ pub trait EthFees: LoadFee {

// Also need to include the `base_fee_per_gas` and `base_fee_per_blob_gas` for the
// next block
base_fee_per_gas
.push(last_entry.next_block_base_fee(self.provider().chain_spec()) as u128);
base_fee_per_gas.push(
self.provider()
.chain_spec()
.next_block_base_fee(&last_entry.header, last_entry.header.timestamp())
.unwrap_or_default() as u128,
);

base_fee_per_blob_gas.push(last_entry.next_block_blob_fee().unwrap_or_default());
} else {
Expand All @@ -166,13 +171,12 @@ pub trait EthFees: LoadFee {
return Err(EthApiError::InvalidBlockRange.into())
}


let chain_spec = self.provider().chain_spec();
for header in &headers {
base_fee_per_gas.push(header.base_fee_per_gas().unwrap_or_default() as u128);
gas_used_ratio.push(header.gas_used() as f64 / header.gas_limit() as f64);

let blob_params = self.provider()
.chain_spec()
let blob_params = chain_spec
.blob_params_at_timestamp(header.timestamp())
.unwrap_or_else(BlobParams::cancun);

Expand Down Expand Up @@ -209,18 +213,16 @@ pub trait EthFees: LoadFee {
// The unwrap is safe since we checked earlier that we got at least 1 header.
let last_header = headers.last().expect("is present");
base_fee_per_gas.push(
last_header.next_block_base_fee(
self.provider()
.chain_spec()
.base_fee_params_at_timestamp(last_header.timestamp())).unwrap_or_default() as u128
chain_spec
.next_block_base_fee(last_header.header(), last_header.timestamp())
.unwrap_or_default() as u128,
);

// Same goes for the `base_fee_per_blob_gas`:
// > "[..] includes the next block after the newest of the returned range, because this value can be derived from the newest block.
base_fee_per_blob_gas.push(
last_header
.maybe_next_block_blob_fee(
self.provider().chain_spec().blob_params_at_timestamp(last_header.timestamp())
chain_spec.blob_params_at_timestamp(last_header.timestamp())
).unwrap_or_default()
);
};
Expand All @@ -238,7 +240,11 @@ pub trait EthFees: LoadFee {

/// Approximates reward at a given percentile for a specific block
/// Based on the configured resolution
fn approximate_percentile(&self, entry: &FeeHistoryEntry, requested_percentile: f64) -> u128 {
fn approximate_percentile(
&self,
entry: &FeeHistoryEntry<ProviderHeader<Self::Provider>>,
requested_percentile: f64,
) -> u128 {
let resolution = self.fee_history_cache().resolution();
let rounded_percentile =
(requested_percentile * resolution as f64).round() / resolution as f64;
Expand Down Expand Up @@ -266,7 +272,7 @@ where
/// Returns a handle for reading fee history data from memory.
///
/// Data access in default (L1) trait method implementations.
fn fee_history_cache(&self) -> &FeeHistoryCache;
fn fee_history_cache(&self) -> &FeeHistoryCache<ProviderHeader<Self::Provider>>;

/// Returns the gas price if it is set, otherwise fetches a suggested gas price for legacy
/// transactions.
Expand Down
Loading
Loading