From b033e1d9041f15ec924d65679fbc04def6ff3a4c Mon Sep 17 00:00:00 2001 From: Rob Walker Date: Thu, 9 Aug 2018 22:14:04 -0700 Subject: [PATCH] enhance ledger-tool * add json, which does the thing with json, move print to Rust's {:?} * add --head NUM, to limit how much work gets done for print, json, verify * add verify-internal, which very carefully checks ledger format without trying first to "recover" it * exit with errors on mis-usage --- src/bin/ledger-tool.rs | 62 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/src/bin/ledger-tool.rs b/src/bin/ledger-tool.rs index 38334d46f9..ad0ffa50d3 100644 --- a/src/bin/ledger-tool.rs +++ b/src/bin/ledger-tool.rs @@ -5,7 +5,7 @@ extern crate solana; use clap::{App, Arg, SubCommand}; use solana::bank::Bank; -use solana::ledger::read_ledger; +use solana::ledger::{read_ledger, verify_ledger}; use solana::logger; use std::io::{stdout, Write}; use std::process::exit; @@ -23,23 +23,57 @@ fn main() { .required(true) .help("use DIR for ledger location"), ) + .arg( + Arg::with_name("head") + .short("n") + .long("head") + .value_name("NUM") + .takes_value(true) + .help("at most the first NUM entries in ledger\n (only applies to verify, print, json commands)"), + ) .subcommand(SubCommand::with_name("print").about("Print the ledger")) - .subcommand(SubCommand::with_name("verify").about("Verify 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")) + .subcommand( + SubCommand::with_name("verify-internal") + .about("Verify the ledger's internal structure"), + ) .get_matches(); let ledger_path = matches.value_of("ledger").unwrap(); let entries = match read_ledger(ledger_path, true) { Ok(entries) => entries, Err(err) => { - println!("Failed to open ledger at {}: {}", ledger_path, err); + eprintln!("Failed to open ledger at {}: {}", ledger_path, err); exit(1); } }; + let head = match matches.value_of("head") { + Some(head) => head.parse().expect("please pass a number for --head"), + None => ::max_value(), + }; + match matches.subcommand() { ("print", _) => { + let mut i = 0; + for entry in entries { + if i >= head { + break; + } + i += 1; + let entry = entry.unwrap(); + println!("{:?}", entry); + } + } + ("json", _) => { + let mut i = 0; stdout().write_all(b"{\"ledger\":[\n").expect("open array"); for entry in entries { + if i >= head { + break; + } + i += 1; let entry = entry.unwrap(); serde_json::to_writer(stdout(), &entry).expect("serialize"); stdout().write_all(b",\n").expect("newline"); @@ -47,13 +81,27 @@ fn main() { stdout().write_all(b"\n]}\n").expect("close array"); } ("verify", _) => { - let entries = entries.map(|entry| entry.unwrap()); let bank = Bank::default(); - let entry_height = bank.process_ledger(entries).expect("process_ledger").0; - println!("Ledger is valid. Height: {}", entry_height); + if head != ::max_value() { + let entries = entries.map(|entry| entry.unwrap()).take(head); + bank.process_ledger(entries).expect("process_ledger").0; + } else { + let entries = entries.map(|entry| entry.unwrap()); + bank.process_ledger(entries).expect("process_ledger").0; + } } + ("verify-internal", _) => { + if let Err(e) = verify_ledger(&ledger_path, false) { + eprintln!("Error {:?} ", e); + exit(1); + } else { + println!("Ledger is valid"); + } + } + ("", _) => { - println!("{}", matches.usage()); + eprintln!("{}", matches.usage()); + exit(1); } _ => unreachable!(), };