mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 18:41:03 +00:00
Block import and export (#272)
* Block export and import * Export and import using std streams * Made AuthorituId::from_slice private
This commit is contained in:
committed by
Gav Wood
parent
5e4ef36e40
commit
4c8f902fa3
@@ -26,6 +26,7 @@ parking_lot = "0.4"
|
|||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
substrate-client = { path = "../../substrate/client" }
|
substrate-client = { path = "../../substrate/client" }
|
||||||
|
substrate-codec = { path = "../../substrate/codec" }
|
||||||
substrate-network = { path = "../../substrate/network" }
|
substrate-network = { path = "../../substrate/network" }
|
||||||
substrate-primitives = { path = "../../substrate/primitives" }
|
substrate-primitives = { path = "../../substrate/primitives" }
|
||||||
substrate-rpc = { path = "../../substrate/rpc" }
|
substrate-rpc = { path = "../../substrate/rpc" }
|
||||||
|
|||||||
@@ -104,3 +104,53 @@ subcommands:
|
|||||||
value_name: CHAIN_SPEC
|
value_name: CHAIN_SPEC
|
||||||
help: Specify the chain specification (one of dev, local or poc-2)
|
help: Specify the chain specification (one of dev, local or poc-2)
|
||||||
takes_value: true
|
takes_value: true
|
||||||
|
- export-blocks:
|
||||||
|
about: Export blocks to a file
|
||||||
|
args:
|
||||||
|
- OUTPUT:
|
||||||
|
index: 1
|
||||||
|
help: Output file name or stdout if unspecified.
|
||||||
|
required: false
|
||||||
|
- chain:
|
||||||
|
long: chain
|
||||||
|
value_name: CHAIN_SPEC
|
||||||
|
help: Specify the chain specification.
|
||||||
|
takes_value: true
|
||||||
|
- base-path:
|
||||||
|
long: base-path
|
||||||
|
short: d
|
||||||
|
value_name: PATH
|
||||||
|
help: Specify custom base path.
|
||||||
|
takes_value: true
|
||||||
|
- from:
|
||||||
|
long: from
|
||||||
|
value_name: BLOCK
|
||||||
|
help: Specify starting block number. 1 by default.
|
||||||
|
takes_value: true
|
||||||
|
- to:
|
||||||
|
long: to
|
||||||
|
value_name: BLOCK
|
||||||
|
help: Specify last block number. Best block by default.
|
||||||
|
takes_value: true
|
||||||
|
- json:
|
||||||
|
long: json
|
||||||
|
help: Use JSON output rather than binary.
|
||||||
|
takes_value: false
|
||||||
|
- import-blocks:
|
||||||
|
about: Import blocks from file.
|
||||||
|
args:
|
||||||
|
- INPUT:
|
||||||
|
index: 1
|
||||||
|
help: Input file or stdin if unspecified.
|
||||||
|
required: false
|
||||||
|
- chain:
|
||||||
|
long: chain
|
||||||
|
value_name: CHAIN_SPEC
|
||||||
|
help: Specify the chain specification.
|
||||||
|
takes_value: true
|
||||||
|
- base-path:
|
||||||
|
long: base-path
|
||||||
|
short: d
|
||||||
|
value_name: PATH
|
||||||
|
help: Specify custom base path.
|
||||||
|
takes_value: true
|
||||||
|
|||||||
+138
-13
@@ -36,6 +36,7 @@ extern crate serde_json;
|
|||||||
|
|
||||||
extern crate substrate_client as client;
|
extern crate substrate_client as client;
|
||||||
extern crate substrate_network as network;
|
extern crate substrate_network as network;
|
||||||
|
extern crate substrate_codec as codec;
|
||||||
extern crate substrate_primitives;
|
extern crate substrate_primitives;
|
||||||
extern crate substrate_rpc;
|
extern crate substrate_rpc;
|
||||||
extern crate substrate_rpc_servers as rpc;
|
extern crate substrate_rpc_servers as rpc;
|
||||||
@@ -65,11 +66,15 @@ mod chain_spec;
|
|||||||
|
|
||||||
pub use chain_spec::ChainSpec;
|
pub use chain_spec::ChainSpec;
|
||||||
|
|
||||||
use std::io;
|
use std::io::{self, Write, Read, stdin, stdout};
|
||||||
|
use std::fs::File;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use substrate_telemetry::{init_telemetry, TelemetryConfig};
|
use substrate_telemetry::{init_telemetry, TelemetryConfig};
|
||||||
use polkadot_primitives::Block;
|
use polkadot_primitives::{Block, BlockId};
|
||||||
|
use codec::Slicable;
|
||||||
|
use client::BlockOrigin;
|
||||||
|
use runtime_primitives::generic::SignedBlock;
|
||||||
|
|
||||||
use futures::sync::mpsc;
|
use futures::sync::mpsc;
|
||||||
use futures::{Sink, Future, Stream};
|
use futures::{Sink, Future, Stream};
|
||||||
@@ -106,6 +111,12 @@ fn load_spec(matches: &clap::ArgMatches) -> Result<service::ChainSpec, String> {
|
|||||||
Ok(spec)
|
Ok(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn base_path(matches: &clap::ArgMatches) -> PathBuf {
|
||||||
|
matches.value_of("base-path")
|
||||||
|
.map(|x| Path::new(x).to_owned())
|
||||||
|
.unwrap_or_else(default_base_path)
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse command line arguments and start the node.
|
/// Parse command line arguments and start the node.
|
||||||
///
|
///
|
||||||
/// IANA unassigned port ranges that we could use:
|
/// IANA unassigned port ranges that we could use:
|
||||||
@@ -123,10 +134,10 @@ pub fn run<I, T>(args: I) -> error::Result<()> where
|
|||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(ref e) if e.kind == clap::ErrorKind::VersionDisplayed => return Ok(()),
|
Err(ref e) if e.kind == clap::ErrorKind::VersionDisplayed => return Ok(()),
|
||||||
Err(ref e) if e.kind == clap::ErrorKind::HelpDisplayed => {
|
Err(ref e) if e.kind == clap::ErrorKind::HelpDisplayed => {
|
||||||
let _ = clap::App::from_yaml(yaml).print_long_help();
|
print!("{}", e);
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e.into()),
|
Err(e) => e.exit(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO [ToDr] Split parameters parsing from actual execution.
|
// TODO [ToDr] Split parameters parsing from actual execution.
|
||||||
@@ -139,11 +150,15 @@ pub fn run<I, T>(args: I) -> error::Result<()> where
|
|||||||
info!(" by Parity Technologies, 2017, 2018");
|
info!(" by Parity Technologies, 2017, 2018");
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("build-spec") {
|
if let Some(matches) = matches.subcommand_matches("build-spec") {
|
||||||
let spec = load_spec(&matches)?;
|
return build_spec(matches);
|
||||||
info!("Building chain spec");
|
}
|
||||||
let json = spec.to_json(matches.is_present("raw"))?;
|
|
||||||
print!("{}", json);
|
if let Some(matches) = matches.subcommand_matches("export-blocks") {
|
||||||
return Ok(())
|
return export_blocks(matches);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(matches) = matches.subcommand_matches("import-blocks") {
|
||||||
|
return import_blocks(matches);
|
||||||
}
|
}
|
||||||
|
|
||||||
let spec = load_spec(&matches)?;
|
let spec = load_spec(&matches)?;
|
||||||
@@ -154,10 +169,7 @@ pub fn run<I, T>(args: I) -> error::Result<()> where
|
|||||||
info!("Node name: {}", config.name);
|
info!("Node name: {}", config.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
let base_path = matches.value_of("base-path")
|
let base_path = base_path(&matches);
|
||||||
.map(|x| Path::new(x).to_owned())
|
|
||||||
.unwrap_or_else(default_base_path);
|
|
||||||
|
|
||||||
config.keystore_path = matches.value_of("keystore")
|
config.keystore_path = matches.value_of("keystore")
|
||||||
.map(|x| Path::new(x).to_owned())
|
.map(|x| Path::new(x).to_owned())
|
||||||
.unwrap_or_else(|| keystore_path(&base_path))
|
.unwrap_or_else(|| keystore_path(&base_path))
|
||||||
@@ -245,6 +257,119 @@ pub fn run<I, T>(args: I) -> error::Result<()> where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_spec(matches: &clap::ArgMatches) -> error::Result<()> {
|
||||||
|
let spec = load_spec(&matches)?;
|
||||||
|
info!("Building chain spec");
|
||||||
|
let json = spec.to_json(matches.is_present("raw"))?;
|
||||||
|
print!("{}", json);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn export_blocks(matches: &clap::ArgMatches) -> error::Result<()> {
|
||||||
|
let base_path = base_path(matches);
|
||||||
|
let spec = load_spec(&matches)?;
|
||||||
|
let mut config = service::Configuration::default_with_spec(spec);
|
||||||
|
config.database_path = db_path(&base_path).to_string_lossy().into();
|
||||||
|
info!("DB path: {}", config.database_path);
|
||||||
|
let client = service::new_client(config)?;
|
||||||
|
let (exit_send, exit) = std::sync::mpsc::channel();
|
||||||
|
ctrlc::CtrlC::set_handler(move || {
|
||||||
|
exit_send.clone().send(()).expect("Error sending exit notification");
|
||||||
|
});
|
||||||
|
info!("Exporting blocks");
|
||||||
|
let mut block: u32 = match matches.value_of("from") {
|
||||||
|
Some(v) => v.parse().map_err(|_| "Invalid --from argument")?,
|
||||||
|
None => 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let last = match matches.value_of("to") {
|
||||||
|
Some(v) => v.parse().map_err(|_| "Invalid --to argument")?,
|
||||||
|
None => client.info()?.chain.best_number as u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
if last < block {
|
||||||
|
return Err("Invalid block range specified".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let json = matches.is_present("json");
|
||||||
|
|
||||||
|
let mut file: Box<Write> = match matches.value_of("OUTPUT") {
|
||||||
|
Some(filename) => Box::new(File::open(filename)?),
|
||||||
|
None => Box::new(stdout()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if !json {
|
||||||
|
file.write(&(last - block + 1).encode())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if exit.try_recv().is_ok() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
match client.block(&BlockId::number(block as u64))? {
|
||||||
|
Some(block) => {
|
||||||
|
if json {
|
||||||
|
serde_json::to_writer(&mut *file, &block).map_err(|e| format!("Eror writing JSON: {}", e))?;
|
||||||
|
} else {
|
||||||
|
file.write(&block.encode())?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
|
if block % 10000 == 0 {
|
||||||
|
info!("#{}", block);
|
||||||
|
}
|
||||||
|
if block == last {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
block += 1;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn import_blocks(matches: &clap::ArgMatches) -> error::Result<()> {
|
||||||
|
let spec = load_spec(&matches)?;
|
||||||
|
let base_path = base_path(matches);
|
||||||
|
let mut config = service::Configuration::default_with_spec(spec);
|
||||||
|
config.database_path = db_path(&base_path).to_string_lossy().into();
|
||||||
|
let client = service::new_client(config)?;
|
||||||
|
let (exit_send, exit) = std::sync::mpsc::channel();
|
||||||
|
ctrlc::CtrlC::set_handler(move || {
|
||||||
|
exit_send.clone().send(()).expect("Error sending exit notification");
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut file: Box<Read> = match matches.value_of("INPUT") {
|
||||||
|
Some(filename) => Box::new(File::open(filename)?),
|
||||||
|
None => Box::new(stdin()),
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("Importing blocks");
|
||||||
|
let count: u32 = Slicable::decode(&mut file).ok_or("Error reading file")?;
|
||||||
|
let mut block = 0;
|
||||||
|
for _ in 0 .. count {
|
||||||
|
if exit.try_recv().is_ok() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
match SignedBlock::decode(&mut file) {
|
||||||
|
Some(block) => {
|
||||||
|
let header = client.check_justification(block.block.header, block.justification.into())?;
|
||||||
|
client.import_block(BlockOrigin::File, header, Some(block.block.extrinsics))?;
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
warn!("Error reading block data.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
block += 1;
|
||||||
|
if block % 10000 == 0 {
|
||||||
|
info!("#{}", block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info!("Imported {} blocks. Best: #{}", block, client.info()?.chain.best_number);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run_until_exit<C>(mut core: reactor::Core, service: service::Service<C>, matches: &clap::ArgMatches, sys_conf: SystemConfiguration) -> error::Result<()>
|
fn run_until_exit<C>(mut core: reactor::Core, service: service::Service<C>, matches: &clap::ArgMatches, sys_conf: SystemConfiguration) -> error::Result<()>
|
||||||
where
|
where
|
||||||
C: service::Components,
|
C: service::Components,
|
||||||
|
|||||||
@@ -99,6 +99,25 @@ pub fn new_full(config: Configuration) -> Result<Service<components::FullCompone
|
|||||||
Service::new(components::FullComponents { is_validator }, config)
|
Service::new(components::FullComponents { is_validator }, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates bare client without any networking.
|
||||||
|
pub fn new_client(config: Configuration) -> Result<Arc<Client<
|
||||||
|
<components::FullComponents as Components>::Backend,
|
||||||
|
<components::FullComponents as Components>::Executor,
|
||||||
|
Block>>,
|
||||||
|
error::Error>
|
||||||
|
{
|
||||||
|
let db_settings = client_db::DatabaseSettings {
|
||||||
|
cache_size: None,
|
||||||
|
path: config.database_path.into(),
|
||||||
|
pruning: config.pruning,
|
||||||
|
};
|
||||||
|
let executor = polkadot_executor::Executor::new();
|
||||||
|
let is_validator = (config.roles & Role::VALIDATOR) == Role::VALIDATOR;
|
||||||
|
let components = components::FullComponents { is_validator };
|
||||||
|
let (client, _) = components.build_client(db_settings, executor, &config.chain_spec)?;
|
||||||
|
Ok(client)
|
||||||
|
}
|
||||||
|
|
||||||
impl<Components> Service<Components>
|
impl<Components> Service<Components>
|
||||||
where
|
where
|
||||||
Components: components::Components,
|
Components: components::Components,
|
||||||
|
|||||||
Reference in New Issue
Block a user