reth_cli_commands/init_state/
without_evm.rs

1use 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,
10};
11use reth_stages::{StageCheckpoint, StageId};
12use reth_static_file_types::StaticFileSegment;
13use std::{fs::File, io::Read, path::PathBuf};
14use tracing::info;
15/// Reads the header RLP from a file and returns the Header.
16pub(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
28/// Creates a dummy chain (with no transactions) up to the last EVM block and appends the
29/// first valid block.
30pub 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    // Write EVM dummy data up to `header - 1` block
49    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
64/// Appends the first block.
65///
66/// By appending it, static file writer also verifies that all segments are at the same
67/// height.
68fn 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    )?;
85
86    let sf_provider = provider_rw.static_file_provider();
87
88    sf_provider.latest_writer(StaticFileSegment::Headers)?.append_header(
89        header,
90        total_difficulty,
91        &header.hash(),
92    )?;
93
94    sf_provider.latest_writer(StaticFileSegment::Receipts)?.increment_block(header.number())?;
95
96    sf_provider.latest_writer(StaticFileSegment::Transactions)?.increment_block(header.number())?;
97
98    Ok(())
99}
100
101/// Creates a dummy chain with no transactions/receipts up to `target_height` block inclusive.
102///
103/// * Headers: It will push an empty block.
104/// * Transactions: It will not push any tx, only increments the end block range.
105/// * Receipts: It will not push any receipt, only increments the end block range.
106fn append_dummy_chain<N, F>(
107    sf_provider: &StaticFileProvider<N>,
108    target_height: BlockNumber,
109    header_factory: F,
110) -> ProviderResult<()>
111where
112    N: NodePrimitives,
113    F: Fn(BlockNumber) -> N::BlockHeader + Send + Sync + 'static,
114{
115    let (tx, rx) = std::sync::mpsc::channel();
116
117    // Spawn jobs for incrementing the block end range of transactions and receipts
118    for segment in [StaticFileSegment::Transactions, StaticFileSegment::Receipts] {
119        let tx_clone = tx.clone();
120        let provider = sf_provider.clone();
121        std::thread::spawn(move || {
122            let result = provider.latest_writer(segment).and_then(|mut writer| {
123                for block_num in 1..=target_height {
124                    writer.increment_block(block_num)?;
125                }
126                Ok(())
127            });
128
129            tx_clone.send(result).unwrap();
130        });
131    }
132
133    // Spawn job for appending empty headers
134    let provider = sf_provider.clone();
135    std::thread::spawn(move || {
136        let result = provider.latest_writer(StaticFileSegment::Headers).and_then(|mut writer| {
137            for block_num in 1..=target_height {
138                // TODO: should we fill with real parent_hash?
139                let header = header_factory(block_num);
140                writer.append_header(&header, U256::ZERO, &B256::ZERO)?;
141            }
142            Ok(())
143        });
144
145        tx.send(result).unwrap();
146    });
147
148    // Catches any StaticFileWriter error.
149    while let Ok(append_result) = rx.recv() {
150        if let Err(err) = append_result {
151            tracing::error!(target: "reth::cli", "Error appending dummy chain: {err}");
152            return Err(err)
153        }
154    }
155
156    // If, for any reason, rayon crashes this verifies if all segments are at the same
157    // target_height.
158    for segment in
159        [StaticFileSegment::Headers, StaticFileSegment::Receipts, StaticFileSegment::Transactions]
160    {
161        assert_eq!(
162            sf_provider.latest_writer(segment)?.user_header().block_end(),
163            Some(target_height),
164            "Static file segment {segment} was unsuccessful advancing its block height."
165        );
166    }
167
168    Ok(())
169}