feat(cli): drop execution stage (#1854)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Georgios Konstantopoulos
2023-03-20 07:17:00 -07:00
committed by GitHub
parent 8673e95d0a
commit 876df20cac
12 changed files with 211 additions and 101 deletions

View File

@ -4,7 +4,7 @@ use std::str::FromStr;
use crate::{
chain, db,
dirs::{LogsDir, PlatformPath},
dump_stage, node, p2p,
drop_stage, dump_stage, node, p2p,
runner::CliRunner,
stage, test_eth_chain, test_vectors,
};
@ -31,6 +31,7 @@ pub fn run() -> eyre::Result<()> {
Commands::Db(command) => runner.run_until_ctrl_c(command.execute()),
Commands::Stage(command) => runner.run_until_ctrl_c(command.execute()),
Commands::DumpStage(command) => runner.run_until_ctrl_c(command.execute()),
Commands::DropStage(command) => runner.run_until_ctrl_c(command.execute()),
Commands::P2P(command) => runner.run_until_ctrl_c(command.execute()),
Commands::TestVectors(command) => runner.run_until_ctrl_c(command.execute()),
Commands::TestEthChain(command) => runner.run_until_ctrl_c(command.execute()),
@ -63,6 +64,9 @@ pub enum Commands {
/// Dumps a stage from a range into a new database.
#[command(name = "dump-stage")]
DumpStage(dump_stage::Command),
/// Drops a stage's tables from the database.
#[command(name = "drop-stage")]
DropStage(drop_stage::Command),
/// P2P Debugging utilities
#[command(name = "p2p")]
P2P(p2p::Command),

View File

@ -1,20 +1,14 @@
//! Database debugging tool
use crate::dirs::{DbPath, PlatformPath};
use crate::{
dirs::{DbPath, PlatformPath},
utils::DbTool,
};
use clap::{Parser, Subcommand};
use comfy_table::{Cell, Row, Table as ComfyTable};
use eyre::{Result, WrapErr};
use eyre::WrapErr;
use human_bytes::human_bytes;
use reth_db::{
cursor::{DbCursorRO, Walker},
database::Database,
table::Table,
tables,
transaction::DbTx,
};
use reth_interfaces::test_utils::generators::random_block_range;
use reth_provider::insert_canonical_block;
use std::collections::BTreeMap;
use tracing::{error, info};
use reth_db::{database::Database, tables};
use tracing::error;
/// DB List TUI
mod tui;
@ -189,55 +183,3 @@ impl Command {
Ok(())
}
}
/// Wrapper over DB that implements many useful DB queries.
pub(crate) struct DbTool<'a, DB: Database> {
pub(crate) db: &'a DB,
}
impl<'a, DB: Database> DbTool<'a, DB> {
/// Takes a DB where the tables have already been created.
pub(crate) fn new(db: &'a DB) -> eyre::Result<Self> {
Ok(Self { db })
}
/// Seeds the database with some random data, only used for testing
fn seed(&mut self, len: u64) -> Result<()> {
info!(target: "reth::cli", "Generating random block range from 0 to {len}");
let chain = random_block_range(0..len, Default::default(), 0..64);
self.db.update(|tx| {
chain.into_iter().try_for_each(|block| {
insert_canonical_block(tx, block, None, true)?;
Ok::<_, eyre::Error>(())
})
})??;
info!(target: "reth::cli", "Database seeded with {len} blocks");
Ok(())
}
/// Grabs the contents of the table within a certain index range and places the
/// entries into a [`HashMap`][std::collections::HashMap].
fn list<T: Table>(&mut self, start: usize, len: usize) -> Result<BTreeMap<T::Key, T::Value>> {
let data = self.db.view(|tx| {
let mut cursor = tx.cursor_read::<T>().expect("Was not able to obtain a cursor.");
// TODO: Upstream this in the DB trait.
let start_walker = cursor.current().transpose();
let walker = Walker::new(&mut cursor, start_walker);
walker.skip(start).take(len).collect::<Vec<_>>()
})?;
data.into_iter()
.collect::<Result<BTreeMap<T::Key, T::Value>, _>>()
.map_err(|e| eyre::eyre!(e))
}
fn drop(&mut self, path: &PlatformPath<DbPath>) -> Result<()> {
info!(target: "reth::cli", "Dropping db at {}", path);
std::fs::remove_dir_all(path).wrap_err("Dropping the database failed")?;
Ok(())
}
}

View File

@ -0,0 +1,82 @@
//! Database debugging tool
use crate::{
dirs::{DbPath, PlatformPath},
utils::DbTool,
StageEnum,
};
use clap::Parser;
use reth_db::{
database::Database,
mdbx::{Env, WriteMap},
tables,
transaction::DbTxMut,
};
use reth_primitives::ChainSpec;
use reth_staged_sync::utils::{chainspec::genesis_value_parser, init::insert_genesis_state};
use reth_stages::stages::EXECUTION;
use std::sync::Arc;
use tracing::info;
/// `reth drop-stage` command
#[derive(Debug, Parser)]
pub struct Command {
/// The path to the database folder.
///
/// Defaults to the OS-specific data directory:
///
/// - Linux: `$XDG_DATA_HOME/reth/db` or `$HOME/.local/share/reth/db`
/// - Windows: `{FOLDERID_RoamingAppData}/reth/db`
/// - macOS: `$HOME/Library/Application Support/reth/db`
#[arg(global = true, long, value_name = "PATH", verbatim_doc_comment, default_value_t)]
db: PlatformPath<DbPath>,
/// The chain this node is running.
///
/// Possible values are either a built-in chain or the path to a chain specification file.
///
/// Built-in chains:
/// - mainnet
/// - goerli
/// - sepolia
#[arg(
long,
value_name = "CHAIN_OR_PATH",
verbatim_doc_comment,
default_value = "mainnet",
value_parser = genesis_value_parser
)]
chain: Arc<ChainSpec>,
stage: StageEnum,
}
impl Command {
/// Execute `db` command
pub async fn execute(&self) -> eyre::Result<()> {
std::fs::create_dir_all(&self.db)?;
let db = Env::<WriteMap>::open(self.db.as_ref(), reth_db::mdbx::EnvKind::RW)?;
let tool = DbTool::new(&db)?;
match &self.stage {
StageEnum::Execution => {
tool.db.update(|tx| {
tx.clear::<tables::PlainAccountState>()?;
tx.clear::<tables::PlainStorageState>()?;
tx.clear::<tables::AccountChangeSet>()?;
tx.clear::<tables::StorageChangeSet>()?;
tx.clear::<tables::Bytecodes>()?;
tx.put::<tables::SyncStage>(EXECUTION.0.to_string(), 0)?;
insert_genesis_state::<Env<WriteMap>>(tx, self.chain.genesis())?;
Ok::<_, eyre::Error>(())
})??;
}
_ => {
info!("Nothing to do for stage {:?}", self.stage);
}
}
Ok(())
}
}

View File

@ -1,7 +1,7 @@
use crate::{
db::DbTool,
dirs::{DbPath, PlatformPath},
dump_stage::setup,
utils::DbTool,
};
use eyre::Result;
use reth_db::{

View File

@ -1,7 +1,7 @@
use crate::{
db::DbTool,
dirs::{DbPath, PlatformPath},
dump_stage::setup,
utils::DbTool,
};
use eyre::Result;
use reth_db::{database::Database, table::TableImporter, tables, transaction::DbTx};

View File

@ -1,7 +1,7 @@
use crate::{
db::DbTool,
dirs::{DbPath, PlatformPath},
dump_stage::setup,
utils::DbTool,
};
use eyre::Result;
use reth_db::{database::Database, table::TableImporter, tables};

View File

@ -1,7 +1,7 @@
use crate::{
db::DbTool,
dirs::{DbPath, PlatformPath},
dump_stage::setup,
utils::DbTool,
};
use eyre::Result;
use reth_db::{database::Database, table::TableImporter, tables, transaction::DbTx};

View File

@ -12,8 +12,8 @@ mod merkle;
use merkle::dump_merkle_stage;
use crate::{
db::DbTool,
dirs::{DbPath, PlatformPath},
utils::DbTool,
};
use clap::Parser;
use reth_db::{

View File

@ -12,6 +12,7 @@ pub mod chain;
pub mod cli;
pub mod db;
pub mod dirs;
pub mod drop_stage;
pub mod dump_stage;
pub mod node;
pub mod p2p;
@ -21,3 +22,11 @@ pub mod stage;
pub mod test_eth_chain;
pub mod test_vectors;
pub mod utils;
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, clap::ValueEnum)]
enum StageEnum {
Headers,
Bodies,
Senders,
Execution,
}

View File

@ -4,9 +4,9 @@
use crate::{
args::NetworkArgs,
dirs::{ConfigPath, DbPath, PlatformPath},
prometheus_exporter,
prometheus_exporter, StageEnum,
};
use clap::{Parser, ValueEnum};
use clap::Parser;
use reth_beacon_consensus::BeaconConsensus;
use reth_downloaders::bodies::bodies::BodiesDownloaderBuilder;
use reth_primitives::ChainSpec;
@ -86,14 +86,6 @@ pub struct Command {
network: NetworkArgs,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, ValueEnum)]
enum StageEnum {
Headers,
Bodies,
Senders,
Execution,
}
impl Command {
/// Execute `stage` command
pub async fn execute(&self) -> eyre::Result<()> {

View File

@ -1,12 +1,25 @@
//! Common CLI utility functions.
use reth_interfaces::p2p::{
download::DownloadClient,
headers::client::{HeadersClient, HeadersRequest},
priority::Priority,
use crate::dirs::{DbPath, PlatformPath};
use eyre::{Result, WrapErr};
use reth_db::{
cursor::{DbCursorRO, Walker},
database::Database,
table::Table,
transaction::{DbTx, DbTxMut},
};
use reth_interfaces::{
p2p::{
download::DownloadClient,
headers::client::{HeadersClient, HeadersRequest},
priority::Priority,
},
test_utils::generators::random_block_range,
};
use reth_network::FetchClient;
use reth_primitives::{BlockHashOrNumber, HeadersDirection, SealedHeader};
use reth_provider::insert_canonical_block;
use std::collections::BTreeMap;
use tracing::info;
/// Get a single header from network
pub async fn get_single_header(
@ -41,3 +54,66 @@ pub async fn get_single_header(
Ok(header)
}
/// Wrapper over DB that implements many useful DB queries.
pub struct DbTool<'a, DB: Database> {
pub(crate) db: &'a DB,
}
impl<'a, DB: Database> DbTool<'a, DB> {
/// Takes a DB where the tables have already been created.
pub(crate) fn new(db: &'a DB) -> eyre::Result<Self> {
Ok(Self { db })
}
/// Seeds the database with some random data, only used for testing
pub fn seed(&mut self, len: u64) -> Result<()> {
info!(target: "reth::cli", "Generating random block range from 0 to {len}");
let chain = random_block_range(0..len, Default::default(), 0..64);
self.db.update(|tx| {
chain.into_iter().try_for_each(|block| {
insert_canonical_block(tx, block, None, true)?;
Ok::<_, eyre::Error>(())
})
})??;
info!(target: "reth::cli", "Database seeded with {len} blocks");
Ok(())
}
/// Grabs the contents of the table within a certain index range and places the
/// entries into a [`HashMap`][std::collections::HashMap].
pub fn list<T: Table>(
&mut self,
start: usize,
len: usize,
) -> Result<BTreeMap<T::Key, T::Value>> {
let data = self.db.view(|tx| {
let mut cursor = tx.cursor_read::<T>().expect("Was not able to obtain a cursor.");
// TODO: Upstream this in the DB trait.
let start_walker = cursor.current().transpose();
let walker = Walker::new(&mut cursor, start_walker);
walker.skip(start).take(len).collect::<Vec<_>>()
})?;
data.into_iter()
.collect::<Result<BTreeMap<T::Key, T::Value>, _>>()
.map_err(|e| eyre::eyre!(e))
}
/// Drops the database at the given path.
pub fn drop(&mut self, path: &PlatformPath<DbPath>) -> Result<()> {
info!(target: "reth::cli", "Dropping db at {}", path);
std::fs::remove_dir_all(path).wrap_err("Dropping the database failed")?;
Ok(())
}
/// Drops the provided table from the database.
pub fn drop_table<T: Table>(&mut self) -> Result<()> {
self.db.update(|tx| tx.clear::<T>())??;
Ok(())
}
}