diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 56048382a..83b77b774 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -374,6 +374,16 @@ impl Client where V: Verifier { self.chain.configure_cache(pref_cache_size, max_cache_size); } + /// Look up the block number for the given block ID. + pub fn block_number(&self, id: BlockID) -> Option { + match id { + BlockID::Number(number) => Some(number), + BlockID::Hash(ref hash) => self.chain.block_number(hash), + BlockID::Earliest => Some(0), + BlockID::Latest => Some(self.chain.best_block_number()) + } + } + fn block_hash(chain: &BlockChain, id: BlockID) -> Option { match id { BlockID::Hash(hash) => Some(hash), @@ -383,15 +393,6 @@ impl Client where V: Verifier { } } - fn block_number(&self, id: BlockID) -> Option { - match id { - BlockID::Number(number) => Some(number), - BlockID::Hash(ref hash) => self.chain.block_number(hash), - BlockID::Earliest => Some(0), - BlockID::Latest => Some(self.chain.best_block_number()) - } - } - fn transaction_address(&self, id: TransactionID) -> Option { match id { TransactionID::Hash(ref hash) => self.chain.transaction_address(hash), diff --git a/parity/cli.rs b/parity/cli.rs index e09c4b7f4..e0edec29f 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -24,6 +24,7 @@ Parity. Ethereum Client. Usage: parity daemon [options] parity account (new | list) [options] + parity export [ ] [options] parity [options] Protocol Options: @@ -42,9 +43,9 @@ Account Options: ACCOUNTS is a comma-delimited list of addresses. --password FILE Provide a file containing a password for unlocking an account. - --keys-iterations NUM Specify the number of iterations to use when deriving key - from the password (bigger is more secure) - [default: 10240]. + --keys-iterations NUM Specify the number of iterations to use when + deriving key from the password (bigger is more + secure) [default: 10240]. --no-import-keys Do not import keys from legacy clients. Networking Options: @@ -142,6 +143,14 @@ Footprint Options: the entire system, overrides other cache and queue options. +Export Options: + --from BLOCK Export from block BLOCK, which may be an index or + hash [default: 0]. + --to BLOCK Export to (including) block NUMBER, which may be an + index, hash or 'latest' [default: latest]. + --format FORMAT Export in given format. FORMAT must be one of 'hex' + and 'binary' [default: hex]. + Virtual Machine Options: --jitvm Enable the JIT VM. @@ -186,7 +195,9 @@ pub struct Args { pub cmd_account: bool, pub cmd_new: bool, pub cmd_list: bool, + pub cmd_export: bool, pub arg_pid_file: String, + pub arg_file: Option, pub flag_chain: String, pub flag_db_path: String, pub flag_identity: String, @@ -230,6 +241,9 @@ pub struct Args { pub flag_tx_limit: usize, pub flag_logging: Option, pub flag_version: bool, + pub flag_from: String, + pub flag_to: String, + pub flag_format: String, pub flag_jitvm: bool, // legacy... pub flag_geth: bool, diff --git a/parity/main.rs b/parity/main.rs index a2750dff4..b36bfbe58 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -65,7 +65,9 @@ mod configuration; use ctrlc::CtrlC; use util::*; +use std::fs::File; use util::panics::{MayPanic, ForwardPanic, PanicHandler}; +use ethcore::client::{BlockID, BlockChainClient}; use ethcore::service::ClientService; use ethsync::EthSync; use ethminer::{Miner, MinerService, ExternalMiner}; @@ -104,6 +106,11 @@ fn execute(conf: Configuration) { return; } + if conf.args.cmd_export { + execute_export(conf); + return; + } + execute_client(conf); } @@ -216,6 +223,80 @@ fn flush_stdout() { ::std::io::stdout().flush().expect("stdout is flushable; qed"); } +enum DataFormat { + Hex, + Binary, +} + +fn execute_export(conf: Configuration) { + println!("Exporting to {:?} from {}, to {}", conf.args.arg_file, conf.args.flag_from, conf.args.flag_to); + + // Setup panic handler + let panic_handler = PanicHandler::new_in_arc(); + + // Raise fdlimit + unsafe { ::fdlimit::raise_fd_limit(); } + + let spec = conf.spec(); + let net_settings = NetworkConfiguration { + config_path: None, + listen_address: None, + public_address: None, + udp_port: None, + nat_enabled: false, + discovery_enabled: false, + pin: true, + boot_nodes: Vec::new(), + use_secret: None, + ideal_peers: 0, + }; + let client_config = conf.client_config(&spec); + + // Build client + let service = ClientService::start( + client_config, spec, net_settings, Path::new(&conf.path()) + ).unwrap_or_else(|e| die_with_error("Client", e)); + + panic_handler.forward_from(&service); + let client = service.client(); + + // we have a client! + let parse_block_id = |s: &str, arg: &str| -> u64 { + if s == "latest" { + client.chain_info().best_block_number + } else if let Ok(n) = s.parse::() { + n + } else if let Ok(h) = H256::from_str(s) { + client.block_number(BlockID::Hash(h)).unwrap_or_else(|| { + die!("Unknown block hash passed to {} parameter: {:?}", arg, s); + }) + } else { + die!("Invalid {} parameter given: {:?}", arg, s); + } + }; + let from = parse_block_id(&conf.args.flag_from, "--from"); + let to = parse_block_id(&conf.args.flag_to, "--to"); + let format = match conf.args.flag_format.deref() { + "binary" | "bin" => DataFormat::Binary, + "hex" => DataFormat::Hex, + x => die!("Invalid --format parameter given: {:?}", x), + }; + + let mut out: Box = if let Some(f) = conf.args.arg_file { + Box::new(File::create(&f).unwrap_or_else(|_| die!("Cannot write to file given: {}", f))) + } else { + Box::new(::std::io::stdout()) + }; + + for i in from..(to + 1) { + let b = client.deref().block(BlockID::Number(i)).unwrap(); + match format { + DataFormat::Binary => { out.write(&b).expect("Couldn't write to stream."); } + DataFormat::Hex => { out.write_fmt(format_args!("{}", b.pretty())).expect("Couldn't write to stream."); } + } + } +} + fn execute_account_cli(conf: Configuration) { use util::keys::store::SecretStore; use rpassword::read_password;