Skip to content

Commit 8f08b2e

Browse files
authored
feat: implement p2p layer and broadcast flashblocks (#275)
1 parent b601bcd commit 8f08b2e

File tree

20 files changed

+3177
-1086
lines changed

20 files changed

+3177
-1086
lines changed

Cargo.lock

Lines changed: 2039 additions & 990 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ repository = "https://github.com/flashbots/op-rbuilder"
88
exclude = [".github/"]
99

1010
[workspace]
11-
members = [ "crates/op-rbuilder", "crates/tdx-quote-provider"]
11+
members = [ "crates/op-rbuilder", "crates/p2p", "crates/tdx-quote-provider"]
1212
default-members = ["crates/op-rbuilder"]
1313
resolver = "2"
1414

@@ -182,6 +182,9 @@ flate2 = "1.0.37"
182182
prometheus = "0.13.4"
183183
ctor = "0.2"
184184
dashmap = "6.1"
185+
hex = "0.4"
186+
futures = "0.3"
187+
futures-util = "0.3.31"
185188

186189
lazy_static = "1.4.0"
187190
tikv-jemallocator = { version = "0.6" }

crates/op-rbuilder/Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ default-run = "op-rbuilder"
1212
workspace = true
1313

1414
[dependencies]
15+
p2p = { path = "../p2p" }
16+
1517
reth.workspace = true
1618
reth-optimism-node.workspace = true
1719
reth-optimism-cli.workspace = true
@@ -109,10 +111,11 @@ url.workspace = true
109111
anyhow = "1"
110112
opentelemetry = { workspace = true, optional = true }
111113
dashmap.workspace = true
114+
hex = { workspace = true }
115+
futures = { workspace = true }
116+
futures-util = { workspace = true }
112117

113118
tower = "0.5"
114-
futures = "0.3"
115-
futures-util = "0.3.31"
116119
time = { version = "0.3.36", features = ["macros", "formatting", "parsing"] }
117120
chrono = "0.4"
118121
uuid = { version = "1.6.1", features = ["serde", "v5", "v4"] }
@@ -124,7 +127,6 @@ serde_yaml = { version = "0.9" }
124127
moka = "0.12"
125128
http = "1.0"
126129
sha3 = "0.10"
127-
hex = "0.4"
128130
reqwest = "0.12.23"
129131
k256 = "0.13.4"
130132

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ pub struct FlashblocksArgs {
166166
env = "FLASHBLOCK_NUMBER_CONTRACT_ADDRESS"
167167
)]
168168
pub flashblocks_number_contract_address: Option<Address>,
169+
170+
/// Flashblocks p2p configuration
171+
#[command(flatten)]
172+
pub p2p: FlashblocksP2pArgs,
169173
}
170174

171175
impl Default for FlashblocksArgs {
@@ -178,6 +182,49 @@ impl Default for FlashblocksArgs {
178182
}
179183
}
180184

185+
#[derive(Debug, Clone, PartialEq, Eq, clap::Args)]
186+
pub struct FlashblocksP2pArgs {
187+
/// Enable libp2p networking for flashblock propagation
188+
#[arg(
189+
long = "flashblocks.p2p_enabled",
190+
env = "FLASHBLOCK_P2P_ENABLED",
191+
default_value = "false"
192+
)]
193+
pub p2p_enabled: bool,
194+
195+
/// Port for the flashblocks p2p node
196+
#[arg(
197+
long = "flashblocks.p2p_port",
198+
env = "FLASHBLOCK_P2P_PORT",
199+
default_value = "9009"
200+
)]
201+
pub p2p_port: u16,
202+
203+
/// Path to the file containing a hex-encoded libp2p private key.
204+
/// If the file does not exist, a new key will be generated.
205+
#[arg(
206+
long = "flashblocks.p2p_private_key_file",
207+
env = "FLASHBLOCK_P2P_PRIVATE_KEY_FILE"
208+
)]
209+
pub p2p_private_key_file: Option<String>,
210+
211+
/// Comma-separated list of multiaddrs of known Flashblocks peers
212+
/// Example: "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ,/ip4/104.131.131.82/udp/4001/quic-v1/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"
213+
#[arg(
214+
long = "flashblocks.p2p_known_peers",
215+
env = "FLASHBLOCK_P2P_KNOWN_PEERS"
216+
)]
217+
pub p2p_known_peers: Option<String>,
218+
219+
/// Maximum number of peers for the flashblocks p2p node
220+
#[arg(
221+
long = "flashblocks.p2p_max_peer_count",
222+
env = "FLASHBLOCK_P2P_MAX_PEER_COUNT",
223+
default_value = "50"
224+
)]
225+
pub p2p_max_peer_count: u32,
226+
}
227+
181228
/// Parameters for telemetry configuration
182229
#[derive(Debug, Clone, Default, PartialEq, Eq, clap::Args)]
183230
pub struct TelemetryArgs {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use alloy_evm::Database;
44
use alloy_op_evm::OpEvm;
55
use alloy_primitives::{
66
Address, B256, Bytes, TxKind, U256,
7-
map::foldhash::{HashMap, HashSet, HashSetExt},
7+
map::{HashMap, HashSet},
88
};
99
use alloy_sol_types::{ContractError, Revert, SolCall, SolError, SolInterface};
1010
use core::fmt::Debug;
@@ -192,7 +192,7 @@ pub trait BuilderTransactions<ExtraCtx: Debug + Default = (), Extra: Debug + Def
192192
.evm_config
193193
.evm_with_env(&mut *db, builder_ctx.evm_env.clone());
194194

195-
let mut invalid: HashSet<Address> = HashSet::new();
195+
let mut invalid = HashSet::new();
196196

197197
for builder_tx in builder_txs.iter() {
198198
if builder_tx.is_top_of_block != top_of_block {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -544,9 +544,9 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
544544
info.executed_transactions.push(tx.into_inner());
545545
}
546546

547-
let payload_tx_simulation_time = execute_txs_start_time.elapsed();
547+
let payload_transaction_simulation_time = execute_txs_start_time.elapsed();
548548
self.metrics.set_payload_builder_metrics(
549-
payload_tx_simulation_time,
549+
payload_transaction_simulation_time,
550550
num_txs_considered,
551551
num_txs_simulated,
552552
num_txs_simulated_success,

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,21 @@ pub struct FlashblocksConfig {
3838
///
3939
/// If set a builder tx will be added to the start of every flashblock instead of the regular builder tx.
4040
pub flashblocks_number_contract_address: Option<Address>,
41+
42+
/// Whether to enable the p2p node for flashblocks
43+
pub p2p_enabled: bool,
44+
45+
/// Port for the p2p node
46+
pub p2p_port: u16,
47+
48+
/// Optional hex-encoded private key file path for the p2p node
49+
pub p2p_private_key_file: Option<String>,
50+
51+
/// Comma-separated list of multiaddresses of known peers to connect to
52+
pub p2p_known_peers: Option<String>,
53+
54+
/// Maximum number of peers for the p2p node
55+
pub p2p_max_peer_count: u32,
4156
}
4257

4358
impl Default for FlashblocksConfig {
@@ -49,6 +64,11 @@ impl Default for FlashblocksConfig {
4964
fixed: false,
5065
calculate_state_root: true,
5166
flashblocks_number_contract_address: None,
67+
p2p_enabled: false,
68+
p2p_port: 9009,
69+
p2p_private_key_file: None,
70+
p2p_known_peers: None,
71+
p2p_max_peer_count: 50,
5272
}
5373
}
5474
}
@@ -80,6 +100,11 @@ impl TryFrom<OpRbuilderArgs> for FlashblocksConfig {
80100
fixed,
81101
calculate_state_root,
82102
flashblocks_number_contract_address,
103+
p2p_enabled: args.flashblocks.p2p.p2p_enabled,
104+
p2p_port: args.flashblocks.p2p.p2p_port,
105+
p2p_private_key_file: args.flashblocks.p2p.p2p_private_key_file,
106+
p2p_known_peers: args.flashblocks.p2p.p2p_known_peers,
107+
p2p_max_peer_count: args.flashblocks.p2p.p2p_max_peer_count,
83108
})
84109
}
85110
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ use service::FlashblocksServiceBuilder;
66
mod best_txs;
77
mod builder_tx;
88
mod config;
9+
mod p2p;
910
mod payload;
11+
mod payload_handler;
1012
mod service;
1113
mod wspub;
1214

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use alloy_primitives::U256;
2+
use reth::{core::primitives::SealedBlock, payload::PayloadId};
3+
use reth_optimism_payload_builder::OpBuiltPayload as RethOpBuiltPayload;
4+
use reth_optimism_primitives::OpBlock;
5+
use serde::{Deserialize, Serialize};
6+
7+
pub(super) const AGENT_VERSION: &str = "op-rbuilder/1.0.0";
8+
pub(super) const FLASHBLOCKS_STREAM_PROTOCOL: p2p::StreamProtocol =
9+
p2p::StreamProtocol::new("/flashblocks/1.0.0");
10+
11+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
12+
pub(super) enum Message {
13+
OpBuiltPayload(OpBuiltPayload),
14+
}
15+
16+
impl p2p::Message for Message {
17+
fn protocol(&self) -> p2p::StreamProtocol {
18+
FLASHBLOCKS_STREAM_PROTOCOL
19+
}
20+
}
21+
22+
/// Internal type analogous to [`reth_optimism_payload_builder::OpBuiltPayload`]
23+
/// which additionally implements `Serialize` and `Deserialize` for p2p transmission.
24+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
25+
pub(crate) struct OpBuiltPayload {
26+
/// Identifier of the payload
27+
pub(crate) id: PayloadId,
28+
/// Sealed block
29+
pub(crate) block: SealedBlock<OpBlock>,
30+
/// The fees of the block
31+
pub(crate) fees: U256,
32+
}
33+
34+
impl From<RethOpBuiltPayload> for Message {
35+
fn from(value: RethOpBuiltPayload) -> Self {
36+
Message::OpBuiltPayload(value.into())
37+
}
38+
}
39+
40+
impl From<OpBuiltPayload> for Message {
41+
fn from(value: OpBuiltPayload) -> Self {
42+
Message::OpBuiltPayload(value)
43+
}
44+
}
45+
46+
impl From<OpBuiltPayload> for RethOpBuiltPayload {
47+
fn from(value: OpBuiltPayload) -> Self {
48+
RethOpBuiltPayload::new(value.id, value.block.into(), value.fees, None)
49+
}
50+
}
51+
52+
impl From<RethOpBuiltPayload> for OpBuiltPayload {
53+
fn from(value: RethOpBuiltPayload) -> Self {
54+
OpBuiltPayload {
55+
id: value.id(),
56+
block: value.block().clone(),
57+
fees: value.fees(),
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)