1#![expect(
2 unused_crate_dependencies,
3 reason = "binary shares same Cargo.toml as library"
4)]
5
6use std::fs::write;
7
8use clap::Parser;
9use tower::{Service, ServiceExt};
10
11use cuprate_blockchain::{
12 config::ConfigBuilder, cuprate_database::DbResult, service::BlockchainReadHandle,
13};
14use cuprate_types::{
15 blockchain::{BlockchainReadRequest, BlockchainResponse},
16 Chain,
17};
18
19use cuprate_fast_sync::FAST_SYNC_BATCH_LEN;
20
21async fn read_batch(
22 handle: &mut BlockchainReadHandle,
23 height_from: usize,
24) -> DbResult<Vec<[u8; 32]>> {
25 let request = BlockchainReadRequest::BlockHashInRange(
26 height_from..(height_from + FAST_SYNC_BATCH_LEN),
27 Chain::Main,
28 );
29 let response_channel = handle.ready().await?.call(request);
30 let response = response_channel.await?;
31
32 let BlockchainResponse::BlockHashInRange(block_ids) = response else {
33 unreachable!()
34 };
35
36 Ok(block_ids)
37}
38
39#[derive(Parser)]
40#[command(version, about, long_about = None)]
41struct Args {
42 #[arg(long)]
43 height: usize,
44}
45
46#[tokio::main]
47async fn main() {
48 let args = Args::parse();
49 let height_target = args.height;
50
51 let config = ConfigBuilder::new().build();
52
53 let (mut read_handle, _, _) = cuprate_blockchain::service::init(config).unwrap();
54
55 let mut hashes_of_hashes = Vec::new();
56
57 let mut height = 0_usize;
58
59 while (height + FAST_SYNC_BATCH_LEN) < height_target {
60 if let Ok(block_ids) = read_batch(&mut read_handle, height).await {
61 let hash = hash_of_hashes(block_ids.as_slice());
62 hashes_of_hashes.push(hash);
63 } else {
64 println!("Failed to read next batch from database");
65 break;
66 }
67 height += FAST_SYNC_BATCH_LEN;
68
69 println!("height: {height}");
70 }
71
72 drop(read_handle);
73
74 write("fast_sync_hashes.bin", hashes_of_hashes.concat().as_slice())
75 .expect("Could not write file");
76
77 println!("Generated hashes up to block height {height}");
78}
79
80pub fn hash_of_hashes(hashes: &[[u8; 32]]) -> [u8; 32] {
81 blake3::hash(hashes.concat().as_slice()).into()
82}