Skip to content

Commit e335539

Browse files
authored
fix: jovian hardfork tests & fixes (#320)
* chore: fixes for jovian * blob fee fixes * Update tests to Jovian * run miner limit tests on both standard/flashblocks * Ensure builder transactions count towards DA usage * Increment DA usage for non-deposit sequencer transactions (e.g. via CL sync)
1 parent e95a48f commit e335539

13 files changed

Lines changed: 326 additions & 78 deletions

File tree

crates/op-rbuilder/src/builders/context.rs

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use alloy_consensus::{Eip658Value, Transaction, conditional::BlockConditionalAttributes};
2-
use alloy_eips::Typed2718;
2+
use alloy_eips::{Encodable2718, Typed2718};
33
use alloy_evm::Database;
44
use alloy_op_evm::block::receipt_builder::OpReceiptBuilder;
55
use alloy_primitives::{BlockHash, Bytes, U256};
@@ -146,12 +146,20 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
146146

147147
/// Returns the blob fields for the header.
148148
///
149-
/// This will always return `Some(0)` after ecotone.
150-
pub fn blob_fields(&self) -> (Option<u64>, Option<u64>) {
151-
// OP doesn't support blobs/EIP-4844.
152-
// https://specs.optimism.io/protocol/exec-engine.html#ecotone-disable-blob-transactions
153-
// Need [Some] or [None] based on hardfork to match block hash.
154-
if self.is_ecotone_active() {
149+
/// This will return the culmative DA bytes * scalar after Jovian
150+
/// after Ecotone, this will always return Some(0) as blobs aren't supported
151+
/// pre Ecotone, these fields aren't used.
152+
pub fn blob_fields<Extra: Debug + Default>(
153+
&self,
154+
info: &ExecutionInfo<Extra>,
155+
) -> (Option<u64>, Option<u64>) {
156+
if self.is_jovian_active() {
157+
let scalar = info
158+
.da_footprint_scalar
159+
.expect("Scalar must be defined for Jovian blocks");
160+
let result = info.cumulative_da_bytes_used * scalar as u64;
161+
(Some(0), Some(result))
162+
} else if self.is_ecotone_active() {
155163
(Some(0), Some(0))
156164
} else {
157165
(None, None)
@@ -162,7 +170,15 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
162170
///
163171
/// After holocene this extracts the extradata from the payload
164172
pub fn extra_data(&self) -> Result<Bytes, PayloadBuilderError> {
165-
if self.is_holocene_active() {
173+
if self.is_jovian_active() {
174+
self.attributes()
175+
.get_jovian_extra_data(
176+
self.chain_spec.base_fee_params_at_timestamp(
177+
self.attributes().payload_attributes.timestamp,
178+
),
179+
)
180+
.map_err(PayloadBuilderError::other)
181+
} else if self.is_holocene_active() {
166182
self.attributes()
167183
.get_holocene_extra_data(
168184
self.chain_spec.base_fee_params_at_timestamp(
@@ -215,6 +231,12 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
215231
.is_isthmus_active_at_timestamp(self.attributes().timestamp())
216232
}
217233

234+
/// Returns true if isthmus is active for the payload.
235+
pub fn is_jovian_active(&self) -> bool {
236+
self.chain_spec
237+
.is_jovian_active_at_timestamp(self.attributes().timestamp())
238+
}
239+
218240
/// Returns the chain id
219241
pub fn chain_id(&self) -> u64 {
220242
self.chain_spec.chain_id()
@@ -316,13 +338,20 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
316338
let gas_used = result.gas_used();
317339
info.cumulative_gas_used += gas_used;
318340

341+
if !sequencer_tx.is_deposit() {
342+
info.cumulative_da_bytes_used += op_alloy_flz::tx_estimated_size_fjord_bytes(
343+
sequencer_tx.encoded_2718().as_slice(),
344+
);
345+
}
346+
319347
let ctx = ReceiptBuilderCtx {
320348
tx: sequencer_tx.inner(),
321349
evm: &evm,
322350
result,
323351
state: &state,
324352
cumulative_gas_used: info.cumulative_gas_used,
325353
};
354+
326355
info.receipts.push(self.build_receipt(ctx, depositor_nonce));
327356

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

365+
let da_footprint_gas_scalar = self
366+
.chain_spec
367+
.is_jovian_active_at_timestamp(self.attributes().timestamp())
368+
.then(|| {
369+
L1BlockInfo::fetch_da_footprint_gas_scalar(evm.db_mut())
370+
.expect("DA footprint should always be available from the database post jovian")
371+
});
372+
373+
info.da_footprint_scalar = da_footprint_gas_scalar;
374+
336375
Ok(info)
337376
}
338377

@@ -355,6 +394,7 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
355394
let mut num_bundles_reverted = 0;
356395
let mut reverted_gas_used = 0;
357396
let base_fee = self.base_fee();
397+
358398
let tx_da_limit = self.da_config.max_da_tx_size();
359399
let mut evm = self.evm_config.evm_with_env(&mut *db, self.evm_env.clone());
360400

@@ -422,23 +462,14 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
422462
}
423463
}
424464

425-
let da_footprint_gas_scalar = self
426-
.chain_spec
427-
.is_jovian_active_at_timestamp(self.attributes().timestamp())
428-
.then_some(
429-
L1BlockInfo::fetch_da_footprint_gas_scalar(evm.db_mut()).expect(
430-
"DA footprint should always be available from the database post jovian",
431-
),
432-
);
433-
434465
// ensure we still have capacity for this transaction
435466
if let Err(result) = info.is_tx_over_limits(
436467
tx_da_size,
437468
block_gas_limit,
438469
tx_da_limit,
439470
block_da_limit,
440471
tx.gas_limit(),
441-
da_footprint_gas_scalar,
472+
info.da_footprint_scalar,
442473
) {
443474
// we can't fit this transaction into the block, so we need to mark it as
444475
// invalid which also removes all dependent transaction from

crates/op-rbuilder/src/builders/flashblocks/payload.rs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use either::Either;
2222
use eyre::WrapErr as _;
2323
use reth::payload::PayloadBuilderAttributes;
2424
use reth_basic_payload_builder::BuildOutcome;
25+
use reth_chainspec::EthChainSpec;
2526
use reth_evm::{ConfigureEvm, execute::BlockBuilder};
2627
use reth_node_api::{Block, NodePrimitives, PayloadBuilderError};
2728
use reth_optimism_consensus::{calculate_receipt_root_no_memo_optimism, isthmus};
@@ -222,6 +223,21 @@ where
222223
) -> eyre::Result<OpPayloadBuilderCtx<FlashblocksExtraCtx>> {
223224
let chain_spec = self.client.chain_spec();
224225
let timestamp = config.attributes.timestamp();
226+
227+
let extra_data = if chain_spec.is_jovian_active_at_timestamp(timestamp) {
228+
config
229+
.attributes
230+
.get_jovian_extra_data(chain_spec.base_fee_params_at_timestamp(timestamp))
231+
.wrap_err("failed to get holocene extra data for flashblocks payload builder")?
232+
} else if chain_spec.is_holocene_active_at_timestamp(timestamp) {
233+
config
234+
.attributes
235+
.get_holocene_extra_data(chain_spec.base_fee_params_at_timestamp(timestamp))
236+
.wrap_err("failed to get holocene extra data for flashblocks payload builder")?
237+
} else {
238+
Default::default()
239+
};
240+
225241
let block_env_attributes = OpNextBlockEnvAttributes {
226242
timestamp,
227243
suggested_fee_recipient: config.attributes.suggested_fee_recipient(),
@@ -234,18 +250,12 @@ where
234250
.attributes
235251
.payload_attributes
236252
.parent_beacon_block_root,
237-
extra_data: if chain_spec.is_holocene_active_at_timestamp(timestamp) {
238-
config
239-
.attributes
240-
.get_holocene_extra_data(chain_spec.base_fee_params_at_timestamp(timestamp))
241-
.wrap_err("failed to get holocene extra data for flashblocks payload builder")?
242-
} else {
243-
Default::default()
244-
},
253+
extra_data,
245254
};
246255

247-
let evm_env = self
248-
.evm_config
256+
let evm_config = self.evm_config.clone();
257+
258+
let evm_env = evm_config
249259
.next_evm_env(&config.parent_header, &block_env_attributes)
250260
.wrap_err("failed to create next evm env")?;
251261

@@ -352,6 +362,7 @@ where
352362
// We subtract gas limit and da limit for builder transaction from the whole limit
353363
let builder_tx_gas = builder_txs.iter().fold(0, |acc, tx| acc + tx.gas_used);
354364
let builder_tx_da_size: u64 = builder_txs.iter().fold(0, |acc, tx| acc + tx.da_size);
365+
info.cumulative_da_bytes_used += builder_tx_da_size;
355366

356367
let (payload, fb_payload) = build_block(
357368
&mut state,
@@ -628,6 +639,7 @@ where
628639

629640
let builder_tx_gas = builder_txs.iter().fold(0, |acc, tx| acc + tx.gas_used);
630641
let builder_tx_da_size: u64 = builder_txs.iter().fold(0, |acc, tx| acc + tx.da_size);
642+
info.cumulative_da_bytes_used += builder_tx_da_size;
631643
target_gas_for_batch = target_gas_for_batch.saturating_sub(builder_tx_gas);
632644

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

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

10411050
let header = Header {

crates/op-rbuilder/src/builders/generator.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ where
134134
type Job = BlockPayloadJob<Tasks, Builder>;
135135

136136
/// This is invoked when the node receives payload attributes from the beacon node via
137-
/// `engine_forkchoiceUpdatedV1`
137+
/// `engine_forkchoiceUpdatedVX`
138138
fn new_payload_job(
139139
&self,
140140
attributes: <Builder as PayloadBuilder>::Attributes,
@@ -470,7 +470,6 @@ mod tests {
470470
use alloy_primitives::U256;
471471
use rand::rng;
472472
use reth::tasks::TokioTaskExecutor;
473-
use reth_chain_state::ExecutedBlock;
474473
use reth_node_api::{BuiltPayloadExecutedBlock, NodePrimitives};
475474
use reth_optimism_payload_builder::{OpPayloadPrimitives, payload::OpPayloadBuilderAttributes};
476475
use reth_optimism_primitives::OpPrimitives;

crates/op-rbuilder/src/builders/standard/payload.rs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,21 @@ where
201201

202202
let chain_spec = self.client.chain_spec();
203203
let timestamp = config.attributes.timestamp();
204+
205+
let extra_data = if chain_spec.is_jovian_active_at_timestamp(timestamp) {
206+
config
207+
.attributes
208+
.get_jovian_extra_data(chain_spec.base_fee_params_at_timestamp(timestamp))
209+
.map_err(PayloadBuilderError::other)?
210+
} else if chain_spec.is_holocene_active_at_timestamp(timestamp) {
211+
config
212+
.attributes
213+
.get_holocene_extra_data(chain_spec.base_fee_params_at_timestamp(timestamp))
214+
.map_err(PayloadBuilderError::other)?
215+
} else {
216+
Default::default()
217+
};
218+
204219
let block_env_attributes = OpNextBlockEnvAttributes {
205220
timestamp,
206221
suggested_fee_recipient: config.attributes.suggested_fee_recipient(),
@@ -213,14 +228,7 @@ where
213228
.attributes
214229
.payload_attributes
215230
.parent_beacon_block_root,
216-
extra_data: if chain_spec.is_holocene_active_at_timestamp(timestamp) {
217-
config
218-
.attributes
219-
.get_holocene_extra_data(chain_spec.base_fee_params_at_timestamp(timestamp))
220-
.map_err(PayloadBuilderError::other)?
221-
} else {
222-
Default::default()
223-
},
231+
extra_data,
224232
};
225233

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

360368
let builder_tx_gas = builder_txs.iter().fold(0, |acc, tx| acc + tx.gas_used);
369+
361370
let block_gas_limit = ctx.block_gas_limit().saturating_sub(builder_tx_gas);
362371
if block_gas_limit == 0 {
363372
error!(
@@ -366,6 +375,7 @@ impl<Txs: PayloadTxsBounds> OpBuilder<'_, Txs> {
366375
}
367376
// Save some space in the block_da_limit for builder tx
368377
let builder_tx_da_size = builder_txs.iter().fold(0, |acc, tx| acc + tx.da_size);
378+
info.cumulative_da_bytes_used += builder_tx_da_size;
369379
let block_da_limit = ctx
370380
.da_config
371381
.max_da_block_size()
@@ -459,6 +469,11 @@ impl<Txs: PayloadTxsBounds> OpBuilder<'_, Txs> {
459469
};
460470

461471
let block_number = ctx.block_number();
472+
// OP doesn't support blobs/EIP-4844.
473+
// https://specs.optimism.io/protocol/exec-engine.html#ecotone-disable-blob-transactions
474+
// Need [Some] or [None] based on hardfork to match block hash.
475+
let (excess_blob_gas, blob_gas_used) = ctx.blob_fields(&info);
476+
462477
let execution_outcome = ExecutionOutcome::new(
463478
db.take_bundle(),
464479
vec![info.receipts],
@@ -521,10 +536,6 @@ impl<Txs: PayloadTxsBounds> OpBuilder<'_, Txs> {
521536
// create the block header
522537
let transactions_root = proofs::calculate_transaction_root(&info.executed_transactions);
523538

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

530541
let header = Header {

crates/op-rbuilder/src/primitives/reth/execution.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ pub struct ExecutionInfo<Extra: Debug + Default = ()> {
4040
pub total_fees: U256,
4141
/// Extra execution information that can be attached by individual builders.
4242
pub extra: Extra,
43+
/// DA Footprint Scalar for Jovian
44+
pub da_footprint_scalar: Option<u16>,
4345
}
4446

4547
impl<T: Debug + Default> ExecutionInfo<T> {
@@ -53,6 +55,7 @@ impl<T: Debug + Default> ExecutionInfo<T> {
5355
cumulative_da_bytes_used: 0,
5456
total_fees: U256::ZERO,
5557
extra: Default::default(),
58+
da_footprint_scalar: None,
5659
}
5760
}
5861

crates/op-rbuilder/src/tests/data_availability.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,10 @@ async fn block_fill(rbuilder: LocalInstance) -> eyre::Result<()> {
6464
let driver = rbuilder.driver().await?;
6565

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

0 commit comments

Comments
 (0)