Skip to content

Commit ce8b77a

Browse files
authored
feat: break payload building (#238)
* feat: break payload building Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> * fix: lints Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> * feat: breaker provider Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> * feat: update payload building Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> * fix: lint Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> --------- Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com>
1 parent 6f544fb commit ce8b77a

9 files changed

Lines changed: 102 additions & 70 deletions

File tree

Cargo.lock

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

crates/scroll/alloy/provider/Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ workspace = true
1313

1414
[dependencies]
1515
# alloy
16-
alloy-json-rpc.workspace = true
1716
alloy-provider.workspace = true
1817
alloy-primitives.workspace = true
1918
alloy-rpc-types-engine = { workspace = true, features = ["serde"] }
@@ -40,7 +39,6 @@ reqwest.workspace = true
4039
tower.workspace = true
4140
thiserror.workspace = true
4241
jsonrpsee.workspace = true
43-
jsonrpsee-types.workspace = true
4442

4543
[dev-dependencies]
4644
reth-payload-builder = { workspace = true, features = ["test-utils"] }
@@ -72,7 +70,6 @@ std = [
7270
"reth-engine-primitives/std",
7371
"reth-primitives/std",
7472
"reth-primitives-traits/std",
75-
"reth-scroll-payload/std",
7673
"futures-util/std",
7774
"reth-scroll-chainspec/std",
7875
"thiserror/std",

crates/scroll/node/src/builder/payload.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,30 @@ use reth_scroll_evm::ScrollNextBlockEnvAttributes;
1010
use reth_scroll_payload::{ScrollBuilderConfig, ScrollPayloadTransactions};
1111
use reth_scroll_primitives::{ScrollPrimitives, ScrollTransactionSigned};
1212
use reth_transaction_pool::{PoolTransaction, TransactionPool};
13+
use std::time::Duration;
1314

1415
/// Payload builder for Scroll.
15-
#[derive(Debug, Clone, Default, Copy)]
16-
pub struct ScrollPayloadBuilder<Txs = ()> {
16+
#[derive(Debug, Clone, Copy)]
17+
pub struct ScrollPayloadBuilderBuilder<Txs = ()> {
1718
/// Returns the current best transactions from the mempool.
1819
pub best_transactions: Txs,
20+
/// The payload building time limit.
21+
pub payload_building_time_limit: Duration,
22+
}
23+
24+
impl Default for ScrollPayloadBuilderBuilder {
25+
fn default() -> Self {
26+
Self {
27+
best_transactions: (),
28+
payload_building_time_limit: SCROLL_PAYLOAD_BUILDING_DURATION,
29+
}
30+
}
1931
}
2032

2133
const SCROLL_GAS_LIMIT: u64 = 20_000_000;
34+
const SCROLL_PAYLOAD_BUILDING_DURATION: Duration = Duration::from_secs(1);
2235

23-
impl<Txs> ScrollPayloadBuilder<Txs> {
36+
impl<Txs> ScrollPayloadBuilderBuilder<Txs> {
2437
/// A helper method to initialize [`reth_scroll_payload::ScrollPayloadBuilder`] with the
2538
/// given EVM config.
2639
pub fn build<Node, Evm, Pool>(
@@ -43,26 +56,25 @@ impl<Txs> ScrollPayloadBuilder<Txs> {
4356
Evm: ConfigureEvm<Primitives = PrimitivesTy<Node::Types>>,
4457
Txs: ScrollPayloadTransactions<Pool::Transaction>,
4558
{
46-
let gas_limit = if let Some(gas) = ctx.payload_builder_config().gas_limit() {
47-
gas
48-
} else {
59+
let gas_limit = ctx.payload_builder_config().gas_limit().unwrap_or_else (|| {
4960
tracing::warn!(target: "reth::cli", "Using {SCROLL_GAS_LIMIT} gas limit for ScrollPayloadBuilder. Configure with --builder.gaslimit");
5061
SCROLL_GAS_LIMIT
51-
};
62+
});
5263

5364
let payload_builder = reth_scroll_payload::ScrollPayloadBuilder::new(
5465
pool,
5566
evm_config,
5667
ctx.provider().clone(),
57-
ScrollBuilderConfig::new(gas_limit),
68+
ScrollBuilderConfig::new(gas_limit, self.payload_building_time_limit),
5869
)
5970
.with_transactions(self.best_transactions);
6071

6172
Ok(payload_builder)
6273
}
6374
}
6475

65-
impl<Node, Pool, Txs, Evm> PayloadBuilderBuilder<Node, Pool, Evm> for ScrollPayloadBuilder<Txs>
76+
impl<Node, Pool, Txs, Evm> PayloadBuilderBuilder<Node, Pool, Evm>
77+
for ScrollPayloadBuilderBuilder<Txs>
6678
where
6779
Node: FullNodeTypes<
6880
Types: NodeTypes<

crates/scroll/node/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub use builder::{
55
engine::{ScrollEngineValidator, ScrollEngineValidatorBuilder},
66
execution::ScrollExecutorBuilder,
77
network::{ScrollHeaderTransform, ScrollNetworkBuilder, ScrollNetworkPrimitives},
8-
payload::ScrollPayloadBuilder,
8+
payload::ScrollPayloadBuilderBuilder,
99
pool::ScrollPoolBuilder,
1010
};
1111

crates/scroll/node/src/node.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use crate::{
44
ScrollAddOns, ScrollConsensusBuilder, ScrollExecutorBuilder, ScrollNetworkBuilder,
5-
ScrollPayloadBuilder, ScrollPoolBuilder, ScrollStorage,
5+
ScrollPayloadBuilderBuilder, ScrollPoolBuilder, ScrollStorage,
66
};
77
use reth_node_builder::{
88
components::{BasicPayloadServiceBuilder, ComponentsBuilder},
@@ -23,7 +23,7 @@ impl ScrollNode {
2323
pub fn components<Node>() -> ComponentsBuilder<
2424
Node,
2525
ScrollPoolBuilder,
26-
BasicPayloadServiceBuilder<ScrollPayloadBuilder>,
26+
BasicPayloadServiceBuilder<ScrollPayloadBuilderBuilder>,
2727
ScrollNetworkBuilder,
2828
ScrollExecutorBuilder,
2929
ScrollConsensusBuilder,
@@ -41,7 +41,7 @@ impl ScrollNode {
4141
.node_types::<Node>()
4242
.pool(ScrollPoolBuilder::default())
4343
.executor(ScrollExecutorBuilder::default())
44-
.payload(BasicPayloadServiceBuilder::new(ScrollPayloadBuilder::default()))
44+
.payload(BasicPayloadServiceBuilder::new(ScrollPayloadBuilderBuilder::default()))
4545
.network(ScrollNetworkBuilder)
4646
.executor(ScrollExecutorBuilder)
4747
.consensus(ScrollConsensusBuilder)
@@ -55,7 +55,7 @@ where
5555
type ComponentsBuilder = ComponentsBuilder<
5656
N,
5757
ScrollPoolBuilder,
58-
BasicPayloadServiceBuilder<ScrollPayloadBuilder>,
58+
BasicPayloadServiceBuilder<ScrollPayloadBuilderBuilder>,
5959
ScrollNetworkBuilder,
6060
ScrollExecutorBuilder,
6161
ScrollConsensusBuilder,

crates/scroll/payload/Cargo.toml

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ alloy-primitives.workspace = true
2121
reth-scroll-evm.workspace = true
2222
scroll-alloy-hardforks.workspace = true
2323
scroll-alloy-evm.workspace = true
24-
scroll-alloy-consensus.workspace = true
2524

2625
# revm
2726
revm.workspace = true
@@ -36,8 +35,6 @@ reth-payload-builder.workspace = true
3635
reth-payload-primitives.workspace = true
3736
reth-primitives-traits.workspace = true
3837
reth-revm.workspace = true
39-
reth-scroll-chainspec.workspace = true
40-
reth-scroll-forks.workspace = true
4138
reth-storage-api.workspace = true
4239
reth-transaction-pool.workspace = true
4340
reth-payload-util.workspace = true
@@ -52,28 +49,6 @@ thiserror.workspace = true
5249
tracing.workspace = true
5350

5451
[features]
55-
std = [
56-
"futures-util/std",
57-
"reth-payload-primitives/std",
58-
"reth-primitives-traits/std",
59-
"reth-scroll-engine-primitives/std",
60-
"alloy-consensus/std",
61-
"alloy-primitives/std",
62-
"alloy-rlp/std",
63-
"reth-chainspec/std",
64-
"reth-evm/std",
65-
"reth-execution-types/std",
66-
"reth-revm/std",
67-
"reth-storage-api/std",
68-
"revm/std",
69-
"thiserror/std",
70-
"tracing/std",
71-
"reth-scroll-chainspec/std",
72-
"reth-scroll-forks/std",
73-
"scroll-alloy-consensus/std",
74-
"scroll-alloy-hardforks/std",
75-
"scroll-alloy-evm/std",
76-
]
7752
test-utils = [
7853
"dep:futures-util",
7954
"reth-payload-builder/test-utils",

crates/scroll/payload/src/builder.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Scroll's payload builder implementation.
22
33
use super::{PayloadBuildingBaseFeeProvider, ScrollPayloadBuilderError};
4-
use crate::config::ScrollBuilderConfig;
4+
use crate::config::{PayloadBuildingBreaker, ScrollBuilderConfig};
55

66
use alloy_consensus::{Transaction, Typed2718};
77
use alloy_primitives::{B256, U256};
@@ -57,7 +57,7 @@ impl<T: PoolTransaction> ScrollPayloadTransactions<T> for () {
5757
}
5858

5959
/// Scroll's payload builder.
60-
#[derive(Debug, Clone)]
60+
#[derive(Clone, Debug)]
6161
pub struct ScrollPayloadBuilder<Pool, Client, Evm, Txs = ()> {
6262
/// The type responsible for creating the evm.
6363
pub evm_config: Evm,
@@ -134,15 +134,10 @@ where
134134
let state = StateProviderDatabase::new(&state_provider);
135135

136136
if ctx.attributes().no_tx_pool {
137-
builder.build(state, &state_provider, ctx, self.builder_config.clone())
137+
builder.build(state, &state_provider, ctx, &self.builder_config)
138138
} else {
139139
// sequencer mode we can reuse cachedreads from previous runs
140-
builder.build(
141-
cached_reads.as_db_mut(state),
142-
&state_provider,
143-
ctx,
144-
self.builder_config.clone(),
145-
)
140+
builder.build(cached_reads.as_db_mut(state), &state_provider, ctx, &self.builder_config)
146141
}
147142
.map(|out| out.with_cached_reads(cached_reads))
148143
}
@@ -222,7 +217,7 @@ impl<Txs> ScrollBuilder<'_, Txs> {
222217
db: impl Database<Error = ProviderError>,
223218
state_provider: impl StateProvider,
224219
ctx: ScrollPayloadBuilderCtx<EvmConfig, ChainSpec>,
225-
builder_config: ScrollBuilderConfig,
220+
builder_config: &ScrollBuilderConfig,
226221
) -> Result<BuildOutcomeKind<ScrollBuiltPayload>, PayloadBuilderError>
227222
where
228223
EvmConfig: ConfigureEvm<
@@ -234,6 +229,7 @@ impl<Txs> ScrollBuilder<'_, Txs> {
234229
{
235230
let Self { best } = self;
236231
tracing::debug!(target: "payload_builder", id=%ctx.payload_id(), parent_header = ?ctx.parent().hash(), parent_number = ctx.parent().number, "building new payload");
232+
let breaker = builder_config.breaker();
237233

238234
let mut db = State::builder().with_database(db).with_bundle_update().build();
239235

@@ -251,8 +247,9 @@ impl<Txs> ScrollBuilder<'_, Txs> {
251247
// 3. if mem pool transactions are requested we execute them
252248
if !ctx.attributes().no_tx_pool {
253249
let best_txs = best(ctx.best_transaction_attributes(builder.evm_mut().block()));
254-
if ctx.execute_best_transactions(&mut info, &mut builder, best_txs)?.is_some() {
255-
return Ok(BuildOutcomeKind::Cancelled)
250+
if ctx.execute_best_transactions(&mut info, &mut builder, best_txs, breaker)?.is_some()
251+
{
252+
return Ok(BuildOutcomeKind::Cancelled);
256253
}
257254

258255
// check if the new payload is even more valuable
@@ -371,7 +368,7 @@ where
371368
pub fn block_builder<'a, DB: Database>(
372369
&'a self,
373370
db: &'a mut State<DB>,
374-
builder_config: ScrollBuilderConfig,
371+
builder_config: &ScrollBuilderConfig,
375372
) -> Result<impl BlockBuilder<Primitives = Evm::Primitives> + 'a, PayloadBuilderError> {
376373
// get the base fee for the attributes.
377374
let base_fee: u64 = if self.chain_spec.is_curie_active_at_block(self.parent().number + 1) {
@@ -390,7 +387,7 @@ where
390387
ScrollNextBlockEnvAttributes {
391388
timestamp: self.attributes().timestamp(),
392389
suggested_fee_recipient: self.attributes().suggested_fee_recipient(),
393-
gas_limit: builder_config.desired_gas_limit,
390+
gas_limit: builder_config.gas_limit,
394391
base_fee,
395392
},
396393
)
@@ -459,6 +456,7 @@ where
459456
mut best_txs: impl PayloadTransactions<
460457
Transaction: PoolTransaction<Consensus = TxTy<Evm::Primitives>>,
461458
>,
459+
breaker: PayloadBuildingBreaker,
462460
) -> Result<Option<()>, PayloadBuilderError> {
463461
let block_gas_limit = builder.evm_mut().block().gas_limit;
464462
let base_fee = builder.evm_mut().block().basefee;
@@ -484,6 +482,12 @@ where
484482
return Ok(Some(()))
485483
}
486484

485+
// check if the execution needs to be halted.
486+
if breaker.should_break(info.cumulative_gas_used) {
487+
tracing::trace!(target: "scroll::payload_builder", ?info, "breaking execution loop");
488+
return Ok(None);
489+
}
490+
487491
let gas_used = match builder.execute_transaction(tx.clone()) {
488492
Ok(gas_used) => gas_used,
489493
Err(BlockExecutionError::Validation(BlockValidationError::InvalidTx {
Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,68 @@
11
//! Configuration for the payload builder.
22
3+
use core::time::Duration;
4+
use reth_chainspec::MIN_TRANSACTION_GAS;
5+
use std::{fmt::Debug, time::Instant};
6+
37
/// Settings for the Scroll builder.
4-
#[derive(PartialEq, Eq, Clone, Debug)]
8+
#[derive(Debug, PartialEq, Eq, Clone)]
59
pub struct ScrollBuilderConfig {
6-
/// Desired gas limit.
7-
pub desired_gas_limit: u64,
10+
/// Gas limit.
11+
pub gas_limit: u64,
12+
/// Time limit for payload building.
13+
pub time_limit: Duration,
814
}
915

1016
impl ScrollBuilderConfig {
1117
/// Returns a new instance of [`ScrollBuilderConfig`].
12-
pub const fn new(desired_gas_limit: u64) -> Self {
13-
Self { desired_gas_limit }
18+
pub const fn new(gas_limit: u64, time_limit: Duration) -> Self {
19+
Self { gas_limit, time_limit }
20+
}
21+
22+
/// Returns the [`PayloadBuildingBreaker`] for the config.
23+
pub(super) fn breaker(&self) -> PayloadBuildingBreaker {
24+
PayloadBuildingBreaker::new(self.time_limit, self.gas_limit)
25+
}
26+
}
27+
28+
/// Used in the [`super::ScrollPayloadBuilder`] to exit the transactions execution loop early.
29+
#[derive(Debug, Clone)]
30+
pub struct PayloadBuildingBreaker {
31+
start: Instant,
32+
time_limit: Duration,
33+
gas_limit: u64,
34+
}
35+
36+
impl PayloadBuildingBreaker {
37+
/// Returns a new instance of the [`PayloadBuildingBreaker`].
38+
fn new(time_limit: Duration, gas_limit: u64) -> Self {
39+
Self { start: Instant::now(), time_limit, gas_limit }
40+
}
41+
42+
/// Returns whether the payload building should stop.
43+
pub(super) fn should_break(&self, cumulative_gas_used: u64) -> bool {
44+
self.start.elapsed() >= self.time_limit ||
45+
cumulative_gas_used > self.gas_limit.saturating_sub(MIN_TRANSACTION_GAS)
46+
}
47+
}
48+
49+
#[cfg(test)]
50+
mod tests {
51+
use super::*;
52+
53+
#[test]
54+
fn test_should_break_on_time_limit() {
55+
let breaker =
56+
PayloadBuildingBreaker::new(Duration::from_millis(200), 2 * MIN_TRANSACTION_GAS);
57+
assert!(!breaker.should_break(MIN_TRANSACTION_GAS));
58+
std::thread::sleep(Duration::from_millis(201));
59+
assert!(breaker.should_break(MIN_TRANSACTION_GAS));
60+
}
61+
62+
#[test]
63+
fn test_should_break_on_gas_limit() {
64+
let breaker = PayloadBuildingBreaker::new(Duration::from_secs(1), 2 * MIN_TRANSACTION_GAS);
65+
assert!(!breaker.should_break(MIN_TRANSACTION_GAS));
66+
assert!(breaker.should_break(MIN_TRANSACTION_GAS + 1));
1467
}
1568
}

0 commit comments

Comments
 (0)