Skip to content
Merged
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
67 changes: 49 additions & 18 deletions crates/op-rbuilder/src/builders/context.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use alloy_consensus::{Eip658Value, Transaction, conditional::BlockConditionalAttributes};
use alloy_eips::Typed2718;
use alloy_eips::{Encodable2718, Typed2718};
use alloy_evm::Database;
use alloy_op_evm::block::receipt_builder::OpReceiptBuilder;
use alloy_primitives::{BlockHash, Bytes, U256};
Expand Down Expand Up @@ -146,12 +146,20 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {

/// Returns the blob fields for the header.
///
/// This will always return `Some(0)` after ecotone.
pub fn blob_fields(&self) -> (Option<u64>, Option<u64>) {
// OP doesn't support blobs/EIP-4844.
// https://specs.optimism.io/protocol/exec-engine.html#ecotone-disable-blob-transactions
// Need [Some] or [None] based on hardfork to match block hash.
if self.is_ecotone_active() {
/// This will return the culmative DA bytes * scalar after Jovian
/// after Ecotone, this will always return Some(0) as blobs aren't supported
/// pre Ecotone, these fields aren't used.
pub fn blob_fields<Extra: Debug + Default>(
&self,
info: &ExecutionInfo<Extra>,
) -> (Option<u64>, Option<u64>) {
if self.is_jovian_active() {
let scalar = info
.da_footprint_scalar
.expect("Scalar must be defined for Jovian blocks");
let result = info.cumulative_da_bytes_used * scalar as u64;
(Some(0), Some(result))
} else if self.is_ecotone_active() {
(Some(0), Some(0))
} else {
(None, None)
Expand All @@ -162,7 +170,15 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
///
/// After holocene this extracts the extradata from the payload
pub fn extra_data(&self) -> Result<Bytes, PayloadBuilderError> {
if self.is_holocene_active() {
if self.is_jovian_active() {
self.attributes()
.get_jovian_extra_data(
self.chain_spec.base_fee_params_at_timestamp(
self.attributes().payload_attributes.timestamp,
),
)
.map_err(PayloadBuilderError::other)
} else if self.is_holocene_active() {
self.attributes()
.get_holocene_extra_data(
self.chain_spec.base_fee_params_at_timestamp(
Expand Down Expand Up @@ -215,6 +231,12 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
.is_isthmus_active_at_timestamp(self.attributes().timestamp())
}

/// Returns true if isthmus is active for the payload.
pub fn is_jovian_active(&self) -> bool {
self.chain_spec
.is_jovian_active_at_timestamp(self.attributes().timestamp())
}

/// Returns the chain id
pub fn chain_id(&self) -> u64 {
self.chain_spec.chain_id()
Expand Down Expand Up @@ -316,13 +338,20 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
let gas_used = result.gas_used();
info.cumulative_gas_used += gas_used;

if !sequencer_tx.is_deposit() {
info.cumulative_da_bytes_used += op_alloy_flz::tx_estimated_size_fjord_bytes(
sequencer_tx.encoded_2718().as_slice(),
);
}

let ctx = ReceiptBuilderCtx {
tx: sequencer_tx.inner(),
evm: &evm,
result,
state: &state,
cumulative_gas_used: info.cumulative_gas_used,
};

info.receipts.push(self.build_receipt(ctx, depositor_nonce));

// commit changes
Expand All @@ -333,6 +362,16 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
info.executed_transactions.push(sequencer_tx.into_inner());
}

let da_footprint_gas_scalar = self
.chain_spec
.is_jovian_active_at_timestamp(self.attributes().timestamp())
.then(|| {
L1BlockInfo::fetch_da_footprint_gas_scalar(evm.db_mut())
.expect("DA footprint should always be available from the database post jovian")
});

info.da_footprint_scalar = da_footprint_gas_scalar;

Ok(info)
}

Expand All @@ -355,6 +394,7 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
let mut num_bundles_reverted = 0;
let mut reverted_gas_used = 0;
let base_fee = self.base_fee();

let tx_da_limit = self.da_config.max_da_tx_size();
let mut evm = self.evm_config.evm_with_env(&mut *db, self.evm_env.clone());

Expand Down Expand Up @@ -422,23 +462,14 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
}
}

let da_footprint_gas_scalar = self
.chain_spec
.is_jovian_active_at_timestamp(self.attributes().timestamp())
.then_some(
L1BlockInfo::fetch_da_footprint_gas_scalar(evm.db_mut()).expect(
"DA footprint should always be available from the database post jovian",
),
);

// ensure we still have capacity for this transaction
if let Err(result) = info.is_tx_over_limits(
tx_da_size,
block_gas_limit,
tx_da_limit,
block_da_limit,
tx.gas_limit(),
da_footprint_gas_scalar,
info.da_footprint_scalar,
) {
// we can't fit this transaction into the block, so we need to mark it as
// invalid which also removes all dependent transaction from
Expand Down
37 changes: 23 additions & 14 deletions crates/op-rbuilder/src/builders/flashblocks/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use either::Either;
use eyre::WrapErr as _;
use reth::payload::PayloadBuilderAttributes;
use reth_basic_payload_builder::BuildOutcome;
use reth_chainspec::EthChainSpec;
use reth_evm::{ConfigureEvm, execute::BlockBuilder};
use reth_node_api::{Block, NodePrimitives, PayloadBuilderError};
use reth_optimism_consensus::{calculate_receipt_root_no_memo_optimism, isthmus};
Expand Down Expand Up @@ -222,6 +223,21 @@ where
) -> eyre::Result<OpPayloadBuilderCtx<FlashblocksExtraCtx>> {
let chain_spec = self.client.chain_spec();
let timestamp = config.attributes.timestamp();

let extra_data = if chain_spec.is_jovian_active_at_timestamp(timestamp) {
config
.attributes
.get_jovian_extra_data(chain_spec.base_fee_params_at_timestamp(timestamp))
.wrap_err("failed to get holocene extra data for flashblocks payload builder")?
} else if chain_spec.is_holocene_active_at_timestamp(timestamp) {
config
.attributes
.get_holocene_extra_data(chain_spec.base_fee_params_at_timestamp(timestamp))
.wrap_err("failed to get holocene extra data for flashblocks payload builder")?
} else {
Default::default()
};

let block_env_attributes = OpNextBlockEnvAttributes {
timestamp,
suggested_fee_recipient: config.attributes.suggested_fee_recipient(),
Expand All @@ -234,18 +250,12 @@ where
.attributes
.payload_attributes
.parent_beacon_block_root,
extra_data: if chain_spec.is_holocene_active_at_timestamp(timestamp) {
config
.attributes
.get_holocene_extra_data(chain_spec.base_fee_params_at_timestamp(timestamp))
.wrap_err("failed to get holocene extra data for flashblocks payload builder")?
} else {
Default::default()
},
extra_data,
};

let evm_env = self
.evm_config
let evm_config = self.evm_config.clone();

let evm_env = evm_config
.next_evm_env(&config.parent_header, &block_env_attributes)
.wrap_err("failed to create next evm env")?;

Expand Down Expand Up @@ -352,6 +362,7 @@ where
// We subtract gas limit and da limit for builder transaction from the whole limit
let builder_tx_gas = builder_txs.iter().fold(0, |acc, tx| acc + tx.gas_used);
let builder_tx_da_size: u64 = builder_txs.iter().fold(0, |acc, tx| acc + tx.da_size);
info.cumulative_da_bytes_used += builder_tx_da_size;
Copy link
Collaborator

Choose a reason for hiding this comment

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

this should be in here as the builder tx isn't necessarily committed yet


let (payload, fb_payload) = build_block(
&mut state,
Expand Down Expand Up @@ -628,6 +639,7 @@ where

let builder_tx_gas = builder_txs.iter().fold(0, |acc, tx| acc + tx.gas_used);
let builder_tx_da_size: u64 = builder_txs.iter().fold(0, |acc, tx| acc + tx.da_size);
info.cumulative_da_bytes_used += builder_tx_da_size;
Copy link
Collaborator

Choose a reason for hiding this comment

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

same here

target_gas_for_batch = target_gas_for_batch.saturating_sub(builder_tx_gas);

// saturating sub just in case, we will log an error if da_limit too small for builder_tx_da_size
Expand Down Expand Up @@ -1032,10 +1044,7 @@ where
// create the block header
let transactions_root = proofs::calculate_transaction_root(&info.executed_transactions);

// OP doesn't support blobs/EIP-4844.
// https://specs.optimism.io/protocol/exec-engine.html#ecotone-disable-blob-transactions
// Need [Some] or [None] based on hardfork to match block hash.
let (excess_blob_gas, blob_gas_used) = ctx.blob_fields();
let (excess_blob_gas, blob_gas_used) = ctx.blob_fields(info);
let extra_data = ctx.extra_data()?;

let header = Header {
Expand Down
3 changes: 1 addition & 2 deletions crates/op-rbuilder/src/builders/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ where
type Job = BlockPayloadJob<Tasks, Builder>;

/// This is invoked when the node receives payload attributes from the beacon node via
/// `engine_forkchoiceUpdatedV1`
/// `engine_forkchoiceUpdatedVX`
fn new_payload_job(
&self,
attributes: <Builder as PayloadBuilder>::Attributes,
Expand Down Expand Up @@ -470,7 +470,6 @@ mod tests {
use alloy_primitives::U256;
use rand::rng;
use reth::tasks::TokioTaskExecutor;
use reth_chain_state::ExecutedBlock;
use reth_node_api::{BuiltPayloadExecutedBlock, NodePrimitives};
use reth_optimism_payload_builder::{OpPayloadPrimitives, payload::OpPayloadBuilderAttributes};
use reth_optimism_primitives::OpPrimitives;
Expand Down
35 changes: 23 additions & 12 deletions crates/op-rbuilder/src/builders/standard/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,21 @@ where

let chain_spec = self.client.chain_spec();
let timestamp = config.attributes.timestamp();

let extra_data = if chain_spec.is_jovian_active_at_timestamp(timestamp) {
config
.attributes
.get_jovian_extra_data(chain_spec.base_fee_params_at_timestamp(timestamp))
.map_err(PayloadBuilderError::other)?
} else if chain_spec.is_holocene_active_at_timestamp(timestamp) {
config
.attributes
.get_holocene_extra_data(chain_spec.base_fee_params_at_timestamp(timestamp))
.map_err(PayloadBuilderError::other)?
} else {
Default::default()
};

let block_env_attributes = OpNextBlockEnvAttributes {
timestamp,
suggested_fee_recipient: config.attributes.suggested_fee_recipient(),
Expand All @@ -213,14 +228,7 @@ where
.attributes
.payload_attributes
.parent_beacon_block_root,
extra_data: if chain_spec.is_holocene_active_at_timestamp(timestamp) {
config
.attributes
.get_holocene_extra_data(chain_spec.base_fee_params_at_timestamp(timestamp))
.map_err(PayloadBuilderError::other)?
} else {
Default::default()
},
extra_data,
};

let evm_env = self
Expand Down Expand Up @@ -358,6 +366,7 @@ impl<Txs: PayloadTxsBounds> OpBuilder<'_, Txs> {
};

let builder_tx_gas = builder_txs.iter().fold(0, |acc, tx| acc + tx.gas_used);

let block_gas_limit = ctx.block_gas_limit().saturating_sub(builder_tx_gas);
if block_gas_limit == 0 {
error!(
Expand All @@ -366,6 +375,7 @@ impl<Txs: PayloadTxsBounds> OpBuilder<'_, Txs> {
}
// Save some space in the block_da_limit for builder tx
let builder_tx_da_size = builder_txs.iter().fold(0, |acc, tx| acc + tx.da_size);
info.cumulative_da_bytes_used += builder_tx_da_size;
Copy link
Collaborator

Choose a reason for hiding this comment

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

this should be in here as the builder tx isn't necessarily committed yet

let block_da_limit = ctx
.da_config
.max_da_block_size()
Expand Down Expand Up @@ -459,6 +469,11 @@ impl<Txs: PayloadTxsBounds> OpBuilder<'_, Txs> {
};

let block_number = ctx.block_number();
// OP doesn't support blobs/EIP-4844.
// https://specs.optimism.io/protocol/exec-engine.html#ecotone-disable-blob-transactions
// Need [Some] or [None] based on hardfork to match block hash.
let (excess_blob_gas, blob_gas_used) = ctx.blob_fields(&info);

let execution_outcome = ExecutionOutcome::new(
db.take_bundle(),
vec![info.receipts],
Expand Down Expand Up @@ -521,10 +536,6 @@ impl<Txs: PayloadTxsBounds> OpBuilder<'_, Txs> {
// create the block header
let transactions_root = proofs::calculate_transaction_root(&info.executed_transactions);

// OP doesn't support blobs/EIP-4844.
// https://specs.optimism.io/protocol/exec-engine.html#ecotone-disable-blob-transactions
// Need [Some] or [None] based on hardfork to match block hash.
let (excess_blob_gas, blob_gas_used) = ctx.blob_fields();
let extra_data = ctx.extra_data()?;

let header = Header {
Expand Down
3 changes: 3 additions & 0 deletions crates/op-rbuilder/src/primitives/reth/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ pub struct ExecutionInfo<Extra: Debug + Default = ()> {
pub total_fees: U256,
/// Extra execution information that can be attached by individual builders.
pub extra: Extra,
/// DA Footprint Scalar for Jovian
pub da_footprint_scalar: Option<u16>,
}

impl<T: Debug + Default> ExecutionInfo<T> {
Expand All @@ -53,6 +55,7 @@ impl<T: Debug + Default> ExecutionInfo<T> {
cumulative_da_bytes_used: 0,
total_fees: U256::ZERO,
extra: Default::default(),
da_footprint_scalar: None,
}
}

Expand Down
3 changes: 2 additions & 1 deletion crates/op-rbuilder/src/tests/data_availability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ async fn block_fill(rbuilder: LocalInstance) -> eyre::Result<()> {
let driver = rbuilder.driver().await?;

// Set block big enough so it could fit 3 transactions without tx size limit
// Deposit transactions also count towards DA and there is one deposit txn in this block too
let call = driver
.provider()
.raw_request::<(i32, i32), bool>("miner_setMaxDASize".into(), (0, 100 * 3))
.raw_request::<(i32, i32), bool>("miner_setMaxDASize".into(), (0, 100 * 4))
.await?;
assert!(call, "miner_setMaxDASize should be executed successfully");

Expand Down
Loading
Loading