mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: Enable testnet block recovery
This commit is contained in:
@ -12,7 +12,7 @@ use reth_provider::{
|
|||||||
BlockNumReader, DatabaseProviderFactory, StaticFileProviderFactory, StaticFileWriter,
|
BlockNumReader, DatabaseProviderFactory, StaticFileProviderFactory, StaticFileWriter,
|
||||||
};
|
};
|
||||||
use std::{io::BufReader, path::PathBuf, str::FromStr};
|
use std::{io::BufReader, path::PathBuf, str::FromStr};
|
||||||
use tracing::info;
|
use tracing::{info, warn};
|
||||||
|
|
||||||
pub mod without_evm;
|
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
|
/// 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.
|
/// and including the non-genesis block to init chain at. See 'import' command.
|
||||||
#[arg(value_name = "STATE_DUMP_FILE", verbatim_doc_comment)]
|
#[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.
|
/// 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.
|
/// Hash of the header.
|
||||||
#[arg(long, value_name = "HEADER_HASH", verbatim_doc_comment)]
|
#[arg(long, value_name = "HEADER_HASH", verbatim_doc_comment)]
|
||||||
pub header_hash: Option<String>,
|
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> {
|
impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> InitStateCommand<C> {
|
||||||
@ -98,36 +102,48 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> InitStateC
|
|||||||
let last_block_number = provider_rw.last_block_number()?;
|
let last_block_number = provider_rw.last_block_number()?;
|
||||||
|
|
||||||
if last_block_number == 0 {
|
if last_block_number == 0 {
|
||||||
without_evm::setup_without_evm(
|
info!(target: "reth::cli", "Data directory is empty, setting up dummy chain");
|
||||||
&provider_rw,
|
|
||||||
// &header,
|
|
||||||
// header_hash,
|
|
||||||
SealedHeader::new(header, header_hash),
|
|
||||||
total_difficulty,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// SAFETY: it's safe to commit static files, since in the event of a crash, they
|
|
||||||
// will be unwound according to database checkpoints.
|
|
||||||
//
|
|
||||||
// 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 {
|
} else if last_block_number > 0 && last_block_number < header.number {
|
||||||
return Err(eyre::eyre!(
|
if !self.force {
|
||||||
"Data directory should be empty when calling init-state with --without-evm-history."
|
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,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// SAFETY: it's safe to commit static files, since in the event of a crash, they
|
||||||
|
// will be unwound according to database checkpoints.
|
||||||
|
//
|
||||||
|
// Necessary to commit, so the header is accessible to provider_rw and
|
||||||
|
// init_state_dump
|
||||||
|
static_file_provider.commit()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
info!(target: "reth::cli", "Initiating state dump");
|
if let Some(state) = self.state {
|
||||||
|
info!(target: "reth::cli", "Initiating state dump");
|
||||||
|
let reader = BufReader::new(reth_fs_util::open(state)?);
|
||||||
|
let hash = init_from_state_dump(reader, &provider_rw, config.stages.etl)?;
|
||||||
|
provider_rw.commit()?;
|
||||||
|
|
||||||
let reader = BufReader::new(reth_fs_util::open(self.state)?);
|
info!(target: "reth::cli", hash = ?hash, "Genesis block written");
|
||||||
|
Ok(())
|
||||||
let hash = init_from_state_dump(reader, &provider_rw, config.stages.etl)?;
|
} else {
|
||||||
|
provider_rw.commit()?;
|
||||||
provider_rw.commit()?;
|
Ok(())
|
||||||
|
}
|
||||||
info!(target: "reth::cli", hash = ?hash, "Genesis block written");
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,7 @@ pub(crate) fn read_header_from_file(path: PathBuf) -> Result<Header, eyre::Error
|
|||||||
/// first valid block.
|
/// first valid block.
|
||||||
pub fn setup_without_evm<Provider>(
|
pub fn setup_without_evm<Provider>(
|
||||||
provider_rw: &Provider,
|
provider_rw: &Provider,
|
||||||
|
start_height: BlockNumber,
|
||||||
header: SealedHeader<<Provider::Primitives as NodePrimitives>::BlockHeader>,
|
header: SealedHeader<<Provider::Primitives as NodePrimitives>::BlockHeader>,
|
||||||
total_difficulty: U256,
|
total_difficulty: U256,
|
||||||
) -> Result<(), eyre::Error>
|
) -> Result<(), eyre::Error>
|
||||||
@ -39,7 +40,7 @@ where
|
|||||||
|
|
||||||
let static_file_provider = provider_rw.static_file_provider();
|
let static_file_provider = provider_rw.static_file_provider();
|
||||||
// Write EVM dummy data up to `header - 1` block
|
// 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.");
|
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.
|
/// * Receipts: It will not push any receipt, only increments the end block range.
|
||||||
fn append_dummy_chain<N: NodePrimitives<BlockHeader = Header>>(
|
fn append_dummy_chain<N: NodePrimitives<BlockHeader = Header>>(
|
||||||
sf_provider: &StaticFileProvider<N>,
|
sf_provider: &StaticFileProvider<N>,
|
||||||
|
start_height: BlockNumber,
|
||||||
target_height: BlockNumber,
|
target_height: BlockNumber,
|
||||||
) -> Result<(), eyre::Error> {
|
) -> Result<(), eyre::Error> {
|
||||||
let (tx, rx) = std::sync::mpsc::channel();
|
let (tx, rx) = std::sync::mpsc::channel();
|
||||||
@ -109,7 +111,7 @@ fn append_dummy_chain<N: NodePrimitives<BlockHeader = Header>>(
|
|||||||
let provider = sf_provider.clone();
|
let provider = sf_provider.clone();
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let result = provider.latest_writer(segment).and_then(|mut writer| {
|
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)?;
|
writer.increment_block(block_num)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -124,7 +126,7 @@ fn append_dummy_chain<N: NodePrimitives<BlockHeader = Header>>(
|
|||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let mut empty_header = Header::default();
|
let mut empty_header = Header::default();
|
||||||
let result = provider.latest_writer(StaticFileSegment::Headers).and_then(|mut writer| {
|
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?
|
// TODO: should we fill with real parent_hash?
|
||||||
empty_header.number = block_num;
|
empty_header.number = block_num;
|
||||||
writer.append_header(&empty_header, U256::ZERO, &B256::ZERO)?;
|
writer.append_header(&empty_header, U256::ZERO, &B256::ZERO)?;
|
||||||
|
|||||||
@ -56,6 +56,7 @@ impl<C: ChainSpecParser<ChainSpec = OpChainSpec>> InitStateCommandOp<C> {
|
|||||||
if last_block_number == 0 {
|
if last_block_number == 0 {
|
||||||
reth_cli_commands::init_state::without_evm::setup_without_evm(
|
reth_cli_commands::init_state::without_evm::setup_without_evm(
|
||||||
&provider_rw,
|
&provider_rw,
|
||||||
|
last_block_number + 1,
|
||||||
SealedHeader::new(BEDROCK_HEADER, BEDROCK_HEADER_HASH),
|
SealedHeader::new(BEDROCK_HEADER, BEDROCK_HEADER_HASH),
|
||||||
BEDROCK_HEADER_TTD,
|
BEDROCK_HEADER_TTD,
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user