Skip to content

Commit cf95a4f

Browse files
committed
Remove timer.
Instead use `interval` to update the time every second (unless busy sending).
1 parent 580a1a1 commit cf95a4f

File tree

4 files changed

+55
-90
lines changed

4 files changed

+55
-90
lines changed

timeboost-builder/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ pub use robusta;
88
pub use certifier::{Certifier, CertifierDown, CertifierError, Handle};
99
pub use config::{CertifierConfig, CertifierConfigBuilder};
1010
pub use config::{SubmitterConfig, SubmitterConfigBuilder};
11-
pub use submit::Submitter;
11+
pub use submit::{SenderTaskDown, Submitter};

timeboost-builder/src/submit.rs

Lines changed: 49 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
1-
use std::{collections::HashMap, sync::Arc, time::Duration};
1+
use std::{collections::BTreeMap, mem, sync::Arc, time::Duration};
22

33
use bon::Builder;
44
use multisig::{Committee, PublicKey, Validated};
55
use robusta::{Client, espresso_types::NamespaceId};
66
use timeboost_types::{
7-
BlockNumber, CertifiedBlock,
7+
CertifiedBlock,
88
sailfish::{CommitteeVec, Empty},
99
};
1010
use tokio::{
1111
select, spawn,
1212
sync::{Mutex, mpsc},
1313
task::JoinHandle,
14-
time::sleep,
14+
time::{Instant, MissedTickBehavior, interval, sleep},
1515
};
1616
use tracing::{debug, warn};
1717

18-
mod time;
1918
mod verify;
2019

2120
use crate::{config::SubmitterConfig, metrics::BuilderMetrics};
22-
use time::Timer;
2321
use verify::{Verified, Verifier};
2422

2523
const DELAY: Duration = Duration::from_secs(30);
@@ -62,10 +60,10 @@ impl Submitter {
6260
let sender = Sender::builder()
6361
.label(cfg.pubkey)
6462
.nsid(cfg.namespace)
65-
.timer(Timer::new(cfg.pubkey))
6663
.client(client)
6764
.verified(verified.clone())
6865
.receiver(rx)
66+
.clock(Instant::now())
6967
.build();
7068
let mut configs = vec![cfg.robusta.0.clone()];
7169
configs.extend(cfg.robusta.1.iter().cloned());
@@ -88,88 +86,92 @@ impl Submitter {
8886
self.committees.lock().await.add(c);
8987
}
9088

91-
pub async fn submit(&mut self, cb: CertifiedBlock<Validated>) {
89+
pub async fn submit(&mut self, cb: CertifiedBlock<Validated>) -> Result<(), SenderTaskDown> {
9290
self.metrics.blocks_submitted.add(1);
9391
if self.verified.contains(cb.cert().data().num()) {
94-
return;
92+
return Ok(());
9593
}
96-
self.sender.send(cb).await.unwrap() // TODO
94+
self.sender.send(cb).await.map_err(|_| SenderTaskDown(()))
9795
}
9896
}
9997

98+
#[derive(Debug, thiserror::Error)]
99+
#[error("submit sender task terminated")]
100+
pub struct SenderTaskDown(());
101+
100102
#[derive(Builder)]
101103
struct Sender {
102104
label: PublicKey,
103-
timer: Timer<BlockNumber>,
104105
nsid: NamespaceId,
105106
client: Client,
106107
verified: Verified<15_000>,
107108
receiver: mpsc::Receiver<CertifiedBlock<Validated>>,
109+
clock: Instant,
110+
#[builder(default)]
111+
pending: BTreeMap<Instant, Vec<CertifiedBlock<Validated>>>,
108112
}
109113

110114
impl Sender {
111115
async fn go(mut self) {
112-
let mut pending = HashMap::new();
113116
let mut inbox = Vec::new();
114117
let mut outbox = Vec::new();
115-
let mut timeouts = Vec::new();
116118

117-
loop {
119+
let drop_verified_blocks = |v: &mut Vec<CertifiedBlock<Validated>>| {
120+
v.retain(|b| !self.verified.contains(b.cert().data().num()));
121+
};
122+
123+
let mut checkpoints = interval(Duration::from_secs(1));
124+
checkpoints.set_missed_tick_behavior(MissedTickBehavior::Skip);
125+
126+
'main: loop {
118127
select! {
119128
k = self.receiver.recv_many(&mut inbox, 10) => {
120-
if k == 0 {
129+
if k == 0 { // channel is closed
121130
return
122-
} else {
123-
for b in inbox.drain(..) {
124-
let n = b.cert().data().num();
125-
if self.verified.contains(n) {
126-
continue
127-
}
128-
if b.is_leader() {
129-
outbox.push(b)
130-
} else {
131-
pending.insert(n, b);
132-
}
133-
self.timer.set(n, DELAY)
134-
}
135-
}
136-
},
137-
n = self.timer.next() => {
138-
timeouts.push(n);
139-
while let Some(n) = self.timer.try_next() {
140-
timeouts.push(n)
141131
}
142-
timeouts.sort();
143-
for n in timeouts.drain(..) {
144-
let Some(b) = pending.remove(&n) else {
145-
continue
146-
};
147-
if self.verified.contains(n) {
148-
continue
132+
for b in inbox.drain(..) {
133+
if b.is_leader() {
134+
outbox.push(b)
135+
} else {
136+
self.pending.entry(self.clock + DELAY).or_default().push(b);
149137
}
150-
debug!(node = %self.label, num = %n, "block timeout");
151-
outbox.push(b)
152138
}
153139
}
140+
t = checkpoints.tick() => {
141+
self.clock = t;
142+
// Move blocks that timed out into `outbox`:
143+
let mut blocks = self.pending.split_off(&self.clock);
144+
mem::swap(&mut blocks, &mut self.pending);
145+
outbox.extend(blocks.into_values().flatten());
146+
}
154147
}
155148

149+
drop_verified_blocks(&mut outbox);
150+
156151
if outbox.is_empty() {
157152
continue;
158153
}
159154

160-
let mut delays = self.client.config().delay_iter();
155+
// TODO: Ensure that the resulting payload size does not exceed the allowed maximum.
161156

162157
debug!(node = %self.label, blocks = %outbox.len(), "submitting blocks");
163158

159+
let mut delays = self.client.config().delay_iter();
160+
164161
while let Err(err) = self.client.submit(self.nsid, &outbox).await {
165162
warn!(node= %self.label, %err, "error submitting blocks");
166163
let d = delays.next().expect("delay iterator repeats");
167-
sleep(d).await
164+
sleep(d).await;
165+
drop_verified_blocks(&mut outbox);
166+
if outbox.is_empty() {
167+
continue 'main;
168+
}
168169
}
169170

170-
for b in outbox.drain(..) {
171-
pending.insert(b.cert().data().num(), b);
172-
}
171+
self.pending
172+
.entry(self.clock + DELAY)
173+
.or_default()
174+
.append(&mut outbox);
173175
}
174176
}
175177
}

timeboost-builder/src/submit/time.rs

Lines changed: 0 additions & 40 deletions
This file was deleted.

timeboost/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use ::metrics::prometheus::PrometheusMetrics;
77
use anyhow::Result;
88
use metrics::TimeboostMetrics;
99
use multisig::PublicKey;
10-
use timeboost_builder::{Certifier, CertifierDown, Submitter};
10+
use timeboost_builder::{Certifier, CertifierDown, SenderTaskDown, Submitter};
1111
use timeboost_sequencer::{Output, Sequencer};
1212
use timeboost_types::BundleVariant;
1313
use tokio::select;
@@ -121,7 +121,10 @@ impl Timeboost {
121121
blk = self.certifier.next_block() => match blk {
122122
Ok(b) => {
123123
info!(node = %self.label, block = %b.data().round(), "certified block");
124-
self.submitter.submit(b).await
124+
if let Err(e) = self.submitter.submit(b).await {
125+
let e: SenderTaskDown = e;
126+
return Err(e.into())
127+
}
125128
}
126129
Err(e) => {
127130
let e: CertifierDown = e;

0 commit comments

Comments
 (0)