Skip to content

Commit 36f8ae8

Browse files
committed
start
1 parent 115833f commit 36f8ae8

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ members = [
1717
"timeboost-types",
1818
"timeboost-utils",
1919
"yapper",
20+
"tests/block-verifier"
2021
]
2122
resolver = "2"
2223

tests/block-verifier/Cargo.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "block_verifier"
3+
version.workspace = true
4+
edition.workspace = true
5+
rust-version.workspace = true
6+
7+
[dependencies]
8+
alloy = { workspace = true }
9+
anyhow = { workspace = true }
10+
clap = { workspace = true }
11+
futures = { workspace = true }
12+
timeboost-utils = { path = "../../timeboost-utils" }
13+
tokio = { workspace = true }
14+
tracing = { workspace = true }

tests/block-verifier/src/main.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use alloy::{
2+
eips::BlockNumberOrTag,
3+
network::{Ethereum, Network},
4+
providers::{Provider, RootProvider},
5+
rpc::types::Block,
6+
};
7+
use anyhow::{Context, Result};
8+
use clap::Parser;
9+
use futures::future::join_all;
10+
use timeboost_utils::types::logging::init_logging;
11+
use tracing::{error, info};
12+
13+
#[derive(Parser, Debug)]
14+
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
17+
#[clap(
18+
long,
19+
default_value = "http://localhost:8547;http://localhost:8647",
20+
use_value_delimiter = true,
21+
value_delimiter = ';'
22+
)]
23+
nitro_urls: Vec<String>,
24+
}
25+
26+
async fn connect_to_chain<N: Network>(urls: &[String]) -> Result<Vec<RootProvider<N>>> {
27+
let mut p = Vec::new();
28+
for url in urls {
29+
p.push(RootProvider::<N>::connect(url).await?)
30+
}
31+
Ok(p)
32+
}
33+
34+
#[tokio::main]
35+
async fn main() -> Result<()> {
36+
init_logging();
37+
let cli = Cli::parse();
38+
39+
let providers = connect_to_chain::<Ethereum>(&cli.nitro_urls).await?;
40+
41+
// take the minimum block in to avoid race conditions
42+
let min_block = join_all(providers.iter().map(|p| async {
43+
p.get_block_number()
44+
.await
45+
.map(|b| b)
46+
.context("provider request failed")
47+
}))
48+
.await
49+
.into_iter()
50+
.collect::<Result<Vec<u64>>>()?
51+
.into_iter()
52+
.min()
53+
.context("failed to get min block")?;
54+
55+
for i in 0..=min_block {
56+
info!(num = %i, "getting block number");
57+
let blocks = join_all(providers.iter().map(|p| async {
58+
p.get_block_by_number(BlockNumberOrTag::Number(i))
59+
.await
60+
.map(|b| b)
61+
.context("provider request failed")
62+
}))
63+
.await
64+
.into_iter()
65+
.collect::<Result<Vec<Option<Block>>>>()?;
66+
let first_block = blocks
67+
.first()
68+
.and_then(|b| b.as_ref())
69+
.ok_or_else(|| anyhow::anyhow!("No blocks received from any provider"))?;
70+
info!(hash = %first_block.hash(), "verifying against block hash");
71+
for block in blocks.iter().skip(1) {
72+
let b = block
73+
.as_ref()
74+
.ok_or_else(|| anyhow::anyhow!("provider returned no block"))?;
75+
if b != first_block {
76+
error!(
77+
block_a = ?b,
78+
block_b = ?first_block,
79+
"block mismatch between block state"
80+
);
81+
anyhow::bail!(
82+
"block mismatch between blocks: left: {:?}, right: {:?}",
83+
b,
84+
first_block
85+
);
86+
}
87+
}
88+
}
89+
90+
Ok(())
91+
}

0 commit comments

Comments
 (0)