Skip to content

Commit 6c4f9c2

Browse files
authored
Merge branch 'main' into feat-penalize-peer-on-duplicate-block
2 parents 1f7109d + b77ae04 commit 6c4f9c2

20 files changed

Lines changed: 738 additions & 50 deletions

crates/chain-orchestrator/src/handle/command.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ use crate::{ChainOrchestratorEvent, ChainOrchestratorStatus};
33
use reth_network_api::FullNetwork;
44
use reth_scroll_node::ScrollNetworkPrimitives;
55
use reth_tokio_util::EventStream;
6-
use rollup_node_primitives::{BlockInfo, L1MessageEnvelope};
6+
use rollup_node_primitives::{BlockInfo, ChainImport, L1MessageEnvelope};
77
use scroll_db::L1MessageKey;
8-
use scroll_network::ScrollNetworkHandle;
8+
use scroll_network::{NewBlockWithPeer, ScrollNetworkHandle};
99
use tokio::sync::oneshot;
1010

1111
/// The commands that can be sent to the rollup manager.
@@ -29,6 +29,13 @@ pub enum ChainOrchestratorCommand<N: FullNetwork<Primitives = ScrollNetworkPrimi
2929
DatabaseQuery(DatabaseQuery),
3030
/// Revert the rollup node state to the specified L1 block number.
3131
RevertToL1Block((u64, oneshot::Sender<bool>)),
32+
/// Import a block from a remote source.
33+
ImportBlock {
34+
/// The block to import with peer info
35+
block_with_peer: NewBlockWithPeer,
36+
/// Response channel
37+
response: oneshot::Sender<Result<ChainImport, String>>,
38+
},
3239
/// Enable gossiping of blocks to peers.
3340
#[cfg(feature = "test-utils")]
3441
SetGossip((bool, oneshot::Sender<()>)),

crates/chain-orchestrator/src/handle/mod.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use super::ChainOrchestratorEvent;
55
use reth_network_api::FullNetwork;
66
use reth_scroll_node::ScrollNetworkPrimitives;
77
use reth_tokio_util::EventStream;
8-
use rollup_node_primitives::{BlockInfo, L1MessageEnvelope};
8+
use rollup_node_primitives::{BlockInfo, ChainImport, L1MessageEnvelope};
99
use scroll_db::L1MessageKey;
10-
use scroll_network::ScrollNetworkHandle;
10+
use scroll_network::{NewBlockWithPeer, ScrollNetworkHandle};
1111
use tokio::sync::{mpsc, oneshot};
1212
use tracing::error;
1313

@@ -132,6 +132,16 @@ impl<N: FullNetwork<Primitives = ScrollNetworkPrimitives>> ChainOrchestratorHand
132132
rx.await
133133
}
134134

135+
/// Import a block from a remote source.
136+
pub async fn import_block(
137+
&self,
138+
block_with_peer: NewBlockWithPeer,
139+
) -> Result<Result<ChainImport, String>, oneshot::error::RecvError> {
140+
let (tx, rx) = oneshot::channel();
141+
self.send_command(ChainOrchestratorCommand::ImportBlock { block_with_peer, response: tx });
142+
rx.await
143+
}
144+
135145
/// Sends a command to the rollup manager to enable or disable gossiping of blocks to peers.
136146
#[cfg(feature = "test-utils")]
137147
pub async fn set_gossip(&self, enabled: bool) -> Result<(), oneshot::error::RecvError> {

crates/chain-orchestrator/src/lib.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -292,13 +292,16 @@ impl<
292292
}
293293
}
294294
SequencerEvent::PayloadReady(payload_id) => {
295-
if let Some(block) = self
295+
let block = self
296296
.sequencer
297297
.as_mut()
298298
.expect("sequencer must be present")
299299
.finalize_payload_building(payload_id, &mut self.engine)
300-
.await?
301-
{
300+
.await?;
301+
302+
self.metric_handler.finish_block_building_recording(block.as_ref());
303+
304+
if let Some(block) = block {
302305
let block_info: L2BlockInfoWithL1Messages = (&block).into();
303306
self.database
304307
.update_l1_messages_from_l2_blocks(vec![block_info.clone()])
@@ -307,7 +310,6 @@ impl<
307310
.as_mut()
308311
.expect("signer must be present")
309312
.sign_block(block.clone())?;
310-
self.metric_handler.finish_block_building_recording();
311313
return Ok(Some(ChainOrchestratorEvent::BlockSequenced(block)));
312314
}
313315
}
@@ -425,6 +427,13 @@ impl<
425427
self.notify(ChainOrchestratorEvent::UnwoundToL1Block(block_number));
426428
let _ = tx.send(true);
427429
}
430+
ChainOrchestratorCommand::ImportBlock { block_with_peer, response } => {
431+
let result = self
432+
.import_chain(vec![block_with_peer.block.clone()], block_with_peer)
433+
.await
434+
.map_err(|e| e.to_string());
435+
let _ = response.send(result);
436+
}
428437
#[cfg(feature = "test-utils")]
429438
ChainOrchestratorCommand::SetGossip((enabled, tx)) => {
430439
self.network.handle().set_gossip(enabled).await;
@@ -1229,6 +1238,7 @@ impl<
12291238
chain,
12301239
peer_id: block_with_peer.peer_id,
12311240
signature: block_with_peer.signature,
1241+
result,
12321242
})
12331243
}
12341244

crates/chain-orchestrator/src/metrics.rs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use metrics::Histogram;
22
use metrics_derive::Metrics;
3+
use reth_scroll_primitives::ScrollBlock;
34
use std::{collections::HashMap, time::Instant};
45
use strum::{EnumIter, IntoEnumIterator};
56

@@ -20,17 +21,33 @@ impl MetricsHandler {
2021

2122
/// Starts tracking a new block building task.
2223
pub(crate) fn start_block_building_recording(&mut self) {
23-
if self.block_building_meter.start.is_some() {
24+
if self.block_building_meter.block_building_start.is_some() {
2425
tracing::warn!(target: "scroll::chain_orchestrator", "block building recording is already ongoing, overwriting");
2526
}
26-
self.block_building_meter.start = Some(Instant::now());
27+
self.block_building_meter.block_building_start = Some(Instant::now());
2728
}
2829

29-
/// The duration of the current block building task if any.
30-
pub(crate) fn finish_block_building_recording(&mut self) {
31-
let duration = self.block_building_meter.start.take().map(|start| start.elapsed());
32-
if let Some(duration) = duration {
33-
self.block_building_meter.metric.block_building_duration.record(duration.as_secs_f64());
30+
/// Finishes tracking the current block building task.
31+
pub(crate) fn finish_block_building_recording(&mut self, block: Option<&ScrollBlock>) {
32+
let now = Instant::now();
33+
if let Some(t) = self.block_building_meter.block_building_start.take() {
34+
let elapsed = now.duration_since(t).as_secs_f64();
35+
self.block_building_meter.metric.all_block_building_duration.record(elapsed);
36+
37+
// Record only if it's not an empty block
38+
let is_empty_block = block.map(|b| b.body.transactions.is_empty()).unwrap_or(true);
39+
if !is_empty_block {
40+
self.block_building_meter.metric.block_building_duration.record(elapsed);
41+
}
42+
}
43+
44+
if block.is_some() {
45+
if let Some(t) = self.block_building_meter.last_block_building_time.replace(now) {
46+
self.block_building_meter
47+
.metric
48+
.consecutive_block_interval
49+
.record(now.duration_since(t).as_secs_f64());
50+
}
3451
}
3552
}
3653
}
@@ -104,13 +121,18 @@ pub(crate) struct ChainOrchestratorMetrics {
104121
#[derive(Debug, Default)]
105122
pub(crate) struct BlockBuildingMeter {
106123
metric: BlockBuildingMetric,
107-
start: Option<Instant>,
124+
block_building_start: Option<Instant>,
125+
last_block_building_time: Option<Instant>,
108126
}
109127

110128
/// Block building related metric.
111129
#[derive(Metrics, Clone)]
112130
#[metrics(scope = "chain_orchestrator")]
113131
pub(crate) struct BlockBuildingMetric {
114-
/// The duration of the block building task.
132+
/// The duration of the block building task without empty block
115133
block_building_duration: Histogram,
134+
/// The duration of the block building task for all blocks include empty block
135+
all_block_building_duration: Histogram,
136+
/// The duration of the block interval include empty block
137+
consecutive_block_interval: Histogram,
116138
}

crates/node/Cargo.toml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ async-trait.workspace = true
1919

2020
# alloy
2121
alloy-chains.workspace = true
22+
alloy-eips.workspace = true
2223
alloy-primitives.workspace = true
2324
alloy-provider.workspace = true
2425
alloy-rpc-client.workspace = true
26+
alloy-rpc-types-engine.workspace = true
2527
alloy-signer-local.workspace = true
2628
alloy-signer-aws = "1.0.30"
2729
alloy-signer = "1.0.30"
@@ -59,6 +61,7 @@ reth-rpc-api.workspace = true
5961
reth-rpc-eth-api.workspace = true
6062
reth-rpc-eth-types.workspace = true
6163
reth-tasks.workspace = true
64+
reth-tokio-util.workspace = true
6265
reth-transaction-pool.workspace = true
6366
reth-trie-db.workspace = true
6467

@@ -76,16 +79,13 @@ aws-config = "1.8.0"
7679
aws-sdk-kms = "1.76.0"
7780

7881
# test-utils
79-
alloy-eips = { workspace = true, optional = true }
8082
alloy-rpc-types-eth = { workspace = true, optional = true }
81-
alloy-rpc-types-engine = { workspace = true, optional = true }
8283
reth-e2e-test-utils = { workspace = true, optional = true }
8384
reth-engine-local = { workspace = true, optional = true }
8485
reth-provider = { workspace = true, optional = true }
8586
reth-rpc-layer = { workspace = true, optional = true }
8687
reth-rpc-server-types = { workspace = true, optional = true }
8788
reth-storage-api = { workspace = true, optional = true }
88-
reth-tokio-util = { workspace = true, optional = true }
8989
scroll-alloy-rpc-types-engine = { workspace = true, optional = true }
9090
scroll-alloy-rpc-types.workspace = true
9191

@@ -154,14 +154,11 @@ test-utils = [
154154
"reth-e2e-test-utils",
155155
"reth-rpc-server-types",
156156
"reth-rpc-layer",
157-
"reth-tokio-util",
158157
"scroll-alloy-rpc-types-engine",
159-
"alloy-rpc-types-engine",
160158
"reth-primitives-traits/test-utils",
161159
"reth-network-p2p/test-utils",
162160
"rollup-node-chain-orchestrator/test-utils",
163161
"scroll-network/test-utils",
164-
"alloy-eips",
165162
"reth-storage-api",
166163
"alloy-rpc-types-eth",
167164
]

crates/node/src/add_ons/mod.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ use std::sync::Arc;
3232
mod handle;
3333
pub use handle::ScrollAddOnsHandle;
3434

35+
mod remote_block_source;
36+
pub use remote_block_source::RemoteBlockSourceAddOn;
37+
3538
mod rpc;
3639
pub use rpc::{
3740
RollupNodeAdminApiClient, RollupNodeAdminApiServer, RollupNodeApiClient, RollupNodeApiServer,
@@ -133,6 +136,8 @@ where
133136

134137
let (tx, rx) = tokio::sync::oneshot::channel();
135138
let rpc_config = rollup_node_manager_addon.config().rpc_args.clone();
139+
let remote_block_source_config =
140+
rollup_node_manager_addon.config().remote_block_source_args.clone();
136141

137142
// Register rollupNode API and rollupNodeAdmin API if enabled
138143
let rollup_node_rpc_ext = Arc::new(RollupNodeRpcExt::<N::Network>::new(rx));
@@ -161,6 +166,22 @@ where
161166
.map_err(|_| eyre::eyre!("failed to send rollup manager handle"))?;
162167
}
163168

169+
// Launch remote block source if enabled
170+
if remote_block_source_config.enabled {
171+
let remote_source = RemoteBlockSourceAddOn::new(
172+
remote_block_source_config,
173+
rollup_manager_handle.clone(),
174+
)
175+
.await?;
176+
ctx.node
177+
.task_executor()
178+
.spawn_critical_with_shutdown_signal("remote_block_source", |shutdown| async move {
179+
if let Err(e) = remote_source.run_until_shutdown(shutdown).await {
180+
tracing::error!(target: "scroll::remote_source", ?e, "Remote block source failed");
181+
}
182+
});
183+
}
184+
164185
Ok(ScrollAddOnsHandle { rollup_manager_handle, rpc_handle })
165186
}
166187
}

0 commit comments

Comments
 (0)