Skip to content

Commit c678f28

Browse files
authored
Add cumulative da of builder tx da size (#322)
* Fix builder tx cumulative da * fix builder gas and da calculation * add test
1 parent c119be1 commit c678f28

6 files changed

Lines changed: 189 additions & 49 deletions

File tree

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ pub trait BuilderTransactions<ExtraCtx: Debug + Default = (), Extra: Debug + Def
235235
// Add gas used by the transaction to cumulative gas used, before creating the receipt
236236
let gas_used = result.gas_used();
237237
info.cumulative_gas_used += gas_used;
238+
info.cumulative_da_bytes_used += builder_tx.da_size;
238239

239240
let ctx = ReceiptBuilderCtx {
240241
tx: builder_tx.signed_tx.inner(),

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
385385
best_txs: &mut impl PayloadTxsBounds,
386386
block_gas_limit: u64,
387387
block_da_limit: Option<u64>,
388+
block_da_footprint_limit: Option<u64>,
388389
) -> Result<Option<()>, PayloadBuilderError> {
389390
let execute_txs_start_time = Instant::now();
390391
let mut num_txs_considered = 0;
@@ -470,6 +471,7 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
470471
block_da_limit,
471472
tx.gas_limit(),
472473
info.da_footprint_scalar,
474+
block_da_footprint_limit,
473475
) {
474476
// we can't fit this transaction into the block, so we need to mark it as
475477
// invalid which also removes all dependent transaction from

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

Lines changed: 62 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -85,20 +85,30 @@ pub struct FlashblocksExtraCtx {
8585
target_gas_for_batch: u64,
8686
/// Total DA bytes left for the current flashblock
8787
target_da_for_batch: Option<u64>,
88+
/// Total DA footprint left for the current flashblock
89+
target_da_footprint_for_batch: Option<u64>,
8890
/// Gas limit per flashblock
8991
gas_per_batch: u64,
9092
/// DA bytes limit per flashblock
9193
da_per_batch: Option<u64>,
94+
/// DA footprint limit per flashblock
95+
da_footprint_per_batch: Option<u64>,
9296
/// Whether to disable state root calculation for each flashblock
9397
disable_state_root: bool,
9498
}
9599

96100
impl FlashblocksExtraCtx {
97-
fn next(self, target_gas_for_batch: u64, target_da_for_batch: Option<u64>) -> Self {
101+
fn next(
102+
self,
103+
target_gas_for_batch: u64,
104+
target_da_for_batch: Option<u64>,
105+
target_da_footprint_for_batch: Option<u64>,
106+
) -> Self {
98107
Self {
99108
flashblock_index: self.flashblock_index + 1,
100109
target_gas_for_batch,
101110
target_da_for_batch,
111+
target_da_footprint_for_batch,
102112
..self
103113
}
104114
}
@@ -344,29 +354,18 @@ where
344354
ctx.metrics.sequencer_tx_gauge.set(sequencer_tx_time);
345355

346356
// We add first builder tx right after deposits
347-
let builder_txs = if ctx.attributes().no_tx_pool {
348-
vec![]
349-
} else {
350-
match self.builder_tx.add_builder_txs(
351-
&state_provider,
352-
&mut info,
353-
&ctx,
354-
&mut state,
355-
false,
356-
) {
357-
Ok(builder_txs) => builder_txs,
358-
Err(e) => {
359-
error!(target: "payload_builder", "Error adding builder txs to fallback block: {}", e);
360-
vec![]
361-
}
362-
}
357+
if !ctx.attributes().no_tx_pool
358+
&& let Err(e) =
359+
self.builder_tx
360+
.add_builder_txs(&state_provider, &mut info, &ctx, &mut state, false)
361+
{
362+
error!(
363+
target: "payload_builder",
364+
"Error adding builder txs to fallback block: {}",
365+
e
366+
);
363367
};
364368

365-
// We subtract gas limit and da limit for builder transaction from the whole limit
366-
let builder_tx_gas = builder_txs.iter().fold(0, |acc, tx| acc + tx.gas_used);
367-
let builder_tx_da_size: u64 = builder_txs.iter().fold(0, |acc, tx| acc + tx.da_size);
368-
info.cumulative_da_bytes_used += builder_tx_da_size;
369-
370369
let (payload, fb_payload) = build_block(
371370
&mut state,
372371
&ctx,
@@ -439,34 +438,33 @@ where
439438
.first_flashblock_time_offset
440439
.record(first_flashblock_offset.as_millis() as f64);
441440
let gas_per_batch = ctx.block_gas_limit() / flashblocks_per_block;
442-
let target_gas_for_batch = gas_per_batch;
443441
let da_per_batch = ctx
444442
.da_config
445443
.max_da_block_size()
446444
.map(|da_limit| da_limit / flashblocks_per_block);
447445
// Check that builder tx won't affect fb limit too much
448446
if let Some(da_limit) = da_per_batch {
449447
// We error if we can't insert any tx aside from builder tx in flashblock
450-
if da_limit / 2 < builder_tx_da_size {
448+
if info.cumulative_da_bytes_used >= da_limit {
451449
error!(
452450
"Builder tx da size subtraction caused max_da_block_size to be 0. No transaction would be included."
453451
);
454452
}
455453
}
456-
let mut target_da_for_batch = da_per_batch;
454+
let da_footprint_per_batch = info
455+
.da_footprint_scalar
456+
.map(|_| ctx.block_gas_limit() / flashblocks_per_block);
457457

458-
// Account for already included builder tx
459-
if let Some(da_limit) = target_da_for_batch.as_mut() {
460-
*da_limit = da_limit.saturating_sub(builder_tx_da_size);
461-
}
462458
let extra_ctx = FlashblocksExtraCtx {
463459
flashblock_index: 1,
464460
target_flashblock_count: flashblocks_per_block,
465-
target_gas_for_batch: target_gas_for_batch.saturating_sub(builder_tx_gas),
466-
target_da_for_batch,
461+
target_gas_for_batch: gas_per_batch,
462+
target_da_for_batch: da_per_batch,
467463
gas_per_batch,
468464
da_per_batch,
465+
da_footprint_per_batch,
469466
disable_state_root,
467+
target_da_footprint_for_batch: da_footprint_per_batch,
470468
};
471469

472470
let mut fb_cancel = block_cancel.child_token();
@@ -614,6 +612,7 @@ where
614612
let flashblock_index = ctx.flashblock_index();
615613
let mut target_gas_for_batch = ctx.extra_ctx.target_gas_for_batch;
616614
let mut target_da_for_batch = ctx.extra_ctx.target_da_for_batch;
615+
let mut target_da_footprint_for_batch = ctx.extra_ctx.target_da_footprint_for_batch;
617616

618617
info!(
619618
target: "payload_builder",
@@ -624,6 +623,7 @@ where
624623
target_da = target_da_for_batch,
625624
da_used = info.cumulative_da_bytes_used,
626625
block_gas_used = ctx.block_gas_limit(),
626+
target_da_footprint = target_da_footprint_for_batch,
627627
"Building flashblock",
628628
);
629629
let flashblock_build_start_time = Instant::now();
@@ -640,16 +640,30 @@ where
640640
}
641641
};
642642

643-
let builder_tx_gas = builder_txs.iter().fold(0, |acc, tx| acc + tx.gas_used);
644-
let builder_tx_da_size: u64 = builder_txs.iter().fold(0, |acc, tx| acc + tx.da_size);
645-
info.cumulative_da_bytes_used += builder_tx_da_size;
643+
// only reserve builder tx gas / da size that has not been committed yet
644+
// committed builder txs would have counted towards the gas / da used
645+
let builder_tx_gas = builder_txs
646+
.iter()
647+
.filter(|tx| !tx.is_top_of_block)
648+
.fold(0, |acc, tx| acc + tx.gas_used);
649+
let builder_tx_da_size: u64 = builder_txs
650+
.iter()
651+
.filter(|tx| !tx.is_top_of_block)
652+
.fold(0, |acc, tx| acc + tx.da_size);
646653
target_gas_for_batch = target_gas_for_batch.saturating_sub(builder_tx_gas);
647654

648655
// saturating sub just in case, we will log an error if da_limit too small for builder_tx_da_size
649656
if let Some(da_limit) = target_da_for_batch.as_mut() {
650657
*da_limit = da_limit.saturating_sub(builder_tx_da_size);
651658
}
652659

660+
if let (Some(footprint), Some(scalar)) = (
661+
target_da_footprint_for_batch.as_mut(),
662+
info.da_footprint_scalar,
663+
) {
664+
*footprint = footprint.saturating_sub(builder_tx_da_size.saturating_mul(scalar as u64));
665+
}
666+
653667
let best_txs_start_time = Instant::now();
654668
best_txs.refresh_iterator(
655669
BestPayloadTransactions::new(
@@ -673,6 +687,7 @@ where
673687
best_txs,
674688
target_gas_for_batch.min(ctx.block_gas_limit()),
675689
target_da_for_batch,
690+
target_da_footprint_for_batch,
676691
)
677692
.wrap_err("failed to execute best transactions")?;
678693
// Extract last transactions
@@ -781,10 +796,19 @@ where
781796

782797
let target_gas_for_batch =
783798
ctx.extra_ctx.target_gas_for_batch + ctx.extra_ctx.gas_per_batch;
784-
let next_extra_ctx = ctx
785-
.extra_ctx
786-
.clone()
787-
.next(target_gas_for_batch, target_da_for_batch);
799+
800+
if let (Some(footprint), Some(da_footprint_limit)) = (
801+
target_da_footprint_for_batch.as_mut(),
802+
ctx.extra_ctx.da_footprint_per_batch,
803+
) {
804+
*footprint += da_footprint_limit;
805+
}
806+
807+
let next_extra_ctx = ctx.extra_ctx.clone().next(
808+
target_gas_for_batch,
809+
target_da_for_batch,
810+
target_da_footprint_for_batch,
811+
);
788812

789813
info!(
790814
target: "payload_builder",

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,6 @@ impl<Txs: PayloadTxsBounds> OpBuilder<'_, Txs> {
375375
}
376376
// Save some space in the block_da_limit for builder tx
377377
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;
379378
let block_da_limit = ctx
380379
.da_config
381380
.max_da_block_size()
@@ -386,6 +385,14 @@ impl<Txs: PayloadTxsBounds> OpBuilder<'_, Txs> {
386385
}
387386
da_limit
388387
});
388+
let block_da_footprint = info.da_footprint_scalar
389+
.map(|da_footprint_scalar| {
390+
let da_footprint_limit = ctx.block_gas_limit().saturating_sub(builder_tx_da_size.saturating_mul(da_footprint_scalar as u64));
391+
if da_footprint_limit == 0 {
392+
error!("Builder tx da size subtraction caused max_da_footprint to be 0. No transaction would be included.");
393+
}
394+
da_footprint_limit
395+
});
389396

390397
if !ctx.attributes().no_tx_pool {
391398
let best_txs_start_time = Instant::now();
@@ -405,6 +412,7 @@ impl<Txs: PayloadTxsBounds> OpBuilder<'_, Txs> {
405412
&mut best_txs,
406413
block_gas_limit,
407414
block_da_limit,
415+
block_da_footprint,
408416
)?
409417
.is_some()
410418
{

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ impl<T: Debug + Default> ExecutionInfo<T> {
6565
/// per tx.
6666
/// - block DA limit: if configured, ensures the transaction's DA size does not exceed the
6767
/// maximum allowed DA limit per block.
68+
#[allow(clippy::too_many_arguments)]
6869
pub fn is_tx_over_limits(
6970
&self,
7071
tx_da_size: u64,
@@ -73,12 +74,12 @@ impl<T: Debug + Default> ExecutionInfo<T> {
7374
block_data_limit: Option<u64>,
7475
tx_gas_limit: u64,
7576
da_footprint_gas_scalar: Option<u16>,
77+
block_da_footprint_limit: Option<u64>,
7678
) -> Result<(), TxnExecutionResult> {
7779
if tx_data_limit.is_some_and(|da_limit| tx_da_size > da_limit) {
7880
return Err(TxnExecutionResult::TransactionDALimitExceeded);
7981
}
8082
let total_da_bytes_used = self.cumulative_da_bytes_used.saturating_add(tx_da_size);
81-
8283
if block_data_limit.is_some_and(|da_limit| total_da_bytes_used > da_limit) {
8384
return Err(TxnExecutionResult::BlockDALimitExceeded(
8485
self.cumulative_da_bytes_used,
@@ -91,7 +92,7 @@ impl<T: Debug + Default> ExecutionInfo<T> {
9192
if let Some(da_footprint_gas_scalar) = da_footprint_gas_scalar {
9293
let tx_da_footprint =
9394
total_da_bytes_used.saturating_mul(da_footprint_gas_scalar as u64);
94-
if tx_da_footprint > block_gas_limit {
95+
if tx_da_footprint > block_da_footprint_limit.unwrap_or(block_gas_limit) {
9596
return Err(TxnExecutionResult::BlockDALimitExceeded(
9697
total_da_bytes_used,
9798
tx_da_size,

0 commit comments

Comments
 (0)