@@ -10,10 +10,13 @@ use futures::future::join_all;
10
10
use timeboost_utils:: types:: logging:: init_logging;
11
11
use tracing:: { error, info} ;
12
12
13
+ /// Max. Difference between l2 block heights for potential race conditions when heights are fetched
14
+ /// from the sequencers
15
+ const MAX_BLOCK_HEIGHT_DIFF : u64 = 2 ;
16
+
13
17
#[ derive( Parser , Debug ) ]
14
18
struct Cli {
15
- /// Nitro node URLs used for gas estimations and getting nonce when sending transactions
16
- /// Can be specified multiple times: --nitro-url url1 --nitro-url url2
19
+ /// Nitro node URLs use to check state for different sequencers to ensure consistency
17
20
#[ clap(
18
21
long,
19
22
default_value = "http://localhost:8547;http://localhost:8647" ,
@@ -23,7 +26,7 @@ struct Cli {
23
26
nitro_urls : Vec < String > ,
24
27
}
25
28
26
- async fn connect_to_chain < N : Network > ( urls : & [ String ] ) -> Result < Vec < RootProvider < N > > > {
29
+ async fn connect_to_nitro < N : Network > ( urls : & [ String ] ) -> Result < Vec < RootProvider < N > > > {
27
30
let mut p = Vec :: new ( ) ;
28
31
for url in urls {
29
32
p. push ( RootProvider :: < N > :: connect ( url) . await ?)
@@ -36,23 +39,34 @@ async fn main() -> Result<()> {
36
39
init_logging ( ) ;
37
40
let cli = Cli :: parse ( ) ;
38
41
39
- let providers = connect_to_chain :: < Ethereum > ( & cli. nitro_urls ) . await ?;
42
+ let providers = connect_to_nitro :: < Ethereum > ( & cli. nitro_urls ) . await ?;
40
43
41
- // take the minimum block in to avoid race conditions
42
- let min_block = join_all ( providers. iter ( ) . map ( |p| async {
44
+ let block_numbers = join_all ( providers. iter ( ) . map ( |p| async {
43
45
p. get_block_number ( )
44
46
. await
45
47
. context ( "provider request failed" )
46
48
} ) )
47
49
. await
48
50
. into_iter ( )
49
- . collect :: < Result < Vec < u64 > > > ( ) ?
50
- . into_iter ( )
51
- . min ( )
52
- . context ( "failed to get min block" ) ?;
51
+ . collect :: < Result < Vec < u64 > > > ( ) ?;
52
+
53
+ let min = * block_numbers. iter ( ) . min ( ) . context ( "no blocks received" ) ?;
54
+ let max = * block_numbers. iter ( ) . max ( ) . context ( "no blocks received" ) ?;
55
+ let diff = max - min;
56
+
57
+ // ensure the max - min is within MAX_BLOCK_HEIGHT_DIFF
58
+ if diff > MAX_BLOCK_HEIGHT_DIFF {
59
+ error ! ( %max, %min, %diff, max_diff = %MAX_BLOCK_HEIGHT_DIFF , "❌ block numbers too far apart" ) ;
60
+ anyhow:: bail!(
61
+ "block numbers too far apart (min: {}, max: {}, diff: {})" ,
62
+ min,
63
+ max,
64
+ diff
65
+ ) ;
66
+ }
53
67
54
- for i in 0 ..=min_block {
55
- info ! ( num = %i , "getting block number" ) ;
68
+ // use minimum block in to avoid race conditions
69
+ for i in 0 ..=min {
56
70
let blocks = join_all ( providers. iter ( ) . map ( |p| async {
57
71
p. get_block_by_number ( BlockNumberOrTag :: Number ( i) )
58
72
. await
@@ -71,6 +85,7 @@ async fn main() -> Result<()> {
71
85
. ok_or_else ( || anyhow:: anyhow!( "provider returned no block" ) ) ?;
72
86
if b != first_block {
73
87
error ! (
88
+ num = %b. number( ) ,
74
89
block_a = ?b,
75
90
block_b = ?first_block,
76
91
"❌ block mismatch between state"
@@ -82,7 +97,7 @@ async fn main() -> Result<()> {
82
97
) ;
83
98
}
84
99
if i == blocks. len ( ) - 1 {
85
- info ! ( block_hash = %b. hash( ) , txns = ?b. transactions, "✅ verified block" ) ;
100
+ info ! ( num = %b . number ( ) , block_hash = %b. hash( ) , txns = ?b. transactions, "✅ verified block" ) ;
86
101
}
87
102
}
88
103
}
0 commit comments