feat: Enable testnet block recovery

This commit is contained in:
sprites0
2025-04-29 03:57:09 +00:00
parent db419400c2
commit 41d72ae949
3 changed files with 50 additions and 31 deletions

View File

@ -12,7 +12,7 @@ use reth_provider::{
BlockNumReader, DatabaseProviderFactory, StaticFileProviderFactory, StaticFileWriter,
};
use std::{io::BufReader, path::PathBuf, str::FromStr};
use tracing::info;
use tracing::{info, warn};
pub mod without_evm;
@ -40,7 +40,7 @@ pub struct InitStateCommand<C: ChainSpecParser> {
/// Allows init at a non-genesis block. Caution! Blocks must be manually imported up until
/// and including the non-genesis block to init chain at. See 'import' command.
#[arg(value_name = "STATE_DUMP_FILE", verbatim_doc_comment)]
pub state: PathBuf,
pub state: Option<PathBuf>,
/// Specifies whether to initialize the state without relying on EVM historical data.
///
@ -63,6 +63,10 @@ pub struct InitStateCommand<C: ChainSpecParser> {
/// Hash of the header.
#[arg(long, value_name = "HEADER_HASH", verbatim_doc_comment)]
pub header_hash: Option<String>,
/// Force the initialization of the state even if the data directory is not empty.
#[arg(long)]
pub force: bool,
}
impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> InitStateCommand<C> {
@ -98,10 +102,25 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> InitStateC
let last_block_number = provider_rw.last_block_number()?;
if last_block_number == 0 {
info!(target: "reth::cli", "Data directory is empty, setting up dummy chain");
} else if last_block_number > 0 && last_block_number < header.number {
if !self.force {
return Err(eyre::eyre!(
"Data directory is not empty, use --force to override"
));
} else {
warn!(target: "reth::cli", "Data directory is not empty, setting up dummy chain");
}
}
info!(target: "reth::cli", "Setting up dummy chain from block {} to {}",
last_block_number + 1,
header.number);
without_evm::setup_without_evm(
&provider_rw,
// &header,
// header_hash,
last_block_number + 1,
SealedHeader::new(header, header_hash),
total_difficulty,
)?;
@ -112,22 +131,19 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> InitStateC
// Necessary to commit, so the header is accessible to provider_rw and
// init_state_dump
static_file_provider.commit()?;
} else if last_block_number > 0 && last_block_number < header.number {
return Err(eyre::eyre!(
"Data directory should be empty when calling init-state with --without-evm-history."
));
}
}
if let Some(state) = self.state {
info!(target: "reth::cli", "Initiating state dump");
let reader = BufReader::new(reth_fs_util::open(self.state)?);
let reader = BufReader::new(reth_fs_util::open(state)?);
let hash = init_from_state_dump(reader, &provider_rw, config.stages.etl)?;
provider_rw.commit()?;
info!(target: "reth::cli", hash = ?hash, "Genesis block written");
Ok(())
} else {
provider_rw.commit()?;
Ok(())
}
}
}

View File

@ -27,6 +27,7 @@ pub(crate) fn read_header_from_file(path: PathBuf) -> Result<Header, eyre::Error
/// first valid block.
pub fn setup_without_evm<Provider>(
provider_rw: &Provider,
start_height: BlockNumber,
header: SealedHeader<<Provider::Primitives as NodePrimitives>::BlockHeader>,
total_difficulty: U256,
) -> Result<(), eyre::Error>
@ -39,7 +40,7 @@ where
let static_file_provider = provider_rw.static_file_provider();
// Write EVM dummy data up to `header - 1` block
append_dummy_chain(&static_file_provider, header.number() - 1)?;
append_dummy_chain(&static_file_provider, start_height, header.number() - 1)?;
info!(target: "reth::cli", "Appending first valid block.");
@ -99,6 +100,7 @@ where
/// * Receipts: It will not push any receipt, only increments the end block range.
fn append_dummy_chain<N: NodePrimitives<BlockHeader = Header>>(
sf_provider: &StaticFileProvider<N>,
start_height: BlockNumber,
target_height: BlockNumber,
) -> Result<(), eyre::Error> {
let (tx, rx) = std::sync::mpsc::channel();
@ -109,7 +111,7 @@ fn append_dummy_chain<N: NodePrimitives<BlockHeader = Header>>(
let provider = sf_provider.clone();
std::thread::spawn(move || {
let result = provider.latest_writer(segment).and_then(|mut writer| {
for block_num in 1..=target_height {
for block_num in start_height..=target_height {
writer.increment_block(block_num)?;
}
Ok(())
@ -124,7 +126,7 @@ fn append_dummy_chain<N: NodePrimitives<BlockHeader = Header>>(
std::thread::spawn(move || {
let mut empty_header = Header::default();
let result = provider.latest_writer(StaticFileSegment::Headers).and_then(|mut writer| {
for block_num in 1..=target_height {
for block_num in start_height..=target_height {
// TODO: should we fill with real parent_hash?
empty_header.number = block_num;
writer.append_header(&empty_header, U256::ZERO, &B256::ZERO)?;

View File

@ -56,6 +56,7 @@ impl<C: ChainSpecParser<ChainSpec = OpChainSpec>> InitStateCommandOp<C> {
if last_block_number == 0 {
reth_cli_commands::init_state::without_evm::setup_without_evm(
&provider_rw,
last_block_number + 1,
SealedHeader::new(BEDROCK_HEADER, BEDROCK_HEADER_HASH),
BEDROCK_HEADER_TTD,
)?;