Skip to content

Commit 00466e3

Browse files
authored
feat: use checkpoint context from rblib to track flashblock number (#44)
* update rblib commit * use new rblib checkpoint context to track flashblocks * fix all the tests
1 parent 809b0f4 commit 00466e3

File tree

17 files changed

+177
-166
lines changed

17 files changed

+177
-166
lines changed

Cargo.toml

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jemalloc = ["rblib/jemalloc"]
3434
debug = ["tokio/full", "tokio/tracing", "dep:console-subscriber"]
3535

3636
[dependencies]
37-
rblib = { git = "https://github.com/flashbots/rblib", rev = "66c5c15a8834a6f677bec0d6b34f54ffc7cdd4ff" }
37+
rblib = { git = "https://github.com/flashbots/rblib", rev = "9eccd22047c3f8978ae022d575dca749a81684a8" }
3838

3939
futures = "0.3"
4040
tokio = "1.46"
@@ -60,24 +60,12 @@ atomic-time = "0.1"
6060
secp256k1 = "0.30"
6161
jsonrpsee = "0.26.0"
6262

63-
alloy-json-rpc = "1.0.37"
64-
alloy-serde = "1.0.37"
65-
66-
67-
# reth dependencies
68-
reth-network-peers = { git = "https://github.com/paradigmxyz/reth", tag = "v1.8.2" }
69-
reth-db-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.8.2" }
70-
reth-node-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.8.2" }
71-
reth-optimism-node = { git = "https://github.com/paradigmxyz/reth", tag = "v1.8.2" }
72-
reth-optimism-rpc = { git = "https://github.com/paradigmxyz/reth", tag = "v1.8.2" }
73-
reth-provider = { git = "https://github.com/paradigmxyz/reth", tag = "v1.8.2" }
74-
7563
# debug flag
7664
console-subscriber = { version = "0.4", optional = true }
7765
tracing-subscriber = "0.3.20"
7866

7967
[dev-dependencies]
80-
rblib = { git = "https://github.com/flashbots/rblib", rev = "66c5c15a8834a6f677bec0d6b34f54ffc7cdd4ff", features = [
68+
rblib = { git = "https://github.com/flashbots/rblib", rev = "9eccd22047c3f8978ae022d575dca749a81684a8", features = [
8169
"test-utils",
8270
] }
8371

src/bundle.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
//! - The `eth_sendBundle` input parameters and their validation.
1010
1111
use {
12-
crate::platform::Flashblocks,
12+
crate::{platform::Flashblocks, state::FlashblockNumber},
1313
core::convert::Infallible,
1414
rblib::{
1515
alloy::{
@@ -51,7 +51,7 @@ pub struct FlashblocksBundle {
5151

5252
#[serde(
5353
default,
54-
with = "alloy_serde::quantity::opt",
54+
with = "rblib::alloy::serde::quantity::opt",
5555
skip_serializing_if = "Option::is_none"
5656
)]
5757
pub min_block_number: Option<u64>,
@@ -60,7 +60,7 @@ pub struct FlashblocksBundle {
6060
/// blocks with a block number higher than this value.
6161
#[serde(
6262
default,
63-
with = "alloy_serde::quantity::opt",
63+
with = "rblib::alloy::serde::quantity::opt",
6464
skip_serializing_if = "Option::is_none"
6565
)]
6666
pub max_block_number: Option<u64>,
@@ -123,7 +123,11 @@ impl Bundle<Flashblocks> for FlashblocksBundle {
123123

124124
/// Tests the eligibility of the bundle for inclusion in a block before
125125
/// executing any of its transactions.
126-
fn is_eligible(&self, block: &BlockContext<Flashblocks>) -> Eligibility {
126+
fn is_eligible(
127+
&self,
128+
block: &BlockContext<Flashblocks>,
129+
_ctx: &FlashblockNumber,
130+
) -> Eligibility {
127131
if self.txs.is_empty() {
128132
// empty bundles are never eligible
129133
return Eligibility::PermanentlyIneligible;

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod bundle;
22
mod platform;
33
mod primitives;
4+
mod state;
45

5-
pub use {bundle::*, platform::*, primitives::*};
6+
pub use {bundle::*, platform::*, primitives::*, state::*};

src/limits.rs

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55
//! flashblock partitioning logic.
66
77
use {
8-
crate::{Flashblocks, state::FlashblockNumber},
8+
crate::{
9+
Flashblocks,
10+
state::{FlashblockNumber, TargetFlashblocks},
11+
},
912
core::time::Duration,
1013
rblib::{alloy::consensus::BlockHeader, prelude::*},
1114
std::sync::{Arc, Mutex},
15+
tracing::debug,
1216
};
1317

1418
/// Specifies the limits for individual flashblocks.
@@ -33,7 +37,7 @@ pub struct FlashblockState {
3337
current_block: Option<u64>,
3438
/// Current flashblock number. Used to check if we're on the first
3539
/// flashblock or to adjust the target number of flashblocks for a block.
36-
flashblock_number: Arc<FlashblockNumber>,
40+
target_flashblocks: Arc<TargetFlashblocks>,
3741
/// Duration for the first flashblock, which may be shortened to absorb
3842
/// timing variance.
3943
first_flashblock_interval: Duration,
@@ -43,20 +47,20 @@ pub struct FlashblockState {
4347
}
4448

4549
impl FlashblockState {
46-
fn current_gas_limit(&self) -> u64 {
50+
fn current_gas_limit(&self, flashblock_number: &FlashblockNumber) -> u64 {
4751
self
4852
.gas_per_flashblock
49-
.saturating_mul(self.flashblock_number.current())
53+
.saturating_mul(flashblock_number.current())
5054
}
5155
}
5256

5357
impl FlashblockLimits {
5458
pub fn new(
5559
interval: Duration,
56-
flashblock_number: Arc<FlashblockNumber>,
60+
target_flashblocks: Arc<TargetFlashblocks>,
5761
) -> Self {
5862
let state = FlashblockState {
59-
flashblock_number,
63+
target_flashblocks,
6064
..Default::default()
6165
};
6266
FlashblockLimits {
@@ -77,7 +81,7 @@ impl FlashblockLimits {
7781
pub fn update_state(
7882
&self,
7983
payload: &Checkpoint<Flashblocks>,
80-
enclosing: &Limits,
84+
enclosing: &Limits<Flashblocks>,
8185
) {
8286
let mut state = self.state.lock().expect("mutex is not poisoned");
8387

@@ -88,38 +92,45 @@ impl FlashblockLimits {
8892
let elapsed = payload.building_since().elapsed();
8993
let remaining_time = payload_deadline.saturating_sub(elapsed);
9094

91-
let (target_flashblock, first_flashblock_interval) =
95+
let (target_flashblocks, first_flashblock_interval) =
9296
self.calculate_flashblocks(payload, remaining_time);
9397

9498
state.gas_per_flashblock = enclosing
9599
.gas_limit
96-
.checked_div(target_flashblock)
100+
.checked_div(target_flashblocks)
97101
.unwrap_or(enclosing.gas_limit);
98102
state.current_block = Some(payload.block().number());
99103
state.first_flashblock_interval = first_flashblock_interval;
100-
state.flashblock_number.reset_current_flashblock();
101-
state
102-
.flashblock_number
103-
.set_target_flashblocks(target_flashblock);
104+
state.target_flashblocks.set(target_flashblocks);
105+
106+
debug!(
107+
target_flashblocks = target_flashblocks,
108+
first_flashblock_interval = ?first_flashblock_interval,
109+
"Set flashblock timing for this block"
110+
);
104111
}
105112
}
106113

107114
/// Returns limits for the current flashblock.
108115
///
109116
/// If all flashblocks have been produced, returns a deadline of 1ms to stop
110117
/// production.
111-
pub fn get_limits(&self, enclosing: &Limits) -> Limits {
118+
pub fn get_limits(
119+
&self,
120+
enclosing: &Limits<Flashblocks>,
121+
flashblock_number: &FlashblockNumber,
122+
) -> Limits<Flashblocks> {
112123
let state = self.state.lock().expect("mutex is not poisoned");
113124
// If flashblock number == 1, we're building the first flashblock
114-
let deadline = if state.flashblock_number.current() == 1 {
125+
let deadline = if flashblock_number.current() == 1 {
115126
state.first_flashblock_interval
116127
} else {
117128
self.interval
118129
};
119130

120131
enclosing
121132
.with_deadline(deadline)
122-
.with_gas_limit(state.current_gas_limit())
133+
.with_gas_limit(state.current_gas_limit(flashblock_number))
123134
}
124135

125136
/// Calculates the number of flashblocks and first flashblock interval for
@@ -148,29 +159,32 @@ impl ScopedLimits<Flashblocks> for FlashblockLimits {
148159
fn create(
149160
&self,
150161
payload: &Checkpoint<Flashblocks>,
151-
enclosing: &Limits,
152-
) -> Limits {
162+
enclosing: &Limits<Flashblocks>,
163+
) -> Limits<Flashblocks> {
164+
let flashblock_number = payload.context();
153165
// Check the state and reset if we started building next block
154166
self.update_state(payload, enclosing);
155167

156-
let limits = self.get_limits(enclosing);
168+
let limits = self.get_limits(enclosing, flashblock_number);
157169

158170
let state = self.state.lock().expect("mutex is not poisoned");
159-
if state.flashblock_number.in_bounds() {
171+
let flashblock_number = payload.context();
172+
if flashblock_number.current() <= state.target_flashblocks.get() {
160173
let gas_used = payload.cumulative_gas_used();
161174
let remaining_gas = enclosing.gas_limit.saturating_sub(gas_used);
162175
tracing::info!(
163176
"Creating flashblocks limits: {}, payload txs: {}, gas used: {} \
164177
({}%), gas_remaining: {} ({}%), next_block_gas_limit: {} ({}%), gas \
165178
per block: {} ({}%), remaining_time: {}ms, gas_limit: {}",
166-
state.flashblock_number,
179+
flashblock_number,
167180
payload.history().transactions().count(),
168181
gas_used,
169182
(gas_used * 100 / enclosing.gas_limit),
170183
remaining_gas,
171184
(remaining_gas * 100 / enclosing.gas_limit),
172-
state.current_gas_limit(),
173-
(state.current_gas_limit() * 100 / enclosing.gas_limit),
185+
state.current_gas_limit(flashblock_number),
186+
(state.current_gas_limit(flashblock_number) * 100
187+
/ enclosing.gas_limit),
174188
state.gas_per_flashblock,
175189
(state.gas_per_flashblock * 100 / enclosing.gas_limit),
176190
limits.deadline.expect("deadline is set").as_millis(),

src/main.rs

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,21 @@ use {
66
publish::{PublishFlashblock, WebSocketSink},
77
rpc::TransactionStatusRpc,
88
signer::BuilderSigner,
9-
state::FlashblockNumber,
9+
state::TargetFlashblocks,
1010
stop::BreakAfterMaxFlashblocks,
1111
},
1212
platform::Flashblocks,
13-
rblib::{pool::*, prelude::*, steps::*},
14-
reth_optimism_node::{
15-
OpAddOns,
16-
OpEngineApiBuilder,
17-
OpEngineValidatorBuilder,
18-
OpNode,
13+
rblib::{
14+
pool::*,
15+
prelude::*,
16+
reth::optimism::{
17+
node::{OpAddOns, OpEngineApiBuilder, OpEngineValidatorBuilder, OpNode},
18+
rpc::OpEthApiBuilder,
19+
},
20+
steps::*,
1921
},
20-
reth_optimism_rpc::OpEthApiBuilder,
2122
std::sync::Arc,
23+
tracing::info,
2224
};
2325

2426
mod args;
@@ -103,9 +105,12 @@ fn build_pipeline(
103105
.clone()
104106
.unwrap_or(BuilderSigner::random());
105107

106-
// Multiple steps need to access flashblock number state, so we need to
107-
// initialize it outside
108-
let flashblock_number = Arc::new(FlashblockNumber::new());
108+
let target_flashblocks = Arc::new(TargetFlashblocks::new());
109+
110+
info!(
111+
"cli_args.builder_signer.is_some() = {}",
112+
cli_args.builder_signer.is_some()
113+
);
109114

110115
let pipeline = Pipeline::<Flashblocks>::named("top")
111116
.with_step(OptimismPrologue)
@@ -124,35 +129,38 @@ fn build_pipeline(
124129
Once,
125130
Pipeline::named("single_flashblock")
126131
.with_pipeline(
127-
Loop,
132+
Once,
128133
Pipeline::named("flashblock_steps")
129-
.with_step(AppendOrders::from_pool(pool).with_ok_on_limit())
130-
.with_step(OrderByPriorityFee::default())
131-
.with_step_if(
132-
cli_args.revert_protection,
133-
RemoveRevertedTransactions::default(),
134+
.with_pipeline(
135+
Loop,
136+
Pipeline::named("inner_flashblock_steps")
137+
.with_step(AppendOrders::from_pool(pool).with_ok_on_limit())
138+
.with_step(OrderByPriorityFee::default())
139+
.with_step_if(
140+
cli_args.revert_protection,
141+
RemoveRevertedTransactions::default(),
142+
)
143+
.with_step(BreakAfterDeadline),
134144
)
135-
.with_step(BreakAfterDeadline)
136-
.with_epilogue_if(
145+
.with_step_if(
137146
cli_args.builder_signer.is_some(),
138147
BuilderEpilogue::with_signer(builder_signer.clone().into())
139148
.with_message(|block| {
140149
format!("Block Number: {}", block.number())
141150
}),
142151
)
143-
.with_epilogue(PublishFlashblock::new(
152+
.with_step(PublishFlashblock::new(
144153
ws.clone(),
145-
flashblock_number.clone(),
146154
cli_args.flashblocks_args.calculate_state_root,
147155
))
148156
.with_limits(FlashblockLimits::new(
149157
interval,
150-
flashblock_number.clone(),
158+
target_flashblocks.clone(),
151159
)),
152160
)
153161
.with_step(BreakAfterDeadline),
154162
)
155-
.with_step(BreakAfterMaxFlashblocks::new(flashblock_number)),
163+
.with_step(BreakAfterMaxFlashblocks::new(target_flashblocks)),
156164
)
157165
.with_limits(Scaled::default().deadline(total_building_time));
158166

src/platform.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use {
2-
crate::bundle::FlashblocksBundle,
2+
crate::{bundle::FlashblocksBundle, state::FlashblockNumber},
33
rblib::{prelude::*, reth::providers::StateProvider},
44
serde::{Deserialize, Serialize},
55
std::sync::Arc,
@@ -19,8 +19,10 @@ pub struct Flashblocks;
1919

2020
impl Platform for Flashblocks {
2121
type Bundle = FlashblocksBundle;
22+
type CheckpointContext = FlashblockNumber;
2223
type DefaultLimits = types::DefaultLimits<Optimism>;
2324
type EvmConfig = types::EvmConfig<Optimism>;
25+
type ExtraLimits = types::ExtraLimits<Optimism>;
2426
type NodeTypes = types::NodeTypes<Optimism>;
2527
type PooledTransaction = types::PooledTransaction<Optimism>;
2628

@@ -35,7 +37,7 @@ impl Platform for Flashblocks {
3537
chainspec: &types::ChainSpec<P>,
3638
parent: &types::Header<P>,
3739
attributes: &types::PayloadBuilderAttributes<P>,
38-
) -> types::NextBlockEnvContext<P>
40+
) -> Result<types::NextBlockEnvContext<P>, types::EvmEnvError<P>>
3941
where
4042
P: traits::PlatformExecBounds<Self>,
4143
{

src/playground.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ use {
3636
alloy::hex,
3737
reth::{
3838
cli::chainspec::ChainSpecParser,
39+
network_peers::TrustedPeer,
3940
optimism::{
4041
chainspec::OpChainSpec,
4142
cli::{chainspec::OpChainSpecParser, commands::Commands},
4243
},
4344
},
4445
},
45-
reth_network_peers::TrustedPeer,
4646
secp256k1::SecretKey,
4747
std::{
4848
fs::read_to_string,

0 commit comments

Comments
 (0)