Skip to content

Commit fa22d5c

Browse files
authored
Add builder txn to Flashblocks (#89)
* Add changes * Remove print
1 parent 7cd15e1 commit fa22d5c

File tree

9 files changed

+60
-36
lines changed

9 files changed

+60
-36
lines changed

crates/op-rbuilder/src/args/op.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pub struct FlashblocksArgs {
9595

9696
/// flashblock block time in milliseconds
9797
#[arg(
98-
long = "flashblock.block-time",
98+
long = "flashblocks.block-time",
9999
default_value = "250",
100100
env = "FLASHBLOCK_BLOCK_TIME"
101101
)]

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use alloy_consensus::{Eip658Value, Transaction, TxEip1559};
2-
use alloy_eips::{Encodable2718, Typed2718};
2+
use alloy_eips::{eip7623::TOTAL_COST_FLOOR_PER_TOKEN, Encodable2718, Typed2718};
33
use alloy_op_evm::block::receipt_builder::OpReceiptBuilder;
44
use alloy_primitives::{Address, Bytes, TxKind, U256};
55
use alloy_rpc_types_eth::Withdrawals;
@@ -500,9 +500,9 @@ impl OpPayloadBuilderCtx {
500500
Ok(None)
501501
}
502502

503-
pub fn add_builder_tx<DB>(
503+
pub fn add_builder_tx<DB, Extra: Debug + Default>(
504504
&self,
505-
info: &mut ExecutionInfo,
505+
info: &mut ExecutionInfo<Extra>,
506506
db: &mut State<DB>,
507507
builder_tx_gas: u64,
508508
message: Vec<u8>,
@@ -583,6 +583,27 @@ impl OpPayloadBuilderCtx {
583583
}
584584
}
585585

586+
pub fn estimate_gas_for_builder_tx(input: Vec<u8>) -> u64 {
587+
// Count zero and non-zero bytes
588+
let (zero_bytes, nonzero_bytes) = input.iter().fold((0, 0), |(zeros, nonzeros), &byte| {
589+
if byte == 0 {
590+
(zeros + 1, nonzeros)
591+
} else {
592+
(zeros, nonzeros + 1)
593+
}
594+
});
595+
596+
// Calculate gas cost (4 gas per zero byte, 16 gas per non-zero byte)
597+
let zero_cost = zero_bytes * 4;
598+
let nonzero_cost = nonzero_bytes * 16;
599+
600+
// Tx gas should be not less than floor gas https://eips.ethereum.org/EIPS/eip-7623
601+
let tokens_in_calldata = zero_bytes + nonzero_bytes * 4;
602+
let floor_gas = 21_000 + tokens_in_calldata * TOTAL_COST_FLOOR_PER_TOKEN;
603+
604+
std::cmp::max(zero_cost + nonzero_cost + 21_000, floor_gas)
605+
}
606+
586607
/// Creates signed builder tx to Address::ZERO and specified message as input
587608
pub fn signed_builder_tx<DB>(
588609
db: &mut State<DB>,

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{sync::Arc, time::Instant};
44
use super::{config::FlashblocksConfig, wspub::WebSocketPublisher};
55
use crate::{
66
builders::{
7-
context::OpPayloadBuilderCtx,
7+
context::{estimate_gas_for_builder_tx, OpPayloadBuilderCtx},
88
flashblocks::config::FlashBlocksConfigExt,
99
generator::{BlockCell, BuildArguments},
1010
BuilderConfig,
@@ -257,6 +257,13 @@ where
257257
}
258258
});
259259

260+
let message = format!("Block Number: {}", ctx.block_number())
261+
.as_bytes()
262+
.to_vec();
263+
let builder_tx_gas = ctx
264+
.builder_signer()
265+
.map_or(0, |_| estimate_gas_for_builder_tx(message.clone()));
266+
260267
// Process flashblocks in a blocking loop
261268
loop {
262269
// Block on receiving a message, break on cancellation or closed channel
@@ -340,6 +347,12 @@ where
340347
return Ok(());
341348
}
342349

350+
// If it is the last flashblocks, add the builder txn to the block if enabled
351+
if flashblock_count == self.config.flashblocks_per_block() - 1 {
352+
// TODO: Account for DA size limits
353+
ctx.add_builder_tx(&mut info, &mut db, builder_tx_gas, message.clone());
354+
}
355+
343356
let total_block_built_duration = Instant::now();
344357
let build_result = build_block(db, &ctx, &mut info);
345358
ctx.metrics

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ where
147147
builder_signer: args.builder_signer,
148148
revert_protection: args.enable_revert_protection,
149149
block_time: Duration::from_millis(args.chain_block_time),
150-
block_time_leeway: Duration::from_millis(500),
150+
block_time_leeway: Duration::from_secs(args.extra_block_deadline_secs),
151151
da_config: Default::default(),
152152
specific: S::try_from(args)?,
153153
})

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

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
use alloy_consensus::{
22
constants::EMPTY_WITHDRAWALS, proofs, BlockBody, Header, EMPTY_OMMER_ROOT_HASH,
33
};
4-
use alloy_eips::{
5-
eip7623::TOTAL_COST_FLOOR_PER_TOKEN, eip7685::EMPTY_REQUESTS_HASH, merge::BEACON_NONCE,
6-
};
4+
use alloy_eips::{eip7685::EMPTY_REQUESTS_HASH, merge::BEACON_NONCE};
75
use alloy_primitives::U256;
86
use reth::payload::PayloadBuilderAttributes;
97
use reth_basic_payload_builder::{BuildOutcome, BuildOutcomeKind, MissingPayloadBehaviour};
@@ -38,7 +36,7 @@ use crate::{
3836
traits::{ClientBounds, NodeBounds, PayloadTxsBounds, PoolBounds},
3937
};
4038

41-
use super::super::context::OpPayloadBuilderCtx;
39+
use super::super::context::{estimate_gas_for_builder_tx, OpPayloadBuilderCtx};
4240

4341
pub struct StandardPayloadBuilderBuilder(pub BuilderConfig<()>);
4442

@@ -566,24 +564,3 @@ impl<Txs: PayloadTxsBounds> OpBuilder<'_, Txs> {
566564
}
567565
}
568566
}
569-
570-
fn estimate_gas_for_builder_tx(input: Vec<u8>) -> u64 {
571-
// Count zero and non-zero bytes
572-
let (zero_bytes, nonzero_bytes) = input.iter().fold((0, 0), |(zeros, nonzeros), &byte| {
573-
if byte == 0 {
574-
(zeros + 1, nonzeros)
575-
} else {
576-
(zeros, nonzeros + 1)
577-
}
578-
});
579-
580-
// Calculate gas cost (4 gas per zero byte, 16 gas per non-zero byte)
581-
let zero_cost = zero_bytes * 4;
582-
let nonzero_cost = nonzero_bytes * 16;
583-
584-
// Tx gas should be not less than floor gas https://eips.ethereum.org/EIPS/eip-7623
585-
let tokens_in_calldata = zero_bytes + nonzero_bytes * 4;
586-
let floor_gas = 21_000 + tokens_in_calldata * TOTAL_COST_FLOOR_PER_TOKEN;
587-
588-
std::cmp::max(zero_cost + nonzero_cost + 21_000, floor_gas)
589-
}

crates/op-rbuilder/src/tests/flashblocks/smoke.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use tokio_util::sync::CancellationToken;
99
use crate::tests::TestHarnessBuilder;
1010

1111
#[tokio::test]
12-
#[ignore = "Flashblocks tests need more work"]
1312
async fn chain_produces_blocks() -> eyre::Result<()> {
1413
let harness = TestHarnessBuilder::new("flashbots_chain_produces_blocks")
1514
.with_flashblocks_port(1239)
@@ -49,7 +48,9 @@ async fn chain_produces_blocks() -> eyre::Result<()> {
4948
let _ = harness.send_valid_transaction().await?;
5049
}
5150

52-
generator.generate_block().await?;
51+
let generated_block = generator.generate_block().await?;
52+
assert_eq!(generated_block.num_transactions(), 7); // 5 normal txn + deposit + builder txn
53+
5354
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
5455
}
5556

crates/op-rbuilder/src/tests/framework/blocks.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,4 +402,8 @@ impl BlockGenerated {
402402
pub fn not_includes_vec(&self, tx_hashes: Vec<B256>) -> bool {
403403
tx_hashes.iter().all(|hash| self.not_includes(*hash))
404404
}
405+
406+
pub fn num_transactions(&self) -> usize {
407+
self.block.transactions.len()
408+
}
405409
}

crates/op-rbuilder/src/tests/framework/harness.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ impl TestHarnessBuilder {
133133
builder_http_port,
134134
validator_auth_rpc_port,
135135
builder_log_path,
136+
chain_block_time: self.chain_block_time,
136137
})
137138
}
138139
}
@@ -143,6 +144,7 @@ pub struct TestHarness {
143144
builder_http_port: u16,
144145
validator_auth_rpc_port: u16,
145146
builder_log_path: PathBuf,
147+
chain_block_time: Option<u64>,
146148
}
147149

148150
impl TestHarness {
@@ -173,7 +175,13 @@ impl TestHarness {
173175
let engine_api = EngineApi::new_with_port(self.builder_auth_rpc_port).unwrap();
174176
let validation_api = Some(EngineApi::new_with_port(self.validator_auth_rpc_port).unwrap());
175177

176-
let mut generator = BlockGenerator::new(engine_api, validation_api, false, 1, None);
178+
let mut generator = BlockGenerator::new(
179+
engine_api,
180+
validation_api,
181+
false,
182+
self.chain_block_time.map_or(1, |time| time / 1000), // in seconds
183+
None,
184+
);
177185
generator.init().await?;
178186

179187
Ok(generator)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ impl Service for OpRbuilderConfig {
153153
}
154154

155155
if let Some(flashblocks_port) = &self.flashblocks_port {
156-
cmd.arg("--flashblocks.enabled").arg("true");
156+
cmd.arg("--flashblocks.enabled");
157157
cmd.arg("--flashblocks.addr").arg("127.0.0.1");
158158
cmd.arg("--flashblocks.port")
159159
.arg(flashblocks_port.to_string());
@@ -165,7 +165,7 @@ impl Service for OpRbuilderConfig {
165165
}
166166

167167
if let Some(flashbots_block_time) = self.flashbots_block_time {
168-
cmd.arg("--rollup.flashblock-block-time")
168+
cmd.arg("--flashblocks.block-time")
169169
.arg(flashbots_block_time.to_string());
170170
}
171171

0 commit comments

Comments
 (0)