mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-15 16:11:05 +00:00
Phase 1 of repo reorg (#719)
* Remove unneeded script * Rename Substrate Demo -> Substrate * Rename demo -> node * Build wasm from last rename. * Merge ed25519 into substrate-primitives * Minor tweak * Rename substrate -> core * Move substrate-runtime-support to core/runtime/support * Rename/move substrate-runtime-version * Move codec up a level * Rename substrate-codec -> parity-codec * Move environmental up a level * Move pwasm-* up to top, ready for removal * Remove requirement of s-r-support from s-r-primitives * Move core/runtime/primitives into core/runtime-primitives * Remove s-r-support dep from s-r-version * Remove dep of s-r-support from bft * Remove dep of s-r-support from node/consensus * Sever all other core deps from s-r-support * Forgot the no_std directive * Rename non-SRML modules to sr-* to avoid match clashes * Move runtime/* to srml/* * Rename substrate-runtime-* -> srml-* * Move srml to top-level
This commit is contained in:
committed by
Arkadiy Paronyan
parent
8fe5aa4c81
commit
1e01162505
@@ -0,0 +1,139 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Chain utilities.
|
||||
|
||||
use std::{self, io::{Read, Write}};
|
||||
use futures::Future;
|
||||
use serde_json;
|
||||
|
||||
use client::BlockOrigin;
|
||||
use runtime_primitives::generic::{SignedBlock, BlockId};
|
||||
use runtime_primitives::traits::{As};
|
||||
use components::{ServiceFactory, FactoryFullConfiguration, FactoryBlockNumber, RuntimeGenesis};
|
||||
use new_client;
|
||||
use codec::{Decode, Encode};
|
||||
use error;
|
||||
use chain_spec::ChainSpec;
|
||||
|
||||
/// Export a range of blocks to a binary stream.
|
||||
pub fn export_blocks<F, E, W>(config: FactoryFullConfiguration<F>, exit: E, mut output: W, from: FactoryBlockNumber<F>, to: Option<FactoryBlockNumber<F>>, json: bool) -> error::Result<()>
|
||||
where F: ServiceFactory, E: Future<Item=(),Error=()> + Send + 'static, W: Write,
|
||||
{
|
||||
let client = new_client::<F>(config)?;
|
||||
let mut block = from;
|
||||
|
||||
let last = match to {
|
||||
Some(v) if v == As::sa(0) => As::sa(1),
|
||||
Some(v) => v,
|
||||
None => client.info()?.chain.best_number,
|
||||
};
|
||||
|
||||
if last < block {
|
||||
return Err("Invalid block range specified".into());
|
||||
}
|
||||
|
||||
let (exit_send, exit_recv) = std::sync::mpsc::channel();
|
||||
::std::thread::spawn(move || {
|
||||
let _ = exit.wait();
|
||||
let _ = exit_send.send(());
|
||||
});
|
||||
info!("Exporting blocks from #{} to #{}", block, last);
|
||||
if !json {
|
||||
output.write(&(last - block + As::sa(1)).encode())?;
|
||||
}
|
||||
|
||||
loop {
|
||||
if exit_recv.try_recv().is_ok() {
|
||||
break;
|
||||
}
|
||||
match client.block(&BlockId::number(block))? {
|
||||
Some(block) => {
|
||||
if json {
|
||||
serde_json::to_writer(&mut output, &block).map_err(|e| format!("Eror writing JSON: {}", e))?;
|
||||
} else {
|
||||
output.write(&block.encode())?;
|
||||
}
|
||||
},
|
||||
None => break,
|
||||
}
|
||||
if block.as_() % 10000 == 0 {
|
||||
info!("#{}", block);
|
||||
}
|
||||
if block == last {
|
||||
break;
|
||||
}
|
||||
block += As::sa(1);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Import blocks from a binary stream.
|
||||
pub fn import_blocks<F, E, R>(config: FactoryFullConfiguration<F>, exit: E, mut input: R) -> error::Result<()>
|
||||
where F: ServiceFactory, E: Future<Item=(),Error=()> + Send + 'static, R: Read,
|
||||
{
|
||||
let client = new_client::<F>(config)?;
|
||||
|
||||
let (exit_send, exit_recv) = std::sync::mpsc::channel();
|
||||
::std::thread::spawn(move || {
|
||||
let _ = exit.wait();
|
||||
let _ = exit_send.send(());
|
||||
});
|
||||
|
||||
let count: u32 = Decode::decode(&mut input).ok_or("Error reading file")?;
|
||||
info!("Importing {} blocks", count);
|
||||
let mut block = 0;
|
||||
for _ in 0 .. count {
|
||||
if exit_recv.try_recv().is_ok() {
|
||||
break;
|
||||
}
|
||||
match SignedBlock::decode(&mut input) {
|
||||
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 % 1000 == 0 {
|
||||
info!("#{}", block);
|
||||
}
|
||||
}
|
||||
info!("Imported {} blocks. Best: #{}", block, client.info()?.chain.best_number);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Revert the chain.
|
||||
pub fn revert_chain<F>(config: FactoryFullConfiguration<F>, blocks: FactoryBlockNumber<F>) -> error::Result<()>
|
||||
where F: ServiceFactory,
|
||||
{
|
||||
let client = new_client::<F>(config)?;
|
||||
let reverted = client.revert(blocks)?;
|
||||
let info = client.info()?.chain;
|
||||
info!("Reverted {} blocks. Best: #{} ({})", reverted, info.best_number, info.best_hash);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Build a chain spec json
|
||||
pub fn build_spec<G>(spec: ChainSpec<G>, raw: bool) -> error::Result<String>
|
||||
where G: RuntimeGenesis,
|
||||
{
|
||||
Ok(spec.to_json(raw)?)
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Substrate chain configurations.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
use primitives::storage::{StorageKey, StorageData};
|
||||
use runtime_primitives::{BuildStorage, StorageMap};
|
||||
use serde_json as json;
|
||||
use components::RuntimeGenesis;
|
||||
|
||||
enum GenesisSource<G> {
|
||||
File(PathBuf),
|
||||
Embedded(&'static [u8]),
|
||||
Factory(fn() -> G),
|
||||
}
|
||||
|
||||
impl<G: RuntimeGenesis> GenesisSource<G> {
|
||||
fn resolve(&self) -> Result<Genesis<G>, String> {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct GenesisContainer<G> {
|
||||
genesis: Genesis<G>,
|
||||
}
|
||||
|
||||
match *self {
|
||||
GenesisSource::File(ref path) => {
|
||||
let file = File::open(path).map_err(|e| format!("Error opening spec file: {}", e))?;
|
||||
let genesis: GenesisContainer<G> = json::from_reader(file).map_err(|e| format!("Error parsing spec file: {}", e))?;
|
||||
Ok(genesis.genesis)
|
||||
},
|
||||
GenesisSource::Embedded(buf) => {
|
||||
let genesis: GenesisContainer<G> = json::from_reader(buf).map_err(|e| format!("Error parsing embedded file: {}", e))?;
|
||||
Ok(genesis.genesis)
|
||||
},
|
||||
GenesisSource::Factory(f) => Ok(Genesis::Runtime(f())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, G: RuntimeGenesis> BuildStorage for &'a ChainSpec<G> {
|
||||
fn build_storage(self) -> Result<StorageMap, String> {
|
||||
match self.genesis.resolve()? {
|
||||
Genesis::Runtime(gc) => gc.build_storage(),
|
||||
Genesis::Raw(map) => Ok(map.into_iter().map(|(k, v)| (k.0, v.0)).collect()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
enum Genesis<G> {
|
||||
Runtime(G),
|
||||
Raw(HashMap<StorageKey, StorageData>),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ChainSpecFile {
|
||||
pub name: String,
|
||||
pub id: String,
|
||||
pub boot_nodes: Vec<String>,
|
||||
pub telemetry_url: Option<String>,
|
||||
}
|
||||
|
||||
/// A configuration of a chain. Can be used to build a genesis block.
|
||||
pub struct ChainSpec<G: RuntimeGenesis> {
|
||||
spec: ChainSpecFile,
|
||||
genesis: GenesisSource<G>,
|
||||
}
|
||||
|
||||
impl<G: RuntimeGenesis> ChainSpec<G> {
|
||||
pub fn boot_nodes(&self) -> &[String] {
|
||||
&self.spec.boot_nodes
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.spec.name
|
||||
}
|
||||
|
||||
pub fn id(&self) -> &str {
|
||||
&self.spec.id
|
||||
}
|
||||
|
||||
pub fn telemetry_url(&self) -> Option<&str> {
|
||||
self.spec.telemetry_url.as_ref().map(String::as_str)
|
||||
}
|
||||
|
||||
/// Parse json content into a `ChainSpec`
|
||||
pub fn from_embedded(json: &'static [u8]) -> Result<Self, String> {
|
||||
let spec = json::from_slice(json).map_err(|e| format!("Error parsing spec file: {}", e))?;
|
||||
Ok(ChainSpec {
|
||||
spec,
|
||||
genesis: GenesisSource::Embedded(json),
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse json file into a `ChainSpec`
|
||||
pub fn from_json_file(path: PathBuf) -> Result<Self, String> {
|
||||
let file = File::open(&path).map_err(|e| format!("Error opening spec file: {}", e))?;
|
||||
let spec = json::from_reader(file).map_err(|e| format!("Error parsing spec file: {}", e))?;
|
||||
Ok(ChainSpec {
|
||||
spec,
|
||||
genesis: GenesisSource::File(path),
|
||||
})
|
||||
}
|
||||
|
||||
/// Create hardcoded spec.
|
||||
pub fn from_genesis(
|
||||
name: &str,
|
||||
id: &str,
|
||||
constructor: fn() -> G,
|
||||
boot_nodes: Vec<String>,
|
||||
telemetry_url: Option<&str>
|
||||
) -> Self
|
||||
{
|
||||
let spec = ChainSpecFile {
|
||||
name: name.to_owned(),
|
||||
id: id.to_owned(),
|
||||
boot_nodes: boot_nodes,
|
||||
telemetry_url: telemetry_url.map(str::to_owned),
|
||||
};
|
||||
ChainSpec {
|
||||
spec,
|
||||
genesis: GenesisSource::Factory(constructor),
|
||||
}
|
||||
}
|
||||
|
||||
/// Dump to json string.
|
||||
pub fn to_json(self, raw: bool) -> Result<String, String> {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Container<G> {
|
||||
#[serde(flatten)]
|
||||
spec: ChainSpecFile,
|
||||
#[serde(flatten)]
|
||||
genesis: Genesis<G>,
|
||||
|
||||
};
|
||||
let genesis = match (raw, self.genesis.resolve()?) {
|
||||
(true, Genesis::Runtime(g)) => {
|
||||
let storage = g.build_storage()?.into_iter()
|
||||
.map(|(k, v)| (StorageKey(k), StorageData(v)))
|
||||
.collect();
|
||||
|
||||
Genesis::Raw(storage)
|
||||
},
|
||||
(_, genesis) => genesis,
|
||||
};
|
||||
let spec = Container {
|
||||
spec: self.spec,
|
||||
genesis,
|
||||
};
|
||||
json::to_string_pretty(&spec).map_err(|e| format!("Error generating spec json: {}", e))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Polkadot service components.
|
||||
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use std::marker::PhantomData;
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use chain_spec::ChainSpec;
|
||||
use client_db;
|
||||
use client::{self, Client};
|
||||
use error;
|
||||
use network::{self, OnDemand};
|
||||
use substrate_executor::{NativeExecutor, NativeExecutionDispatch};
|
||||
use extrinsic_pool::{self, Options as ExtrinsicPoolOptions, Pool as ExtrinsicPool};
|
||||
use runtime_primitives::{traits::Block as BlockT, traits::Header as HeaderT, BuildStorage};
|
||||
use config::Configuration;
|
||||
use primitives::{Blake2Hasher, RlpCodec, H256};
|
||||
|
||||
// Type aliases.
|
||||
// These exist mainly to avoid typing `<F as Factory>::Foo` all over the code.
|
||||
/// Network service type for a factory.
|
||||
pub type NetworkService<F> = network::Service<
|
||||
<F as ServiceFactory>::Block,
|
||||
<F as ServiceFactory>::NetworkProtocol,
|
||||
<F as ServiceFactory>::ExtrinsicHash,
|
||||
>;
|
||||
|
||||
/// Code executor type for a factory.
|
||||
pub type CodeExecutor<F> = NativeExecutor<<F as ServiceFactory>::RuntimeDispatch>;
|
||||
|
||||
/// Full client backend type for a factory.
|
||||
pub type FullBackend<F> = client_db::Backend<<F as ServiceFactory>::Block>;
|
||||
|
||||
/// Full client executor type for a factory.
|
||||
pub type FullExecutor<F> = client::LocalCallExecutor<
|
||||
client_db::Backend<<F as ServiceFactory>::Block>,
|
||||
CodeExecutor<F>,
|
||||
>;
|
||||
|
||||
/// Light client backend type for a factory.
|
||||
pub type LightBackend<F> = client::light::backend::Backend<
|
||||
client_db::light::LightStorage<<F as ServiceFactory>::Block>,
|
||||
network::OnDemand<<F as ServiceFactory>::Block, NetworkService<F>>,
|
||||
>;
|
||||
|
||||
/// Light client executor type for a factory.
|
||||
pub type LightExecutor<F> = client::light::call_executor::RemoteCallExecutor<
|
||||
client::light::blockchain::Blockchain<
|
||||
client_db::light::LightStorage<<F as ServiceFactory>::Block>,
|
||||
network::OnDemand<<F as ServiceFactory>::Block, NetworkService<F>>
|
||||
>,
|
||||
network::OnDemand<<F as ServiceFactory>::Block, NetworkService<F>>,
|
||||
Blake2Hasher,
|
||||
RlpCodec,
|
||||
>;
|
||||
|
||||
/// Full client type for a factory.
|
||||
pub type FullClient<F> = Client<FullBackend<F>, FullExecutor<F>, <F as ServiceFactory>::Block>;
|
||||
|
||||
/// Light client type for a factory.
|
||||
pub type LightClient<F> = Client<LightBackend<F>, LightExecutor<F>, <F as ServiceFactory>::Block>;
|
||||
|
||||
/// `ChainSpec` specialization for a factory.
|
||||
pub type FactoryChainSpec<F> = ChainSpec<<F as ServiceFactory>::Genesis>;
|
||||
|
||||
/// `Genesis` specialization for a factory.
|
||||
pub type FactoryGenesis<F> = <F as ServiceFactory>::Genesis;
|
||||
|
||||
/// `Block` type for a factory.
|
||||
pub type FactoryBlock<F> = <F as ServiceFactory>::Block;
|
||||
|
||||
/// `Number` type for a factory.
|
||||
pub type FactoryBlockNumber<F> = <<FactoryBlock<F> as BlockT>::Header as HeaderT>::Number;
|
||||
|
||||
/// Full `Configuration` type for a factory.
|
||||
pub type FactoryFullConfiguration<F> = Configuration<<F as ServiceFactory>::Configuration, FactoryGenesis<F>>;
|
||||
|
||||
/// Client type for `Components`.
|
||||
pub type ComponentClient<C> = Client<
|
||||
<C as Components>::Backend,
|
||||
<C as Components>::Executor,
|
||||
FactoryBlock<<C as Components>::Factory>
|
||||
>;
|
||||
|
||||
/// Block type for `Components`
|
||||
pub type ComponentBlock<C> = <<C as Components>::Factory as ServiceFactory>::Block;
|
||||
|
||||
/// Extrinsic hash type for `Components`
|
||||
pub type ComponentExHash<C> = <<C as Components>::ExtrinsicPoolApi as extrinsic_pool::ChainApi>::Hash;
|
||||
|
||||
/// Extrinsic type.
|
||||
pub type ComponentExtrinsic<C> = <ComponentBlock<C> as BlockT>::Extrinsic;
|
||||
|
||||
/// Extrinsic pool API type for `Components`.
|
||||
pub type PoolApi<C> = <C as Components>::ExtrinsicPoolApi;
|
||||
|
||||
/// A set of traits for the runtime genesis config.
|
||||
pub trait RuntimeGenesis: Serialize + DeserializeOwned + BuildStorage {}
|
||||
impl<T: Serialize + DeserializeOwned + BuildStorage> RuntimeGenesis for T {}
|
||||
|
||||
/// A collection of types and methods to build a service on top of the substrate service.
|
||||
pub trait ServiceFactory: 'static {
|
||||
/// Block type.
|
||||
type Block: BlockT;
|
||||
/// Extrinsic hash type.
|
||||
type ExtrinsicHash: ::std::hash::Hash + Eq + Copy + fmt::Debug + fmt::LowerHex + Serialize + DeserializeOwned + ::std::str::FromStr + Send + Sync + Default + 'static;
|
||||
/// Network protocol extensions.
|
||||
type NetworkProtocol: network::specialization::Specialization<Self::Block>;
|
||||
/// Chain runtime.
|
||||
type RuntimeDispatch: NativeExecutionDispatch + Send + Sync + 'static;
|
||||
/// Extrinsic pool backend type for the full client.
|
||||
type FullExtrinsicPoolApi: extrinsic_pool::ChainApi<Hash=Self::ExtrinsicHash, Block=Self::Block> + Send + 'static;
|
||||
/// Extrinsic pool backend type for the light client.
|
||||
type LightExtrinsicPoolApi: extrinsic_pool::ChainApi<Hash=Self::ExtrinsicHash, Block=Self::Block> + 'static;
|
||||
/// Genesis configuration for the runtime.
|
||||
type Genesis: RuntimeGenesis;
|
||||
/// Other configuration for service members.
|
||||
type Configuration: Default;
|
||||
|
||||
/// Network protocol id.
|
||||
const NETWORK_PROTOCOL_ID: network::ProtocolId;
|
||||
|
||||
//TODO: replace these with a constructor trait. that ExtrinsicPool implements.
|
||||
/// Extrinsic pool constructor for the full client.
|
||||
fn build_full_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<FullClient<Self>>)
|
||||
-> Result<ExtrinsicPool<Self::FullExtrinsicPoolApi>, error::Error>;
|
||||
/// Extrinsic pool constructor for the light client.
|
||||
fn build_light_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<LightClient<Self>>)
|
||||
-> Result<ExtrinsicPool<Self::LightExtrinsicPoolApi>, error::Error>;
|
||||
|
||||
/// Build network protocol.
|
||||
fn build_network_protocol(config: &FactoryFullConfiguration<Self>)
|
||||
-> Result<Self::NetworkProtocol, error::Error>;
|
||||
}
|
||||
|
||||
/// A collection of types and function to generalise over full / light client type.
|
||||
pub trait Components: 'static {
|
||||
/// Associated service factory.
|
||||
type Factory: ServiceFactory;
|
||||
/// Client backend.
|
||||
type Backend: 'static + client::backend::Backend<FactoryBlock<Self::Factory>, Blake2Hasher, RlpCodec>;
|
||||
/// Client executor.
|
||||
type Executor: 'static + client::CallExecutor<FactoryBlock<Self::Factory>, Blake2Hasher, RlpCodec> + Send + Sync;
|
||||
/// Extrinsic pool type.
|
||||
type ExtrinsicPoolApi: 'static + extrinsic_pool::ChainApi<Hash=<Self::Factory as ServiceFactory>::ExtrinsicHash, Block=FactoryBlock<Self::Factory>>;
|
||||
|
||||
/// Create client.
|
||||
fn build_client(
|
||||
config: &FactoryFullConfiguration<Self::Factory>,
|
||||
executor: CodeExecutor<Self::Factory>,
|
||||
)
|
||||
-> Result<(
|
||||
Arc<ComponentClient<Self>>,
|
||||
Option<Arc<OnDemand<FactoryBlock<Self::Factory>, NetworkService<Self::Factory>>>>
|
||||
), error::Error>;
|
||||
|
||||
/// Create extrinsic pool.
|
||||
fn build_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<ComponentClient<Self>>)
|
||||
-> Result<ExtrinsicPool<Self::ExtrinsicPoolApi>, error::Error>;
|
||||
}
|
||||
|
||||
/// A struct that implement `Components` for the full client.
|
||||
pub struct FullComponents<Factory: ServiceFactory> {
|
||||
_factory: PhantomData<Factory>,
|
||||
}
|
||||
|
||||
impl<Factory: ServiceFactory> Components for FullComponents<Factory> {
|
||||
type Factory = Factory;
|
||||
type Executor = FullExecutor<Factory>;
|
||||
type Backend = FullBackend<Factory>;
|
||||
type ExtrinsicPoolApi = <Factory as ServiceFactory>::FullExtrinsicPoolApi;
|
||||
|
||||
fn build_client(
|
||||
config: &FactoryFullConfiguration<Factory>,
|
||||
executor: CodeExecutor<Self::Factory>,
|
||||
)
|
||||
-> Result<(
|
||||
Arc<ComponentClient<Self>>,
|
||||
Option<Arc<OnDemand<FactoryBlock<Self::Factory>, NetworkService<Self::Factory>>>>
|
||||
), error::Error>
|
||||
{
|
||||
let db_settings = client_db::DatabaseSettings {
|
||||
cache_size: None,
|
||||
path: config.database_path.as_str().into(),
|
||||
pruning: config.pruning.clone(),
|
||||
};
|
||||
Ok((Arc::new(client_db::new_client(db_settings, executor, &config.chain_spec, config.execution_strategy)?), None))
|
||||
}
|
||||
|
||||
fn build_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<ComponentClient<Self>>)
|
||||
-> Result<ExtrinsicPool<Self::ExtrinsicPoolApi>, error::Error>
|
||||
{
|
||||
Factory::build_full_extrinsic_pool(config, client)
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct that implement `Components` for the light client.
|
||||
pub struct LightComponents<Factory: ServiceFactory> {
|
||||
_factory: PhantomData<Factory>,
|
||||
}
|
||||
|
||||
impl<Factory: ServiceFactory> Components for LightComponents<Factory>
|
||||
where
|
||||
<<Factory as ServiceFactory>::Block as BlockT>::Hash: From<H256>,
|
||||
H256: From<<<Factory as ServiceFactory>::Block as BlockT>::Hash>,
|
||||
{
|
||||
type Factory = Factory;
|
||||
type Executor = LightExecutor<Factory>;
|
||||
type Backend = LightBackend<Factory>;
|
||||
type ExtrinsicPoolApi = <Factory as ServiceFactory>::LightExtrinsicPoolApi;
|
||||
|
||||
fn build_client(
|
||||
config: &FactoryFullConfiguration<Factory>,
|
||||
executor: CodeExecutor<Self::Factory>,
|
||||
)
|
||||
-> Result<(
|
||||
Arc<ComponentClient<Self>>,
|
||||
Option<Arc<OnDemand<FactoryBlock<Self::Factory>,
|
||||
NetworkService<Self::Factory>>>>
|
||||
), error::Error>
|
||||
{
|
||||
let db_settings = client_db::DatabaseSettings {
|
||||
cache_size: None,
|
||||
path: config.database_path.as_str().into(),
|
||||
pruning: config.pruning.clone(),
|
||||
};
|
||||
let db_storage = client_db::light::LightStorage::new(db_settings)?;
|
||||
let light_blockchain = client::light::new_light_blockchain(db_storage);
|
||||
let fetch_checker = Arc::new(client::light::new_fetch_checker::<_, Blake2Hasher, RlpCodec>(executor));
|
||||
let fetcher = Arc::new(network::OnDemand::new(fetch_checker));
|
||||
let client_backend = client::light::new_light_backend(light_blockchain, fetcher.clone());
|
||||
let client = client::light::new_light(client_backend, fetcher.clone(), &config.chain_spec)?;
|
||||
Ok((Arc::new(client), Some(fetcher)))
|
||||
}
|
||||
|
||||
fn build_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc<ComponentClient<Self>>)
|
||||
-> Result<ExtrinsicPool<Self::ExtrinsicPoolApi>, error::Error>
|
||||
{
|
||||
Factory::build_light_extrinsic_pool(config, client)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Service configuration.
|
||||
|
||||
use std::net::SocketAddr;
|
||||
use extrinsic_pool;
|
||||
use chain_spec::ChainSpec;
|
||||
pub use client::ExecutionStrategy;
|
||||
pub use network::Roles;
|
||||
pub use network::NetworkConfiguration;
|
||||
pub use client_db::PruningMode;
|
||||
use runtime_primitives::BuildStorage;
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use target_info::Target;
|
||||
|
||||
/// Service configuration.
|
||||
pub struct Configuration<C, G: Serialize + DeserializeOwned + BuildStorage> {
|
||||
/// Implementation name
|
||||
pub impl_name: &'static str,
|
||||
/// Implementation version
|
||||
pub impl_version: &'static str,
|
||||
/// Git commit if any.
|
||||
pub impl_commit: &'static str,
|
||||
/// Node roles.
|
||||
pub roles: Roles,
|
||||
/// Extrinsic pool configuration.
|
||||
pub extrinsic_pool: extrinsic_pool::Options,
|
||||
/// Network configuration.
|
||||
pub network: NetworkConfiguration,
|
||||
/// Path to key files.
|
||||
pub keystore_path: String,
|
||||
/// Path to the database.
|
||||
pub database_path: String,
|
||||
/// Pruning settings.
|
||||
pub pruning: PruningMode,
|
||||
/// Additional key seeds.
|
||||
pub keys: Vec<String>,
|
||||
/// Chain configuration.
|
||||
pub chain_spec: ChainSpec<G>,
|
||||
/// Custom configuration.
|
||||
pub custom: C,
|
||||
/// Telemetry server URL, optional - only `Some` if telemetry reporting is enabled
|
||||
pub telemetry: Option<String>,
|
||||
/// Node name.
|
||||
pub name: String,
|
||||
/// Execution strategy.
|
||||
pub execution_strategy: ExecutionStrategy,
|
||||
/// RPC over HTTP binding address. `None` if disabled.
|
||||
pub rpc_http: Option<SocketAddr>,
|
||||
/// RPC over Websockets binding address. `None` if disabled.
|
||||
pub rpc_ws: Option<SocketAddr>,
|
||||
/// Telemetry service URL. `None` if disabled.
|
||||
pub telemetry_url: Option<String>,
|
||||
}
|
||||
|
||||
impl<C: Default, G: Serialize + DeserializeOwned + BuildStorage> Configuration<C, G> {
|
||||
/// Create default config for given chain spec.
|
||||
pub fn default_with_spec(chain_spec: ChainSpec<G>) -> Self {
|
||||
let mut configuration = Configuration {
|
||||
impl_name: "parity-substrate",
|
||||
impl_version: "0.0.0",
|
||||
impl_commit: "",
|
||||
chain_spec,
|
||||
name: Default::default(),
|
||||
roles: Roles::FULL,
|
||||
extrinsic_pool: Default::default(),
|
||||
network: Default::default(),
|
||||
keystore_path: Default::default(),
|
||||
database_path: Default::default(),
|
||||
keys: Default::default(),
|
||||
custom: Default::default(),
|
||||
telemetry: Default::default(),
|
||||
pruning: PruningMode::default(),
|
||||
execution_strategy: ExecutionStrategy::Both,
|
||||
rpc_http: None,
|
||||
rpc_ws: None,
|
||||
telemetry_url: None,
|
||||
};
|
||||
configuration.network.boot_nodes = configuration.chain_spec.boot_nodes().to_vec();
|
||||
configuration.telemetry_url = configuration.chain_spec.telemetry_url().map(str::to_owned);
|
||||
configuration
|
||||
}
|
||||
|
||||
/// Returns full version string of this configuration.
|
||||
pub fn full_version(&self) -> String {
|
||||
full_version_from_strs(self.impl_version, self.impl_commit)
|
||||
}
|
||||
|
||||
/// Implementation id and version.
|
||||
pub fn client_id(&self) -> String {
|
||||
format!("{}/v{}", self.impl_name, self.full_version())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns platform info
|
||||
pub fn platform() -> String {
|
||||
let env = Target::env();
|
||||
let env_dash = if env.is_empty() { "" } else { "-" };
|
||||
format!("{}-{}{}{}", Target::arch(), Target::os(), env_dash, env)
|
||||
}
|
||||
|
||||
/// Returns full version string, using supplied version and commit.
|
||||
pub fn full_version_from_strs(impl_version: &str, impl_commit: &str) -> String {
|
||||
let commit_dash = if impl_commit.is_empty() { "" } else { "-" };
|
||||
format!("{}{}{}-{}", impl_version, commit_dash, impl_commit, platform())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Errors that can occur during the service operation.
|
||||
|
||||
use client;
|
||||
use network;
|
||||
use keystore;
|
||||
|
||||
error_chain! {
|
||||
foreign_links {
|
||||
Io(::std::io::Error) #[doc="IO error"];
|
||||
}
|
||||
links {
|
||||
Client(client::error::Error, client::error::ErrorKind) #[doc="Client error"];
|
||||
Network(network::error::Error, network::error::ErrorKind) #[doc="Network error"];
|
||||
Keystore(keystore::Error, keystore::ErrorKind) #[doc="Keystore error"];
|
||||
}
|
||||
|
||||
errors {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// tag::description[]
|
||||
//! Substrate service. Starts a thread that spins the network, the client and the extrinsic pool.
|
||||
//! Manages communication between them.
|
||||
// end::description[]
|
||||
|
||||
#![warn(unused_extern_crates)]
|
||||
|
||||
extern crate futures;
|
||||
extern crate exit_future;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
extern crate substrate_keystore as keystore;
|
||||
extern crate substrate_primitives as primitives;
|
||||
extern crate sr_primitives as runtime_primitives;
|
||||
extern crate substrate_network as network;
|
||||
extern crate substrate_executor;
|
||||
extern crate substrate_client as client;
|
||||
extern crate substrate_client_db as client_db;
|
||||
extern crate parity_codec as codec;
|
||||
extern crate substrate_extrinsic_pool as extrinsic_pool;
|
||||
extern crate substrate_rpc;
|
||||
extern crate substrate_rpc_servers as rpc;
|
||||
extern crate target_info;
|
||||
extern crate tokio;
|
||||
|
||||
#[macro_use]
|
||||
extern crate substrate_telemetry as tel;
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
#[macro_use]
|
||||
extern crate slog; // needed until we can reexport `slog_info` from `substrate_telemetry`
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
mod components;
|
||||
mod error;
|
||||
mod chain_spec;
|
||||
pub mod config;
|
||||
pub mod chain_ops;
|
||||
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use futures::prelude::*;
|
||||
use keystore::Store as Keystore;
|
||||
use client::BlockchainEvents;
|
||||
use runtime_primitives::traits::{Header, As};
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use exit_future::Signal;
|
||||
use tokio::runtime::TaskExecutor;
|
||||
use substrate_executor::NativeExecutor;
|
||||
use codec::{Encode, Decode};
|
||||
|
||||
pub use self::error::{ErrorKind, Error};
|
||||
pub use config::{Configuration, Roles, PruningMode};
|
||||
pub use chain_spec::ChainSpec;
|
||||
pub use extrinsic_pool::{Pool as ExtrinsicPool, Options as ExtrinsicPoolOptions, ChainApi, VerifiedTransaction, IntoPoolError};
|
||||
pub use client::ExecutionStrategy;
|
||||
|
||||
pub use components::{ServiceFactory, FullBackend, FullExecutor, LightBackend,
|
||||
LightExecutor, Components, PoolApi, ComponentClient,
|
||||
ComponentBlock, FullClient, LightClient, FullComponents, LightComponents,
|
||||
CodeExecutor, NetworkService, FactoryChainSpec, FactoryBlock,
|
||||
FactoryFullConfiguration, RuntimeGenesis, FactoryGenesis,
|
||||
ComponentExHash, ComponentExtrinsic,
|
||||
};
|
||||
|
||||
/// Substrate service.
|
||||
pub struct Service<Components: components::Components> {
|
||||
client: Arc<ComponentClient<Components>>,
|
||||
network: Option<Arc<components::NetworkService<Components::Factory>>>,
|
||||
extrinsic_pool: Arc<ExtrinsicPool<Components::ExtrinsicPoolApi>>,
|
||||
keystore: Keystore,
|
||||
exit: ::exit_future::Exit,
|
||||
signal: Option<Signal>,
|
||||
_rpc_http: Option<rpc::HttpServer>,
|
||||
_rpc_ws: Option<rpc::WsServer>,
|
||||
_telemetry: Option<tel::Telemetry>,
|
||||
}
|
||||
|
||||
/// Creates bare client without any networking.
|
||||
pub fn new_client<Factory: components::ServiceFactory>(config: FactoryFullConfiguration<Factory>)
|
||||
-> Result<Arc<ComponentClient<components::FullComponents<Factory>>>, error::Error>
|
||||
{
|
||||
let executor = NativeExecutor::new();
|
||||
let (client, _) = components::FullComponents::<Factory>::build_client(
|
||||
&config,
|
||||
executor,
|
||||
)?;
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
impl<Components> Service<Components>
|
||||
where
|
||||
Components: components::Components,
|
||||
{
|
||||
/// Creates a new service.
|
||||
pub fn new(
|
||||
config: FactoryFullConfiguration<Components::Factory>,
|
||||
task_executor: TaskExecutor,
|
||||
)
|
||||
-> Result<Self, error::Error>
|
||||
{
|
||||
let (signal, exit) = ::exit_future::signal();
|
||||
|
||||
// Create client
|
||||
let executor = NativeExecutor::new();
|
||||
|
||||
let mut keystore = Keystore::open(config.keystore_path.as_str().into())?;
|
||||
for seed in &config.keys {
|
||||
keystore.generate_from_seed(seed)?;
|
||||
}
|
||||
|
||||
// Keep the public key for telemetry
|
||||
let public_key = match keystore.contents()?.get(0) {
|
||||
Some(public_key) => public_key.clone(),
|
||||
None => {
|
||||
let key = keystore.generate("")?;
|
||||
let public_key = key.public();
|
||||
info!("Generated a new keypair: {:?}", public_key);
|
||||
|
||||
public_key
|
||||
}
|
||||
};
|
||||
|
||||
let (client, on_demand) = Components::build_client(&config, executor)?;
|
||||
let best_header = client.best_block_header()?;
|
||||
|
||||
let version = config.full_version();
|
||||
info!("Best block: #{}", best_header.number());
|
||||
telemetry!("node.start"; "height" => best_header.number().as_(), "best" => ?best_header.hash());
|
||||
|
||||
let network_protocol = <Components::Factory>::build_network_protocol(&config)?;
|
||||
let extrinsic_pool = Arc::new(
|
||||
Components::build_extrinsic_pool(config.extrinsic_pool, client.clone())?
|
||||
);
|
||||
let extrinsic_pool_adapter = ExtrinsicPoolAdapter::<Components> {
|
||||
imports_external_transactions: !config.roles == Roles::LIGHT,
|
||||
pool: extrinsic_pool.clone(),
|
||||
client: client.clone(),
|
||||
};
|
||||
|
||||
let network_params = network::Params {
|
||||
config: network::ProtocolConfig {
|
||||
roles: config.roles,
|
||||
},
|
||||
network_config: config.network,
|
||||
chain: client.clone(),
|
||||
on_demand: on_demand.clone()
|
||||
.map(|d| d as Arc<network::OnDemandService<ComponentBlock<Components>>>),
|
||||
transaction_pool: Arc::new(extrinsic_pool_adapter),
|
||||
specialization: network_protocol,
|
||||
};
|
||||
|
||||
let network = network::Service::new(network_params, Components::Factory::NETWORK_PROTOCOL_ID)?;
|
||||
on_demand.map(|on_demand| on_demand.set_service_link(Arc::downgrade(&network)));
|
||||
|
||||
{
|
||||
// block notifications
|
||||
let network = network.clone();
|
||||
let txpool = extrinsic_pool.clone();
|
||||
|
||||
let events = client.import_notification_stream()
|
||||
.for_each(move |notification| {
|
||||
network.on_block_imported(notification.hash, ¬ification.header);
|
||||
txpool.cull(&BlockId::hash(notification.hash))
|
||||
.map_err(|e| warn!("Error removing extrinsics: {:?}", e))?;
|
||||
Ok(())
|
||||
})
|
||||
.select(exit.clone())
|
||||
.then(|_| Ok(()));
|
||||
task_executor.spawn(events);
|
||||
}
|
||||
|
||||
{
|
||||
// extrinsic notifications
|
||||
let network = network.clone();
|
||||
let events = extrinsic_pool.import_notification_stream()
|
||||
// TODO [ToDr] Consider throttling?
|
||||
.for_each(move |_| {
|
||||
network.trigger_repropagate();
|
||||
Ok(())
|
||||
})
|
||||
.select(exit.clone())
|
||||
.then(|_| Ok(()));
|
||||
|
||||
task_executor.spawn(events);
|
||||
}
|
||||
|
||||
// RPC
|
||||
let rpc_config = RpcConfig {
|
||||
chain_name: config.chain_spec.name().to_string(),
|
||||
impl_name: config.impl_name,
|
||||
impl_version: config.impl_version,
|
||||
};
|
||||
|
||||
let (rpc_http, rpc_ws) = {
|
||||
let handler = || {
|
||||
let client = client.clone();
|
||||
let chain = rpc::apis::chain::Chain::new(client.clone(), task_executor.clone());
|
||||
let state = rpc::apis::state::State::new(client.clone(), task_executor.clone());
|
||||
let author = rpc::apis::author::Author::new(client.clone(), extrinsic_pool.clone(), task_executor.clone());
|
||||
rpc::rpc_handler::<ComponentBlock<Components>, ComponentExHash<Components>, _, _, _, _, _>(
|
||||
state,
|
||||
chain,
|
||||
author,
|
||||
rpc_config.clone(),
|
||||
)
|
||||
};
|
||||
(
|
||||
maybe_start_server(config.rpc_http, |address| rpc::start_http(address, handler()))?,
|
||||
maybe_start_server(config.rpc_ws, |address| rpc::start_ws(address, handler()))?,
|
||||
)
|
||||
};
|
||||
|
||||
// Telemetry
|
||||
let telemetry = match config.telemetry_url {
|
||||
Some(url) => {
|
||||
let is_authority = config.roles == Roles::AUTHORITY;
|
||||
let pubkey = format!("{}", public_key);
|
||||
let name = config.name.clone();
|
||||
let impl_name = config.impl_name.to_owned();
|
||||
let version = version.clone();
|
||||
let chain_name = config.chain_spec.name().to_owned();
|
||||
Some(tel::init_telemetry(tel::TelemetryConfig {
|
||||
url: url,
|
||||
on_connect: Box::new(move || {
|
||||
telemetry!("system.connected";
|
||||
"name" => name.clone(),
|
||||
"implementation" => impl_name.clone(),
|
||||
"version" => version.clone(),
|
||||
"config" => "",
|
||||
"chain" => chain_name.clone(),
|
||||
"pubkey" => &pubkey,
|
||||
"authority" => is_authority
|
||||
);
|
||||
}),
|
||||
}))
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
Ok(Service {
|
||||
client: client,
|
||||
network: Some(network),
|
||||
extrinsic_pool: extrinsic_pool,
|
||||
signal: Some(signal),
|
||||
keystore: keystore,
|
||||
exit,
|
||||
_rpc_http: rpc_http,
|
||||
_rpc_ws: rpc_ws,
|
||||
_telemetry: telemetry,
|
||||
})
|
||||
}
|
||||
|
||||
/// Get shared client instance.
|
||||
pub fn client(&self) -> Arc<ComponentClient<Components>> {
|
||||
self.client.clone()
|
||||
}
|
||||
|
||||
/// Get shared network instance.
|
||||
pub fn network(&self) -> Arc<components::NetworkService<Components::Factory>> {
|
||||
self.network.as_ref().expect("self.network always Some").clone()
|
||||
}
|
||||
|
||||
/// Get shared extrinsic pool instance.
|
||||
pub fn extrinsic_pool(&self) -> Arc<ExtrinsicPool<Components::ExtrinsicPoolApi>> {
|
||||
self.extrinsic_pool.clone()
|
||||
}
|
||||
|
||||
/// Get shared keystore.
|
||||
pub fn keystore(&self) -> &Keystore {
|
||||
&self.keystore
|
||||
}
|
||||
|
||||
/// Get a handle to a future that will resolve on exit.
|
||||
pub fn on_exit(&self) -> ::exit_future::Exit {
|
||||
self.exit.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Components> Drop for Service<Components> where Components: components::Components {
|
||||
fn drop(&mut self) {
|
||||
debug!(target: "service", "Substrate service shutdown");
|
||||
|
||||
drop(self.network.take());
|
||||
|
||||
if let Some(signal) = self.signal.take() {
|
||||
signal.fire();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_start_server<T, F>(address: Option<SocketAddr>, start: F) -> Result<Option<T>, io::Error> where
|
||||
F: Fn(&SocketAddr) -> Result<T, io::Error>,
|
||||
{
|
||||
Ok(match address {
|
||||
Some(mut address) => Some(start(&address)
|
||||
.or_else(|e| match e.kind() {
|
||||
io::ErrorKind::AddrInUse |
|
||||
io::ErrorKind::PermissionDenied => {
|
||||
warn!("Unable to bind server to {}. Trying random port.", address);
|
||||
address.set_port(0);
|
||||
start(&address)
|
||||
},
|
||||
_ => Err(e),
|
||||
})?),
|
||||
None => None,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct RpcConfig {
|
||||
chain_name: String,
|
||||
impl_name: &'static str,
|
||||
impl_version: &'static str,
|
||||
}
|
||||
|
||||
impl substrate_rpc::system::SystemApi for RpcConfig {
|
||||
fn system_name(&self) -> substrate_rpc::system::error::Result<String> {
|
||||
Ok(self.impl_name.into())
|
||||
}
|
||||
|
||||
fn system_version(&self) -> substrate_rpc::system::error::Result<String> {
|
||||
Ok(self.impl_version.into())
|
||||
}
|
||||
|
||||
fn system_chain(&self) -> substrate_rpc::system::error::Result<String> {
|
||||
Ok(self.chain_name.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Transaction pool adapter.
|
||||
pub struct ExtrinsicPoolAdapter<C: Components> {
|
||||
imports_external_transactions: bool,
|
||||
pool: Arc<ExtrinsicPool<C::ExtrinsicPoolApi>>,
|
||||
client: Arc<ComponentClient<C>>,
|
||||
}
|
||||
|
||||
impl<C: Components> ExtrinsicPoolAdapter<C> {
|
||||
fn best_block_id(&self) -> Option<BlockId<ComponentBlock<C>>> {
|
||||
self.client.info()
|
||||
.map(|info| BlockId::hash(info.chain.best_hash))
|
||||
.map_err(|e| {
|
||||
debug!("Error getting best block: {:?}", e);
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Components> network::TransactionPool<ComponentExHash<C>, ComponentBlock<C>> for ExtrinsicPoolAdapter<C> {
|
||||
fn transactions(&self) -> Vec<(ComponentExHash<C>, ComponentExtrinsic<C>)> {
|
||||
let best_block_id = match self.best_block_id() {
|
||||
Some(id) => id,
|
||||
None => return vec![],
|
||||
};
|
||||
self.pool.cull_and_get_pending(&best_block_id, |pending| pending
|
||||
.map(|t| {
|
||||
let hash = t.hash().clone();
|
||||
let ex: ComponentExtrinsic<C> = t.original.clone();
|
||||
(hash, ex)
|
||||
})
|
||||
.collect()
|
||||
).unwrap_or_else(|e| {
|
||||
warn!("Error retrieving pending set: {}", e);
|
||||
vec![]
|
||||
})
|
||||
}
|
||||
|
||||
fn import(&self, transaction: &ComponentExtrinsic<C>) -> Option<ComponentExHash<C>> {
|
||||
if !self.imports_external_transactions {
|
||||
return None;
|
||||
}
|
||||
|
||||
let encoded = transaction.encode();
|
||||
if let Some(uxt) = Decode::decode(&mut &encoded[..]) {
|
||||
let best_block_id = self.best_block_id()?;
|
||||
match self.pool.submit_one(&best_block_id, uxt) {
|
||||
Ok(xt) => Some(*xt.hash()),
|
||||
Err(e) => match e.into_pool_error() {
|
||||
Ok(e) => match e.kind() {
|
||||
extrinsic_pool::ErrorKind::AlreadyImported(hash) =>
|
||||
Some(::std::str::FromStr::from_str(&hash).map_err(|_| {})
|
||||
.expect("Hash string is always valid")),
|
||||
_ => {
|
||||
debug!("Error adding transaction to the pool: {:?}", e);
|
||||
None
|
||||
},
|
||||
},
|
||||
Err(e) => {
|
||||
debug!("Error converting pool error: {:?}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug!("Error decoding transaction");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn on_broadcasted(&self, propagations: HashMap<ComponentExHash<C>, Vec<String>>) {
|
||||
self.pool.on_broadcasted(propagations)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user