@@ -3,7 +3,7 @@ use std::{iter::repeat, time::Duration};
3
3
use multisig:: PublicKey ;
4
4
use robusta:: { Error , Height , espresso_types:: NamespaceId } ;
5
5
use timeboost_types:: CertifiedBlock ;
6
- use tokio:: time:: sleep;
6
+ use tokio:: time:: { error :: Elapsed , sleep, timeout } ;
7
7
use tracing:: { debug, warn} ;
8
8
9
9
use crate :: config:: SubmitterConfig ;
@@ -48,7 +48,61 @@ impl<H> Submitter<H> {
48
48
}
49
49
50
50
impl Submitter < Height > {
51
- pub async fn submit ( & mut self , cb : & CertifiedBlock , force : bool ) {
51
+ pub async fn submit ( & mut self , cb : CertifiedBlock ) {
52
+ enum State {
53
+ Submit ( bool ) ,
54
+ Verify ,
55
+ }
56
+
57
+ let delay = Duration :: from_secs ( 30 ) ;
58
+ let mut state = State :: Submit ( false ) ;
59
+
60
+ loop {
61
+ match state {
62
+ State :: Submit ( force) => match timeout ( delay, self . submit_block ( & cb, force) ) . await {
63
+ Ok ( ( ) ) => state = State :: Verify ,
64
+ Err ( e) => {
65
+ debug ! (
66
+ node = %self . public_key( ) ,
67
+ num = %cb. cert( ) . data( ) . num( ) ,
68
+ "block submission timeout"
69
+ ) ;
70
+ let _: Elapsed = e;
71
+ state = State :: Submit ( true )
72
+ }
73
+ } ,
74
+ State :: Verify => match timeout ( delay, self . verify_inclusion ( & cb) ) . await {
75
+ Ok ( Ok ( ( ) ) ) => {
76
+ debug ! (
77
+ node = %self . public_key( ) ,
78
+ num = %cb. cert( ) . data( ) . num( ) ,
79
+ "block submission verified"
80
+ ) ;
81
+ return ;
82
+ }
83
+ Ok ( Err ( ( ) ) ) => {
84
+ debug ! (
85
+ node = %self . public_key( ) ,
86
+ num = %cb. cert( ) . data( ) . num( ) ,
87
+ "block submission verification failed"
88
+ ) ;
89
+ state = State :: Submit ( true )
90
+ }
91
+ Err ( e) => {
92
+ debug ! (
93
+ node = %self . public_key( ) ,
94
+ num = %cb. cert( ) . data( ) . num( ) ,
95
+ "block submission verification timeout"
96
+ ) ;
97
+ let _: Elapsed = e;
98
+ state = State :: Submit ( true )
99
+ }
100
+ } ,
101
+ }
102
+ }
103
+ }
104
+
105
+ pub async fn submit_block ( & mut self , cb : & CertifiedBlock , force : bool ) {
52
106
if !( cb. is_leader ( ) || force) {
53
107
return ;
54
108
}
@@ -68,12 +122,12 @@ impl Submitter<Height> {
68
122
}
69
123
}
70
124
71
- pub async fn verify ( & mut self , cb : & CertifiedBlock ) -> Result < ( ) , ( ) > {
125
+ pub async fn verify_inclusion ( & mut self , cb : & CertifiedBlock ) -> Result < ( ) , ( ) > {
72
126
debug ! (
73
127
node = %self . public_key( ) ,
74
128
num = %cb. cert( ) . data( ) . num( ) ,
75
129
round = %cb. cert( ) . data( ) . round( ) ,
76
- "verifying block submission "
130
+ "verifying block inclusion "
77
131
) ;
78
132
let nsid = NamespaceId :: from ( u64:: from ( u32:: from ( cb. data ( ) . namespace ( ) ) ) ) ;
79
133
let mut delays = delay_iter ( ) ;
@@ -98,7 +152,7 @@ impl Submitter<Height> {
98
152
return Err ( ( ) ) ;
99
153
}
100
154
Err ( err) => {
101
- warn ! ( node = %self . config. pubkey, %err, "error during validation " ) ;
155
+ warn ! ( node = %self . config. pubkey, %err, "error during verification " ) ;
102
156
let d = delays. next ( ) . expect ( "delay iterator repeats" ) ;
103
157
sleep ( d) . await
104
158
}
@@ -113,3 +167,93 @@ fn delay_iter() -> impl Iterator<Item = Duration> {
113
167
. chain ( repeat ( 5 ) )
114
168
. map ( Duration :: from_secs)
115
169
}
170
+
171
+ #[ cfg( test) ]
172
+ mod tests {
173
+ use bytes:: Bytes ;
174
+ use multisig:: { Committee , Keypair , PublicKey , Signed , VoteAccumulator } ;
175
+ use timeboost_types:: { Block , BlockHash , BlockInfo , BlockNumber , NamespaceId , sailfish:: Round } ;
176
+ use tokio:: { task:: JoinSet , time:: sleep} ;
177
+
178
+ use super :: * ;
179
+
180
+ struct BlockGen {
181
+ p : PublicKey ,
182
+ n : NamespaceId ,
183
+ r : Round ,
184
+ i : BlockNumber ,
185
+ k : Vec < Keypair > ,
186
+ c : Committee ,
187
+ }
188
+
189
+ impl BlockGen {
190
+ fn next ( & mut self ) -> CertifiedBlock {
191
+ let i = BlockInfo :: new ( self . i , self . r , BlockHash :: default ( ) ) ;
192
+ self . i = self . i + 1 ;
193
+ self . r . set_num ( self . r . num ( ) + 1 ) ;
194
+ let mut a = VoteAccumulator :: new ( self . c . clone ( ) ) ;
195
+ for k in & self . k {
196
+ if a. add ( Signed :: new ( i. clone ( ) , k) ) . unwrap ( ) . is_some ( ) {
197
+ break ;
198
+ }
199
+ }
200
+ let b = Block :: new ( self . n , i. round ( ) . num ( ) , * i. hash ( ) , Bytes :: new ( ) ) ;
201
+ let l = self . c . leader ( * i. round ( ) . num ( ) as usize ) == self . p ;
202
+ CertifiedBlock :: new ( a. certificate ( ) . cloned ( ) . unwrap ( ) , b, l)
203
+ }
204
+ }
205
+
206
+ #[ tokio:: test]
207
+ async fn submit_random_block ( ) {
208
+ const NODES : usize = 5 ;
209
+
210
+ let _ = tracing_subscriber:: fmt ( )
211
+ . with_env_filter ( "timeboost_builder=debug,robusta=debug" )
212
+ . try_init ( ) ;
213
+
214
+ let keys: Vec < Keypair > = ( 0 ..NODES ) . map ( |_| Keypair :: generate ( ) ) . collect ( ) ;
215
+
216
+ let committee = Committee :: new (
217
+ 0 ,
218
+ keys. iter ( )
219
+ . enumerate ( )
220
+ . map ( |( i, k) | ( i as u8 , k. public_key ( ) ) ) ,
221
+ ) ;
222
+
223
+ let rcfg = robusta:: Config :: builder ( )
224
+ . base_url ( "https://query.decaf.testnet.espresso.network/v1/" )
225
+ . unwrap ( )
226
+ . wss_base_url ( "wss://query.decaf.testnet.espresso.network/v1/" )
227
+ . unwrap ( )
228
+ . build ( ) ;
229
+
230
+ let mut tasks = JoinSet :: new ( ) ;
231
+
232
+ for k in & keys {
233
+ let mut g = BlockGen {
234
+ p : k. public_key ( ) ,
235
+ n : NamespaceId :: from ( 10_101 ) ,
236
+ r : Round :: new ( 1 , 0 ) ,
237
+ i : BlockNumber :: from ( 1 ) ,
238
+ k : keys. clone ( ) ,
239
+ c : committee. clone ( ) ,
240
+ } ;
241
+
242
+ let scfg = SubmitterConfig :: builder ( )
243
+ . pubkey ( k. public_key ( ) )
244
+ . robusta ( rcfg. clone ( ) )
245
+ . build ( ) ;
246
+
247
+ let mut s = Submitter :: new ( scfg) . init ( ) . await ;
248
+
249
+ tasks. spawn ( async move {
250
+ for _ in 0 ..3 {
251
+ s. submit ( g. next ( ) ) . await ;
252
+ sleep ( Duration :: from_secs ( rand:: random_range ( 0 ..5 ) ) ) . await
253
+ }
254
+ } ) ;
255
+ }
256
+
257
+ tasks. join_all ( ) . await ;
258
+ }
259
+ }
0 commit comments