reth_cli_commands/stage/dump/
execution.rs1use super::setup;
2use reth_consensus::{noop::NoopConsensus, ConsensusError, FullConsensus};
3use reth_db::DatabaseEnv;
4use reth_db_api::{
5 cursor::DbCursorRO, database::Database, table::TableImporter, tables, transaction::DbTx,
6};
7use reth_db_common::DbTool;
8use reth_evm::ConfigureEvm;
9use reth_node_builder::NodeTypesWithDB;
10use reth_node_core::dirs::{ChainPath, DataDirPath};
11use reth_provider::{
12 providers::{ProviderNodeTypes, RocksDBProvider, StaticFileProvider},
13 DatabaseProviderFactory, ProviderFactory,
14};
15use reth_stages::{stages::ExecutionStage, Stage, StageCheckpoint, UnwindInput};
16use std::sync::Arc;
17use tracing::info;
18
19pub(crate) async fn dump_execution_stage<N, E, C>(
20 db_tool: &DbTool<N>,
21 from: u64,
22 to: u64,
23 output_datadir: ChainPath<DataDirPath>,
24 should_run: bool,
25 evm_config: E,
26 consensus: C,
27) -> eyre::Result<()>
28where
29 N: ProviderNodeTypes<DB = Arc<DatabaseEnv>>,
30 E: ConfigureEvm<Primitives = N::Primitives> + 'static,
31 C: FullConsensus<E::Primitives, Error = ConsensusError> + 'static,
32{
33 let (output_db, tip_block_number) = setup(from, to, &output_datadir.db(), db_tool)?;
34
35 import_tables_with_range(&output_db, db_tool, from, to)?;
36
37 unwind_and_copy(db_tool, from, tip_block_number, &output_db, evm_config.clone())?;
38
39 if should_run {
40 dry_run(
41 ProviderFactory::<N>::new(
42 Arc::new(output_db),
43 db_tool.chain(),
44 StaticFileProvider::read_write(output_datadir.static_files())?,
45 RocksDBProvider::builder(output_datadir.rocksdb()).build()?,
46 )?,
47 to,
48 from,
49 evm_config,
50 consensus,
51 )?;
52 }
53
54 Ok(())
55}
56
57fn import_tables_with_range<N: NodeTypesWithDB>(
59 output_db: &DatabaseEnv,
60 db_tool: &DbTool<N>,
61 from: u64,
62 to: u64,
63) -> eyre::Result<()> {
64 output_db.update(|tx| {
67 tx.import_table_with_range::<tables::CanonicalHeaders, _>(
68 &db_tool.provider_factory.db_ref().tx()?,
69 Some(from),
70 to,
71 )
72 })??;
73 output_db.update(|tx| {
74 tx.import_table_with_range::<tables::Headers, _>(
75 &db_tool.provider_factory.db_ref().tx()?,
76 Some(from),
77 to,
78 )
79 })??;
80 output_db.update(|tx| {
81 tx.import_table_with_range::<tables::BlockBodyIndices, _>(
82 &db_tool.provider_factory.db_ref().tx()?,
83 Some(from),
84 to,
85 )
86 })??;
87 output_db.update(|tx| {
88 tx.import_table_with_range::<tables::BlockOmmers, _>(
89 &db_tool.provider_factory.db_ref().tx()?,
90 Some(from),
91 to,
92 )
93 })??;
94
95 let (from_tx, to_tx) = db_tool.provider_factory.db_ref().view(|read_tx| {
97 let mut read_cursor = read_tx.cursor_read::<tables::BlockBodyIndices>()?;
98 let (_, from_block) =
99 read_cursor.seek(from)?.ok_or(eyre::eyre!("BlockBody {from} does not exist."))?;
100 let (_, to_block) =
101 read_cursor.seek(to)?.ok_or(eyre::eyre!("BlockBody {to} does not exist."))?;
102
103 Ok::<(u64, u64), eyre::ErrReport>((
104 from_block.first_tx_num,
105 to_block.first_tx_num + to_block.tx_count,
106 ))
107 })??;
108
109 output_db.update(|tx| {
110 tx.import_table_with_range::<tables::Transactions, _>(
111 &db_tool.provider_factory.db_ref().tx()?,
112 Some(from_tx),
113 to_tx,
114 )
115 })??;
116
117 output_db.update(|tx| {
118 tx.import_table_with_range::<tables::TransactionSenders, _>(
119 &db_tool.provider_factory.db_ref().tx()?,
120 Some(from_tx),
121 to_tx,
122 )
123 })??;
124
125 Ok(())
126}
127
128fn unwind_and_copy<N: ProviderNodeTypes>(
132 db_tool: &DbTool<N>,
133 from: u64,
134 tip_block_number: u64,
135 output_db: &DatabaseEnv,
136 evm_config: impl ConfigureEvm<Primitives = N::Primitives>,
137) -> eyre::Result<()> {
138 let provider = db_tool.provider_factory.database_provider_rw()?;
139
140 let mut exec_stage = ExecutionStage::new_with_executor(evm_config, NoopConsensus::arc());
141
142 exec_stage.unwind(
143 &provider,
144 UnwindInput {
145 unwind_to: from,
146 checkpoint: StageCheckpoint::new(tip_block_number),
147 bad_block: None,
148 },
149 )?;
150
151 let unwind_inner_tx = provider.into_tx();
152
153 output_db
154 .update(|tx| tx.import_dupsort::<tables::PlainStorageState, _>(&unwind_inner_tx))??;
155 output_db.update(|tx| tx.import_table::<tables::PlainAccountState, _>(&unwind_inner_tx))??;
156 output_db.update(|tx| tx.import_table::<tables::Bytecodes, _>(&unwind_inner_tx))??;
157
158 Ok(())
159}
160
161fn dry_run<N, E, C>(
163 output_provider_factory: ProviderFactory<N>,
164 to: u64,
165 from: u64,
166 evm_config: E,
167 consensus: C,
168) -> eyre::Result<()>
169where
170 N: ProviderNodeTypes,
171 E: ConfigureEvm<Primitives = N::Primitives> + 'static,
172 C: FullConsensus<E::Primitives, Error = ConsensusError> + 'static,
173{
174 info!(target: "reth::cli", "Executing stage. [dry-run]");
175
176 let mut exec_stage = ExecutionStage::new_with_executor(evm_config, Arc::new(consensus));
177
178 let input =
179 reth_stages::ExecInput { target: Some(to), checkpoint: Some(StageCheckpoint::new(from)) };
180 exec_stage.execute(&output_provider_factory.database_provider_rw()?, input)?;
181
182 info!(target: "reth::cli", "Success");
183
184 Ok(())
185}