solana/ledger-tool/src/main.rs

149 lines
4.8 KiB
Rust
Raw Normal View History

2018-12-14 20:39:10 -08:00
use clap::{crate_version, App, Arg, SubCommand};
2019-02-07 20:52:39 -08:00
use solana::blocktree::Blocktree;
use solana::blocktree_processor;
use solana_runtime::bank::Bank;
use solana_sdk::genesis_block::GenesisBlock;
use std::io::{stdout, Write};
2018-08-06 16:03:08 -07:00
use std::process::exit;
fn main() {
solana_logger::setup();
2018-08-06 16:03:08 -07:00
let matches = App::new("ledger-tool")
.version(crate_version!())
.arg(
Arg::with_name("ledger")
.short("l")
.long("ledger")
.value_name("DIR")
.takes_value(true)
.required(true)
2018-09-14 15:32:57 -07:00
.help("Use directory for ledger location"),
)
.arg(
Arg::with_name("head")
.short("n")
.long("head")
.value_name("NUM")
.takes_value(true)
2018-09-14 15:32:57 -07:00
.help("Limit to at most the first NUM entries in ledger\n (only applies to verify, print, json commands)"),
)
.arg(
Arg::with_name("min-hashes")
.short("h")
.long("min-hashes")
.value_name("NUM")
.takes_value(true)
.help("Skip entries with fewer than NUM hashes\n (only applies to print and json commands)"),
)
.arg(
Arg::with_name("continue")
.short("c")
.long("continue")
.help("Continue verify even if verification fails"),
)
2018-08-06 16:03:08 -07:00
.subcommand(SubCommand::with_name("print").about("Print the ledger"))
.subcommand(SubCommand::with_name("json").about("Print the ledger in JSON format"))
.subcommand(SubCommand::with_name("verify").about("Verify the ledger's PoH"))
.get_matches();
let ledger_path = matches.value_of("ledger").unwrap();
2019-01-24 12:04:04 -08:00
let genesis_block = GenesisBlock::load(ledger_path).unwrap_or_else(|err| {
eprintln!(
"Failed to open ledger genesis_block at {}: {}",
ledger_path, err
);
exit(1);
});
2019-02-07 20:52:39 -08:00
let blocktree = match Blocktree::open(ledger_path) {
Ok(blocktree) => blocktree,
Err(err) => {
eprintln!("Failed to open ledger at {}: {}", ledger_path, err);
exit(1);
}
};
2019-02-07 20:52:39 -08:00
let entries = match blocktree.read_ledger() {
2018-08-06 16:03:08 -07:00
Ok(entries) => entries,
Err(err) => {
eprintln!("Failed to read ledger at {}: {}", ledger_path, err);
2018-08-06 16:03:08 -07:00
exit(1);
}
};
let head = match matches.value_of("head") {
Some(head) => head.parse().expect("please pass a number for --head"),
None => <usize>::max_value(),
};
let min_hashes = match matches.value_of("min-hashes") {
Some(hashes) => hashes
.parse()
.expect("please pass a number for --min-hashes"),
None => 0,
} as u64;
2018-08-06 16:03:08 -07:00
match matches.subcommand() {
("print", _) => {
2018-08-10 11:46:37 -07:00
for (i, entry) in entries.enumerate() {
if i >= head {
break;
}
if entry.num_hashes < min_hashes {
continue;
}
println!("{:?}", entry);
}
}
("json", _) => {
2018-08-06 16:03:08 -07:00
stdout().write_all(b"{\"ledger\":[\n").expect("open array");
2018-08-10 11:46:37 -07:00
for (i, entry) in entries.enumerate() {
if i >= head {
break;
}
if entry.num_hashes < min_hashes {
continue;
}
2018-08-06 16:03:08 -07:00
serde_json::to_writer(stdout(), &entry).expect("serialize");
stdout().write_all(b",\n").expect("newline");
}
stdout().write_all(b"\n]}\n").expect("close array");
}
("verify", _) => {
2019-01-24 12:04:04 -08:00
let bank = Bank::new(&genesis_block);
let mut last_id = bank.last_id();
let mut num_entries = 0;
for (i, entry) in entries.enumerate() {
2018-08-10 19:34:39 -07:00
if i >= head {
break;
}
if !entry.verify(&last_id) {
eprintln!("entry.verify() failed at entry[{}]", i + 2);
if !matches.is_present("continue") {
exit(1);
}
}
2019-03-01 08:57:42 -08:00
last_id = entry.hash;
num_entries += 1;
2019-02-21 13:37:08 -08:00
if let Err(e) = blocktree_processor::process_entry(&bank, &entry) {
eprintln!("verify failed at entry[{}], err: {:?}", i + 2, e);
if !matches.is_present("continue") {
exit(1);
}
}
}
println!("{} entries. last_id={:?}", num_entries, last_id);
2018-08-06 16:03:08 -07:00
}
("", _) => {
eprintln!("{}", matches.usage());
exit(1);
2018-08-06 16:03:08 -07:00
}
_ => unreachable!(),
};
}