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

Add eip1559 params to payload #11473

Closed
wants to merge 16 commits into from
Closed
376 changes: 183 additions & 193 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -459,10 +459,10 @@ alloy-transport-ipc = { version = "0.4.2", default-features = false }
alloy-transport-ws = { version = "0.4.2", default-features = false }

# op
op-alloy-rpc-types = "0.3.2"
op-alloy-rpc-types-engine = "0.3.2"
op-alloy-network = "0.3.2"
op-alloy-consensus = "0.3.2"
op-alloy-rpc-types = "0.3.3"
op-alloy-rpc-types-engine = "0.3.3"
op-alloy-network = "0.3.3"
op-alloy-consensus = "0.3.3"

# misc
aquamarine = "0.5"
Expand Down
14 changes: 14 additions & 0 deletions crates/ethereum/engine-primitives/src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,20 @@ impl PayloadBuilderAttributes for EthPayloadBuilderAttributes {
}
}

impl Default for EthPayloadBuilderAttributes {
fn default() -> Self {
Self {
id: PayloadId::new([0; 8]),
parent: B256::default(),
timestamp: 0,
suggested_fee_recipient: Address::ZERO,
prev_randao: B256::default(),
withdrawals: Withdrawals::default(),
parent_beacon_block_root: None,
}
}
}
Comment on lines +251 to +263
Copy link
Member

Choose a reason for hiding this comment

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

this can probably be derived

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Requires this change in alloy I think, PTAL
alloy-rs/alloy#1442


/// Generates the payload id for the configured payload from the [`PayloadAttributes`].
///
/// Returns an 8-byte identifier by hashing the payload components with sha256 hash.
Expand Down
70 changes: 68 additions & 2 deletions crates/optimism/chainspec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ mod dev;
mod op;
mod op_sepolia;

use std::fmt::Display;
use std::{fmt::Display, str::FromStr};

use alloy_genesis::Genesis;
use alloy_primitives::{Parity, Signature, B256, U256};
use alloy_primitives::{Parity, Signature, B256, B64, U256};
pub use base::BASE_MAINNET;
pub use base_sepolia::BASE_SEPOLIA;
pub use dev::OP_DEV;
Expand All @@ -32,21 +32,53 @@ use reth_chainspec::{
Hardforks, Head,
};
use reth_network_peers::NodeRecord;
use reth_optimism_forks::OptimismHardfork;
use reth_primitives_traits::Header;

const DENOMINATOR_MASK: u64 = 0xFFFFFFFF00000000;
cody-wang-cb marked this conversation as resolved.
Show resolved Hide resolved
const ELASTICITY_MASK: u64 = 0x00000000FFFFFFFF;

/// OP stack chain spec type.
#[derive(Debug, Clone, Deref, Into, Constructor, PartialEq, Eq)]
pub struct OpChainSpec {
/// [`ChainSpec`].
pub inner: ChainSpec,
}

/// Fee trait for OP chain specs.
pub trait Fee {
/// Read from parent to determine the base fee for the next block
fn next_block_base_fee(&self, parent: &Header, timestamp: u64) -> U256;
}

/// Returns the signature for the optimism deposit transactions, which don't include a
/// signature.
pub fn optimism_deposit_tx_signature() -> Signature {
Signature::new(U256::ZERO, U256::ZERO, Parity::Parity(false))
}

impl Fee for OpChainSpec {
fn next_block_base_fee(&self, parent: &Header, timestamp: u64) -> U256 {
clabby marked this conversation as resolved.
Show resolved Hide resolved
let is_holocene =
self.inner.is_fork_active_at_timestamp(OptimismHardfork::Holocene, timestamp);
if is_holocene {
cody-wang-cb marked this conversation as resolved.
Show resolved Hide resolved
// First 4 bytes of the nonce are the base fee denominator, the last 4 bytes are the
// elasticity
let denominator = parent.nonce & B64::from_str(&DENOMINATOR_MASK.to_string()).unwrap();
let elasticity = parent.nonce & B64::from_str(&ELASTICITY_MASK.to_string()).unwrap();
cody-wang-cb marked this conversation as resolved.
Show resolved Hide resolved
let base_fee_params =
BaseFeeParams::new(u64::from(denominator) as u128, u64::from(elasticity) as u128);
U256::from(parent.next_block_base_fee(base_fee_params).unwrap_or_default())
} else {
U256::from(
parent
.next_block_base_fee(self.base_fee_params_at_timestamp(timestamp))
.unwrap_or_default(),
)
}
}
}

impl EthChainSpec for OpChainSpec {
fn chain(&self) -> alloy_chains::Chain {
self.inner.chain()
Expand Down Expand Up @@ -552,4 +584,38 @@ mod tests {

assert!(chainspec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, 20));
}

#[test]
fn test_get_base_fee_pre_holocene() {
let op_chain_spec = &BASE_SEPOLIA;
let mut parent = Header::default();
parent.nonce = B64::from_str("0x1234567812345678").unwrap();

let base_fee = op_chain_spec.next_block_base_fee(&parent, 0);
assert_eq!(
base_fee,
U256::from(
parent
.next_block_base_fee(op_chain_spec.base_fee_params_at_timestamp(0))
.unwrap_or_default()
)
);
}

#[test]
fn test_get_base_fee_holocene() {
let op_chain_spec = &BASE_SEPOLIA;
let mut parent = Header::default();
parent.nonce = B64::from_str("0x1234567812345678").unwrap();

let base_fee = op_chain_spec.next_block_base_fee(&parent, 0);
assert_eq!(
base_fee,
U256::from(
parent
.next_block_base_fee(BaseFeeParams::new(0x12345678, 0x12345678))
.unwrap_or_default()
)
);
}
}
3 changes: 1 addition & 2 deletions crates/optimism/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ reth-prune-types.workspace = true

# ethereum
alloy-primitives.workspace = true
alloy-eips.workspace = true

# Optimism
reth-optimism-consensus.workspace = true
Expand All @@ -38,8 +39,6 @@ thiserror.workspace = true
tracing.workspace = true

[dev-dependencies]
alloy-eips.workspace = true

reth-revm = { workspace = true, features = ["test-utils"] }
reth-optimism-chainspec.workspace = true
alloy-genesis.workspace = true
Expand Down
8 changes: 6 additions & 2 deletions crates/optimism/evm/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ pub fn revm_spec_by_timestamp_after_bedrock(
chain_spec: &ChainSpec,
timestamp: u64,
) -> revm_primitives::SpecId {
if chain_spec.fork(OptimismHardfork::Granite).active_at_timestamp(timestamp) {
if chain_spec.fork(OptimismHardfork::Holocene).active_at_timestamp(timestamp) {
revm_primitives::HOLOCENE
} else if chain_spec.fork(OptimismHardfork::Granite).active_at_timestamp(timestamp) {
revm_primitives::GRANITE
} else if chain_spec.fork(OptimismHardfork::Fjord).active_at_timestamp(timestamp) {
revm_primitives::FJORD
Expand All @@ -29,7 +31,9 @@ pub fn revm_spec_by_timestamp_after_bedrock(

/// Map the latest active hardfork at the given block to a revm [`SpecId`](revm_primitives::SpecId).
pub fn revm_spec(chain_spec: &ChainSpec, block: &Head) -> revm_primitives::SpecId {
if chain_spec.fork(OptimismHardfork::Granite).active_at_head(block) {
if chain_spec.fork(OptimismHardfork::Holocene).active_at_head(block) {
revm_primitives::HOLOCENE
} else if chain_spec.fork(OptimismHardfork::Granite).active_at_head(block) {
revm_primitives::GRANITE
} else if chain_spec.fork(OptimismHardfork::Fjord).active_at_head(block) {
revm_primitives::FJORD
Expand Down
12 changes: 3 additions & 9 deletions crates/optimism/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@

use alloy_primitives::{Address, U256};
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes};
use reth_optimism_chainspec::OpChainSpec;
use reth_optimism_chainspec::{Fee, OpChainSpec};
use reth_primitives::{
revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv},
transaction::FillTxEnv,
Head, Header, TransactionSigned,
};
use reth_revm::{inspector_handle_register, Database, Evm, EvmBuilder, GetInspector};
use std::sync::Arc;
use std::{str::FromStr, sync::Arc};

mod config;
pub use config::{revm_spec, revm_spec_by_timestamp_after_bedrock};
Expand Down Expand Up @@ -160,13 +160,7 @@ impl ConfigureEvmEnv for OptimismEvmConfig {
prevrandao: Some(attributes.prev_randao),
gas_limit: U256::from(parent.gas_limit),
// calculate basefee based on parent block's gas usage
basefee: U256::from(
parent
.next_block_base_fee(
self.chain_spec.base_fee_params_at_timestamp(attributes.timestamp),
)
.unwrap_or_default(),
),
basefee: self.chain_spec.next_block_base_fee(parent, attributes.timestamp),
// calculate excess gas based on parent block's blob gas usage
blob_excess_gas_and_price,
};
Expand Down
4 changes: 4 additions & 0 deletions crates/optimism/hardforks/src/hardfork.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ hardfork!(
Fjord,
/// Granite: <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/superchain-upgrades.md#granite>
Granite,
/// Holocene: <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/superchain-upgrades.md#holocene>
Holocene,
}
);

Expand Down Expand Up @@ -156,6 +158,7 @@ impl OptimismHardfork {
Self::Ecotone => Some(1708534800),
Self::Fjord => Some(1716998400),
Self::Granite => Some(1723478400),
Self::Holocene => None, // TODO: update when Holocene is defined
},
)
}
Expand Down Expand Up @@ -190,6 +193,7 @@ impl OptimismHardfork {
Self::Ecotone => Some(1710374401),
Self::Fjord => Some(1720627201),
Self::Granite => Some(1726070401),
Self::Holocene => None, // TODO: update when Holocene is defined
},
)
}
Expand Down
3 changes: 2 additions & 1 deletion crates/optimism/node/tests/e2e/utils.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::sync::Arc;

use alloy_genesis::Genesis;
use alloy_primitives::{Address, B256};
use alloy_primitives::{Address, B256, B64};
use reth::{rpc::types::engine::PayloadAttributes, tasks::TaskManager};
use reth_chainspec::ChainSpecBuilder;
use reth_e2e_test_utils::{transaction::TransactionTestContext, wallet::Wallet, NodeHelperType};
Expand Down Expand Up @@ -72,5 +72,6 @@ pub(crate) fn optimism_payload_attributes(timestamp: u64) -> OptimismPayloadBuil
transactions: vec![],
no_tx_pool: false,
gas_limit: Some(30_000_000),
eip_1559_params: B64::default(),
}
}
71 changes: 67 additions & 4 deletions crates/optimism/payload/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//! Optimism payload builder implementation.

use std::sync::Arc;
use std::{str::FromStr, sync::Arc};

use alloy_primitives::U256;
use alloy_primitives::{B64, U256};
use reth_basic_payload_builder::*;
use reth_chain_state::ExecutedBlock;
use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
use reth_chainspec::{BaseFeeParams, ChainSpecProvider, EthChainSpec, EthereumHardforks};
use reth_evm::{system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes};
use reth_execution_types::ExecutionOutcome;
use reth_optimism_chainspec::OpChainSpec;
Expand Down Expand Up @@ -485,6 +485,11 @@ where
blob_gas_used = Some(0);
}

let is_holocene = chain_spec.is_fork_active_at_timestamp(
OptimismHardfork::Holocene,
attributes.payload_attributes.timestamp,
);

let header = Header {
parent_hash: parent_block.hash(),
ommers_hash: EMPTY_OMMER_ROOT_HASH,
Expand All @@ -496,7 +501,11 @@ where
logs_bloom,
timestamp: attributes.payload_attributes.timestamp,
mix_hash: attributes.payload_attributes.prev_randao,
nonce: BEACON_NONCE.into(),
nonce: get_nonce(
is_holocene,
&attributes,
chain_spec.base_fee_params_at_timestamp(attributes.payload_attributes.timestamp),
clabby marked this conversation as resolved.
Show resolved Hide resolved
),
base_fee_per_gas: Some(base_fee),
number: parent_block.number + 1,
gas_limit: block_gas_limit,
Expand Down Expand Up @@ -541,3 +550,57 @@ where

Ok(BuildOutcome::Better { payload, cached_reads })
}

fn get_nonce(
is_holocene: bool,
attributes: &OptimismPayloadBuilderAttributes,
default_base_fee_params: BaseFeeParams,
) -> B64 {
if is_holocene {
// If eip 1559 params are set, use them, otherwise use the canyon base fee param constants
if attributes.eip_1559_params != B64::ZERO {
attributes.eip_1559_params
} else {
let mut default_params = [0u8; 8];
default_params[..4].copy_from_slice(
&(default_base_fee_params.max_change_denominator as u32).to_be_bytes(),
);
default_params[4..].copy_from_slice(
&(default_base_fee_params.elasticity_multiplier as u32).to_be_bytes(),
);
B64::from_slice(default_params.as_ref())
}
} else {
BEACON_NONCE.into()
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_get_nonce_pre_holocene() {
let attributes = OptimismPayloadBuilderAttributes::default();
let nonce = get_nonce(false, &attributes, BaseFeeParams::new(80, 60));
assert_eq!(nonce, B64::from(BEACON_NONCE.to_le_bytes()));
}

#[test]
fn test_get_nonce_post_holocene() {
let attributes = OptimismPayloadBuilderAttributes {
eip_1559_params: B64::from_str("0x1234567812345678").unwrap(),
..Default::default()
};
let nonce = get_nonce(true, &attributes, BaseFeeParams::new(80, 60));
assert_eq!(nonce, B64::from_str("0x1234567812345678").unwrap());
}

#[test]
fn test_get_nonce_post_holocene_default() {
let attributes = OptimismPayloadBuilderAttributes::default();
let nonce = get_nonce(true, &attributes, BaseFeeParams::new(80, 60));
let default_params: [u8; 8] = [0, 0, 0, 80, 0, 0, 0, 60];
assert_eq!(nonce, B64::from_slice(&default_params));
}
}
17 changes: 16 additions & 1 deletion crates/optimism/payload/src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! Optimism builder support

use alloy_eips::eip2718::Decodable2718;
use alloy_primitives::{Address, B256, U256};
use alloy_primitives::{Address, B256, B64, U256};
use alloy_rlp::Encodable;
use alloy_rpc_types_engine::{ExecutionPayloadEnvelopeV2, ExecutionPayloadV1, PayloadId};
/// Re-export for use in downstream arguments.
Expand Down Expand Up @@ -37,6 +37,8 @@ pub struct OptimismPayloadBuilderAttributes {
pub transactions: Vec<WithEncoded<TransactionSigned>>,
/// The gas limit for the generated payload
pub gas_limit: Option<u64>,
/// EIP-1559 parameters for the generated payload
pub eip_1559_params: B64,
cody-wang-cb marked this conversation as resolved.
Show resolved Hide resolved
}

impl PayloadBuilderAttributes for OptimismPayloadBuilderAttributes {
Expand Down Expand Up @@ -81,6 +83,7 @@ impl PayloadBuilderAttributes for OptimismPayloadBuilderAttributes {
no_tx_pool: attributes.no_tx_pool.unwrap_or_default(),
transactions,
gas_limit: attributes.gas_limit,
eip_1559_params: attributes.eip_1559_params.unwrap_or_default(),
})
}

Expand Down Expand Up @@ -113,6 +116,18 @@ impl PayloadBuilderAttributes for OptimismPayloadBuilderAttributes {
}
}

impl Default for OptimismPayloadBuilderAttributes {
fn default() -> Self {
Self {
payload_attributes: EthPayloadBuilderAttributes::default(),
no_tx_pool: false,
transactions: Vec::new(),
gas_limit: None,
eip_1559_params: B64::default(),
}
}
}

/// Contains the built payload.
#[derive(Debug, Clone)]
pub struct OptimismBuiltPayload {
Expand Down