Skip to content

Commit

Permalink
Merge branch 'gijs/custom-height-db-dump' (#1468)
Browse files Browse the repository at this point in the history
* origin/gijs/custom-height-db-dump:
  changelog: #1468
  Buffer write for db-dump. Changes arg to ownership
  `dump-db` custom height
  • Loading branch information
Fraccaman committed Sep 6, 2023
2 parents 90f120c + c995021 commit 554a7e3
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Adds the possibility to dump the state of the db at a custom height.
([\#1468](https://github.com/anoma/namada/pull/1468))
36 changes: 18 additions & 18 deletions apps/src/lib/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2420,7 +2420,7 @@ pub mod args {
}),
);
pub const BLOCK_HEIGHT: Arg<BlockHeight> = arg("block-height");
// pub const BLOCK_HEIGHT_OPT: ArgOpt<BlockHeight> = arg_opt("height");
pub const BLOCK_HEIGHT_OPT: ArgOpt<BlockHeight> = arg_opt("height");
pub const BROADCAST_ONLY: ArgFlag = flag("broadcast-only");
pub const CHAIN_ID: Arg<ChainId> = arg("chain-id");
pub const CHAIN_ID_OPT: ArgOpt<ChainId> = CHAIN_ID.opt();
Expand Down Expand Up @@ -2686,41 +2686,41 @@ pub mod args {
#[derive(Clone, Debug)]
pub struct LedgerDumpDb {
// TODO: allow to specify height
// pub block_height: Option<BlockHeight>,
pub block_height: Option<BlockHeight>,
pub out_file_path: PathBuf,
pub historic: bool,
}

impl Args for LedgerDumpDb {
fn parse(matches: &ArgMatches) -> Self {
// let block_height = BLOCK_HEIGHT_OPT.parse(matches);
let block_height = BLOCK_HEIGHT_OPT.parse(matches);
let out_file_path = OUT_FILE_PATH_OPT
.parse(matches)
.unwrap_or_else(|| PathBuf::from("db_dump".to_string()));
let historic = HISTORIC.parse(matches);

Self {
// block_height,
block_height,
out_file_path,
historic,
}
}

fn def(app: App) -> App {
app
// .arg(BLOCK_HEIGHT_OPT.def().help(
// "The block height to dump. Defaults to latest committed
// block.", ))
.arg(OUT_FILE_PATH_OPT.def().help(
"Path for the output file (omitting file extension). \
Defaults to \"db_dump.{block_height}.toml\" in the \
current working directory.",
))
.arg(
HISTORIC.def().help(
"If provided, dump also the diff of the last height",
),
)
app.arg(BLOCK_HEIGHT_OPT.def().help(
"The block height to dump. Defaults to latest committed
block.",
))
.arg(OUT_FILE_PATH_OPT.def().help(
"Path for the output file (omitting file extension). Defaults \
to \"db_dump.{block_height}.toml\" in the current working \
directory.",
))
.arg(
HISTORIC
.def()
.help("If provided, dump also the diff of the last height"),
)
}
}

Expand Down
4 changes: 2 additions & 2 deletions apps/src/lib/node/ledger/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ pub fn reset(config: config::Ledger) -> Result<(), shell::Error> {
pub fn dump_db(
config: config::Ledger,
args::LedgerDumpDb {
// block_height,
block_height,
out_file_path,
historic,
}: args::LedgerDumpDb,
Expand All @@ -226,7 +226,7 @@ pub fn dump_db(
let db_path = config.shell.db_dir(&chain_id);

let db = storage::PersistentDB::open(db_path, None);
db.dump_last_block(out_file_path, historic);
db.dump_block(out_file_path, historic, block_height);
}

/// Roll Namada state back to the previous height
Expand Down
62 changes: 52 additions & 10 deletions apps/src/lib/node/ledger/storage/rocksdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@
//! - `header`: block's header
use std::fs::File;
use std::io::BufWriter;
use std::path::Path;
use std::str::FromStr;
use std::sync::Mutex;

use ark_serialize::Write;
use borsh::{BorshDeserialize, BorshSerialize};
use data_encoding::HEXLOWER;
use namada::core::types::ethereum_structs;
Expand Down Expand Up @@ -252,23 +254,27 @@ impl RocksDB {
}

/// Dump last known block
pub fn dump_last_block(
pub fn dump_block(
&self,
out_file_path: std::path::PathBuf,
historic: bool,
height: Option<BlockHeight>,
) {
// Find the last block height
let state_cf = self
.get_column_family(STATE_CF)
.expect("State column family should exist");
let height: BlockHeight = types::decode(

let last_height: BlockHeight = types::decode(
self.0
.get_cf(state_cf, "height")
.expect("Unable to read DB")
.expect("No block height found"),
)
.expect("Unable to decode block height");

let height = height.unwrap_or(last_height);

let full_path = out_file_path
.with_file_name(format!(
"{}_{height}",
Expand Down Expand Up @@ -306,10 +312,46 @@ impl RocksDB {
}

// subspace
let cf = self
.get_column_family(SUBSPACE_CF)
.expect("Subspace column family should exist");
self.dump_it(cf, None, &mut file);
if height != last_height {
// Restoring subspace at specified height
let restored_subspace = self
.iter_prefix(None)
.par_bridge()
.fold(
|| "".to_string(),
|mut cur, (key, _value, _gas)| match self
.read_subspace_val_with_height(
&Key::from(key.to_db_key()),
height,
last_height,
)
.expect("Unable to find subspace key")
{
Some(value) => {
let val = HEXLOWER.encode(&value);
let new_line = format!("\"{key}\" = \"{val}\"\n");
cur.push_str(new_line.as_str());
cur
}
None => cur,
},
)
.reduce(
|| "".to_string(),
|mut a: String, b: String| {
a.push_str(&b);
a
},
);
file.write_all(restored_subspace.as_bytes())
.expect("Unable to write to output file");
} else {
// Just dump the current subspace
let cf = self
.get_column_family(SUBSPACE_CF)
.expect("Subspace column family should exist");
self.dump_it(cf, None, &mut file);
}

println!("Done writing to {}", full_path.to_string_lossy());
}
Expand All @@ -321,8 +363,6 @@ impl RocksDB {
prefix: Option<String>,
file: &mut File,
) {
use std::io::Write;

let read_opts = make_iter_read_opts(prefix.clone());
let iter = if let Some(prefix) = prefix {
self.0.iterator_cf_opt(
Expand All @@ -334,16 +374,18 @@ impl RocksDB {
self.0.iterator_cf_opt(cf, read_opts, IteratorMode::Start)
};

let mut buf = BufWriter::new(file);
for (key, raw_val, _gas) in PersistentPrefixIterator(
PrefixIterator::new(iter, String::default()),
// Empty string to prevent prefix stripping, the prefix is
// already in the enclosed iterator
) {
let val = HEXLOWER.encode(&raw_val);
let bytes = format!("\"{key}\" = \"{val}\"\n");
file.write_all(bytes.as_bytes())
.expect("Unable to write to output file");
buf.write_all(bytes.as_bytes())
.expect("Unable to write to buffer");
}
buf.flush().expect("Unable to write to output file");
}

/// Rollback to previous block. Given the inner working of tendermint
Expand Down

0 comments on commit 554a7e3

Please sign in to comment.