reth_cli_commands/init_state/
without_evm.rs1use alloy_consensus::BlockHeader;
2use alloy_primitives::{BlockNumber, B256, U256};
3use alloy_rlp::Decodable;
4use reth_codecs::Compact;
5use reth_node_builder::NodePrimitives;
6use reth_primitives_traits::{SealedBlock, SealedHeader, SealedHeaderFor};
7use reth_provider::{
8 providers::StaticFileProvider, BlockWriter, ProviderResult, StageCheckpointWriter,
9 StaticFileProviderFactory, StaticFileWriter, StorageLocation,
10};
11use reth_stages::{StageCheckpoint, StageId};
12use reth_static_file_types::StaticFileSegment;
13use std::{fs::File, io::Read, path::PathBuf};
14use tracing::info;
15pub(crate) fn read_header_from_file<H>(path: PathBuf) -> Result<H, eyre::Error>
17where
18 H: Decodable,
19{
20 let mut file = File::open(path)?;
21 let mut buf = Vec::new();
22 file.read_to_end(&mut buf)?;
23
24 let header = H::decode(&mut &buf[..])?;
25 Ok(header)
26}
27
28pub fn setup_without_evm<Provider, F>(
31 provider_rw: &Provider,
32 header: SealedHeader<<Provider::Primitives as NodePrimitives>::BlockHeader>,
33 total_difficulty: U256,
34 header_factory: F,
35) -> ProviderResult<()>
36where
37 Provider: StaticFileProviderFactory
38 + StageCheckpointWriter
39 + BlockWriter<Block = <Provider::Primitives as NodePrimitives>::Block>,
40 F: Fn(BlockNumber) -> <Provider::Primitives as NodePrimitives>::BlockHeader
41 + Send
42 + Sync
43 + 'static,
44{
45 info!(target: "reth::cli", new_tip = ?header.num_hash(), "Setting up dummy EVM chain before importing state.");
46
47 let static_file_provider = provider_rw.static_file_provider();
48 append_dummy_chain(&static_file_provider, header.number() - 1, header_factory)?;
50
51 info!(target: "reth::cli", "Appending first valid block.");
52
53 append_first_block(provider_rw, &header, total_difficulty)?;
54
55 for stage in StageId::ALL {
56 provider_rw.save_stage_checkpoint(stage, StageCheckpoint::new(header.number()))?;
57 }
58
59 info!(target: "reth::cli", "Set up finished.");
60
61 Ok(())
62}
63
64fn append_first_block<Provider>(
69 provider_rw: &Provider,
70 header: &SealedHeaderFor<Provider::Primitives>,
71 total_difficulty: U256,
72) -> ProviderResult<()>
73where
74 Provider: BlockWriter<Block = <Provider::Primitives as NodePrimitives>::Block>
75 + StaticFileProviderFactory<Primitives: NodePrimitives<BlockHeader: Compact>>,
76{
77 provider_rw.insert_block(
78 SealedBlock::<<Provider::Primitives as NodePrimitives>::Block>::from_sealed_parts(
79 header.clone(),
80 Default::default(),
81 )
82 .try_recover()
83 .expect("no senders or txes"),
84 StorageLocation::Database,
85 )?;
86
87 let sf_provider = provider_rw.static_file_provider();
88
89 sf_provider.latest_writer(StaticFileSegment::Headers)?.append_header(
90 header,
91 total_difficulty,
92 &header.hash(),
93 )?;
94
95 sf_provider.latest_writer(StaticFileSegment::Receipts)?.increment_block(header.number())?;
96
97 sf_provider.latest_writer(StaticFileSegment::Transactions)?.increment_block(header.number())?;
98
99 Ok(())
100}
101
102fn append_dummy_chain<N, F>(
108 sf_provider: &StaticFileProvider<N>,
109 target_height: BlockNumber,
110 header_factory: F,
111) -> ProviderResult<()>
112where
113 N: NodePrimitives,
114 F: Fn(BlockNumber) -> N::BlockHeader + Send + Sync + 'static,
115{
116 let (tx, rx) = std::sync::mpsc::channel();
117
118 for segment in [StaticFileSegment::Transactions, StaticFileSegment::Receipts] {
120 let tx_clone = tx.clone();
121 let provider = sf_provider.clone();
122 std::thread::spawn(move || {
123 let result = provider.latest_writer(segment).and_then(|mut writer| {
124 for block_num in 1..=target_height {
125 writer.increment_block(block_num)?;
126 }
127 Ok(())
128 });
129
130 tx_clone.send(result).unwrap();
131 });
132 }
133
134 let provider = sf_provider.clone();
136 std::thread::spawn(move || {
137 let result = provider.latest_writer(StaticFileSegment::Headers).and_then(|mut writer| {
138 for block_num in 1..=target_height {
139 let header = header_factory(block_num);
141 writer.append_header(&header, U256::ZERO, &B256::ZERO)?;
142 }
143 Ok(())
144 });
145
146 tx.send(result).unwrap();
147 });
148
149 while let Ok(append_result) = rx.recv() {
151 if let Err(err) = append_result {
152 tracing::error!(target: "reth::cli", "Error appending dummy chain: {err}");
153 return Err(err)
154 }
155 }
156
157 for segment in
160 [StaticFileSegment::Headers, StaticFileSegment::Receipts, StaticFileSegment::Transactions]
161 {
162 assert_eq!(
163 sf_provider.latest_writer(segment)?.user_header().block_end(),
164 Some(target_height),
165 "Static file segment {segment} was unsuccessful advancing its block height."
166 );
167 }
168
169 Ok(())
170}