From c2019e35dee29244286278bf1ff8756ebc93daa6 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Wed, 18 Sep 2024 18:10:38 +0100 Subject: [PATCH] feat: allow syncing `op-mainnet` with only state and without importing blocks/receipts (#10850) Co-authored-by: Alexey Shekhirin --- Cargo.lock | 5 + book/run/sync-op-mainnet.md | 32 ++++- crates/cli/commands/src/init_state.rs | 10 +- crates/optimism/cli/Cargo.toml | 1 + crates/optimism/cli/src/commands/import.rs | 2 +- .../cli/src/commands/import_receipts.rs | 2 +- .../cli/src/commands/init_state/bedrock.rs | 136 ++++++++++++++++++ .../cli/src/commands/init_state/mod.rs | 80 +++++++++++ crates/optimism/cli/src/commands/mod.rs | 5 +- crates/optimism/primitives/Cargo.toml | 7 +- crates/optimism/primitives/src/bedrock.rs | 98 +++++++++++++ .../optimism/primitives/src/bedrock_import.rs | 52 ------- crates/optimism/primitives/src/lib.rs | 2 +- crates/storage/db-common/src/init.rs | 31 ++-- .../src/providers/database/provider.rs | 10 +- 15 files changed, 387 insertions(+), 86 deletions(-) create mode 100644 crates/optimism/cli/src/commands/init_state/bedrock.rs create mode 100644 crates/optimism/cli/src/commands/init_state/mod.rs create mode 100644 crates/optimism/primitives/src/bedrock.rs delete mode 100644 crates/optimism/primitives/src/bedrock_import.rs diff --git a/Cargo.lock b/Cargo.lock index 8453ae99f..5c5285d70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8027,6 +8027,11 @@ dependencies = [ [[package]] name = "reth-optimism-primitives" version = "1.0.7" +dependencies = [ + "alloy-primitives", + "reth-primitives", + "reth-primitives-traits", +] [[package]] name = "reth-optimism-rpc" diff --git a/book/run/sync-op-mainnet.md b/book/run/sync-op-mainnet.md index 63f45fe33..d8d7becc1 100644 --- a/book/run/sync-op-mainnet.md +++ b/book/run/sync-op-mainnet.md @@ -1,5 +1,25 @@ # Sync OP Mainnet +To sync OP mainnet, bedrock state needs to be imported as a starting point. There are currently two ways: + +* Minimal bootstrap: only state snapshot at Bedrock block is imported without any OVM historical data. +* Full bootstrap: state, blocks and receipts are imported. + +## Minimal bootstrap + +**The state snapshot at Bedrock block is required.** It can be exported from [op-geth](https://github.com/testinprod-io/op-erigon/blob/pcw109550/bedrock-db-migration/bedrock-migration.md#export-state) (**.jsonl**) or downloaded directly from [here](https://mega.nz/file/GdZ1xbAT#a9cBv3AqzsTGXYgX7nZc_3fl--tcBmOAIwIA5ND6kwc). + +```sh +$ op-reth init-state --without-ovm --chain optimism --datadir op-mainnet world_trie_state.jsonl + +$ op-reth node --chain optimism --datadir op-mainnet --debug.tip 0x098f87b75c8b861c775984f9d5dbe7b70cbbbc30fc15adb03a5044de0144f2d0 # block #125200000 +``` + + +## Full bootstrap + +### Import state + To sync OP mainnet, the Bedrock datadir needs to be imported to use as starting point. Blocks lower than the OP mainnet Bedrock fork, are built on the OVM and cannot be executed on the EVM. For this reason, the chain segment from genesis until Bedrock, must be manually imported to circumvent @@ -10,7 +30,7 @@ Importing OP mainnet Bedrock datadir requires exported data: - Blocks [and receipts] below Bedrock - State snapshot at first Bedrock block -## Manual Export Steps +### Manual Export Steps The `op-geth` Bedrock datadir can be downloaded from . @@ -18,9 +38,9 @@ To export the OVM chain from `op-geth`, clone the `testinprod-io/op-geth` repo a . Commands to export blocks, receipts and state dump can be found in `op-geth/migrate.sh`. -## Manual Import Steps +### Manual Import Steps -### 1. Import Blocks +#### 1. Import Blocks Imports a `.rlp` file of blocks. @@ -30,7 +50,7 @@ Import of >100 million OVM blocks, from genesis to Bedrock, completes in 45 minu $ op-reth import-op ``` -### 2. Import Receipts +#### 2. Import Receipts This step is optional. To run a full node, skip this step. If however receipts are to be imported, the corresponding transactions must already be imported (see [step 1](#1-import-blocks)). @@ -44,7 +64,7 @@ Import of >100 million OVM receipts, from genesis to Bedrock, completes in 30 mi $ op-reth import-receipts-op ``` -### 3. Import State +#### 3. Import State Imports a `.jsonl` state dump. The block at which the state dump is made, must be the latest block in reth's database. This should be block 105 235 063, the first Bedrock block (see [step 1](#1-import-blocks)). @@ -61,4 +81,4 @@ Running the node with `--debug.tip `syncs the node without help from block hash can be taken from the latest block on . Use `op-node` to track the tip. Start `op-node` with `--syncmode=execution-layer` and `--l2.enginekind=reth`. If `op-node`'s RPC -connection to L1 is over localhost, `--l1.trustrpc` can be set to improve performance. \ No newline at end of file +connection to L1 is over localhost, `--l1.trustrpc` can be set to improve performance. diff --git a/crates/cli/commands/src/init_state.rs b/crates/cli/commands/src/init_state.rs index ce94c9fa9..67955d714 100644 --- a/crates/cli/commands/src/init_state.rs +++ b/crates/cli/commands/src/init_state.rs @@ -17,7 +17,7 @@ use tracing::info; #[derive(Debug, Parser)] pub struct InitStateCommand { #[command(flatten)] - env: EnvironmentArgs, + pub env: EnvironmentArgs, /// JSONL file with state dump. /// @@ -37,7 +37,7 @@ pub struct InitStateCommand { /// 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)] - state: PathBuf, + pub state: PathBuf, } impl> InitStateCommand { @@ -71,5 +71,9 @@ pub fn init_at_state>( let file = File::open(state_dump_path)?; let reader = BufReader::new(file); - init_from_state_dump(reader, factory, etl_config) + let provider_rw = factory.provider_rw()?; + let hash = init_from_state_dump(reader, &provider_rw.0, etl_config)?; + provider_rw.commit()?; + + Ok(hash) } diff --git a/crates/optimism/cli/Cargo.toml b/crates/optimism/cli/Cargo.toml index b8779d0d1..edaa6efcf 100644 --- a/crates/optimism/cli/Cargo.toml +++ b/crates/optimism/cli/Cargo.toml @@ -16,6 +16,7 @@ reth-cli-commands.workspace = true reth-consensus.workspace = true reth-db = { workspace = true, features = ["mdbx"] } reth-db-api.workspace = true +reth-db-common.workspace = true reth-downloaders.workspace = true reth-provider.workspace = true reth-prune.workspace = true diff --git a/crates/optimism/cli/src/commands/import.rs b/crates/optimism/cli/src/commands/import.rs index c4823fdf4..b7d2ee13f 100644 --- a/crates/optimism/cli/src/commands/import.rs +++ b/crates/optimism/cli/src/commands/import.rs @@ -12,7 +12,7 @@ use reth_downloaders::file_client::{ }; use reth_node_builder::NodeTypesWithEngine; use reth_node_core::version::SHORT_VERSION; -use reth_optimism_primitives::bedrock_import::is_dup_tx; +use reth_optimism_primitives::bedrock::is_dup_tx; use reth_provider::StageCheckpointReader; use reth_prune::PruneModes; use reth_stages::StageId; diff --git a/crates/optimism/cli/src/commands/import_receipts.rs b/crates/optimism/cli/src/commands/import_receipts.rs index 8074fa92f..58a8590bd 100644 --- a/crates/optimism/cli/src/commands/import_receipts.rs +++ b/crates/optimism/cli/src/commands/import_receipts.rs @@ -15,7 +15,7 @@ use reth_downloaders::{ use reth_execution_types::ExecutionOutcome; use reth_node_builder::{NodeTypesWithDB, NodeTypesWithEngine}; use reth_node_core::version::SHORT_VERSION; -use reth_optimism_primitives::bedrock_import::is_dup_tx; +use reth_optimism_primitives::bedrock::is_dup_tx; use reth_primitives::Receipts; use reth_provider::{ writer::UnifiedStorageWriter, DatabaseProviderFactory, OriginalValuesKnown, ProviderFactory, diff --git a/crates/optimism/cli/src/commands/init_state/bedrock.rs b/crates/optimism/cli/src/commands/init_state/bedrock.rs new file mode 100644 index 000000000..1c77569f9 --- /dev/null +++ b/crates/optimism/cli/src/commands/init_state/bedrock.rs @@ -0,0 +1,136 @@ +use alloy_primitives::B256; +use reth_db::Database; +use reth_optimism_primitives::bedrock::{BEDROCK_HEADER, BEDROCK_HEADER_HASH, BEDROCK_HEADER_TTD}; +use reth_primitives::{ + BlockBody, BlockNumber, Header, SealedBlock, SealedBlockWithSenders, SealedHeader, + StaticFileSegment, U256, +}; +use reth_provider::{ + providers::StaticFileProvider, BlockWriter, DatabaseProviderRW, StageCheckpointWriter, + StaticFileWriter, +}; +use reth_stages::{StageCheckpoint, StageId}; +use tracing::info; + +/// Creates a dummy chain (with no transactions) up to the last OVM block and appends the +/// first valid Bedrock block. +pub(crate) fn setup_op_mainnet_without_ovm( + provider_rw: &DatabaseProviderRW, + static_file_provider: &StaticFileProvider, +) -> Result<(), eyre::Error> { + info!(target: "reth::cli", "Setting up dummy OVM chain before importing state."); + + // Write OVM dummy data up to `BEDROCK_HEADER - 1` block + append_dummy_chain(static_file_provider, BEDROCK_HEADER.number - 1)?; + + info!(target: "reth::cli", "Appending Bedrock block."); + + append_bedrock_block(provider_rw, static_file_provider)?; + + for stage in StageId::ALL { + provider_rw.save_stage_checkpoint(stage, StageCheckpoint::new(BEDROCK_HEADER.number))?; + } + + info!(target: "reth::cli", "Set up finished."); + + Ok(()) +} + +/// Appends the first bedrock block. +/// +/// By appending it, static file writer also verifies that all segments are at the same +/// height. +fn append_bedrock_block( + provider_rw: &DatabaseProviderRW, + sf_provider: &StaticFileProvider, +) -> Result<(), eyre::Error> { + provider_rw.insert_block( + SealedBlockWithSenders::new( + SealedBlock::new( + SealedHeader::new(BEDROCK_HEADER, BEDROCK_HEADER_HASH), + BlockBody::default(), + ), + vec![], + ) + .expect("no senders or txes"), + )?; + + sf_provider.latest_writer(StaticFileSegment::Headers)?.append_header( + &BEDROCK_HEADER, + BEDROCK_HEADER_TTD, + &BEDROCK_HEADER_HASH, + )?; + + sf_provider + .latest_writer(StaticFileSegment::Receipts)? + .increment_block(BEDROCK_HEADER.number)?; + + sf_provider + .latest_writer(StaticFileSegment::Transactions)? + .increment_block(BEDROCK_HEADER.number)?; + + Ok(()) +} + +/// Creates a dummy chain with no transactions/receipts up to `target_height` block inclusive. +/// +/// * Headers: It will push an empty block. +/// * Transactions: It will not push any tx, only increments the end block range. +/// * Receipts: It will not push any receipt, only increments the end block range. +fn append_dummy_chain( + sf_provider: &StaticFileProvider, + target_height: BlockNumber, +) -> Result<(), eyre::Error> { + let (tx, rx) = std::sync::mpsc::channel(); + + // Spawn jobs for incrementing the block end range of transactions and receipts + for segment in [StaticFileSegment::Transactions, StaticFileSegment::Receipts] { + let tx_clone = tx.clone(); + 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 { + writer.increment_block(block_num)?; + } + Ok(()) + }); + + tx_clone.send(result).unwrap(); + }); + } + + // Spawn job for appending empty headers + let provider = sf_provider.clone(); + 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 { + // TODO: should we fill with real parent_hash? + empty_header.number = block_num; + writer.append_header(&empty_header, U256::ZERO, &B256::ZERO)?; + } + Ok(()) + }); + + tx.send(result).unwrap(); + }); + + // Catches any StaticFileWriter error. + while let Ok(r) = rx.recv() { + r?; + } + + // If, for any reason, rayon crashes this verifies if all segments are at the same + // target_height. + for segment in + [StaticFileSegment::Headers, StaticFileSegment::Receipts, StaticFileSegment::Transactions] + { + assert_eq!( + sf_provider.latest_writer(segment)?.user_header().block_end(), + Some(target_height), + "Static file segment {segment} was unsuccessful advancing its block height." + ); + } + + Ok(()) +} diff --git a/crates/optimism/cli/src/commands/init_state/mod.rs b/crates/optimism/cli/src/commands/init_state/mod.rs new file mode 100644 index 000000000..e62ec3d16 --- /dev/null +++ b/crates/optimism/cli/src/commands/init_state/mod.rs @@ -0,0 +1,80 @@ +//! Command that initializes the node from a genesis file. + +use clap::Parser; +use reth_chainspec::ChainSpec; +use reth_cli::chainspec::ChainSpecParser; +use reth_cli_commands::common::{AccessRights, Environment}; +use reth_db_common::init::init_from_state_dump; +use reth_node_builder::NodeTypesWithEngine; +use reth_optimism_primitives::bedrock::BEDROCK_HEADER; +use reth_provider::{ + BlockNumReader, ChainSpecProvider, StaticFileProviderFactory, StaticFileWriter, +}; +use std::{fs::File, io::BufReader}; +use tracing::info; + +mod bedrock; + +/// Initializes the database with the genesis block. +#[derive(Debug, Parser)] +pub struct InitStateCommandOp { + #[command(flatten)] + init_state: reth_cli_commands::init_state::InitStateCommand, + + /// **Optimism Mainnet Only** + /// + /// Specifies whether to initialize the state without relying on OVM historical data. + /// + /// When enabled, and before inserting the state, it creates a dummy chain up to the last OVM + /// block (#105235062) (14GB / 90 seconds). It then, appends the Bedrock block. + /// + /// - **Note**: **Do not** import receipts and blocks beforehand, or this will fail or be + /// ignored. + #[arg(long, default_value = "false")] + without_ovm: bool, +} + +impl> InitStateCommandOp { + /// Execute the `init` command + pub async fn execute>( + self, + ) -> eyre::Result<()> { + info!(target: "reth::cli", "Reth init-state starting"); + + let Environment { config, provider_factory, .. } = + self.init_state.env.init::(AccessRights::RW)?; + + let static_file_provider = provider_factory.static_file_provider(); + let provider_rw = provider_factory.provider_rw()?; + + // OP-Mainnet may want to bootstrap a chain without OVM historical data + if provider_factory.chain_spec().is_optimism_mainnet() && self.without_ovm { + let last_block_number = provider_rw.last_block_number()?; + + if last_block_number == 0 { + bedrock::setup_op_mainnet_without_ovm(&provider_rw, &static_file_provider)?; + + // SAFETY: it's safe to commit static files, since in the event of a crash, they + // will be unwinded according to database checkpoints. + // + // Necessary to commit, so the BEDROCK_HEADER is accessible to provider_rw and + // init_state_dump + static_file_provider.commit()?; + } else if last_block_number > 0 && last_block_number < BEDROCK_HEADER.number { + return Err(eyre::eyre!( + "Data directory should be empty when calling init-state with --without-ovm." + )) + } + } + + info!(target: "reth::cli", "Initiating state dump"); + + let reader = BufReader::new(File::open(self.init_state.state)?); + let hash = init_from_state_dump(reader, &provider_rw.0, config.stages.etl)?; + + provider_rw.commit()?; + + info!(target: "reth::cli", hash = ?hash, "Genesis block written"); + Ok(()) + } +} diff --git a/crates/optimism/cli/src/commands/mod.rs b/crates/optimism/cli/src/commands/mod.rs index 1c2172d67..41a19e3de 100644 --- a/crates/optimism/cli/src/commands/mod.rs +++ b/crates/optimism/cli/src/commands/mod.rs @@ -5,7 +5,7 @@ use import_receipts::ImportReceiptsOpCommand; use reth_chainspec::ChainSpec; use reth_cli::chainspec::ChainSpecParser; use reth_cli_commands::{ - config_cmd, db, dump_genesis, init_cmd, init_state, + config_cmd, db, dump_genesis, init_cmd, node::{self, NoArgs}, p2p, prune, recover, stage, }; @@ -15,6 +15,7 @@ use std::fmt; mod build_pipeline; pub mod import; pub mod import_receipts; +pub mod init_state; /// Commands to be executed #[derive(Debug, Subcommand)] @@ -30,7 +31,7 @@ pub enum Commands< Init(init_cmd::InitCommand), /// Initialize the database from a state dump file. #[command(name = "init-state")] - InitState(init_state::InitStateCommand), + InitState(init_state::InitStateCommandOp), /// This syncs RLP encoded OP blocks below Bedrock from a file, without executing. #[command(name = "import-op")] ImportOp(ImportOpCommand), diff --git a/crates/optimism/primitives/Cargo.toml b/crates/optimism/primitives/Cargo.toml index 0acd2f1eb..73a3bab1e 100644 --- a/crates/optimism/primitives/Cargo.toml +++ b/crates/optimism/primitives/Cargo.toml @@ -9,4 +9,9 @@ repository.workspace = true description = "OP primitive types" [lints] -workspace = true \ No newline at end of file +workspace = true + +[dependencies] +reth-primitives.workspace = true +reth-primitives-traits.workspace = true +alloy-primitives.workspace = true diff --git a/crates/optimism/primitives/src/bedrock.rs b/crates/optimism/primitives/src/bedrock.rs new file mode 100644 index 000000000..f63fc1917 --- /dev/null +++ b/crates/optimism/primitives/src/bedrock.rs @@ -0,0 +1,98 @@ +//! OP mainnet bedrock related data. + +use alloy_primitives::{b256, bloom, bytes, B256, U256}; +use reth_primitives::{address, Header}; +use reth_primitives_traits::constants::EMPTY_OMMER_ROOT_HASH; + +/// Transaction 0x9ed8f713b2cc6439657db52dcd2fdb9cc944915428f3c6e2a7703e242b259cb9 in block 985, +/// replayed in blocks: +/// +/// 19 022 +/// 45 036 +pub const TX_BLOCK_985: [u64; 2] = [19_022, 45_036]; + +/// Transaction 0xc033250c5a45f9d104fc28640071a776d146d48403cf5e95ed0015c712e26cb6 in block +/// 123 322, replayed in block: +/// +/// 123 542 +pub const TX_BLOCK_123_322: u64 = 123_542; + +/// Transaction 0x86f8c77cfa2b439e9b4e92a10f6c17b99fce1220edf4001e4158b57f41c576e5 in block +/// 1 133 328, replayed in blocks: +/// +/// 1 135 391 +/// 1 144 468 +pub const TX_BLOCK_1_133_328: [u64; 2] = [1_135_391, 1_144_468]; + +/// Transaction 0x3cc27e7cc8b7a9380b2b2f6c224ea5ef06ade62a6af564a9dd0bcca92131cd4e in block +/// 1 244 152, replayed in block: +/// +/// 1 272 994 +pub const TX_BLOCK_1_244_152: u64 = 1_272_994; + +/// The six blocks with replayed transactions. +pub const BLOCK_NUMS_REPLAYED_TX: [u64; 6] = [ + TX_BLOCK_985[0], + TX_BLOCK_985[1], + TX_BLOCK_123_322, + TX_BLOCK_1_133_328[0], + TX_BLOCK_1_133_328[1], + TX_BLOCK_1_244_152, +]; + +/// Returns `true` if transaction is the second or third appearance of the transaction. The blocks +/// with replayed transaction happen to only contain the single transaction. +pub fn is_dup_tx(block_number: u64) -> bool { + if block_number > BLOCK_NUMS_REPLAYED_TX[5] { + return false + } + + // these blocks just have one transaction! + if BLOCK_NUMS_REPLAYED_TX.contains(&block_number) { + return true + } + + false +} + +/// Bedrock hash on Optimism Mainnet. +pub const BEDROCK_HEADER_HASH: B256 = + b256!("dbf6a80fef073de06add9b0d14026d6e5a86c85f6d102c36d3d8e9cf89c2afd3"); + +/// Bedrock on Optimism Mainnet. (`105_235_063`) +pub const BEDROCK_HEADER: Header = Header { + difficulty: U256::ZERO, + extra_data: bytes!("424544524f434b"), + gas_limit: 30000000, + gas_used: 0, + logs_bloom: bloom!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + nonce: 0, + number: 105235063, + parent_hash: b256!("21a168dfa5e727926063a28ba16fd5ee84c814e847c81a699c7a0ea551e4ca50"), + receipts_root: b256!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), + state_root: b256!("920314c198da844a041d63bf6cbe8b59583165fd2229d1b3f599da812fd424cb"), + timestamp: 1686068903, + transactions_root: b256!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), + ommers_hash: EMPTY_OMMER_ROOT_HASH, + beneficiary: address!("4200000000000000000000000000000000000011"), + withdrawals_root: None, + mix_hash: B256::ZERO, + base_fee_per_gas: Some(0x3b9aca00), + blob_gas_used: None, + excess_blob_gas: None, + parent_beacon_block_root: None, + requests_root: None, +}; + +/// Bedrock total difficulty on Optimism Mainnet. +pub const BEDROCK_HEADER_TTD: U256 = U256::ZERO; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_bedrock_header() { + assert_eq!(BEDROCK_HEADER.hash_slow(), BEDROCK_HEADER_HASH); + } +} diff --git a/crates/optimism/primitives/src/bedrock_import.rs b/crates/optimism/primitives/src/bedrock_import.rs deleted file mode 100644 index 17020f9f2..000000000 --- a/crates/optimism/primitives/src/bedrock_import.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! Replayed OP mainnet OVM transactions (in blocks below Bedrock). - -/// Transaction 0x9ed8f713b2cc6439657db52dcd2fdb9cc944915428f3c6e2a7703e242b259cb9 in block 985, -/// replayed in blocks: -/// -/// 19 022 -/// 45 036 -pub const TX_BLOCK_985: [u64; 2] = [19_022, 45_036]; - -/// Transaction 0xc033250c5a45f9d104fc28640071a776d146d48403cf5e95ed0015c712e26cb6 in block -/// 123 322, replayed in block: -/// -/// 123 542 -pub const TX_BLOCK_123_322: u64 = 123_542; - -/// Transaction 0x86f8c77cfa2b439e9b4e92a10f6c17b99fce1220edf4001e4158b57f41c576e5 in block -/// 1 133 328, replayed in blocks: -/// -/// 1 135 391 -/// 1 144 468 -pub const TX_BLOCK_1_133_328: [u64; 2] = [1_135_391, 1_144_468]; - -/// Transaction 0x3cc27e7cc8b7a9380b2b2f6c224ea5ef06ade62a6af564a9dd0bcca92131cd4e in block -/// 1 244 152, replayed in block: -/// -/// 1 272 994 -pub const TX_BLOCK_1_244_152: u64 = 1_272_994; - -/// The six blocks with replayed transactions. -pub const BLOCK_NUMS_REPLAYED_TX: [u64; 6] = [ - TX_BLOCK_985[0], - TX_BLOCK_985[1], - TX_BLOCK_123_322, - TX_BLOCK_1_133_328[0], - TX_BLOCK_1_133_328[1], - TX_BLOCK_1_244_152, -]; - -/// Returns `true` if transaction is the second or third appearance of the transaction. The blocks -/// with replayed transaction happen to only contain the single transaction. -pub fn is_dup_tx(block_number: u64) -> bool { - if block_number > BLOCK_NUMS_REPLAYED_TX[5] { - return false - } - - // these blocks just have one transaction! - if BLOCK_NUMS_REPLAYED_TX.contains(&block_number) { - return true - } - - false -} diff --git a/crates/optimism/primitives/src/lib.rs b/crates/optimism/primitives/src/lib.rs index 5cdb53def..659900b9a 100644 --- a/crates/optimism/primitives/src/lib.rs +++ b/crates/optimism/primitives/src/lib.rs @@ -7,4 +7,4 @@ )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -pub mod bedrock_import; +pub mod bedrock; diff --git a/crates/storage/db-common/src/init.rs b/crates/storage/db-common/src/init.rs index 864849ebe..53fd1bfee 100644 --- a/crates/storage/db-common/src/init.rs +++ b/crates/storage/db-common/src/init.rs @@ -326,29 +326,27 @@ where /// It's similar to [`init_genesis`] but supports importing state too big to fit in memory, and can /// be set to the highest block present. One practical usecase is to import OP mainnet state at /// bedrock transition block. -pub fn init_from_state_dump( +pub fn init_from_state_dump( mut reader: impl BufRead, - factory: PF, + provider_rw: &Provider, etl_config: EtlConfig, ) -> eyre::Result where - PF: DatabaseProviderFactory - + StaticFileProviderFactory - + ChainSpecProvider - + BlockHashReader + Provider: DBProvider + BlockNumReader - + HeaderProvider, - PF::ProviderRW: StageCheckpointWriter + + BlockHashReader + + ChainSpecProvider + + StageCheckpointWriter + HistoryWriter + HeaderProvider + HashingWriter + StateChangeWriter + TrieWriter - + AsRef, + + AsRef, { - let block = factory.last_block_number()?; - let hash = factory.block_hash(block)?.unwrap(); - let expected_state_root = factory + let block = provider_rw.last_block_number()?; + let hash = provider_rw.block_hash(block)?.unwrap(); + let expected_state_root = provider_rw .header_by_number(block)? .ok_or(ProviderError::HeaderNotFound(block.into()))? .state_root; @@ -370,7 +368,7 @@ where debug!(target: "reth::cli", block, - chain=%factory.chain_spec().chain, + chain=%provider_rw.chain_spec().chain, "Initializing state at block" ); @@ -378,11 +376,10 @@ where let collector = parse_accounts(&mut reader, etl_config)?; // write state to db - let provider_rw = factory.database_provider_rw()?; - dump_state(collector, &provider_rw, block)?; + dump_state(collector, provider_rw, block)?; // compute and compare state root. this advances the stage checkpoints. - let computed_state_root = compute_state_root(&provider_rw)?; + let computed_state_root = compute_state_root(provider_rw)?; if computed_state_root == expected_state_root { info!(target: "reth::cli", ?computed_state_root, @@ -407,8 +404,6 @@ where provider_rw.save_stage_checkpoint(stage, StageCheckpoint::new(block))?; } - provider_rw.commit()?; - Ok(hash) } diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 5b43f7770..e3c7fcbba 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -18,7 +18,7 @@ use crate::{ use alloy_primitives::{keccak256, Address, BlockHash, BlockNumber, TxHash, TxNumber, B256, U256}; use itertools::{izip, Itertools}; use rayon::slice::ParallelSliceMut; -use reth_chainspec::{ChainInfo, ChainSpec, EthereumHardforks}; +use reth_chainspec::{ChainInfo, ChainSpec, ChainSpecProvider, EthereumHardforks}; use reth_db::{ cursor::DbDupCursorRW, tables, BlockNumberList, PlainAccountState, PlainStorageState, }; @@ -1595,6 +1595,14 @@ impl DatabaseProvider { } } +impl ChainSpecProvider for DatabaseProvider { + type ChainSpec = ChainSpec; + + fn chain_spec(&self) -> Arc { + self.chain_spec.clone() + } +} + impl AccountReader for DatabaseProvider { fn basic_account(&self, address: Address) -> ProviderResult> { Ok(self.tx.get::(address)?)