Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1,699 changes: 909 additions & 790 deletions Cargo.lock

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,15 @@ alloy-hardforks = "0.4.7"
alloy-op-evm = { version = "0.26.3", default-features = false }
alloy-op-hardforks = "0.4.7"
op-alloy-rpc-types = { version = "0.23.1", default-features = false }
op-alloy-rpc-types-engine = { version = "0.23.1", default-features = false, features = ["serde"] }
# here
op-alloy-rpc-types-engine = { version = "0.23.2", default-features = false, features = ["serde"] }
op-alloy-rpc-jsonrpsee = { version = "0.23.1", default-features = false }
op-alloy-network = { version = "0.23.1", default-features = false }
op-alloy-consensus = { version = "0.23.1", default-features = false }
op-alloy-flz = { version = "0.13.1", default-features = false }

base-access-lists = { git = "https://github.com/base/base.git", rev = "264ae1ca69ed19d938c4207a0a3a8940ab4abd3f" }

async-trait = { version = "0.1.83" }
clap = { version = "4.4.3", features = ["derive", "env", "string"] }
clap_builder = { version = "4.5.19" }
Expand Down Expand Up @@ -211,3 +214,7 @@ time = { version = "0.3.36", features = ["macros", "formatting", "parsing"] }
vergen = "9.0.4"
vergen-git2 = "9.0.4"
opentelemetry = { version = "0.31", features = ["trace"] }

[patch.crates-io]
op-alloy-rpc-types-engine = { git = "https://github.com/ethereum-optimism/optimism", branch = "joshklop/fbals" }
op-alloy-consensus = { git = "https://github.com/ethereum-optimism/optimism", branch = "joshklop/fbals" }
2 changes: 2 additions & 0 deletions crates/op-rbuilder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ op-alloy-flz.workspace = true
revm.workspace = true
op-revm.workspace = true

base-access-lists.workspace = true

tracing.workspace = true
eyre.workspace = true
serde_with.workspace = true
Expand Down
30 changes: 28 additions & 2 deletions crates/op-rbuilder/src/builder/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use alloy_evm::Database;
use alloy_op_evm::block::receipt_builder::OpReceiptBuilder;
use alloy_primitives::{B256, BlockHash, Bytes, U256};
use alloy_rpc_types_eth::Withdrawals;
use base_access_lists::FBALBuilderDb;
use op_alloy_consensus::OpDepositReceipt;
use op_revm::{OpSpecId, OpTransactionError};
use reth::payload::PayloadBuilderAttributes;
Expand Down Expand Up @@ -38,7 +39,11 @@ use revm::{
context::result::{InvalidTransaction, ResultAndState},
interpreter::as_u64_saturated,
};
use std::{sync::Arc, time::Instant};
use std::{
cmp::{max, min},
sync::Arc,
time::Instant,
};
use tokio_util::sync::CancellationToken;
use tracing::{debug, info, trace};

Expand Down Expand Up @@ -280,9 +285,22 @@ impl OpPayloadBuilderCtx {
) -> Result<ExecutionInfo, PayloadBuilderError> {
let mut info = ExecutionInfo::with_capacity(self.attributes().transactions.len());

let mut evm = self.evm_config.evm_with_env(&mut *db, self.evm_env.clone());
let mut fbal_db = FBALBuilderDb::new(&mut *db);
let min_tx_index = info.executed_transactions.iter().len() as u64;
fbal_db.set_index(min_tx_index);
let mut evm = self
.evm_config
.evm_with_env(&mut fbal_db, self.evm_env.clone());

let mut min_tx_index = u64::MAX;
let mut max_tx_index = u64::MIN;
let mut i: u64 = 0;
for sequencer_tx in &self.attributes().transactions {
evm.db_mut().set_index(i);
min_tx_index = min(min_tx_index, i);
max_tx_index = max(max_tx_index, i);
i += 1;

// A sequencer's block should never contain blob transactions.
if sequencer_tx.value().is_eip4844() {
return Err(PayloadBuilderError::other(
Expand All @@ -309,6 +327,7 @@ impl OpPayloadBuilderCtx {
let depositor_nonce = (self.is_regolith_active() && sequencer_tx.is_deposit())
.then(|| {
evm.db_mut()
.db_mut()
.load_cache_account(sequencer_tx.signer())
.map(|acc| acc.account_info().unwrap_or_default().nonce)
})
Expand Down Expand Up @@ -369,6 +388,13 @@ impl OpPayloadBuilderCtx {

info.da_footprint_scalar = da_footprint_gas_scalar;

match fbal_db.finish() {
Ok(fbal_builder) => {
info.access_lists = Some(fbal_builder.build(min_tx_index, max_tx_index))
}
Err(err) => return Err(PayloadBuilderError::Other(Box::new(err))),
}

Ok(info)
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/op-rbuilder/src/builder/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,7 @@ where
receipts: receipts_with_hash,
new_account_balances,
block_number: ctx.parent().number + 1,
access_lists: info.access_lists.clone(),
};

let (_, blob_gas_used) = ctx.blob_fields(info);
Expand Down
23 changes: 20 additions & 3 deletions crates/op-rbuilder/src/builder/payload_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,15 @@ use reth_optimism_payload_builder::OpBuiltPayload;
use reth_optimism_primitives::{OpReceipt, OpTransactionSigned};
use reth_payload_builder::EthPayloadBuilderAttributes;
use reth_primitives_traits::SealedHeader;
use std::sync::Arc;
use std::{
cmp::{max, min},
sync::Arc,
};
use tokio::sync::mpsc;
use tracing::warn;

use base_access_lists::FBALBuilderDb;

/// Handles newly built or received flashblock payloads.
///
/// In the case of a payload built by this node, it is broadcast to peers and an event is sent to the payload builder.
Expand Down Expand Up @@ -326,9 +331,17 @@ fn execute_transactions(
use reth_primitives_traits::SignedTransaction;
use revm::{DatabaseCommit as _, context::result::ResultAndState};

let mut evm = ctx.evm_config().evm_with_env(&mut *state, evm_env);
let mut fbal_db = FBALBuilderDb::new(state);
let mut evm = ctx.evm_config().evm_with_env(&mut fbal_db, evm_env);

let mut min_tx_index = u64::MAX;
let mut max_tx_index = u64::MIN;
for (i, tx) in txs.into_iter().enumerate() {
let j: u64 = i.try_into().unwrap();
evm.db_mut().set_index(j);
min_tx_index = min(min_tx_index, j);
max_tx_index = max(max_tx_index, j);

for tx in txs {
// Convert to recovered transaction
let tx_recovered = tx
.try_clone_into_recovered()
Expand All @@ -343,6 +356,7 @@ fn execute_transactions(
let depositor_nonce = (ctx.is_regolith_active(timestamp) && tx_recovered.is_deposit())
.then(|| {
evm.db_mut()
.db_mut()
.load_cache_account(sender)
.map(|acc| acc.account_info().unwrap_or_default().nonce)
})
Expand Down Expand Up @@ -399,6 +413,9 @@ fn execute_transactions(
});
info.da_footprint_scalar = da_footprint_gas_scalar;

let fbal_builder = fbal_db.finish()?;
info.access_lists = Some(fbal_builder.build(min_tx_index, max_tx_index));

Ok(())
}

Expand Down
4 changes: 4 additions & 0 deletions crates/op-rbuilder/src/primitives/reth/execution.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Heavily influenced by [reth](https://github.com/paradigmxyz/reth/blob/1e965caf5fa176f244a31c0d2662ba1b590938db/crates/optimism/payload/src/builder.rs#L570)
use alloy_primitives::{Address, U256};
use base_access_lists::FlashblockAccessList;
use core::fmt::Debug;
use derive_more::Display;
use op_revm::OpTransactionError;
Expand Down Expand Up @@ -45,6 +46,8 @@ pub struct ExecutionInfo {
pub da_footprint_scalar: Option<u16>,
/// Optional blob fields for payload validation
pub optional_blob_fields: Option<(Option<u64>, Option<u64>)>,
/// Optional access list
pub access_lists: Option<FlashblockAccessList>,
}

impl ExecutionInfo {
Expand All @@ -59,6 +62,7 @@ impl ExecutionInfo {
total_fees: U256::ZERO,
da_footprint_scalar: None,
optional_blob_fields: None,
access_lists: None,
}
}

Expand Down
23 changes: 23 additions & 0 deletions patches/add-access-lists-to-flashblock-metadata.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--- a/src/flashblock/metadata.rs
+++ b/src/flashblock/metadata.rs
@@ -2,6 +2,7 @@

use alloc::collections::BTreeMap;
use alloy_primitives::{Address, B256, U256};
+use base_access_lists::FlashblockAccessList;
use op_alloy_consensus::OpReceipt;

/// Provides metadata about the block that may be useful for indexing or analysis.
@@ -18,6 +19,12 @@
/// Contains logs, gas usage, and other EVM-level metadata.
#[cfg_attr(feature = "serde", serde(deserialize_with = "deserialize_flashblock_receipts"))]
pub receipts: BTreeMap<B256, OpReceipt>,
+ /// Optional access lists for the flashblock, tracking state access information.
+ // TODO: Remove this vendored crate once upstream op-alloy-rpc-types-engine natively includes
+ // the `access_lists` field in `OpFlashblockPayloadMetadata`.
+ #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
+ #[cfg_attr(feature = "serde", serde(default))]
+ pub access_lists: Option<FlashblockAccessList>,
}

#[cfg(feature = "serde")]