diff --git a/Cargo.lock b/Cargo.lock index d20cc86a20c..c0eb7bb610d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3586,7 +3586,6 @@ dependencies = [ "reth-network-peers", "reth-node-builder", "reth-op", - "reth-optimism-flashblocks", "reth-optimism-forks", "reth-payload-builder", "reth-rpc-api", @@ -6123,9 +6122,9 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "op-alloy-consensus" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42e9de945efe3c2fbd207e69720c9c1af2b8caa6872aee0e216450c25a3ca70" +checksum = "a0d7ec388eb83a3e6c71774131dbbb2ba9c199b6acac7dce172ed8de2f819e91" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6149,9 +6148,9 @@ checksum = "a79f352fc3893dcd670172e615afef993a41798a1d3fc0db88a3e60ef2e70ecc" [[package]] name = "op-alloy-network" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9da49a2812a0189dd05e81e4418c3ae13fd607a92654107f02ebad8e91ed9e" +checksum = "979fe768bbb571d1d0bd7f84bc35124243b4db17f944b94698872a4701e743a0" dependencies = [ "alloy-consensus", "alloy-network", @@ -6165,9 +6164,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-jsonrpsee" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ceb771ab9323647093ea2e58dc7f25289a1b95cbef2faa2620f6ca2dee4d9" +checksum = "7bdbb3c0453fe2605fb008851ea0b45f3f2ba607722c9f2e4ffd7198958ce501" dependencies = [ "alloy-primitives", "jsonrpsee", @@ -6175,9 +6174,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd1eb7bddd2232856ba9d259320a094f9edf2b9061acfe5966e7960208393e6" +checksum = "cc252b5fa74dbd33aa2f9a40e5ff9cfe34ed2af9b9b235781bc7cc8ec7d6aca8" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6195,9 +6194,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types-engine" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5429622150d18d8e6847a701135082622413e2451b64d03f979415d764566bef" +checksum = "c1abe694cd6718b8932da3f824f46778be0f43289e4103c88abc505c63533a04" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9420,19 +9419,18 @@ dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rpc-types-engine", - "alloy-serde", "brotli", "derive_more", "eyre", "futures-util", "metrics", + "op-alloy-rpc-types-engine", "reth-chain-state", "reth-engine-primitives", "reth-errors", "reth-evm", "reth-execution-types", "reth-metrics", - "reth-optimism-evm", "reth-optimism-payload-builder", "reth-optimism-primitives", "reth-payload-primitives", @@ -9442,7 +9440,6 @@ dependencies = [ "reth-storage-api", "reth-tasks", "ringbuffer", - "serde", "serde_json", "test-case", "tokio", diff --git a/Cargo.toml b/Cargo.toml index f9cfff6f5bb..e13d01a155b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -523,11 +523,11 @@ alloy-transport-ws = { version = "1.0.41", default-features = false } # op alloy-op-evm = { version = "0.23.0", default-features = false } alloy-op-hardforks = "0.4.4" -op-alloy-rpc-types = { version = "0.22.0", default-features = false } -op-alloy-rpc-types-engine = { version = "0.22.0", default-features = false } -op-alloy-network = { version = "0.22.0", default-features = false } -op-alloy-consensus = { version = "0.22.0", default-features = false } -op-alloy-rpc-jsonrpsee = { version = "0.22.0", default-features = false } +op-alloy-rpc-types = { version = "0.22.1", default-features = false } +op-alloy-rpc-types-engine = { version = "0.22.1", default-features = false } +op-alloy-network = { version = "0.22.1", default-features = false } +op-alloy-consensus = { version = "0.22.1", default-features = false } +op-alloy-rpc-jsonrpsee = { version = "0.22.1", default-features = false } op-alloy-flz = { version = "0.13.1", default-features = false } # misc diff --git a/crates/optimism/evm/src/config.rs b/crates/optimism/evm/src/config.rs index 6ae2a91a6cb..1f1068c40d9 100644 --- a/crates/optimism/evm/src/config.rs +++ b/crates/optimism/evm/src/config.rs @@ -1,6 +1,7 @@ pub use alloy_op_evm::{ spec as revm_spec, spec_by_timestamp_after_bedrock as revm_spec_by_timestamp_after_bedrock, }; +use op_alloy_rpc_types_engine::OpFlashblockPayloadBase; use revm::primitives::{Address, Bytes, B256}; /// Context relevant for execution of a next block w.r.t OP. @@ -35,3 +36,16 @@ impl reth_rpc_eth_api::helpers::pending_block:: } } } + +impl From for OpNextBlockEnvAttributes { + fn from(base: OpFlashblockPayloadBase) -> Self { + Self { + timestamp: base.timestamp, + suggested_fee_recipient: base.fee_recipient, + prev_randao: base.prev_randao, + gas_limit: base.gas_limit, + parent_beacon_block_root: Some(base.parent_beacon_block_root), + extra_data: base.extra_data, + } + } +} diff --git a/crates/optimism/flashblocks/Cargo.toml b/crates/optimism/flashblocks/Cargo.toml index 977e28d37e1..3bb0038a512 100644 --- a/crates/optimism/flashblocks/Cargo.toml +++ b/crates/optimism/flashblocks/Cargo.toml @@ -13,7 +13,6 @@ workspace = true [dependencies] # reth reth-optimism-primitives = { workspace = true, features = ["serde"] } -reth-optimism-evm.workspace = true reth-chain-state = { workspace = true, features = ["serde"] } reth-primitives-traits = { workspace = true, features = ["serde"] } reth-engine-primitives = { workspace = true, features = ["std"] } @@ -30,15 +29,16 @@ reth-metrics.workspace = true # alloy alloy-eips = { workspace = true, features = ["serde"] } -alloy-serde.workspace = true alloy-primitives = { workspace = true, features = ["serde"] } alloy-rpc-types-engine = { workspace = true, features = ["serde"] } alloy-consensus.workspace = true +# op-alloy +op-alloy-rpc-types-engine.workspace = true + # io tokio.workspace = true tokio-tungstenite = { workspace = true, features = ["rustls-tls-native-roots"] } -serde.workspace = true serde_json.workspace = true url.workspace = true futures-util.workspace = true diff --git a/crates/optimism/flashblocks/src/lib.rs b/crates/optimism/flashblocks/src/lib.rs index 7220f443cc1..74f202aed7a 100644 --- a/crates/optimism/flashblocks/src/lib.rs +++ b/crates/optimism/flashblocks/src/lib.rs @@ -11,23 +11,25 @@ use reth_primitives_traits::NodePrimitives; use std::sync::Arc; -pub use payload::{ - ExecutionPayloadBaseV1, ExecutionPayloadFlashblockDeltaV1, FlashBlock, FlashBlockDecoder, - Metadata, -}; -pub use service::{FlashBlockBuildInfo, FlashBlockService}; -pub use ws::{WsConnect, WsFlashBlockStream}; +// Included to enable serde feature for OpReceipt type used transitively +use reth_optimism_primitives as _; mod consensus; pub use consensus::FlashBlockConsensusClient; + mod payload; -pub use payload::PendingFlashBlock; +pub use payload::{FlashBlock, PendingFlashBlock}; + mod sequence; pub use sequence::{FlashBlockCompleteSequence, FlashBlockPendingSequence}; mod service; +pub use service::{FlashBlockBuildInfo, FlashBlockService}; + mod worker; + mod ws; +pub use ws::{WsConnect, WsFlashBlockStream}; /// Receiver of the most recent [`PendingFlashBlock`] built out of [`FlashBlock`]s. /// diff --git a/crates/optimism/flashblocks/src/payload.rs b/crates/optimism/flashblocks/src/payload.rs index 7469538ee3b..c7031c18567 100644 --- a/crates/optimism/flashblocks/src/payload.rs +++ b/crates/optimism/flashblocks/src/payload.rs @@ -1,154 +1,11 @@ use alloy_consensus::BlockHeader; -use alloy_eips::eip4895::Withdrawal; -use alloy_primitives::{bytes, Address, Bloom, Bytes, B256, U256}; -use alloy_rpc_types_engine::PayloadId; +use alloy_primitives::B256; use derive_more::Deref; -use reth_optimism_evm::OpNextBlockEnvAttributes; -use reth_optimism_primitives::OpReceipt; use reth_primitives_traits::NodePrimitives; use reth_rpc_eth_types::PendingBlock; -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; -/// Represents a Flashblock, a real-time block-like structure emitted by the Base L2 chain. -/// -/// A Flashblock provides a snapshot of a block’s effects before finalization, -/// allowing faster insight into state transitions, balance changes, and logs. -/// It includes a diff of the block’s execution and associated metadata. -/// -/// See: [Base Flashblocks Documentation](https://docs.base.org/chain/flashblocks) -#[derive(Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -pub struct FlashBlock { - /// The unique payload ID as assigned by the execution engine for this block. - pub payload_id: PayloadId, - /// A sequential index that identifies the order of this Flashblock. - pub index: u64, - /// A subset of block header fields. - pub base: Option, - /// The execution diff representing state transitions and transactions. - pub diff: ExecutionPayloadFlashblockDeltaV1, - /// Additional metadata about the block such as receipts and balances. - pub metadata: Metadata, -} - -impl FlashBlock { - /// Returns the block number of this flashblock. - pub const fn block_number(&self) -> u64 { - self.metadata.block_number - } - - /// Returns the first parent hash of this flashblock. - pub fn parent_hash(&self) -> Option { - Some(self.base.as_ref()?.parent_hash) - } - - /// Returns the receipt for the given transaction hash. - pub fn receipt_by_hash(&self, hash: &B256) -> Option<&OpReceipt> { - self.metadata.receipt_by_hash(hash) - } -} - -/// A trait for decoding flashblocks from bytes. -pub trait FlashBlockDecoder: Send + 'static { - /// Decodes `bytes` into a [`FlashBlock`]. - fn decode(&self, bytes: bytes::Bytes) -> eyre::Result; -} - -/// Default implementation of the decoder. -impl FlashBlockDecoder for () { - fn decode(&self, bytes: bytes::Bytes) -> eyre::Result { - FlashBlock::decode(bytes) - } -} - -/// Provides metadata about the block that may be useful for indexing or analysis. -// Note: this uses mixed camel, snake case: -#[derive(Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -pub struct Metadata { - /// The number of the block in the L2 chain. - pub block_number: u64, - /// A map of addresses to their updated balances after the block execution. - /// This represents balance changes due to transactions, rewards, or system transfers. - pub new_account_balances: BTreeMap, - /// Execution receipts for all transactions in the block. - /// Contains logs, gas usage, and other EVM-level metadata. - pub receipts: BTreeMap, -} - -impl Metadata { - /// Returns the receipt for the given transaction hash. - pub fn receipt_by_hash(&self, hash: &B256) -> Option<&OpReceipt> { - self.receipts.get(hash) - } -} - -/// Represents the base configuration of an execution payload that remains constant -/// throughout block construction. This includes fundamental block properties like -/// parent hash, block number, and other header fields that are determined at -/// block creation and cannot be modified. -#[derive(Clone, Debug, Eq, PartialEq, Default, Deserialize, Serialize)] -pub struct ExecutionPayloadBaseV1 { - /// Ecotone parent beacon block root - pub parent_beacon_block_root: B256, - /// The parent hash of the block. - pub parent_hash: B256, - /// The fee recipient of the block. - pub fee_recipient: Address, - /// The previous randao of the block. - pub prev_randao: B256, - /// The block number. - #[serde(with = "alloy_serde::quantity")] - pub block_number: u64, - /// The gas limit of the block. - #[serde(with = "alloy_serde::quantity")] - pub gas_limit: u64, - /// The timestamp of the block. - #[serde(with = "alloy_serde::quantity")] - pub timestamp: u64, - /// The extra data of the block. - pub extra_data: Bytes, - /// The base fee per gas of the block. - pub base_fee_per_gas: U256, -} - -/// Represents the modified portions of an execution payload within a flashblock. -/// This structure contains only the fields that can be updated during block construction, -/// such as state root, receipts, logs, and new transactions. Other immutable block fields -/// like parent hash and block number are excluded since they remain constant throughout -/// the block's construction. -#[derive(Clone, Debug, Eq, PartialEq, Default, Deserialize, Serialize)] -pub struct ExecutionPayloadFlashblockDeltaV1 { - /// The state root of the block. - pub state_root: B256, - /// The receipts root of the block. - pub receipts_root: B256, - /// The logs bloom of the block. - pub logs_bloom: Bloom, - /// The gas used of the block. - #[serde(with = "alloy_serde::quantity")] - pub gas_used: u64, - /// The block hash of the block. - pub block_hash: B256, - /// The transactions of the block. - pub transactions: Vec, - /// Array of [`Withdrawal`] enabled with V2 - pub withdrawals: Vec, - /// The withdrawals root of the block. - pub withdrawals_root: B256, -} - -impl From for OpNextBlockEnvAttributes { - fn from(value: ExecutionPayloadBaseV1) -> Self { - Self { - timestamp: value.timestamp, - suggested_fee_recipient: value.fee_recipient, - prev_randao: value.prev_randao, - gas_limit: value.gas_limit, - parent_beacon_block_root: Some(value.parent_beacon_block_root), - extra_data: value.extra_data, - } - } -} +/// Type alias for the Optimism flashblock payload. +pub type FlashBlock = op_alloy_rpc_types_engine::OpFlashblockPayload; /// The pending block built with all received Flashblocks alongside the metadata for the last added /// Flashblock. diff --git a/crates/optimism/flashblocks/src/sequence.rs b/crates/optimism/flashblocks/src/sequence.rs index f2363207e38..25bebc66365 100644 --- a/crates/optimism/flashblocks/src/sequence.rs +++ b/crates/optimism/flashblocks/src/sequence.rs @@ -1,9 +1,10 @@ -use crate::{ExecutionPayloadBaseV1, FlashBlock, FlashBlockCompleteSequenceRx}; +use crate::{FlashBlock, FlashBlockCompleteSequenceRx}; use alloy_eips::eip2718::WithEncoded; -use alloy_primitives::B256; +use alloy_primitives::{Bytes, B256}; use alloy_rpc_types_engine::PayloadId; use core::mem; use eyre::{bail, OptionExt}; +use op_alloy_rpc_types_engine::OpFlashblockPayloadBase; use reth_primitives_traits::{Recovered, SignedTransaction}; use std::{collections::BTreeMap, ops::Deref}; use tokio::sync::broadcast; @@ -92,7 +93,7 @@ where // only insert if we previously received the same block and payload, assume we received // index 0 - let same_block = self.block_number() == Some(flashblock.metadata.block_number); + let same_block = self.block_number() == Some(flashblock.block_number()); let same_payload = self.payload_id() == Some(flashblock.payload_id); if same_block && same_payload { @@ -129,11 +130,11 @@ where /// Returns the first block number pub fn block_number(&self) -> Option { - Some(self.inner.values().next()?.block().metadata.block_number) + Some(self.inner.values().next()?.block().block_number()) } /// Returns the payload base of the first tracked flashblock. - pub fn payload_base(&self) -> Option { + pub fn payload_base(&self) -> Option { self.inner.values().next()?.block().base.clone() } @@ -194,7 +195,7 @@ impl FlashBlockCompleteSequence { if !blocks.iter().enumerate().all(|(idx, block)| { idx == block.index as usize && block.payload_id == first_block.payload_id && - block.metadata.block_number == first_block.metadata.block_number + block.block_number() == first_block.block_number() }) { bail!("Flashblock inconsistencies detected in sequence"); } @@ -204,11 +205,11 @@ impl FlashBlockCompleteSequence { /// Returns the block number pub fn block_number(&self) -> u64 { - self.inner.first().unwrap().metadata.block_number + self.inner.first().unwrap().block_number() } /// Returns the payload base of the first flashblock. - pub fn payload_base(&self) -> &ExecutionPayloadBaseV1 { + pub fn payload_base(&self) -> &OpFlashblockPayloadBase { self.inner.first().unwrap().base.as_ref().unwrap() } @@ -226,6 +227,11 @@ impl FlashBlockCompleteSequence { pub const fn state_root(&self) -> Option { self.state_root } + + /// Returns all transactions from all flashblocks in the sequence + pub fn all_transactions(&self) -> Vec { + self.inner.iter().flat_map(|fb| fb.diff.transactions.iter().cloned()).collect() + } } impl Deref for FlashBlockCompleteSequence { @@ -297,12 +303,14 @@ impl Deref for PreparedFlashBlock { #[cfg(test)] mod tests { use super::*; - use crate::ExecutionPayloadFlashblockDeltaV1; use alloy_consensus::{ transaction::SignerRecoverable, EthereumTxEnvelope, EthereumTypedTransaction, TxEip1559, }; use alloy_eips::Encodable2718; use alloy_primitives::{hex, Signature, TxKind, U256}; + use op_alloy_rpc_types_engine::{ + OpFlashblockPayload, OpFlashblockPayloadBase, OpFlashblockPayloadDelta, + }; #[test] fn test_sequence_stops_before_gap() { @@ -332,11 +340,11 @@ mod tests { let tx = Recovered::new_unchecked(tx.clone(), tx.recover_signer_unchecked().unwrap()); sequence - .insert(FlashBlock { + .insert(OpFlashblockPayload { payload_id: Default::default(), index: 0, base: None, - diff: ExecutionPayloadFlashblockDeltaV1 { + diff: OpFlashblockPayloadDelta { transactions: vec![tx.encoded_2718().into()], ..Default::default() }, @@ -345,7 +353,7 @@ mod tests { .unwrap(); sequence - .insert(FlashBlock { + .insert(OpFlashblockPayload { payload_id: Default::default(), index: 2, base: None, @@ -367,10 +375,10 @@ mod tests { for idx in 0..10 { sequence - .insert(FlashBlock { + .insert(OpFlashblockPayload { payload_id: Default::default(), index: idx, - base: Some(ExecutionPayloadBaseV1::default()), + base: Some(OpFlashblockPayloadBase::default()), diff: Default::default(), metadata: Default::default(), }) @@ -385,10 +393,10 @@ mod tests { // Let's insert a new flashblock with index 0 sequence - .insert(FlashBlock { + .insert(OpFlashblockPayload { payload_id: Default::default(), index: 0, - base: Some(ExecutionPayloadBaseV1::default()), + base: Some(OpFlashblockPayloadBase::default()), diff: Default::default(), metadata: Default::default(), }) diff --git a/crates/optimism/flashblocks/src/service.rs b/crates/optimism/flashblocks/src/service.rs index f5d4a4a810d..8f4dcba9285 100644 --- a/crates/optimism/flashblocks/src/service.rs +++ b/crates/optimism/flashblocks/src/service.rs @@ -1,13 +1,14 @@ use crate::{ sequence::FlashBlockPendingSequence, worker::{BuildArgs, FlashBlockBuilder}, - ExecutionPayloadBaseV1, FlashBlock, FlashBlockCompleteSequence, FlashBlockCompleteSequenceRx, - InProgressFlashBlockRx, PendingFlashBlock, + FlashBlock, FlashBlockCompleteSequence, FlashBlockCompleteSequenceRx, InProgressFlashBlockRx, + PendingFlashBlock, }; use alloy_eips::eip2718::WithEncoded; use alloy_primitives::B256; use futures_util::{FutureExt, Stream, StreamExt}; use metrics::Histogram; +use op_alloy_rpc_types_engine::OpFlashblockPayloadBase; use reth_chain_state::{CanonStateNotification, CanonStateNotifications, CanonStateSubscriptions}; use reth_evm::ConfigureEvm; use reth_metrics::Metrics; @@ -37,7 +38,7 @@ pub(crate) const FB_STATE_ROOT_FROM_INDEX: usize = 9; pub struct FlashBlockService< N: NodePrimitives, S, - EvmConfig: ConfigureEvm, + EvmConfig: ConfigureEvm + Unpin>, Provider, > { rx: S, @@ -67,7 +68,7 @@ impl FlashBlockService where N: NodePrimitives, S: Stream> + Unpin + 'static, - EvmConfig: ConfigureEvm + Unpin> + EvmConfig: ConfigureEvm + Unpin> + Clone + 'static, Provider: StateProviderFactory @@ -228,7 +229,7 @@ impl Stream for FlashBlockService> + Unpin + 'static, - EvmConfig: ConfigureEvm + Unpin> + EvmConfig: ConfigureEvm + Unpin> + Clone + 'static, Provider: StateProviderFactory diff --git a/crates/optimism/flashblocks/src/worker.rs b/crates/optimism/flashblocks/src/worker.rs index 8cf7777f6a6..88dc7729022 100644 --- a/crates/optimism/flashblocks/src/worker.rs +++ b/crates/optimism/flashblocks/src/worker.rs @@ -1,6 +1,7 @@ -use crate::{ExecutionPayloadBaseV1, PendingFlashBlock}; +use crate::PendingFlashBlock; use alloy_eips::{eip2718::WithEncoded, BlockNumberOrTag}; use alloy_primitives::B256; +use op_alloy_rpc_types_engine::OpFlashblockPayloadBase; use reth_chain_state::{CanonStateSubscriptions, ExecutedBlock}; use reth_errors::RethError; use reth_evm::{ @@ -38,7 +39,7 @@ impl FlashBlockBuilder { } pub(crate) struct BuildArgs { - pub(crate) base: ExecutionPayloadBaseV1, + pub(crate) base: OpFlashblockPayloadBase, pub(crate) transactions: I, pub(crate) cached_state: Option<(B256, CachedReads)>, pub(crate) last_flashblock_index: u64, @@ -49,7 +50,7 @@ pub(crate) struct BuildArgs { impl FlashBlockBuilder where N: NodePrimitives, - EvmConfig: ConfigureEvm + Unpin>, + EvmConfig: ConfigureEvm + Unpin>, Provider: StateProviderFactory + CanonStateSubscriptions + BlockReaderIdExt< @@ -60,7 +61,7 @@ where > + Unpin, { /// Returns the [`PendingFlashBlock`] made purely out of transactions and - /// [`ExecutionPayloadBaseV1`] in `args`. + /// [`OpFlashblockPayloadBase`] in `args`. /// /// Returns `None` if the flashblock doesn't attach to the latest header. pub(crate) fn execute>>>( diff --git a/crates/optimism/flashblocks/src/ws/decoding.rs b/crates/optimism/flashblocks/src/ws/decoding.rs index 267f79cf19a..64d96dc5e3e 100644 --- a/crates/optimism/flashblocks/src/ws/decoding.rs +++ b/crates/optimism/flashblocks/src/ws/decoding.rs @@ -1,50 +1,27 @@ -use crate::{ExecutionPayloadBaseV1, ExecutionPayloadFlashblockDeltaV1, FlashBlock, Metadata}; +use crate::FlashBlock; use alloy_primitives::bytes::Bytes; -use alloy_rpc_types_engine::PayloadId; -use serde::{Deserialize, Serialize}; -use std::{fmt::Debug, io}; +use std::io; -/// Internal helper for decoding -#[derive(Clone, Debug, PartialEq, Default, Deserialize, Serialize)] -struct FlashblocksPayloadV1 { - /// The payload id of the flashblock - pub payload_id: PayloadId, - /// The index of the flashblock in the block - pub index: u64, - /// The base execution payload configuration - #[serde(skip_serializing_if = "Option::is_none")] - pub base: Option, - /// The delta/diff containing modified portions of the execution payload - pub diff: ExecutionPayloadFlashblockDeltaV1, - /// Additional metadata associated with the flashblock - pub metadata: serde_json::Value, +/// A trait for decoding flashblocks from bytes. +pub trait FlashBlockDecoder: Send + 'static { + /// Decodes `bytes` into a [`FlashBlock`]. + fn decode(&self, bytes: Bytes) -> eyre::Result; } -impl FlashBlock { - /// Decodes `bytes` into [`FlashBlock`]. - /// - /// This function is specific to the Base Optimism websocket encoding. - /// - /// It is assumed that the `bytes` are encoded in JSON and optionally compressed using brotli. - /// Whether the `bytes` is compressed or not is determined by looking at the first - /// non ascii-whitespace character. - pub(crate) fn decode(bytes: Bytes) -> eyre::Result { - let bytes = try_parse_message(bytes)?; +/// Default implementation of the decoder. +impl FlashBlockDecoder for () { + fn decode(&self, bytes: Bytes) -> eyre::Result { + decode_flashblock(bytes) + } +} - let payload: FlashblocksPayloadV1 = serde_json::from_slice(&bytes) - .map_err(|e| eyre::eyre!("failed to parse message: {e}"))?; +pub(crate) fn decode_flashblock(bytes: Bytes) -> eyre::Result { + let bytes = crate::ws::decoding::try_parse_message(bytes)?; - let metadata: Metadata = serde_json::from_value(payload.metadata) - .map_err(|e| eyre::eyre!("failed to parse message metadata: {e}"))?; + let payload: FlashBlock = + serde_json::from_slice(&bytes).map_err(|e| eyre::eyre!("failed to parse message: {e}"))?; - Ok(Self { - payload_id: payload.payload_id, - index: payload.index, - base: payload.base, - diff: payload.diff, - metadata, - }) - } + Ok(payload) } /// Maps `bytes` into a potentially different [`Bytes`]. diff --git a/crates/optimism/flashblocks/src/ws/mod.rs b/crates/optimism/flashblocks/src/ws/mod.rs index 2b820899312..8c8a5910892 100644 --- a/crates/optimism/flashblocks/src/ws/mod.rs +++ b/crates/optimism/flashblocks/src/ws/mod.rs @@ -1,4 +1,6 @@ pub use stream::{WsConnect, WsFlashBlockStream}; mod decoding; +pub(crate) use decoding::FlashBlockDecoder; + mod stream; diff --git a/crates/optimism/flashblocks/src/ws/stream.rs b/crates/optimism/flashblocks/src/ws/stream.rs index 64cf6f718e2..5d7d9aad437 100644 --- a/crates/optimism/flashblocks/src/ws/stream.rs +++ b/crates/optimism/flashblocks/src/ws/stream.rs @@ -1,4 +1,4 @@ -use crate::{FlashBlock, FlashBlockDecoder}; +use crate::{ws::FlashBlockDecoder, FlashBlock}; use futures_util::{ stream::{SplitSink, SplitStream}, FutureExt, Sink, Stream, StreamExt, @@ -238,7 +238,6 @@ impl WsConnect for WsConnector { #[cfg(test)] mod tests { use super::*; - use crate::ExecutionPayloadBaseV1; use alloy_primitives::bytes::Bytes; use brotli::enc::BrotliEncoderParams; use std::{future, iter}; @@ -449,23 +448,7 @@ mod tests { } fn flashblock() -> FlashBlock { - FlashBlock { - payload_id: Default::default(), - index: 0, - base: Some(ExecutionPayloadBaseV1 { - parent_beacon_block_root: Default::default(), - parent_hash: Default::default(), - fee_recipient: Default::default(), - prev_randao: Default::default(), - block_number: 0, - gas_limit: 0, - timestamp: 0, - extra_data: Default::default(), - base_fee_per_gas: Default::default(), - }), - diff: Default::default(), - metadata: Default::default(), - } + Default::default() } #[test_case::test_case(to_json_message(Message::Binary); "json binary")] diff --git a/crates/optimism/rpc/src/eth/mod.rs b/crates/optimism/rpc/src/eth/mod.rs index 8adbee93adc..fa2da4f44ec 100644 --- a/crates/optimism/rpc/src/eth/mod.rs +++ b/crates/optimism/rpc/src/eth/mod.rs @@ -16,6 +16,7 @@ use alloy_consensus::BlockHeader; use alloy_primitives::{B256, U256}; use eyre::WrapErr; use op_alloy_network::Optimism; +use op_alloy_rpc_types_engine::OpFlashblockPayloadBase; pub use receipt::{OpReceiptBuilder, OpReceiptFieldsBuilder}; use reqwest::Url; use reth_chainspec::{EthereumHardforks, Hardforks}; @@ -23,8 +24,8 @@ use reth_evm::ConfigureEvm; use reth_node_api::{FullNodeComponents, FullNodeTypes, HeaderTy, NodeTypes}; use reth_node_builder::rpc::{EthApiBuilder, EthApiCtx}; use reth_optimism_flashblocks::{ - ExecutionPayloadBaseV1, FlashBlockBuildInfo, FlashBlockCompleteSequenceRx, FlashBlockRx, - FlashBlockService, FlashblocksListeners, PendingBlockRx, PendingFlashBlock, WsFlashBlockStream, + FlashBlockBuildInfo, FlashBlockCompleteSequenceRx, FlashBlockRx, FlashBlockService, + FlashblocksListeners, PendingBlockRx, PendingFlashBlock, WsFlashBlockStream, }; use reth_rpc::eth::core::EthApiInner; use reth_rpc_eth_api::{ @@ -456,7 +457,7 @@ where N: FullNodeComponents< Evm: ConfigureEvm< NextBlockEnvCtx: BuildPendingEnv> - + From + + From + Unpin, >, Types: NodeTypes, diff --git a/examples/custom-node/Cargo.toml b/examples/custom-node/Cargo.toml index 8eb3dbd143b..7fa0020e01d 100644 --- a/examples/custom-node/Cargo.toml +++ b/examples/custom-node/Cargo.toml @@ -11,7 +11,6 @@ reth-codecs.workspace = true reth-network-peers.workspace = true reth-node-builder.workspace = true reth-optimism-forks.workspace = true -reth-optimism-flashblocks.workspace = true reth-db-api.workspace = true reth-op = { workspace = true, features = ["node", "pool", "rpc"] } reth-payload-builder.workspace = true diff --git a/examples/custom-node/src/evm/config.rs b/examples/custom-node/src/evm/config.rs index a7dee31a835..f2bd3326893 100644 --- a/examples/custom-node/src/evm/config.rs +++ b/examples/custom-node/src/evm/config.rs @@ -9,6 +9,7 @@ use alloy_eips::{eip2718::WithEncoded, Decodable2718}; use alloy_evm::EvmEnv; use alloy_op_evm::OpBlockExecutionCtx; use alloy_rpc_types_engine::PayloadError; +use op_alloy_rpc_types_engine::flashblock::OpFlashblockPayloadBase; use op_revm::OpSpecId; use reth_engine_primitives::ExecutableTxIterator; use reth_ethereum::{ @@ -23,7 +24,6 @@ use reth_op::{ node::{OpEvmConfig, OpNextBlockEnvAttributes, OpRethReceiptBuilder}, primitives::SignedTransaction, }; -use reth_optimism_flashblocks::ExecutionPayloadBaseV1; use reth_rpc_api::eth::helpers::pending_block::BuildPendingEnv; use std::sync::Arc; @@ -143,8 +143,8 @@ pub struct CustomNextBlockEnvAttributes { extension: u64, } -impl From for CustomNextBlockEnvAttributes { - fn from(value: ExecutionPayloadBaseV1) -> Self { +impl From for CustomNextBlockEnvAttributes { + fn from(value: OpFlashblockPayloadBase) -> Self { Self { inner: value.into(), extension: 0 } } }