feat(op-reth): Canyon - Dynamic eip1559 params (#5542)

This commit is contained in:
clabby
2023-11-27 12:26:01 -05:00
committed by GitHub
parent cda471ceb4
commit b2be07aa38
10 changed files with 148 additions and 28 deletions

View File

@ -254,11 +254,13 @@ impl StorageInner {
transactions: &Vec<TransactionSigned>,
chain_spec: Arc<ChainSpec>,
) -> Header {
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs();
// check previous block for base fee
let base_fee_per_gas = self
.headers
.get(&self.best_block)
.and_then(|parent| parent.next_block_base_fee(chain_spec.base_fee_params));
.and_then(|parent| parent.next_block_base_fee(chain_spec.base_fee_params(timestamp)));
let mut header = Header {
parent_hash: self.best_hash,
@ -273,7 +275,7 @@ impl StorageInner {
number: self.best_block + 1,
gas_limit: ETHEREUM_BLOCK_GAS_LIMIT,
gas_used: 0,
timestamp: SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs(),
timestamp,
mix_hash: Default::default(),
nonce: 0,
base_fee_per_gas,

View File

@ -263,7 +263,8 @@ fn check_gas_limit(
// By consensus, gas_limit is multiplied by elasticity (*2) on
// on exact block that hardfork happens.
if chain_spec.fork(Hardfork::London).transitions_at_block(child.number) {
parent_gas_limit = parent.gas_limit * chain_spec.base_fee_params.elasticity_multiplier;
parent_gas_limit =
parent.gas_limit * chain_spec.base_fee_params(child.timestamp).elasticity_multiplier;
}
if child.gas_limit > parent_gas_limit {
@ -336,7 +337,7 @@ pub fn validate_header_regarding_parent(
} else {
// This BaseFeeMissing will not happen as previous blocks are checked to have them.
parent
.next_block_base_fee(chain_spec.base_fee_params)
.next_block_base_fee(chain_spec.base_fee_params(child.timestamp))
.ok_or(ConsensusError::BaseFeeMissing)?
};
if expected_base_fee != base_fee {

View File

@ -251,7 +251,9 @@ impl PayloadBuilderAttributes {
gas_limit: U256::from(parent.gas_limit),
// calculate basefee based on parent block's gas usage
basefee: U256::from(
parent.next_block_base_fee(chain_spec.base_fee_params).unwrap_or_default(),
parent
.next_block_base_fee(chain_spec.base_fee_params(self.timestamp))
.unwrap_or_default(),
),
// calculate excess gas based on parent block's blob gas usage
blob_excess_gas_and_price,

View File

@ -13,8 +13,9 @@ use strum::{AsRefStr, EnumCount, EnumIter, EnumString, EnumVariantNames};
// The chain spec module.
mod spec;
pub use spec::{
AllGenesisFormats, BaseFeeParams, ChainSpec, ChainSpecBuilder, DisplayHardforks, ForkCondition,
ForkTimestamps, DEV, GOERLI, HOLESKY, MAINNET, SEPOLIA,
AllGenesisFormats, BaseFeeParams, BaseFeeParamsKind, ChainSpec, ChainSpecBuilder,
DisplayHardforks, ForkBaseFeeParams, ForkCondition, ForkTimestamps, DEV, GOERLI, HOLESKY,
MAINNET, SEPOLIA,
};
#[cfg(feature = "optimism")]

View File

@ -63,7 +63,7 @@ pub static MAINNET: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
11052984,
b256!("649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5"),
)),
base_fee_params: BaseFeeParams::ethereum(),
base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()),
prune_delete_limit: 3500,
snapshot_block_interval: 500_000,
}
@ -106,7 +106,7 @@ pub static GOERLI: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
4367322,
b256!("649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5"),
)),
base_fee_params: BaseFeeParams::ethereum(),
base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()),
prune_delete_limit: 1700,
snapshot_block_interval: 1_000_000,
}
@ -153,8 +153,7 @@ pub static SEPOLIA: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
1273020,
b256!("649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5"),
)),
base_fee_params: BaseFeeParams::ethereum(),
base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()),
prune_delete_limit: 1700,
snapshot_block_interval: 1_000_000,
}
@ -196,7 +195,7 @@ pub static HOLESKY: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
0,
b256!("649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5"),
)),
base_fee_params: BaseFeeParams::ethereum(),
base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()),
prune_delete_limit: 1700,
snapshot_block_interval: 1_000_000,
}
@ -236,6 +235,7 @@ pub static DEV: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
),
(Hardfork::Shanghai, ForkCondition::Timestamp(0)),
]),
base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()),
deposit_contract: None, // TODO: do we even have?
..Default::default()
}
@ -277,7 +277,13 @@ pub static OP_GOERLI: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
(Hardfork::Shanghai, ForkCondition::Timestamp(1699981200)),
(Hardfork::Canyon, ForkCondition::Timestamp(1699981200)),
]),
base_fee_params: BaseFeeParams::optimism(),
base_fee_params: BaseFeeParamsKind::Variable(
vec![
(Hardfork::London, BaseFeeParams::optimism_goerli()),
(Hardfork::Canyon, BaseFeeParams::optimism_goerli_canyon()),
]
.into(),
),
prune_delete_limit: 1700,
snapshot_block_interval: 1_000_000,
..Default::default()
@ -320,7 +326,13 @@ pub static BASE_GOERLI: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
(Hardfork::Shanghai, ForkCondition::Timestamp(1699981200)),
(Hardfork::Canyon, ForkCondition::Timestamp(1699981200)),
]),
base_fee_params: BaseFeeParams::optimism_goerli(),
base_fee_params: BaseFeeParamsKind::Variable(
vec![
(Hardfork::London, BaseFeeParams::optimism_goerli()),
(Hardfork::Canyon, BaseFeeParams::optimism_goerli_canyon()),
]
.into(),
),
prune_delete_limit: 1700,
snapshot_block_interval: 1_000_000,
..Default::default()
@ -361,7 +373,13 @@ pub static BASE_MAINNET: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
(Hardfork::Bedrock, ForkCondition::Block(0)),
(Hardfork::Regolith, ForkCondition::Timestamp(0)),
]),
base_fee_params: BaseFeeParams::optimism(),
base_fee_params: BaseFeeParamsKind::Variable(
vec![
(Hardfork::London, BaseFeeParams::optimism()),
(Hardfork::Canyon, BaseFeeParams::optimism_canyon()),
]
.into(),
),
prune_delete_limit: 1700,
snapshot_block_interval: 1_000_000,
..Default::default()
@ -369,6 +387,41 @@ pub static BASE_MAINNET: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
.into()
});
/// A wrapper around [BaseFeeParams] that allows for specifying constant or dynamic EIP-1559
/// parameters based on the active [Hardfork].
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum BaseFeeParamsKind {
/// Constant [BaseFeeParams]; used for chains that don't have dynamic EIP-1559 parameters
Constant(BaseFeeParams),
/// Variable [BaseFeeParams]; used for chains that have dynamic EIP-1559 parameters like
/// Optimism
Variable(ForkBaseFeeParams),
}
impl From<BaseFeeParams> for BaseFeeParamsKind {
fn from(params: BaseFeeParams) -> Self {
BaseFeeParamsKind::Constant(params)
}
}
impl From<ForkBaseFeeParams> for BaseFeeParamsKind {
fn from(params: ForkBaseFeeParams) -> Self {
BaseFeeParamsKind::Variable(params)
}
}
/// A type alias to a vector of tuples of [Hardfork] and [BaseFeeParams], sorted by [Hardfork]
/// activation order. This is used to specify dynamic EIP-1559 parameters for chains like Optimism.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ForkBaseFeeParams(Vec<(Hardfork, BaseFeeParams)>);
impl From<Vec<(Hardfork, BaseFeeParams)>> for ForkBaseFeeParams {
fn from(params: Vec<(Hardfork, BaseFeeParams)>) -> Self {
ForkBaseFeeParams(params)
}
}
/// BaseFeeParams contains the config parameters that control block base fee computation
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
pub struct BaseFeeParams {
@ -398,6 +451,17 @@ impl BaseFeeParams {
}
}
/// Get the base fee parameters for optimism goerli (post Canyon)
#[cfg(feature = "optimism")]
pub const fn optimism_goerli_canyon() -> BaseFeeParams {
BaseFeeParams {
max_change_denominator:
crate::constants::OP_GOERLI_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON,
elasticity_multiplier:
crate::constants::OP_GOERLI_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
}
}
/// Get the base fee parameters for optimism mainnet
#[cfg(feature = "optimism")]
pub const fn optimism() -> BaseFeeParams {
@ -408,6 +472,17 @@ impl BaseFeeParams {
crate::constants::OP_MAINNET_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
}
}
/// Get the base fee parameters for optimism mainnet (post Canyon)
#[cfg(feature = "optimism")]
pub const fn optimism_canyon() -> BaseFeeParams {
BaseFeeParams {
max_change_denominator:
crate::constants::OP_MAINNET_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON,
elasticity_multiplier:
crate::constants::OP_MAINNET_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
}
}
}
/// An Ethereum chain specification.
@ -450,7 +525,7 @@ pub struct ChainSpec {
pub deposit_contract: Option<DepositContract>,
/// The parameters that configure how a block's base fee is computed
pub base_fee_params: BaseFeeParams,
pub base_fee_params: BaseFeeParamsKind,
/// The delete limit for pruner, per block. In the actual pruner run it will be multiplied by
/// the amount of blocks between pruner runs to account for the difference in amount of new
@ -472,7 +547,7 @@ impl Default for ChainSpec {
fork_timestamps: Default::default(),
hardforks: Default::default(),
deposit_contract: Default::default(),
base_fee_params: BaseFeeParams::ethereum(),
base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()),
prune_delete_limit: MAINNET.prune_delete_limit,
snapshot_block_interval: Default::default(),
}
@ -559,6 +634,25 @@ impl ChainSpec {
(self.fork(Hardfork::London).active_at_block(0)).then_some(genesis_base_fee)
}
/// Get the [BaseFeeParams] for the chain at the given timestamp.
pub fn base_fee_params(&self, timestamp: u64) -> BaseFeeParams {
match self.base_fee_params {
BaseFeeParamsKind::Constant(bf_params) => bf_params,
BaseFeeParamsKind::Variable(ForkBaseFeeParams { 0: ref bf_params }) => {
// Walk through the base fee params configuration in reverse order, and return the
// first one that corresponds to a hardfork that is active at the
// given timestamp.
for (fork, params) in bf_params.iter().rev() {
if self.is_fork_active_at_timestamp(*fork, timestamp) {
return *params
}
}
bf_params.first().map(|(_, params)| *params).unwrap_or(BaseFeeParams::ethereum())
}
}
}
/// Get the hash of the genesis block.
pub fn genesis_hash(&self) -> B256 {
if let Some(hash) = self.genesis_hash {

View File

@ -67,6 +67,11 @@ pub const EIP1559_DEFAULT_ELASTICITY_MULTIPLIER: u64 = 2;
#[cfg(feature = "optimism")]
pub const OP_MAINNET_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR: u64 = 50;
/// Base fee max change denominator for Optimism Mainnet as defined in the Optimism Canyon
/// hardfork.
#[cfg(feature = "optimism")]
pub const OP_MAINNET_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON: u64 = 250;
/// Base fee max change denominator for Optimism Mainnet as defined in the Optimism
/// [transaction costs](https://community.optimism.io/docs/developers/build/differences/#transaction-costs) doc.
#[cfg(feature = "optimism")]
@ -77,6 +82,11 @@ pub const OP_MAINNET_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER: u64 = 6;
#[cfg(feature = "optimism")]
pub const OP_GOERLI_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR: u64 = 50;
/// Base fee max change denominator for Optimism Goerli as defined in the Optimism Canyon
/// hardfork.
#[cfg(feature = "optimism")]
pub const OP_GOERLI_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON: u64 = 250;
/// Base fee max change denominator for Optimism Goerli as defined in the Optimism
/// [transaction costs](https://community.optimism.io/docs/developers/build/differences/#transaction-costs) doc.
#[cfg(feature = "optimism")]

View File

@ -55,9 +55,9 @@ pub use block::{
};
pub use bytes::{self, Buf, BufMut, BytesMut};
pub use chain::{
AllGenesisFormats, BaseFeeParams, Chain, ChainInfo, ChainSpec, ChainSpecBuilder,
DisplayHardforks, ForkCondition, ForkTimestamps, NamedChain, DEV, GOERLI, HOLESKY, MAINNET,
SEPOLIA,
AllGenesisFormats, BaseFeeParams, BaseFeeParamsKind, Chain, ChainInfo, ChainSpec,
ChainSpecBuilder, DisplayHardforks, ForkBaseFeeParams, ForkCondition, ForkTimestamps,
NamedChain, DEV, GOERLI, HOLESKY, MAINNET, SEPOLIA,
};
#[cfg(feature = "optimism")]
pub use chain::{BASE_GOERLI, BASE_MAINNET, OP_GOERLI};

View File

@ -130,11 +130,18 @@ where
}
}
let last_entry = fee_entries.last().expect("is not empty");
let last_entry_timestamp = self
.provider()
.header_by_hash_or_number(last_entry.header_hash.into())?
.map(|h| h.timestamp)
.unwrap_or_default();
base_fee_per_gas.push(U256::from(calculate_next_block_base_fee(
last_entry.gas_used,
last_entry.gas_limit,
last_entry.base_fee_per_gas,
self.provider().chain_spec().base_fee_params,
self.provider().chain_spec().base_fee_params(last_entry_timestamp),
)));
} else {
// read the requested header range
@ -183,7 +190,7 @@ where
last_header.gas_used,
last_header.gas_limit,
last_header.base_fee_per_gas.unwrap_or_default(),
self.provider().chain_spec().base_fee_params,
self.provider().chain_spec().base_fee_params(last_header.timestamp),
)));
};

View File

@ -277,7 +277,8 @@ where
latest.timestamp += 12;
// base fee of the child block
let chain_spec = self.provider().chain_spec();
latest.base_fee_per_gas = latest.next_block_base_fee(chain_spec.base_fee_params);
latest.base_fee_per_gas =
latest.next_block_base_fee(chain_spec.base_fee_params(latest.timestamp));
PendingBlockEnvOrigin::DerivedFromLatest(latest)
};

View File

@ -92,7 +92,7 @@ pub async fn maintain_transaction_pool<Client, P, St, Tasks>(
last_seen_block_hash: latest.hash,
last_seen_block_number: latest.number,
pending_basefee: latest
.next_block_base_fee(chain_spec.base_fee_params)
.next_block_base_fee(chain_spec.base_fee_params(latest.timestamp + 12))
.unwrap_or_default(),
pending_blob_fee: latest.next_block_blob_fee(),
};
@ -238,8 +238,9 @@ pub async fn maintain_transaction_pool<Client, P, St, Tasks>(
let chain_spec = client.chain_spec();
// fees for the next block: `new_tip+1`
let pending_block_base_fee =
new_tip.next_block_base_fee(chain_spec.base_fee_params).unwrap_or_default();
let pending_block_base_fee = new_tip
.next_block_base_fee(chain_spec.base_fee_params(new_tip.timestamp + 12))
.unwrap_or_default();
let pending_block_blob_fee = new_tip.next_block_blob_fee();
// we know all changed account in the new chain
@ -342,8 +343,9 @@ pub async fn maintain_transaction_pool<Client, P, St, Tasks>(
let chain_spec = client.chain_spec();
// fees for the next block: `tip+1`
let pending_block_base_fee =
tip.next_block_base_fee(chain_spec.base_fee_params).unwrap_or_default();
let pending_block_base_fee = tip
.next_block_base_fee(chain_spec.base_fee_params(tip.timestamp + 12))
.unwrap_or_default();
let pending_block_blob_fee = tip.next_block_blob_fee();
let first_block = blocks.first();