diff --git a/Cargo.toml b/Cargo.toml index 30582f1570..283313d78a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,37 +20,37 @@ include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"] client = ["substrate-subxt-client"] [dependencies] -log = "0.4.8" +log = "0.4.11" thiserror = "1.0.20" futures = "0.3.5" jsonrpsee = { version = "0.1.0", features = ["ws"] } num-traits = { version = "0.2.12", default-features = false } serde = { version = "1.0.114", features = ["derive"] } -serde_json = "1.0.55" +serde_json = "1.0.56" url = "2.1.1" codec = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive", "full"] } -frame-metadata = { version = "11.0.0-rc4", package = "frame-metadata" } -frame-support = { version = "2.0.0-rc4", package = "frame-support" } -sp-runtime = { version = "2.0.0-rc4", package = "sp-runtime" } -sp-version = { version = "2.0.0-rc4", package = "sp-version" } -pallet-indices = { version = "2.0.0-rc4", package = "pallet-indices" } +frame-metadata = { version = "11.0.0-rc5", package = "frame-metadata" } +frame-support = { version = "2.0.0-rc5", package = "frame-support" } +sp-runtime = { version = "2.0.0-rc5", package = "sp-runtime" } +sp-version = { version = "2.0.0-rc5", package = "sp-version" } +pallet-indices = { version = "2.0.0-rc5", package = "pallet-indices" } hex = "0.4.2" -sp-rpc = { version = "2.0.0-rc4", package = "sp-rpc" } -sp-core = { version = "2.0.0-rc4", package = "sp-core" } -sc-rpc-api = { version = "0.8.0-rc4", package = "sc-rpc-api" } -sp-transaction-pool = { version = "2.0.0-rc4", package = "sp-transaction-pool" } +sp-rpc = { version = "2.0.0-rc5", package = "sp-rpc" } +sp-core = { version = "2.0.0-rc5", package = "sp-core" } +sc-rpc-api = { version = "0.8.0-rc5", package = "sc-rpc-api" } +sp-transaction-pool = { version = "2.0.0-rc5", package = "sp-transaction-pool" } substrate-subxt-client = { version = "0.2.0", path = "client", optional = true } substrate-subxt-proc-macro = { version = "0.9.0", path = "proc-macro" } [dev-dependencies] -async-std = { version = "=1.5.0", features = ["attributes"] } +async-std = { version = "1.6.2", features = ["attributes"] } env_logger = "0.7.1" -wabt = "0.9.2" -wabt-sys = "=0.7.1" # pinned because 0.7.2 fails to compile -frame-system = { version = "2.0.0-rc4", package = "frame-system" } -pallet-balances = { version = "2.0.0-rc4", package = "pallet-balances" } -sp-keyring = { version = "2.0.0-rc4", package = "sp-keyring" } +frame-system = { version = "2.0.0-rc5", package = "frame-system" } +pallet-balances = { version = "2.0.0-rc5", package = "pallet-balances" } +sp-keyring = { version = "2.0.0-rc5", package = "sp-keyring" } substrate-subxt-client = { version = "0.2.0", path = "client" } tempdir = "0.3.7" test-node = { path = "test-node" } +wabt = "0.9.2" +wabt-sys = "0.7.2" diff --git a/client/Cargo.toml b/client/Cargo.toml index f94f920cff..d7e28ee247 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -12,19 +12,19 @@ description = "Embed a substrate node into your subxt application." keywords = ["parity", "substrate", "blockchain"] [dependencies] -async-std = "=1.5.0" +async-std = "1.6.2" futures = { version = "0.3.5", features = ["compat"] } futures01 = { package = "futures", version = "0.1.29" } jsonrpsee = "0.1.0" -log = "0.4.8" -sc-network = { version = "0.8.0-rc4", default-features = false } -sc-service = { version = "0.8.0-rc4", default-features = false } -serde_json = "1.0.55" -sp-keyring = "2.0.0-rc4" +log = "0.4.11" +sc-network = { version = "0.8.0-rc5", default-features = false } +sc-service = { version = "0.8.0-rc5", default-features = false } +serde_json = "1.0.56" +sp-keyring = "2.0.0-rc5" thiserror = "1.0.20" [dev-dependencies] -async-std = { version = "=1.5.0", features = ["attributes"] } +async-std = { version = "1.6.2", features = ["attributes"] } env_logger = "0.7.1" substrate-subxt = { path = ".." } tempdir = "0.3.7" diff --git a/client/src/lib.rs b/client/src/lib.rs index 3ca04c0376..a335b11c48 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -20,20 +20,20 @@ use async_std::task; use futures::{ + channel::mpsc, compat::{ Compat01As03, - Compat01As03Sink, Sink01CompatExt, Stream01CompatExt, }, - future::poll_fn, - sink::SinkExt, - stream::{ - Stream, - StreamExt, + future::{ + select, + FutureExt, }, + sink::SinkExt, + stream::StreamExt, }; -use futures01::sync::mpsc; +use futures01::sync::mpsc as mpsc01; use jsonrpsee::{ common::{ Request, @@ -53,16 +53,18 @@ use sc_service::{ config::{ NetworkConfiguration, TaskType, + TelemetryEndpoints, }, - AbstractService, ChainSpec, Configuration, + RpcHandlers, RpcSession, + TaskManager, }; use std::{ future::Future, pin::Pin, - task::Poll, + sync::Arc, }; use thiserror::Error; @@ -74,7 +76,96 @@ pub enum SubxtClientError { Json(#[from] serde_json::Error), /// Channel closed. #[error("{0}")] - Mpsc(#[from] mpsc::SendError), + Mpsc(#[from] mpsc::SendError), +} + +/// Client for an embedded substrate node. +pub struct SubxtClient { + to_back: mpsc::Sender, + from_back: Compat01As03>, +} + +impl SubxtClient { + /// Create a new client. + pub fn new(mut task_manager: TaskManager, rpc: Arc) -> Self { + let (to_back, from_front) = mpsc::channel(4); + let (to_front, from_back) = mpsc01::channel(4); + + let session = RpcSession::new(to_front.clone()); + let session2 = session.clone(); + task::spawn( + select( + Box::pin(from_front.for_each(move |message: String| { + let rpc = rpc.clone(); + let session = session2.clone(); + let mut to_front = to_front.clone().sink_compat(); + async move { + let response = rpc.rpc_query(&session, &message).await; + if let Some(response) = response { + to_front.send(response).await.ok(); + } + } + })), + Box::pin(async move { + task_manager.future().await.ok(); + }), + ) + .map(drop), + ); + + Self { + to_back, + from_back: from_back.compat(), + } + } + + /// Creates a new client from a config. + pub fn from_config( + config: SubxtClientConfig, + builder: impl Fn( + Configuration, + ) -> Result<(TaskManager, Arc), ServiceError>, + ) -> Result { + let config = config.to_service_config(); + let (task_manager, rpc_handlers) = (builder)(config)?; + Ok(Self::new(task_manager, rpc_handlers)) + } +} + +impl TransportClient for SubxtClient { + type Error = SubxtClientError; + + fn send_request<'a>( + &'a mut self, + request: Request, + ) -> Pin> + Send + 'a>> { + Box::pin(async move { + let request = serde_json::to_string(&request)?; + self.to_back.send(request).await?; + Ok(()) + }) + } + + fn next_response<'a>( + &'a mut self, + ) -> Pin> + Send + 'a>> { + Box::pin(async move { + let response = self + .from_back + .next() + .await + .expect("channel shouldn't close") + .unwrap(); + Ok(serde_json::from_str(&response)?) + }) + } +} + +impl From for jsonrpsee::Client { + fn from(client: SubxtClient) -> Self { + let client = jsonrpsee::raw::RawClient::new(client); + jsonrpsee::Client::new(client) + } } /// Role of the node. @@ -110,7 +201,7 @@ impl From for Option { /// Client configuration. #[derive(Clone)] -pub struct SubxtClientConfig { +pub struct SubxtClientConfig { /// Name of the implementation. pub impl_name: &'static str, /// Version of the implementation. @@ -123,180 +214,96 @@ pub struct SubxtClientConfig { pub db: DatabaseConfig, /// Keystore configuration. pub keystore: KeystoreConfig, - /// Service builder. - pub builder: fn(Configuration) -> Result, /// Chain specification. pub chain_spec: C, /// Role of the node. pub role: Role, + /// Enable telemetry. + pub enable_telemetry: bool, } -/// Client for an embedded substrate node. -pub struct SubxtClient { - to_back: Compat01As03Sink, String>, - from_back: Compat01As03>, -} - -impl SubxtClient { - /// Create a new client from a config. - pub fn new( - config: SubxtClientConfig, - ) -> Result { - let (to_back, from_front) = mpsc::channel(4); - let (to_front, from_back) = mpsc::channel(4); - start_subxt_client(config, from_front, to_front)?; - Ok(Self { - to_back: to_back.sink_compat(), - from_back: from_back.compat(), - }) - } -} +impl SubxtClientConfig { + /// Creates a service configuration. + pub fn to_service_config(self) -> Configuration { + let mut network = NetworkConfiguration::new( + format!("{} (subxt client)", self.chain_spec.name()), + "unknown", + Default::default(), + None, + ); + network.boot_nodes = self.chain_spec.boot_nodes().to_vec(); + network.transport = TransportConfig::Normal { + enable_mdns: true, + allow_private_ipv4: true, + wasm_external_transport: None, + use_yamux_flow_control: true, + }; + let telemetry_endpoints = if self.enable_telemetry { + let endpoints = + TelemetryEndpoints::new(vec![("/ip4/127.0.0.1/tcp/99000/ws".into(), 0)]) + .expect("valid config; qed"); + Some(endpoints) + } else { + None + }; + let service_config = Configuration { + network, + impl_name: self.impl_name.to_string(), + impl_version: self.impl_version.to_string(), + chain_spec: Box::new(self.chain_spec), + role: self.role.into(), + task_executor: (move |fut, ty| { + match ty { + TaskType::Async => task::spawn(fut), + TaskType::Blocking => task::spawn_blocking(|| task::block_on(fut)), + } + }) + .into(), + database: self.db, + keystore: self.keystore, + max_runtime_instances: 8, + announce_block: true, + dev_key_seed: self.role.into(), + telemetry_endpoints, -impl TransportClient for SubxtClient { - type Error = SubxtClientError; + telemetry_external_transport: Default::default(), + default_heap_pages: Default::default(), + disable_grandpa: Default::default(), + execution_strategies: Default::default(), + force_authoring: Default::default(), + offchain_worker: Default::default(), + prometheus_config: Default::default(), + pruning: Default::default(), + rpc_cors: Default::default(), + rpc_http: Default::default(), + rpc_ipc: Default::default(), + rpc_ws: Default::default(), + rpc_ws_max_connections: Default::default(), + rpc_methods: Default::default(), + state_cache_child_ratio: Default::default(), + state_cache_size: Default::default(), + tracing_receiver: Default::default(), + tracing_targets: Default::default(), + transaction_pool: Default::default(), + wasm_method: Default::default(), + base_path: Default::default(), + informant_output_format: Default::default(), + }; - fn send_request<'a>( - &'a mut self, - request: Request, - ) -> Pin> + Send + 'a>> { - Box::pin(async move { - let request = serde_json::to_string(&request)?; - self.to_back.send(request).await?; - Ok(()) - }) - } + log::info!("{}", service_config.impl_name); + log::info!("✌️ version {}", service_config.impl_version); + log::info!("❤️ by {}, {}", self.author, self.copyright_start_year); + log::info!( + "📋 Chain specification: {}", + service_config.chain_spec.name() + ); + log::info!("🏷 Node name: {}", service_config.network.node_name); + log::info!("👤 Role: {:?}", self.role); - fn next_response<'a>( - &'a mut self, - ) -> Pin> + Send + 'a>> { - Box::pin(async move { - let response = self - .from_back - .next() - .await - .expect("channel shouldn't close") - .unwrap(); - Ok(serde_json::from_str(&response)?) - }) + service_config } } -impl From for jsonrpsee::Client { - fn from(client: SubxtClient) -> Self { - let client = jsonrpsee::raw::RawClient::new(client); - jsonrpsee::Client::new(client) - } -} - -fn start_subxt_client( - config: SubxtClientConfig, - from_front: mpsc::Receiver, - to_front: mpsc::Sender, -) -> Result<(), ServiceError> { - let mut network = NetworkConfiguration::new( - format!("{} (subxt client)", config.chain_spec.name()), - "unknown", - Default::default(), - None, - ); - network.boot_nodes = config.chain_spec.boot_nodes().to_vec(); - network.transport = TransportConfig::Normal { - enable_mdns: true, - allow_private_ipv4: true, - wasm_external_transport: None, - use_yamux_flow_control: true, - }; - let service_config = Configuration { - network, - impl_name: config.impl_name, - impl_version: config.impl_version, - chain_spec: Box::new(config.chain_spec), - role: config.role.into(), - task_executor: (move |fut, ty| { - match ty { - TaskType::Async => task::spawn(fut), - TaskType::Blocking => task::spawn_blocking(|| task::block_on(fut)), - }; - }) - .into(), - database: config.db, - keystore: config.keystore, - max_runtime_instances: 8, - announce_block: true, - dev_key_seed: config.role.into(), - - telemetry_endpoints: Default::default(), - telemetry_external_transport: Default::default(), - default_heap_pages: Default::default(), - disable_grandpa: Default::default(), - execution_strategies: Default::default(), - force_authoring: Default::default(), - offchain_worker: Default::default(), - prometheus_config: Default::default(), - pruning: Default::default(), - rpc_cors: Default::default(), - rpc_http: Default::default(), - rpc_ipc: Default::default(), - rpc_ws: Default::default(), - rpc_ws_max_connections: Default::default(), - rpc_methods: Default::default(), - state_cache_child_ratio: Default::default(), - state_cache_size: Default::default(), - tracing_receiver: Default::default(), - tracing_targets: Default::default(), - transaction_pool: Default::default(), - wasm_method: Default::default(), - base_path: Default::default(), - informant_output_format: Default::default(), - }; - - log::info!("{}", service_config.impl_name); - log::info!("✌️ version {}", service_config.impl_version); - log::info!("❤️ by {}, {}", config.author, config.copyright_start_year); - log::info!( - "📋 Chain specification: {}", - service_config.chain_spec.name() - ); - log::info!("🏷 Node name: {}", service_config.network.node_name); - log::info!("👤 Role: {:?}", service_config.role); - - // Create the service. This is the most heavy initialization step. - let mut service = (config.builder)(service_config)?; - - // Spawn background task. - let session = RpcSession::new(to_front.clone()); - let mut from_front = from_front.compat(); - task::spawn(poll_fn(move |cx| { - loop { - match Pin::new(&mut from_front).poll_next(cx) { - Poll::Ready(Some(message)) => { - let mut to_front = to_front.clone().sink_compat(); - let message = message - .expect("v1 streams require an error type; Stream of String can't fail; qed"); - let fut = service.rpc_query(&session, &message); - task::spawn(async move { - if let Some(response) = fut.await { - to_front.send(response).await.ok(); - } - }); - } - Poll::Pending => break, - Poll::Ready(None) => return Poll::Ready(()), - } - } - - loop { - match Pin::new(&mut service).poll(cx) { - Poll::Ready(Ok(())) => return Poll::Ready(()), - Poll::Pending => return Poll::Pending, - Poll::Ready(Err(e)) => log::error!("{}", e), - } - } - })); - - Ok(()) -} - #[cfg(test)] mod tests { use super::*; @@ -347,12 +354,14 @@ mod tests { cache_size: 64, }, keystore: KeystoreConfig::InMemory, - builder: test_node::service::new_light, chain_spec, role: Role::Light, + enable_telemetry: false, }; let client = ClientBuilder::::new() - .set_client(SubxtClient::new(config).unwrap()) + .set_client( + SubxtClient::from_config(config, test_node::service::new_light).unwrap(), + ) .build() .await .unwrap(); @@ -378,12 +387,14 @@ mod tests { cache_size: 128, }, keystore: KeystoreConfig::InMemory, - builder: test_node::service::new_full, - chain_spec: test_node::chain_spec::development_config(), + chain_spec: test_node::chain_spec::development_config().unwrap(), role: Role::Authority(AccountKeyring::Alice), + enable_telemetry: false, }; let client = ClientBuilder::::new() - .set_client(SubxtClient::new(config).unwrap()) + .set_client( + SubxtClient::from_config(config, test_node::service::new_full).unwrap(), + ) .build() .await .unwrap(); diff --git a/proc-macro/Cargo.toml b/proc-macro/Cargo.toml index cfd6a07b50..1759249672 100644 --- a/proc-macro/Cargo.toml +++ b/proc-macro/Cargo.toml @@ -16,19 +16,19 @@ proc-macro = true [dependencies] heck = "0.3.1" -proc-macro2 = "1.0.18" -proc-macro-crate = "0.1.4" -proc-macro-error = "1.0.2" +proc-macro2 = "1.0.19" +proc-macro-crate = "0.1.5" +proc-macro-error = "1.0.3" quote = "1.0.7" -syn = "1.0.33" +syn = "1.0.35" synstructure = "0.12.4" [dev-dependencies] -async-std = { version = "=1.5.0", features = ["attributes"] } +async-std = { version = "1.6.2", features = ["attributes"] } codec = { package = "parity-scale-codec", version = "1.3.0", features = ["derive"] } env_logger = "0.7.1" pretty_assertions = "0.6.1" -sp-keyring = "2.0.0-rc4" +sp-keyring = "2.0.0-rc5" substrate-subxt = { path = ".." } trybuild = "1.0.30" diff --git a/src/frame/balances.rs b/src/frame/balances.rs index 4c210ce748..edf146dc26 100644 --- a/src/frame/balances.rs +++ b/src/frame/balances.rs @@ -133,7 +133,7 @@ mod tests { use sp_keyring::AccountKeyring; #[async_std::test] - async fn test_transfer() { + async fn test_basic_transfer() { env_logger::try_init().ok(); let alice = PairSigner::::new(AccountKeyring::Alice.pair()); let bob = PairSigner::::new(AccountKeyring::Bob.pair()); diff --git a/src/lib.rs b/src/lib.rs index c833c93228..5d8148e353 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -490,12 +490,15 @@ mod tests { path: tmp.path().join("keystore"), password: None, }, - builder: test_node::service::new_full, - chain_spec: test_node::chain_spec::development_config(), + chain_spec: test_node::chain_spec::development_config().unwrap(), role: Role::Authority(key), + enable_telemetry: false, }; let client = ClientBuilder::new() - .set_client(SubxtClient::new(config).expect("Error creating subxt client")) + .set_client( + SubxtClient::from_config(config, test_node::service::new_full) + .expect("Error creating subxt client"), + ) .build() .await .expect("Error creating client"); diff --git a/test-node/Cargo.toml b/test-node/Cargo.toml index e286e01eec..82a9c9a20f 100644 --- a/test-node/Cargo.toml +++ b/test-node/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test-node" -version = "2.0.0-rc4" +version = "2.0.0-rc5" authors = ["Anonymous"] description = "Substrate Node template" edition = "2018" @@ -14,29 +14,29 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.5" -log = "0.4.8" +log = "0.4.11" structopt = "0.3.15" parking_lot = "0.11.0" -sc-cli = { version = "0.8.0-rc4", features = ["wasmtime"] } -sp-core = "2.0.0-rc4" -sc-executor = { version = "0.8.0-rc4", features = ["wasmtime"] } -sc-service = { version = "0.8.0-rc4", features = ["wasmtime"] } -sp-inherents = "2.0.0-rc4" -sc-transaction-pool = "2.0.0-rc4" -sp-transaction-pool = "2.0.0-rc4" -sc-network = "0.8.0-rc4" -sc-consensus-aura = "0.8.0-rc4" -sp-consensus-aura = "0.8.0-rc4" -sp-consensus = "0.8.0-rc4" -sc-consensus = "0.8.0-rc4" -sc-finality-grandpa = "0.8.0-rc4" -sp-finality-grandpa = "2.0.0-rc4" -sc-client-api = "2.0.0-rc4" -sp-runtime = "2.0.0-rc4" -sc-basic-authorship = "0.8.0-rc4" +sc-cli = { version = "0.8.0-rc5", features = ["wasmtime"] } +sp-core = "2.0.0-rc5" +sc-executor = { version = "0.8.0-rc5", features = ["wasmtime"] } +sc-service = { version = "0.8.0-rc5", features = ["wasmtime"] } +sp-inherents = "2.0.0-rc5" +sc-transaction-pool = "2.0.0-rc5" +sp-transaction-pool = "2.0.0-rc5" +sc-network = "0.8.0-rc5" +sc-consensus-aura = "0.8.0-rc5" +sp-consensus-aura = "0.8.0-rc5" +sp-consensus = "0.8.0-rc5" +sc-consensus = "0.8.0-rc5" +sc-finality-grandpa = "0.8.0-rc5" +sp-finality-grandpa = "2.0.0-rc5" +sc-client-api = "2.0.0-rc5" +sp-runtime = "2.0.0-rc5" +sc-basic-authorship = "0.8.0-rc5" -test-node-runtime = { version = "2.0.0-rc4", path = "runtime" } +test-node-runtime = { version = "2.0.0-rc5", path = "runtime" } [build-dependencies] -substrate-build-script-utils = "2.0.0-rc4" +substrate-build-script-utils = "2.0.0-rc5" diff --git a/test-node/runtime/Cargo.toml b/test-node/runtime/Cargo.toml index 99009a7003..c8b6793090 100644 --- a/test-node/runtime/Cargo.toml +++ b/test-node/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test-node-runtime" -version = "2.0.0-rc4" +version = "2.0.0-rc5" authors = ["Anonymous"] edition = "2018" license = "Unlicense" @@ -13,29 +13,29 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false, features = ["derive"] } -aura = { version = "2.0.0-rc4", default-features = false, package = "pallet-aura" } -balances = { version = "2.0.0-rc4", default-features = false, package = "pallet-balances" } -frame-support = { version = "2.0.0-rc4", default-features = false } -grandpa = { version = "2.0.0-rc4", default-features = false, package = "pallet-grandpa" } -randomness-collective-flip = { version = "2.0.0-rc4", default-features = false, package = "pallet-randomness-collective-flip" } -sudo = { version = "2.0.0-rc4", default-features = false, package = "pallet-sudo" } -system = { version = "2.0.0-rc4", default-features = false, package = "frame-system" } -timestamp = { version = "2.0.0-rc4", default-features = false, package = "pallet-timestamp" } -transaction-payment = { version = "2.0.0-rc4", default-features = false, package = "pallet-transaction-payment" } -frame-executive = { version = "2.0.0-rc4", default-features = false } +aura = { version = "2.0.0-rc5", default-features = false, package = "pallet-aura" } +balances = { version = "2.0.0-rc5", default-features = false, package = "pallet-balances" } +frame-support = { version = "2.0.0-rc5", default-features = false } +grandpa = { version = "2.0.0-rc5", default-features = false, package = "pallet-grandpa" } +randomness-collective-flip = { version = "2.0.0-rc5", default-features = false, package = "pallet-randomness-collective-flip" } +sudo = { version = "2.0.0-rc5", default-features = false, package = "pallet-sudo" } +system = { version = "2.0.0-rc5", default-features = false, package = "frame-system" } +timestamp = { version = "2.0.0-rc5", default-features = false, package = "pallet-timestamp" } +transaction-payment = { version = "2.0.0-rc5", default-features = false, package = "pallet-transaction-payment" } +frame-executive = { version = "2.0.0-rc5", default-features = false } serde = { version = "1.0.114", optional = true, features = ["derive"] } -sp-api = { version = "2.0.0-rc4", default-features = false } -sp-block-builder = { default-features = false, version = "2.0.0-rc4" } -sp-consensus-aura = { version = "0.8.0-rc4", default-features = false } -sp-core = { version = "2.0.0-rc4", default-features = false } -sp-inherents = { default-features = false, version = "2.0.0-rc4" } -sp-io = { version = "2.0.0-rc4", default-features = false } -sp-offchain = { version = "2.0.0-rc4", default-features = false } -sp-runtime = { version = "2.0.0-rc4", default-features = false } -sp-session = { version = "2.0.0-rc4", default-features = false } -sp-std = { version = "2.0.0-rc4", default-features = false } -sp-transaction-pool = { version = "2.0.0-rc4", default-features = false } -sp-version = { version = "2.0.0-rc4", default-features = false } +sp-api = { version = "2.0.0-rc5", default-features = false } +sp-block-builder = { version = "2.0.0-rc5", default-features = false } +sp-consensus-aura = { version = "0.8.0-rc5", default-features = false } +sp-core = { version = "2.0.0-rc5", default-features = false } +sp-inherents = { version = "2.0.0-rc5", default-features = false } +sp-io = { version = "2.0.0-rc5", default-features = false } +sp-offchain = { version = "2.0.0-rc5", default-features = false } +sp-runtime = { version = "2.0.0-rc5", default-features = false } +sp-session = { version = "2.0.0-rc5", default-features = false } +sp-std = { version = "2.0.0-rc5", default-features = false } +sp-transaction-pool = { version = "2.0.0-rc5", default-features = false } +sp-version = { version = "2.0.0-rc5", default-features = false } [build-dependencies] wasm-builder-runner = { version = "1.0.5", package = "substrate-wasm-builder-runner" } diff --git a/test-node/runtime/src/lib.rs b/test-node/runtime/src/lib.rs index 23858fa174..66f9c1bd52 100644 --- a/test-node/runtime/src/lib.rs +++ b/test-node/runtime/src/lib.rs @@ -235,6 +235,8 @@ impl system::Trait for Runtime { type OnKilledAccount = (); /// The data to be stored in an account. type AccountData = balances::AccountData; + /// Weight information for the extrinsics of this pallet. + type SystemWeightInfo = (); } impl aura::Trait for Runtime { @@ -267,6 +269,7 @@ impl timestamp::Trait for Runtime { type Moment = u64; type OnTimestampSet = Aura; type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); } parameter_types! { @@ -281,6 +284,7 @@ impl balances::Trait for Runtime { type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; + type WeightInfo = (); } parameter_types! { @@ -309,7 +313,7 @@ construct_runtime!( System: system::{Module, Call, Config, Storage, Event}, RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage}, Timestamp: timestamp::{Module, Call, Storage, Inherent}, - Aura: aura::{Module, Config, Inherent(Timestamp)}, + Aura: aura::{Module, Config, Inherent}, Grandpa: grandpa::{Module, Call, Storage, Config, Event}, Balances: balances::{Module, Call, Storage, Config, Event}, TransactionPayment: transaction_payment::{Module, Storage}, @@ -439,7 +443,7 @@ impl_runtime_apis! { Grandpa::grandpa_authorities() } - fn submit_report_equivocation_extrinsic( + fn submit_report_equivocation_unsigned_extrinsic( _equivocation_proof: fg_primitives::EquivocationProof< ::Hash, NumberFor, diff --git a/test-node/src/chain_spec.rs b/test-node/src/chain_spec.rs index 9b751ee0bb..c1e028f39b 100644 --- a/test-node/src/chain_spec.rs +++ b/test-node/src/chain_spec.rs @@ -38,13 +38,13 @@ use test_node_runtime::{ WASM_BINARY, }; -// Note this is the URL for the telemetry server +// The URL for the telemetry server. // const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. pub type ChainSpec = sc_service::GenericChainSpec; -/// Helper function to generate a crypto pair from seed +/// Generate a crypto pair from seed. pub fn get_from_seed(seed: &str) -> ::Public { TPublic::Pair::from_string(&format!("//{}", seed), None) .expect("static values are valid; qed") @@ -53,7 +53,7 @@ pub fn get_from_seed(seed: &str) -> ::Pu type AccountPublic = ::Signer; -/// Helper function to generate an account ID from seed +/// Generate an account ID from seed. pub fn get_account_id_from_seed(seed: &str) -> AccountId where AccountPublic: From<::Public>, @@ -61,20 +61,28 @@ where AccountPublic::from(get_from_seed::(seed)).into_account() } -/// Helper function to generate an authority key for Aura +/// Generate an Aura authority key. pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) { (get_from_seed::(s), get_from_seed::(s)) } -pub fn development_config() -> ChainSpec { - ChainSpec::from_genesis( +pub fn development_config() -> Result { + let wasm_binary = WASM_BINARY; + + Ok(ChainSpec::from_genesis( + // Name "Development", + // ID "dev", ChainType::Development, - || { + move || { testnet_genesis( + wasm_binary, + // Initial PoA authorities vec![authority_keys_from_seed("Alice")], + // Sudo account get_account_id_from_seed::("Alice"), + // Pre-funded accounts vec![ get_account_id_from_seed::("Alice"), get_account_id_from_seed::("Bob"), @@ -84,26 +92,39 @@ pub fn development_config() -> ChainSpec { true, ) }, + // Bootnodes vec![], + // Telemetry None, + // Protocol ID None, + // Properties None, + // Extensions None, - ) + )) } -pub fn local_testnet_config() -> ChainSpec { - ChainSpec::from_genesis( +pub fn local_testnet_config() -> Result { + let wasm_binary = WASM_BINARY; + + Ok(ChainSpec::from_genesis( + // Name "Local Testnet", + // ID "local_testnet", ChainType::Local, - || { + move || { testnet_genesis( + wasm_binary, + // Initial PoA authorities vec![ authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob"), ], + // Sudo account get_account_id_from_seed::("Alice"), + // Pre-funded accounts vec![ get_account_id_from_seed::("Alice"), get_account_id_from_seed::("Bob"), @@ -121,15 +142,22 @@ pub fn local_testnet_config() -> ChainSpec { true, ) }, + // Bootnodes vec![], + // Telemetry None, + // Protocol ID None, + // Properties None, + // Extensions None, - ) + )) } +/// Configure initial storage state for FRAME modules. fn testnet_genesis( + wasm_binary: &[u8], initial_authorities: Vec<(AuraId, GrandpaId)>, root_key: AccountId, endowed_accounts: Vec, @@ -137,10 +165,12 @@ fn testnet_genesis( ) -> GenesisConfig { GenesisConfig { system: Some(SystemConfig { - code: WASM_BINARY.to_vec(), + // Add Wasm runtime to storage. + code: wasm_binary.to_vec(), changes_trie_config: Default::default(), }), balances: Some(BalancesConfig { + // Configure endowed accounts with initial balance of 1 << 60. balances: endowed_accounts .iter() .cloned() @@ -156,6 +186,9 @@ fn testnet_genesis( .map(|x| (x.1.clone(), 1)) .collect(), }), - sudo: Some(SudoConfig { key: root_key }), + sudo: Some(SudoConfig { + // Assign network admin rights. + key: root_key, + }), } } diff --git a/test-node/src/command.rs b/test-node/src/command.rs index ec0b0fed28..c8196d2291 100644 --- a/test-node/src/command.rs +++ b/test-node/src/command.rs @@ -18,42 +18,45 @@ use crate::{ chain_spec, cli::Cli, service, + service::new_full_params, }; -use sc_cli::SubstrateCli; +use sc_cli::{ + ChainSpec, + Role, + RuntimeVersion, + SubstrateCli, +}; +use sc_service::ServiceParams; impl SubstrateCli for Cli { - fn impl_name() -> &'static str { - "Substrate Node" + fn impl_name() -> String { + "Substrate Node".into() } - fn impl_version() -> &'static str { - env!("SUBSTRATE_CLI_IMPL_VERSION") + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() } - fn description() -> &'static str { - env!("CARGO_PKG_DESCRIPTION") + fn description() -> String { + env!("CARGO_PKG_DESCRIPTION").into() } - fn author() -> &'static str { - env!("CARGO_PKG_AUTHORS") + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() } - fn support_url() -> &'static str { - "support.anonymous.an" + fn support_url() -> String { + "support.anonymous.an".into() } fn copyright_start_year() -> i32 { 2017 } - fn executable_name() -> &'static str { - env!("CARGO_PKG_NAME") - } - fn load_spec(&self, id: &str) -> Result, String> { Ok(match id { - "dev" => Box::new(chain_spec::development_config()), - "" | "local" => Box::new(chain_spec::local_testnet_config()), + "dev" => Box::new(chain_spec::development_config()?), + "" | "local" => Box::new(chain_spec::local_testnet_config()?), path => { Box::new(chain_spec::ChainSpec::from_json_file( std::path::PathBuf::from(path), @@ -61,6 +64,10 @@ impl SubstrateCli for Cli { } }) } + + fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { + &test_node_runtime::VERSION + } } /// Parse and run command line arguments @@ -70,15 +77,29 @@ pub fn run() -> sc_cli::Result<()> { match &cli.subcommand { Some(subcommand) => { let runner = cli.create_runner(subcommand)?; - runner.run_subcommand(subcommand, |config| Ok(new_full_start!(config).0)) + runner.run_subcommand(subcommand, |config| { + let ( + ServiceParams { + client, + backend, + task_manager, + import_queue, + .. + }, + .., + ) = new_full_params(config)?; + Ok((client, backend, import_queue, task_manager)) + }) } None => { let runner = cli.create_runner(&cli.run)?; - runner.run_node( - service::new_light, - service::new_full, - test_node_runtime::VERSION, - ) + runner.run_node_until_exit(|config| { + match config.role { + Role::Light => service::new_light(config), + _ => service::new_full(config), + } + .map(|service| service.0) + }) } } } diff --git a/test-node/src/service.rs b/test-node/src/service.rs index 5aba8d00bb..601d19fdc1 100644 --- a/test-node/src/service.rs +++ b/test-node/src/service.rs @@ -16,8 +16,10 @@ //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. -use sc_client_api::ExecutorProvider; -use sc_consensus::LongestChain; +use sc_client_api::{ + ExecutorProvider, + RemoteBackend, +}; use sc_executor::native_executor_instance; pub use sc_executor::NativeExecutor; use sc_finality_grandpa::{ @@ -27,9 +29,10 @@ use sc_finality_grandpa::{ }; use sc_service::{ error::Error as ServiceError, - AbstractService, Configuration, - ServiceBuilder, + RpcHandlers, + ServiceComponents, + TaskManager, }; use sp_consensus_aura::sr25519::AuthorityPair as AuraPair; use sp_inherents::InherentDataProviders; @@ -50,142 +53,184 @@ native_executor_instance!( test_node_runtime::native_version, ); -/// Starts a `ServiceBuilder` for a full service. -/// -/// Use this macro if you don't actually need the full service, but just the builder in order to -/// be able to perform chain operations. -macro_rules! new_full_start { - ($config:expr) => {{ - use sp_consensus_aura::sr25519::AuthorityPair as AuraPair; - use std::sync::Arc; - - let mut import_setup = None; - let inherent_data_providers = sp_inherents::InherentDataProviders::new(); - - let builder = - sc_service::ServiceBuilder::new_full::< - test_node_runtime::opaque::Block, - test_node_runtime::RuntimeApi, - crate::service::Executor, - >($config)? - .with_select_chain(|_config, backend| { - Ok(sc_consensus::LongestChain::new(backend.clone())) - })? - .with_transaction_pool(|builder| { - let pool_api = - sc_transaction_pool::FullChainApi::new(builder.client().clone()); - Ok(sc_transaction_pool::BasicPool::new( - builder.config().transaction_pool.clone(), - std::sync::Arc::new(pool_api), - builder.prometheus_registry(), - )) - })? - .with_import_queue( - |_config, - client, - mut select_chain, - _transaction_pool, - spawn_task_handle, - registry| { - let select_chain = select_chain - .take() - .ok_or_else(|| sc_service::Error::SelectChainRequired)?; - - let (grandpa_block_import, grandpa_link) = - sc_finality_grandpa::block_import( - client.clone(), - &(client.clone() as Arc<_>), - select_chain, - )?; - - let aura_block_import = - sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new( - grandpa_block_import.clone(), - client.clone(), - ); - - let import_queue = - sc_consensus_aura::import_queue::<_, _, _, AuraPair, _>( - sc_consensus_aura::slot_duration(&*client)?, - aura_block_import, - Some(Box::new(grandpa_block_import.clone())), - None, - client, - inherent_data_providers.clone(), - spawn_task_handle, - registry, - )?; - - import_setup = Some((grandpa_block_import, grandpa_link)); - - Ok(import_queue) - }, - )?; - - (builder, import_setup, inherent_data_providers) - }}; +type FullClient = sc_service::TFullClient; +type FullBackend = sc_service::TFullBackend; +type FullSelectChain = sc_consensus::LongestChain; + +pub fn new_full_params( + config: Configuration, +) -> Result< + ( + sc_service::ServiceParams< + Block, + FullClient, + sc_consensus_aura::AuraImportQueue, + sc_transaction_pool::FullPool, + (), + FullBackend, + >, + FullSelectChain, + sp_inherents::InherentDataProviders, + sc_finality_grandpa::GrandpaBlockImport< + FullBackend, + Block, + FullClient, + FullSelectChain, + >, + sc_finality_grandpa::LinkHalf, + ), + ServiceError, +> { + let inherent_data_providers = sp_inherents::InherentDataProviders::new(); + + let (client, backend, keystore, task_manager) = + sc_service::new_full_parts::(&config)?; + let client = Arc::new(client); + + let select_chain = sc_consensus::LongestChain::new(backend.clone()); + + let pool_api = sc_transaction_pool::FullChainApi::new( + client.clone(), + config.prometheus_registry(), + ); + let transaction_pool = sc_transaction_pool::BasicPool::new_full( + config.transaction_pool.clone(), + std::sync::Arc::new(pool_api), + config.prometheus_registry(), + task_manager.spawn_handle(), + client.clone(), + ); + + let (grandpa_block_import, grandpa_link) = sc_finality_grandpa::block_import( + client.clone(), + &(client.clone() as Arc<_>), + select_chain.clone(), + )?; + + let aura_block_import = sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new( + grandpa_block_import.clone(), + client.clone(), + ); + + let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair, _>( + sc_consensus_aura::slot_duration(&*client)?, + aura_block_import, + Some(Box::new(grandpa_block_import.clone())), + None, + client.clone(), + inherent_data_providers.clone(), + &task_manager.spawn_handle(), + config.prometheus_registry(), + )?; + + let provider = client.clone() as Arc>; + let finality_proof_provider = + Arc::new(GrandpaFinalityProofProvider::new(backend.clone(), provider)); + + let params = sc_service::ServiceParams { + backend, + client, + import_queue, + keystore, + task_manager, + transaction_pool, + config, + block_announce_validator_builder: None, + finality_proof_request_builder: None, + finality_proof_provider: Some(finality_proof_provider), + on_demand: None, + remote_blockchain: None, + rpc_extensions_builder: Box::new(|_| ()), + }; + + Ok(( + params, + select_chain, + inherent_data_providers, + grandpa_block_import, + grandpa_link, + )) } /// Builds a new service for a full client. -pub fn new_full(config: Configuration) -> Result { - let role = config.role.clone(); - let force_authoring = config.force_authoring; - let name = config.network.node_name.clone(); - let disable_grandpa = config.disable_grandpa; - - let (builder, mut import_setup, inherent_data_providers) = new_full_start!(config); - - let (block_import, grandpa_link) = - import_setup.take() - .expect("Link Half and Block Import are present for Full Services or setup failed before. qed"); - - let service = builder - .with_finality_proof_provider(|client, backend| { - // GenesisAuthoritySetProvider is implemented for StorageAndProofProvider - let provider = client as Arc>; - Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, provider)) as _) - })? - .build_full()?; +pub fn new_full( + config: Configuration, +) -> Result<(TaskManager, Arc), ServiceError> { + let (params, select_chain, inherent_data_providers, block_import, grandpa_link) = + new_full_params(config)?; + + let ( + role, + force_authoring, + name, + enable_grandpa, + prometheus_registry, + client, + transaction_pool, + keystore, + ) = { + let sc_service::ServiceParams { + config, + client, + transaction_pool, + keystore, + .. + } = ¶ms; + + ( + config.role.clone(), + config.force_authoring, + config.network.node_name.clone(), + !config.disable_grandpa, + config.prometheus_registry().cloned(), + client.clone(), + transaction_pool.clone(), + keystore.clone(), + ) + }; + + let ServiceComponents { + task_manager, + rpc_handlers, + network, + telemetry_on_connect_sinks, + .. + } = sc_service::build(params)?; if role.is_authority() { let proposer = sc_basic_authorship::ProposerFactory::new( - service.client(), - service.transaction_pool(), - service.prometheus_registry().as_ref(), + client.clone(), + transaction_pool, + prometheus_registry.as_ref(), ); - let client = service.client(); - let select_chain = service - .select_chain() - .ok_or(ServiceError::SelectChainRequired)?; - let can_author_with = sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()); let aura = sc_consensus_aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _>( sc_consensus_aura::slot_duration(&*client)?, - client, + client.clone(), select_chain, block_import, proposer, - service.network(), + network.clone(), inherent_data_providers.clone(), force_authoring, - service.keystore(), + keystore.clone(), can_author_with, )?; // the AURA authoring task is considered essential, i.e. if it // fails we take down the service with it. - service - .spawn_essential_task_handle() + task_manager + .spawn_essential_handle() .spawn_blocking("aura", aura); } // if the node isn't actively participating in consensus then it doesn't // need a keystore, regardless of which protocol we use below. let keystore = if role.is_authority() { - Some(service.keystore() as sp_core::traits::BareCryptoStorePtr) + Some(keystore as sp_core::traits::BareCryptoStorePtr) } else { None }; @@ -199,7 +244,6 @@ pub fn new_full(config: Configuration) -> Result Result Result { - let inherent_data_providers = InherentDataProviders::new(); - - ServiceBuilder::new_light::(config)? - .with_select_chain(|_config, backend| { - Ok(LongestChain::new(backend.clone())) - })? - .with_transaction_pool(|builder| { - let fetcher = builder.fetcher() - .ok_or_else(|| "Trying to start light transaction pool without active fetcher")?; - - let pool_api = sc_transaction_pool::LightChainApi::new( - builder.client().clone(), - fetcher.clone(), - ); - let pool = sc_transaction_pool::BasicPool::with_revalidation_type( - builder.config().transaction_pool.clone(), - Arc::new(pool_api), - builder.prometheus_registry(), - sc_transaction_pool::RevalidationType::Light, - ); - Ok(pool) - })? - .with_import_queue_and_fprb(| - _config, - client, - backend, - fetcher, - _select_chain, - _tx_pool, - spawn_task_handle, - prometheus_registry, - | { - let fetch_checker = fetcher - .map(|fetcher| fetcher.checker().clone()) - .ok_or_else(|| "Trying to start light import queue without active fetch checker")?; - let grandpa_block_import = sc_finality_grandpa::light_block_import( - client.clone(), - backend, - &(client.clone() as Arc<_>), - Arc::new(fetch_checker), - )?; - let finality_proof_import = grandpa_block_import.clone(); - let finality_proof_request_builder = - finality_proof_import.create_finality_proof_request_builder(); - - let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair, _>( - sc_consensus_aura::slot_duration(&*client)?, - grandpa_block_import, - None, - Some(Box::new(finality_proof_import)), - client, - inherent_data_providers.clone(), - spawn_task_handle, - prometheus_registry, - )?; - - Ok((import_queue, finality_proof_request_builder)) - })? - .with_finality_proof_provider(|client, backend| { - // GenesisAuthoritySetProvider is implemented for StorageAndProofProvider - let provider = client as Arc>; - Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, provider)) as _) - })? - .build_light() +pub fn new_light( + config: Configuration, +) -> Result<(TaskManager, Arc), ServiceError> { + let (client, backend, keystore, task_manager, on_demand) = + sc_service::new_light_parts::(&config)?; + + let transaction_pool_api = Arc::new(sc_transaction_pool::LightChainApi::new( + client.clone(), + on_demand.clone(), + )); + let transaction_pool = sc_transaction_pool::BasicPool::new_light( + config.transaction_pool.clone(), + transaction_pool_api, + config.prometheus_registry(), + task_manager.spawn_handle(), + ); + + let grandpa_block_import = sc_finality_grandpa::light_block_import( + client.clone(), + backend.clone(), + &(client.clone() as Arc<_>), + Arc::new(on_demand.checker().clone()) as Arc<_>, + )?; + let finality_proof_import = grandpa_block_import.clone(); + let finality_proof_request_builder = + finality_proof_import.create_finality_proof_request_builder(); + + let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair, _>( + sc_consensus_aura::slot_duration(&*client)?, + grandpa_block_import, + None, + Some(Box::new(finality_proof_import)), + client.clone(), + InherentDataProviders::new(), + &task_manager.spawn_handle(), + config.prometheus_registry(), + )?; + + let finality_proof_provider = Arc::new(GrandpaFinalityProofProvider::new( + backend.clone(), + client.clone() as Arc<_>, + )); + + sc_service::build(sc_service::ServiceParams { + block_announce_validator_builder: None, + finality_proof_request_builder: Some(finality_proof_request_builder), + finality_proof_provider: Some(finality_proof_provider), + on_demand: Some(on_demand), + remote_blockchain: Some(backend.remote_blockchain()), + rpc_extensions_builder: Box::new(|_| ()), + transaction_pool: Arc::new(transaction_pool), + config, + client, + import_queue, + keystore, + backend, + task_manager, + }) + .map( + |ServiceComponents { + task_manager, + rpc_handlers, + .. + }| (task_manager, rpc_handlers), + ) }