Skip to content

Commit 21a4e06

Browse files
authored
fix: update builder loop to wake up at target block time (#23)
1 parent 89c8d50 commit 21a4e06

File tree

5 files changed

+34
-11
lines changed

5 files changed

+34
-11
lines changed

src/config.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ const QUINCEY_URL: &str = "QUINCEY_URL";
2020
const BUILDER_PORT: &str = "BUILDER_PORT";
2121
const SEQUENCER_KEY: &str = "SEQUENCER_KEY"; // empty (to use Quincey) OR AWS key ID (to use AWS signer) OR raw private key (to use local signer)
2222
const BUILDER_KEY: &str = "BUILDER_KEY"; // AWS key ID (to use AWS signer) OR raw private key (to use local signer)
23-
const INCOMING_TRANSACTIONS_BUFFER: &str = "INCOMING_TRANSACTIONS_BUFFER";
2423
const BLOCK_CONFIRMATION_BUFFER: &str = "BLOCK_CONFIRMATION_BUFFER";
24+
const CHAIN_OFFSET: &str = "CHAIN_OFFSET";
25+
const TARGET_SLOT_TIME: &str = "TARGET_SLOT_TIME";
2526
const BUILDER_REWARDS_ADDRESS: &str = "BUILDER_REWARDS_ADDRESS";
2627
const ROLLUP_BLOCK_GAS_LIMIT: &str = "ROLLUP_BLOCK_GAS_LIMIT";
2728
const TX_POOL_URL: &str = "TX_POOL_URL";
@@ -57,10 +58,12 @@ pub struct BuilderConfig {
5758
pub sequencer_key: Option<String>,
5859
/// Key to access Builder transaction submission wallet - AWS Key ID _OR_ local private key.
5960
pub builder_key: String,
60-
/// Buffer in seconds that Builder will wait & accept incoming transactions before bundling them and submitting as a block.
61-
pub incoming_transactions_buffer: u64,
6261
/// Buffer in seconds in which the `submitBlock` transaction must confirm on the Host chain.
6362
pub block_confirmation_buffer: u64,
63+
/// The offset between Unix time and the chain's block times. For Holesky, this is 0; for Ethereum, 11.
64+
pub chain_offset: u64,
65+
/// The slot time at which the Builder should begin building a block. 0 to begin at the very start of the slot; 6 to begin in the middle; etc.
66+
pub target_slot_time: u64,
6467
/// Address on Rollup to which Builder will receive user transaction fees.
6568
pub builder_rewards_address: Address,
6669
/// Gas limit for RU block.
@@ -147,8 +150,9 @@ impl BuilderConfig {
147150
builder_port: load_u16(BUILDER_PORT)?,
148151
sequencer_key: load_string_option(SEQUENCER_KEY),
149152
builder_key: load_string(BUILDER_KEY)?,
150-
incoming_transactions_buffer: load_u64(INCOMING_TRANSACTIONS_BUFFER)?,
151153
block_confirmation_buffer: load_u64(BLOCK_CONFIRMATION_BUFFER)?,
154+
chain_offset: load_u64(CHAIN_OFFSET)?,
155+
target_slot_time: load_u64(TARGET_SLOT_TIME)?,
152156
builder_rewards_address: load_address(BUILDER_REWARDS_ADDRESS)?,
153157
rollup_block_gas_limit: load_u64(ROLLUP_BLOCK_GAS_LIMIT)?,
154158
tx_pool_url: load_url(TX_POOL_URL)?,

src/tasks/block.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use alloy::{
44
};
55
use alloy_primitives::{keccak256, Bytes, B256};
66
use alloy_rlp::Buf;
7+
use std::time::{SystemTime, UNIX_EPOCH};
78
use std::{sync::OnceLock, time::Duration};
89
use tokio::{sync::mpsc, task::JoinHandle};
910
use tracing::Instrument;
@@ -14,6 +15,9 @@ use super::oauth::Authenticator;
1415
use super::tx_poller::TxPoller;
1516
use crate::config::BuilderConfig;
1617

18+
/// Ethereum's slot time in seconds.
19+
pub const ETHEREUM_SLOT_TIME: u64 = 12;
20+
1721
#[derive(Debug, Default, Clone)]
1822
/// A block in progress.
1923
pub struct InProgressBlock {
@@ -108,7 +112,6 @@ impl InProgressBlock {
108112

109113
/// BlockBuilder is a task that periodically builds a block then sends it for signing and submission.
110114
pub struct BlockBuilder {
111-
pub incoming_transactions_buffer: u64,
112115
pub config: BuilderConfig,
113116
pub tx_poller: TxPoller,
114117
pub bundle_poller: BundlePoller,
@@ -119,7 +122,6 @@ impl BlockBuilder {
119122
pub fn new(config: &BuilderConfig, authenticator: Authenticator) -> Self {
120123
Self {
121124
config: config.clone(),
122-
incoming_transactions_buffer: config.incoming_transactions_buffer,
123125
tx_poller: TxPoller::new(config),
124126
bundle_poller: BundlePoller::new(config, authenticator),
125127
}
@@ -155,15 +157,27 @@ impl BlockBuilder {
155157
self.bundle_poller.evict();
156158
}
157159

160+
// calculate the duration in seconds until the beginning of the next block slot.
161+
fn secs_to_next_slot(&mut self) -> u64 {
162+
let curr_timestamp: u64 = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
163+
let current_slot_time = (curr_timestamp - self.config.chain_offset) % ETHEREUM_SLOT_TIME;
164+
(ETHEREUM_SLOT_TIME - current_slot_time) % ETHEREUM_SLOT_TIME
165+
}
166+
167+
// add a buffer to the beginning of the block slot.
168+
fn secs_to_next_target(&mut self) -> u64 {
169+
self.secs_to_next_slot() + self.config.target_slot_time
170+
}
171+
158172
/// Spawn the block builder task, returning the inbound channel to it, and
159173
/// a handle to the running task.
160174
pub fn spawn(mut self, outbound: mpsc::UnboundedSender<InProgressBlock>) -> JoinHandle<()> {
161175
tokio::spawn(
162176
async move {
163177
loop {
164178
// sleep the buffer time
165-
tokio::time::sleep(Duration::from_secs(self.incoming_transactions_buffer))
166-
.await;
179+
tokio::time::sleep(Duration::from_secs(self.secs_to_next_target())).await;
180+
tracing::trace!("beginning block build cycle");
167181

168182
// Build a block
169183
let mut in_progress = InProgressBlock::default();
@@ -178,6 +192,8 @@ impl BlockBuilder {
178192
tracing::debug!("downstream task gone");
179193
break;
180194
}
195+
} else {
196+
tracing::debug!("no transactions, skipping block submission");
181197
}
182198
}
183199
}

src/tasks/oauth.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,9 @@ mod tests {
145145
builder_port: 8080,
146146
sequencer_key: None,
147147
builder_key: "0000000000000000000000000000000000000000000000000000000000000000".into(),
148-
incoming_transactions_buffer: 1,
149148
block_confirmation_buffer: 1,
149+
chain_offset: 0,
150+
target_slot_time: 1,
150151
builder_rewards_address: Address::default(),
151152
rollup_block_gas_limit: 100_000,
152153
tx_pool_url: "http://localhost:9000/".into(),

tests/bundle_poller_test.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ mod tests {
2626
builder_port: 8080,
2727
sequencer_key: None,
2828
builder_key: "0000000000000000000000000000000000000000000000000000000000000000".into(),
29-
incoming_transactions_buffer: 1,
3029
block_confirmation_buffer: 1,
30+
chain_offset: 0,
31+
target_slot_time: 1,
3132
builder_rewards_address: Address::default(),
3233
rollup_block_gas_limit: 100_000,
3334
tx_pool_url: "http://localhost:9000/".into(),

tests/tx_poller_test.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ mod tests {
7474
builder_port: 8080,
7575
sequencer_key: None,
7676
builder_key: "0000000000000000000000000000000000000000000000000000000000000000".into(),
77-
incoming_transactions_buffer: 1,
7877
block_confirmation_buffer: 1,
78+
chain_offset: 0,
79+
target_slot_time: 1,
7980
builder_rewards_address: Address::default(),
8081
rollup_block_gas_limit: 100_000,
8182
tx_pool_url: "http://localhost:9000/".into(),

0 commit comments

Comments
 (0)