mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 02:51:08 +00:00
Merge branch 'master' into staking
This commit is contained in:
@@ -16,13 +16,14 @@ jobs:
|
|||||||
|
|
||||||
- name: setup
|
- name: setup
|
||||||
run: |
|
run: |
|
||||||
rustup install nightly --profile default
|
rustup install nightly --profile default
|
||||||
|
rustup +nightly target add wasm32-unknown-unknown
|
||||||
|
|
||||||
- name: fmt
|
- name: fmt
|
||||||
run: cargo +nightly fmt --all -- --check
|
run: cargo +nightly fmt --all -- --check
|
||||||
|
|
||||||
- name: build
|
- name: build
|
||||||
run: cargo build --verbose
|
run: cargo build --workspace --verbose
|
||||||
|
|
||||||
- name: test
|
- name: test
|
||||||
run: cargo test --verbose
|
run: cargo test --workspace --verbose
|
||||||
|
|||||||
+34
-17
@@ -1,5 +1,5 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [".", "proc-macro"]
|
members = [".", "client", "proc-macro"]
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "substrate-subxt"
|
name = "substrate-subxt"
|
||||||
@@ -19,23 +19,33 @@ include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"]
|
|||||||
[features]
|
[features]
|
||||||
kusama = []
|
kusama = []
|
||||||
default = ["kusama"]
|
default = ["kusama"]
|
||||||
|
client = ["substrate-subxt-client"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log = "0.4.8"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0.19"
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
jsonrpsee = { version = "0.1", features = ["ws"] }
|
jsonrpsee = { version = "0.1.0", features = ["ws"] }
|
||||||
num-traits = { version = "0.2", default-features = false }
|
num-traits = { version = "0.2.11", default-features = false }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0.111", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0.53"
|
||||||
url = "2.1"
|
url = "2.1.1"
|
||||||
codec = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive", "full"] }
|
codec = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive", "full"] }
|
||||||
hex = "0.4.0"
|
|
||||||
|
frame-metadata = { version = "11.0.0-rc3", package = "frame-metadata" }
|
||||||
|
frame-support = { version = "2.0.0-rc3", package = "frame-support" }
|
||||||
|
sp-runtime = { version = "2.0.0-rc3", package = "sp-runtime" }
|
||||||
|
sp-version = { version = "2.0.0-rc3", package = "sp-version" }
|
||||||
|
pallet-indices = { version = "2.0.0-rc3", package = "pallet-indices" }
|
||||||
|
hex = "0.4.2"
|
||||||
|
sp-rpc = { version = "2.0.0-rc3", package = "sp-rpc" }
|
||||||
|
sp-core = { version = "2.0.0-rc3", package = "sp-core" }
|
||||||
|
sc-rpc-api = { version = "0.8.0-rc3", package = "sc-rpc-api" }
|
||||||
|
sp-transaction-pool = { version = "2.0.0-rc3", package = "sp-transaction-pool" }
|
||||||
|
substrate-subxt-client = { path = "client", optional = true }
|
||||||
substrate-subxt-proc-macro = { version = "0.8.0", path = "proc-macro" }
|
substrate-subxt-proc-macro = { version = "0.8.0", path = "proc-macro" }
|
||||||
sp-std = "2.0.0-rc3"
|
sp-std = "2.0.0-rc3"
|
||||||
application-crypto = { version = "2.0.0-rc3", package = "sp-application-crypto" }
|
application-crypto = { version = "2.0.0-rc3", package = "sp-application-crypto" }
|
||||||
sp-core = "2.0.0-rc3"
|
|
||||||
sp-rpc = "2.0.0-rc3"
|
|
||||||
pallet-indices = "2.0.0-rc3"
|
pallet-indices = "2.0.0-rc3"
|
||||||
sp-runtime = "2.0.0-rc3"
|
sp-runtime = "2.0.0-rc3"
|
||||||
sp-version = "2.0.0-rc3"
|
sp-version = "2.0.0-rc3"
|
||||||
@@ -49,9 +59,16 @@ frame-support = "2.0.0-rc3"
|
|||||||
sp-transaction-pool = "2.0.0-rc3"
|
sp-transaction-pool = "2.0.0-rc3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
async-std = { version = "1.5.0", features = ["attributes"] }
|
async-std = { version = "=1.5.0", features = ["attributes"] }
|
||||||
env_logger = "0.7"
|
env_logger = "0.7.1"
|
||||||
wabt = "0.9"
|
wabt = "0.9.2"
|
||||||
frame-system = { version = "2.0.0-rc2", package = "frame-system" }
|
frame-system = { version = "2.0.0-rc3", package = "frame-system" }
|
||||||
pallet-balances = { version = "2.0.0-rc2", package = "pallet-balances" }
|
node-template = { git = "https://github.com/paritytech/substrate" }
|
||||||
sp-keyring = { version = "2.0.0-rc2", package = "sp-keyring" }
|
pallet-balances = { version = "2.0.0-rc3", package = "pallet-balances" }
|
||||||
|
sp-keyring = { version = "2.0.0-rc3", package = "sp-keyring" }
|
||||||
|
substrate-subxt-client = { path = "client" }
|
||||||
|
tempdir = "0.3.7"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
sc-network = { git = "https://github.com/paritytech/substrate" }
|
||||||
|
sc-service = { git = "https://github.com/paritytech/substrate" }
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ complaining about an undefined method with a name starting with `with_`.
|
|||||||
|
|
||||||
[substrate-api-client](https://github.com/scs/substrate-api-client) provides similar functionality.
|
[substrate-api-client](https://github.com/scs/substrate-api-client) provides similar functionality.
|
||||||
|
|
||||||
|
## Subxt Client
|
||||||
|
By default the client builder will connect to a full node via rpc. The `subxt-client` helps
|
||||||
|
embedding a light client directly. It can also be used to embed a full node. This is especially
|
||||||
|
useful for testing and ci.
|
||||||
|
|
||||||
#### License
|
#### License
|
||||||
|
|
||||||
<sup>
|
<sup>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
dev-chain.json
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
[package]
|
||||||
|
name = "substrate-subxt-client"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["David Craven <david@craven.ch>", "Parity Technologies <admin@parity.io>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
license = "GPL-3.0"
|
||||||
|
repository = "https://github.com/paritytech/substrate-subxt"
|
||||||
|
documentation = "https://docs.rs/substrate-subxt-client"
|
||||||
|
homepage = "https://www.parity.io/"
|
||||||
|
description = "Embed a substrate node into your subxt application."
|
||||||
|
keywords = ["parity", "substrate", "blockchain"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
async-std = "=1.5.0"
|
||||||
|
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-rc3", default-features = false }
|
||||||
|
sc-service = { version = "0.8.0-rc3", default-features = false }
|
||||||
|
serde_json = "1.0.53"
|
||||||
|
sp-keyring = "2.0.0-rc3"
|
||||||
|
thiserror = "1.0.19"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
async-std = { version = "=1.5.0", features = ["attributes"] }
|
||||||
|
env_logger = "0.7.1"
|
||||||
|
node-template = { git = "https://github.com/paritytech/substrate" }
|
||||||
|
substrate-subxt = { path = ".." }
|
||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
NODE_TEMPLATE=../../substrate/target/release/node-template
|
||||||
|
$NODE_TEMPLATE purge-chain --dev
|
||||||
|
$NODE_TEMPLATE build-spec --dev > dev-chain.json
|
||||||
|
rm -rf /tmp/subxt-light-client
|
||||||
Executable
+4
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
NODE_TEMPLATE=../../substrate/target/release/node-template
|
||||||
|
$NODE_TEMPLATE purge-chain --chain=dev-chain.json
|
||||||
|
rm -rf /tmp/subxt-light-client
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
NODE_TEMPLATE=../../substrate/target/release/node-template
|
||||||
|
$NODE_TEMPLATE --chain=dev-chain.json --alice
|
||||||
@@ -0,0 +1,386 @@
|
|||||||
|
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of substrate-subxt.
|
||||||
|
//
|
||||||
|
// subxt 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.
|
||||||
|
//
|
||||||
|
// subxt 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-subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Client for embedding substrate nodes.
|
||||||
|
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
|
use async_std::task;
|
||||||
|
use futures::{
|
||||||
|
compat::{
|
||||||
|
Compat01As03,
|
||||||
|
Compat01As03Sink,
|
||||||
|
Sink01CompatExt,
|
||||||
|
Stream01CompatExt,
|
||||||
|
},
|
||||||
|
future::poll_fn,
|
||||||
|
sink::SinkExt,
|
||||||
|
stream::{
|
||||||
|
Stream,
|
||||||
|
StreamExt,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use futures01::sync::mpsc;
|
||||||
|
use jsonrpsee::{
|
||||||
|
common::{
|
||||||
|
Request,
|
||||||
|
Response,
|
||||||
|
},
|
||||||
|
transport::TransportClient,
|
||||||
|
};
|
||||||
|
use sc_network::config::TransportConfig;
|
||||||
|
pub use sc_service::{
|
||||||
|
config::DatabaseConfig,
|
||||||
|
Error as ServiceError,
|
||||||
|
};
|
||||||
|
use sc_service::{
|
||||||
|
config::{
|
||||||
|
KeystoreConfig,
|
||||||
|
NetworkConfiguration,
|
||||||
|
TaskType,
|
||||||
|
},
|
||||||
|
AbstractService,
|
||||||
|
ChainSpec,
|
||||||
|
Configuration,
|
||||||
|
RpcSession,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
|
sync::Arc,
|
||||||
|
task::Poll,
|
||||||
|
};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Error thrown by the client.
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum SubxtClientError {
|
||||||
|
/// Failed to parse json rpc message.
|
||||||
|
#[error("{0}")]
|
||||||
|
Json(#[from] serde_json::Error),
|
||||||
|
/// Channel closed.
|
||||||
|
#[error("{0}")]
|
||||||
|
Mpsc(#[from] mpsc::SendError<String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Role of the node.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum Role {
|
||||||
|
/// Light client.
|
||||||
|
Light,
|
||||||
|
/// A full node (maninly used for testing purposes).
|
||||||
|
Authority(sp_keyring::AccountKeyring),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Role> for sc_service::Role {
|
||||||
|
fn from(role: Role) -> Self {
|
||||||
|
match role {
|
||||||
|
Role::Light => Self::Light,
|
||||||
|
Role::Authority(_) => {
|
||||||
|
Self::Authority {
|
||||||
|
sentry_nodes: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Role> for Option<String> {
|
||||||
|
fn from(role: Role) -> Self {
|
||||||
|
match role {
|
||||||
|
Role::Light => None,
|
||||||
|
Role::Authority(key) => Some(key.to_seed()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Client configuration.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SubxtClientConfig<C: ChainSpec + 'static, S: AbstractService> {
|
||||||
|
/// Name of the implementation.
|
||||||
|
pub impl_name: &'static str,
|
||||||
|
/// Version of the implementation.
|
||||||
|
pub impl_version: &'static str,
|
||||||
|
/// Author of the implementation.
|
||||||
|
pub author: &'static str,
|
||||||
|
/// Copyright start year.
|
||||||
|
pub copyright_start_year: i32,
|
||||||
|
/// Database configuration.
|
||||||
|
pub db: DatabaseConfig,
|
||||||
|
/// Service builder.
|
||||||
|
pub builder: fn(Configuration) -> Result<S, sc_service::Error>,
|
||||||
|
/// Chain specification.
|
||||||
|
pub chain_spec: C,
|
||||||
|
/// Role of the node.
|
||||||
|
pub role: Role,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Client for an embedded substrate node.
|
||||||
|
pub struct SubxtClient {
|
||||||
|
to_back: Compat01As03Sink<mpsc::Sender<String>, String>,
|
||||||
|
from_back: Compat01As03<mpsc::Receiver<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubxtClient {
|
||||||
|
/// Create a new client from a config.
|
||||||
|
pub fn new<C: ChainSpec + 'static, S: AbstractService>(
|
||||||
|
config: SubxtClientConfig<C, S>,
|
||||||
|
) -> Result<Self, ServiceError> {
|
||||||
|
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 TransportClient for SubxtClient {
|
||||||
|
type Error = SubxtClientError;
|
||||||
|
|
||||||
|
fn send_request<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
request: Request,
|
||||||
|
) -> Pin<Box<dyn Future<Output = Result<(), Self::Error>> + 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<Box<dyn Future<Output = Result<Response, Self::Error>> + 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<SubxtClient> for jsonrpsee::Client {
|
||||||
|
fn from(client: SubxtClient) -> Self {
|
||||||
|
let client = jsonrpsee::raw::RawClient::new(client);
|
||||||
|
jsonrpsee::Client::new(client)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_subxt_client<C: ChainSpec + 'static, S: AbstractService>(
|
||||||
|
config: SubxtClientConfig<C, S>,
|
||||||
|
from_front: mpsc::Receiver<String>,
|
||||||
|
to_front: mpsc::Sender<String>,
|
||||||
|
) -> 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: Arc::new(move |fut, ty| {
|
||||||
|
match ty {
|
||||||
|
TaskType::Async => task::spawn(fut),
|
||||||
|
TaskType::Blocking => task::spawn_blocking(|| task::block_on(fut)),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
database: config.db,
|
||||||
|
keystore: KeystoreConfig::InMemory,
|
||||||
|
max_runtime_instances: 8,
|
||||||
|
announce_block: true,
|
||||||
|
dev_key_seed: config.role.into(),
|
||||||
|
base_path: None,
|
||||||
|
|
||||||
|
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_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(),
|
||||||
|
};
|
||||||
|
|
||||||
|
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::*;
|
||||||
|
use async_std::path::Path;
|
||||||
|
use sp_keyring::AccountKeyring;
|
||||||
|
use substrate_subxt::{
|
||||||
|
balances::TransferCallExt,
|
||||||
|
ClientBuilder,
|
||||||
|
KusamaRuntime as NodeTemplateRuntime,
|
||||||
|
PairSigner,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
#[ignore]
|
||||||
|
async fn test_client() {
|
||||||
|
env_logger::try_init().ok();
|
||||||
|
let client = ClientBuilder::<NodeTemplateRuntime>::new()
|
||||||
|
.build()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
||||||
|
let to = AccountKeyring::Bob.to_account_id().into();
|
||||||
|
client
|
||||||
|
.transfer_and_watch(&signer, &to, 10_000)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
#[ignore]
|
||||||
|
async fn test_light_client() {
|
||||||
|
env_logger::try_init().ok();
|
||||||
|
let chain_spec_path =
|
||||||
|
Path::new(env!("CARGO_MANIFEST_DIR")).join("dev-chain.json");
|
||||||
|
let bytes = async_std::fs::read(chain_spec_path).await.unwrap();
|
||||||
|
let chain_spec =
|
||||||
|
node_template::chain_spec::ChainSpec::from_json_bytes(bytes).unwrap();
|
||||||
|
let config = SubxtClientConfig {
|
||||||
|
impl_name: "substrate-subxt-light-client",
|
||||||
|
impl_version: "0.0.1",
|
||||||
|
author: "David Craven",
|
||||||
|
copyright_start_year: 2020,
|
||||||
|
db: DatabaseConfig::RocksDb {
|
||||||
|
path: "/tmp/subxt-light-client".into(),
|
||||||
|
cache_size: 64,
|
||||||
|
},
|
||||||
|
builder: node_template::service::new_light,
|
||||||
|
chain_spec,
|
||||||
|
role: Role::Light,
|
||||||
|
};
|
||||||
|
let client = ClientBuilder::<NodeTemplateRuntime>::new()
|
||||||
|
.set_client(SubxtClient::new(config).unwrap())
|
||||||
|
.build()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
||||||
|
let to = AccountKeyring::Bob.to_account_id().into();
|
||||||
|
client
|
||||||
|
.transfer_and_watch(&signer, &to, 10_000)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_full_client() {
|
||||||
|
env_logger::try_init().ok();
|
||||||
|
let chain_spec = node_template::chain_spec::development_config();
|
||||||
|
let config = SubxtClientConfig {
|
||||||
|
impl_name: "substrate-subxt-full-client",
|
||||||
|
impl_version: "0.0.1",
|
||||||
|
author: "David Craven",
|
||||||
|
copyright_start_year: 2020,
|
||||||
|
db: DatabaseConfig::RocksDb {
|
||||||
|
path: "/tmp/subxt-full-client".into(),
|
||||||
|
cache_size: 128,
|
||||||
|
},
|
||||||
|
builder: node_template::service::new_full,
|
||||||
|
chain_spec,
|
||||||
|
role: Role::Authority(AccountKeyring::Alice),
|
||||||
|
};
|
||||||
|
let client = ClientBuilder::<NodeTemplateRuntime>::new()
|
||||||
|
.set_client(SubxtClient::new(config).unwrap())
|
||||||
|
.build()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
||||||
|
let to = AccountKeyring::Bob.to_account_id().into();
|
||||||
|
client
|
||||||
|
.transfer_and_watch(&signer, &to, 10_000)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,20 +16,20 @@ proc-macro = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
heck = "0.3.1"
|
heck = "0.3.1"
|
||||||
proc-macro2 = "1.0.10"
|
proc-macro2 = "1.0.18"
|
||||||
proc-macro-crate = "0.1.4"
|
proc-macro-crate = "0.1.4"
|
||||||
quote = "1.0.3"
|
quote = "1.0.7"
|
||||||
syn = "1.0.17"
|
syn = "1.0.30"
|
||||||
synstructure = "0.12.3"
|
synstructure = "0.12.4"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
async-std = { version = "1.5.0", features = ["attributes"] }
|
async-std = { version = "=1.5.0", features = ["attributes"] }
|
||||||
codec = { package = "parity-scale-codec", version = "1.3.0", features = ["derive"] }
|
codec = { package = "parity-scale-codec", version = "1.3.0", features = ["derive"] }
|
||||||
env_logger = "0.7.1"
|
env_logger = "0.7.1"
|
||||||
pretty_assertions = "0.6.1"
|
pretty_assertions = "0.6.1"
|
||||||
sp-keyring = "2.0.0-rc2"
|
sp-keyring = "2.0.0-rc3"
|
||||||
substrate-subxt = { path = ".." }
|
substrate-subxt = { path = ".." }
|
||||||
trybuild = "1.0.25"
|
trybuild = "1.0.28"
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "balances"
|
name = "balances"
|
||||||
|
|||||||
@@ -142,19 +142,17 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
#[ignore] // requires locally running substrate node
|
|
||||||
async fn test_state_total_issuance() {
|
async fn test_state_total_issuance() {
|
||||||
env_logger::try_init().ok();
|
env_logger::try_init().ok();
|
||||||
let client = test_client().await;
|
let (client, _) = test_client().await;
|
||||||
let total_issuance = client.total_issuance(None).await.unwrap();
|
let total_issuance = client.total_issuance(None).await.unwrap();
|
||||||
assert_ne!(total_issuance, 0);
|
assert_ne!(total_issuance, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
#[ignore] // requires locally running substrate node
|
|
||||||
async fn test_state_read_free_balance() {
|
async fn test_state_read_free_balance() {
|
||||||
env_logger::try_init().ok();
|
env_logger::try_init().ok();
|
||||||
let client = test_client().await;
|
let (client, _) = test_client().await;
|
||||||
let account = AccountKeyring::Alice.to_account_id();
|
let account = AccountKeyring::Alice.to_account_id();
|
||||||
let info = client.account(&account, None).await.unwrap();
|
let info = client.account(&account, None).await.unwrap();
|
||||||
assert_ne!(info.data.free, 0);
|
assert_ne!(info.data.free, 0);
|
||||||
|
|||||||
+37
-19
@@ -41,6 +41,9 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate substrate_subxt_proc_macro;
|
extern crate substrate_subxt_proc_macro;
|
||||||
|
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
pub use substrate_subxt_client as client;
|
||||||
|
|
||||||
pub use sp_core;
|
pub use sp_core;
|
||||||
pub use sp_runtime;
|
pub use sp_runtime;
|
||||||
|
|
||||||
@@ -436,6 +439,7 @@ impl codec::Encode for Encoded {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::*;
|
||||||
use sp_core::{
|
use sp_core::{
|
||||||
storage::{
|
storage::{
|
||||||
well_known_keys,
|
well_known_keys,
|
||||||
@@ -447,24 +451,44 @@ mod tests {
|
|||||||
AccountKeyring,
|
AccountKeyring,
|
||||||
Ed25519Keyring,
|
Ed25519Keyring,
|
||||||
};
|
};
|
||||||
|
use substrate_subxt_client::{
|
||||||
|
DatabaseConfig,
|
||||||
|
Role,
|
||||||
|
SubxtClient,
|
||||||
|
SubxtClientConfig,
|
||||||
|
};
|
||||||
|
use tempdir::TempDir;
|
||||||
|
|
||||||
use super::*;
|
pub(crate) async fn test_client() -> (Client<crate::NodeTemplateRuntime>, TempDir) {
|
||||||
|
let tmp = TempDir::new("subxt-").expect("failed to create tempdir");
|
||||||
pub(crate) async fn test_client() -> Client<crate::DefaultNodeRuntime> {
|
let config = SubxtClientConfig {
|
||||||
ClientBuilder::new()
|
impl_name: "substrate-subxt-full-client",
|
||||||
|
impl_version: "0.0.1",
|
||||||
|
author: "substrate subxt",
|
||||||
|
copyright_start_year: 2020,
|
||||||
|
db: DatabaseConfig::RocksDb {
|
||||||
|
path: tmp.path().into(),
|
||||||
|
cache_size: 128,
|
||||||
|
},
|
||||||
|
builder: node_template::service::new_full,
|
||||||
|
chain_spec: node_template::chain_spec::development_config(),
|
||||||
|
role: Role::Authority(AccountKeyring::Alice),
|
||||||
|
};
|
||||||
|
let client = ClientBuilder::new()
|
||||||
|
.set_client(SubxtClient::new(config).expect("Error creating subxt client"))
|
||||||
.build()
|
.build()
|
||||||
.await
|
.await
|
||||||
.expect("Error creating client")
|
.expect("Error creating client");
|
||||||
|
(client, tmp)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
#[ignore] // requires locally running substrate node
|
|
||||||
async fn test_tx_transfer_balance() {
|
async fn test_tx_transfer_balance() {
|
||||||
env_logger::try_init().ok();
|
env_logger::try_init().ok();
|
||||||
let mut signer = PairSigner::new(AccountKeyring::Alice.pair());
|
let mut signer = PairSigner::new(AccountKeyring::Alice.pair());
|
||||||
let dest = AccountKeyring::Bob.to_account_id().into();
|
let dest = AccountKeyring::Bob.to_account_id().into();
|
||||||
|
|
||||||
let client = test_client().await;
|
let (client, _) = test_client().await;
|
||||||
let nonce = client
|
let nonce = client
|
||||||
.account(&AccountKeyring::Alice.to_account_id(), None)
|
.account(&AccountKeyring::Alice.to_account_id(), None)
|
||||||
.await
|
.await
|
||||||
@@ -497,24 +521,21 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
#[ignore] // requires locally running substrate node
|
|
||||||
async fn test_getting_hash() {
|
async fn test_getting_hash() {
|
||||||
let client = test_client().await;
|
let (client, _) = test_client().await;
|
||||||
client.block_hash(None).await.unwrap();
|
client.block_hash(None).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
#[ignore] // requires locally running substrate node
|
|
||||||
async fn test_getting_block() {
|
async fn test_getting_block() {
|
||||||
let client = test_client().await;
|
let (client, _) = test_client().await;
|
||||||
let block_hash = client.block_hash(None).await.unwrap();
|
let block_hash = client.block_hash(None).await.unwrap();
|
||||||
client.block(block_hash).await.unwrap();
|
client.block(block_hash).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
#[ignore] // requires locally running substrate node
|
|
||||||
async fn test_getting_read_proof() {
|
async fn test_getting_read_proof() {
|
||||||
let client = test_client().await;
|
let (client, _) = test_client().await;
|
||||||
let block_hash = client.block_hash(None).await.unwrap();
|
let block_hash = client.block_hash(None).await.unwrap();
|
||||||
client
|
client
|
||||||
.read_proof(
|
.read_proof(
|
||||||
@@ -529,29 +550,26 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
#[ignore] // requires locally running substrate node
|
|
||||||
async fn test_chain_subscribe_blocks() {
|
async fn test_chain_subscribe_blocks() {
|
||||||
let client = test_client().await;
|
let (client, _) = test_client().await;
|
||||||
let mut blocks = client.subscribe_blocks().await.unwrap();
|
let mut blocks = client.subscribe_blocks().await.unwrap();
|
||||||
blocks.next().await;
|
blocks.next().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
#[ignore] // requires locally running substrate node
|
|
||||||
async fn test_chain_subscribe_finalized_blocks() {
|
async fn test_chain_subscribe_finalized_blocks() {
|
||||||
let client = test_client().await;
|
let (client, _) = test_client().await;
|
||||||
let mut blocks = client.subscribe_finalized_blocks().await.unwrap();
|
let mut blocks = client.subscribe_finalized_blocks().await.unwrap();
|
||||||
blocks.next().await;
|
blocks.next().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
#[ignore] // requires locally running substrate node
|
|
||||||
async fn test_create_raw_payload() {
|
async fn test_create_raw_payload() {
|
||||||
let signer_pair = Ed25519Keyring::Alice.pair();
|
let signer_pair = Ed25519Keyring::Alice.pair();
|
||||||
let signer_account_id = Ed25519Keyring::Alice.to_account_id();
|
let signer_account_id = Ed25519Keyring::Alice.to_account_id();
|
||||||
let dest = AccountKeyring::Bob.to_account_id().into();
|
let dest = AccountKeyring::Bob.to_account_id().into();
|
||||||
|
|
||||||
let client = test_client().await;
|
let (client, _) = test_client().await;
|
||||||
|
|
||||||
// create raw payload with AccoundId and sign it
|
// create raw payload with AccoundId and sign it
|
||||||
let raw_payload = client
|
let raw_payload = client
|
||||||
|
|||||||
@@ -157,6 +157,31 @@ impl Session for DefaultNodeRuntime {
|
|||||||
|
|
||||||
impl Contracts for DefaultNodeRuntime {}
|
impl Contracts for DefaultNodeRuntime {}
|
||||||
|
|
||||||
|
/// Concrete type definitions compatible with the node template.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// Main difference is `type Address = AccountId`.
|
||||||
|
/// Also the contracts module is not part of the node template runtime.
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct NodeTemplateRuntime;
|
||||||
|
|
||||||
|
impl System for NodeTemplateRuntime {
|
||||||
|
type Index = u32;
|
||||||
|
type BlockNumber = u32;
|
||||||
|
type Hash = sp_core::H256;
|
||||||
|
type Hashing = BlakeTwo256;
|
||||||
|
type AccountId = <<MultiSignature as Verify>::Signer as IdentifyAccount>::AccountId;
|
||||||
|
type Address = Self::AccountId;
|
||||||
|
type Header = Header<Self::BlockNumber, BlakeTwo256>;
|
||||||
|
type Extrinsic = OpaqueExtrinsic;
|
||||||
|
type AccountData = AccountData<<Self as Balances>::Balance>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Balances for NodeTemplateRuntime {
|
||||||
|
type Balance = u128;
|
||||||
|
}
|
||||||
|
|
||||||
/// Concrete type definitions compatible with those for kusama, v0.7
|
/// Concrete type definitions compatible with those for kusama, v0.7
|
||||||
///
|
///
|
||||||
/// # Note
|
/// # Note
|
||||||
|
|||||||
Reference in New Issue
Block a user