-
Notifications
You must be signed in to change notification settings - Fork 295
introduce jsonrpsee client abstraction + kill HTTP support. #341
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 7 commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
c8b0907
PoC async rpc client
niklasad1 a45bf14
add client example should be removed from this repo
niklasad1 c2a9c75
fmt
niklasad1 1fb8c8d
cargo fmt
niklasad1 212d79f
subxt client tests
niklasad1 1a3b5a9
cargo fmt
niklasad1 f9860e7
fix some nits
niklasad1 f21ee1a
Merge remote-tracking branch 'origin/master' into na-jsonrpsee-core-c…
niklasad1 a59db8d
try nightly for all CI jobs
jsdw c5b3104
need wasm also for CI
jsdw de869e8
wasm for nightly run too
jsdw fedf6bf
Merge remote-tracking branch 'origin/master' into na-jsonrpsee-core-c…
niklasad1 8e6b277
client: add missing features
niklasad1 752c19e
update jsonrpsee
niklasad1 2bfc389
hacky
niklasad1 bca1473
hacky update jsonrpsee
niklasad1 e2a93e3
use jsonrpsee crates.io release
niklasad1 32555aa
ci: pin nightly 2021-12-15
niklasad1 8d449c3
pin nightly to 2021-12-15
niklasad1 bb10358
Merge remote-tracking branch 'origin/master' into na-jsonrpsee-core-c…
niklasad1 937e9a6
fix build
niklasad1 1551e70
fmt
niklasad1 65fb71a
compile please
niklasad1 c988c4a
rewrite me
niklasad1 8dc7dda
Merge remote-tracking branch 'origin/master' into na-jsonrpsee-core-c…
niklasad1 ae24d3b
fixes
niklasad1 fa3b905
fixes
niklasad1 f603d68
pre-generate metadata
niklasad1 d433828
Merge remote-tracking branch 'origin/na-jsonrpsee-core-client' into n…
niklasad1 a5df40a
fix nit
niklasad1 a09e8a8
get rid of needless deps
niklasad1 b53ae9f
remove embedded client
niklasad1 b9bc61f
Update Cargo.toml
niklasad1 b21fde8
Update subxt/Cargo.toml
niklasad1 4053e30
Update subxt/Cargo.toml
niklasad1 eed8238
Update subxt/src/client.rs
niklasad1 5182b95
Update subxt/src/rpc.rs
niklasad1 9887b39
Update test-runtime/build.rs
niklasad1 73623c1
cargo fmt
niklasad1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| [package] | ||
| name = "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 = { version = "1.8.0", features = ["tokio1"] } | ||
| futures = "0.3.9" | ||
| jsonrpsee = { git = "https://github.com/paritytech/jsonrpsee/", branch = "extract-async-client", features = ["client"] } | ||
| log = "0.4.13" | ||
| thiserror = "1.0.23" | ||
| serde_json = "1" | ||
|
|
||
| sc-client-db = { git = "https://github.com/paritytech/substrate.git", branch = "master" } | ||
| sp-keyring = { git = "https://github.com/paritytech/substrate.git", branch = "master" } | ||
| sc-network = { git = "https://github.com/paritytech/substrate.git", branch = "master", default-features = false } | ||
| sc-service = { git = "https://github.com/paritytech/substrate.git", branch = "master", default-features = false } | ||
|
|
||
| tokio = { version = "1.10", features = ["rt-multi-thread"] } | ||
|
|
||
| [target.'cfg(target_arch="x86_64")'.dependencies] | ||
| sc-service = { git = "https://github.com/paritytech/substrate.git", branch = "master", default-features = false, features = [ | ||
| "wasmtime", | ||
| ] } | ||
|
|
||
| [dev-dependencies] | ||
| async-std = { version = "1.8.0", features = ["attributes"] } | ||
| env_logger = "0.8.2" | ||
| node-cli = { git = "https://github.com/paritytech/substrate.git", branch = "master", default-features = false } | ||
| tempdir = "0.3.7" | ||
| subxt = { path = ".." } | ||
| test-runtime = { path = "../test-runtime" } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,293 @@ | ||
| // Copyright 2019-2021 Parity Technologies (UK) Ltd. | ||
| // This file is part of 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 subxt. If not, see <http://www.gnu.org/licenses/>. | ||
|
|
||
| //! Client for embedding substrate nodes. | ||
|
|
||
| #![deny(missing_docs)] | ||
|
|
||
| #[cfg(test)] | ||
| mod tests; | ||
|
|
||
| use async_std::task; | ||
| use futures::{ | ||
| channel::mpsc, | ||
| future::{ | ||
| select, | ||
| FutureExt, | ||
| }, | ||
| sink::SinkExt, | ||
| stream::StreamExt, | ||
| }; | ||
| use jsonrpsee::{ | ||
| core_client::Client as JsonRpcClient, | ||
| types::{ | ||
| async_trait, | ||
| traits::{ | ||
| TransportReceiver, | ||
| TransportSender, | ||
| }, | ||
| }, | ||
| }; | ||
| use sc_network::config::TransportConfig; | ||
| pub use sc_service::{ | ||
| config::{ | ||
| DatabaseSource, | ||
| KeystoreConfig, | ||
| WasmExecutionMethod, | ||
| }, | ||
| Error as ServiceError, | ||
| }; | ||
| use sc_service::{ | ||
| config::{ | ||
| NetworkConfiguration, | ||
| TelemetryEndpoints, | ||
| }, | ||
| ChainSpec, | ||
| Configuration, | ||
| KeepBlocks, | ||
| RpcHandlers, | ||
| RpcSession, | ||
| TaskManager, | ||
| }; | ||
| 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), | ||
| } | ||
|
|
||
| /// Sending end. | ||
| pub struct Sender(mpsc::UnboundedSender<String>); | ||
|
|
||
| /// Receiving end | ||
| pub struct Receiver(mpsc::UnboundedReceiver<String>); | ||
|
|
||
| #[async_trait] | ||
| impl TransportSender for Sender { | ||
| type Error = SubxtClientError; | ||
|
|
||
| async fn send(&mut self, msg: String) -> Result<(), Self::Error> { | ||
| self.0.send(msg).await?; | ||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| #[async_trait] | ||
| impl TransportReceiver for Receiver { | ||
| type Error = SubxtClientError; | ||
|
|
||
| async fn receive(&mut self) -> Result<String, Self::Error> { | ||
| let msg = self.0.next().await.expect("channel should be open"); | ||
| Ok(msg) | ||
| } | ||
| } | ||
|
|
||
| /// Client for an embedded substrate node. | ||
| pub struct SubxtClient { | ||
| sender: Sender, | ||
| receiver: Receiver, | ||
| } | ||
|
|
||
| impl SubxtClient { | ||
| /// Create a new client. | ||
| pub fn new(mut task_manager: TaskManager, rpc: RpcHandlers) -> Self { | ||
| let (to_back, from_front) = mpsc::unbounded(); | ||
| let (to_front, from_back) = mpsc::unbounded(); | ||
|
|
||
| let session = RpcSession::new(to_front.clone()); | ||
| task::spawn( | ||
| select( | ||
| Box::pin(from_front.for_each(move |message: String| { | ||
| let rpc = rpc.clone(); | ||
| let session = session.clone(); | ||
| let mut to_front = to_front.clone(); | ||
| 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 { | ||
| sender: Sender(to_back), | ||
| receiver: Receiver(from_back), | ||
| } | ||
| } | ||
|
|
||
| /// Creates a new client from a config. | ||
| pub fn from_config<C: ChainSpec + 'static>( | ||
| config: SubxtClientConfig<C>, | ||
| builder: impl Fn(Configuration) -> Result<(TaskManager, RpcHandlers), ServiceError>, | ||
| ) -> Result<Self, ServiceError> { | ||
| let config = config.into_service_config(); | ||
| let (task_manager, rpc_handlers) = (builder)(config)?; | ||
| Ok(Self::new(task_manager, rpc_handlers)) | ||
| } | ||
| } | ||
|
|
||
| impl From<SubxtClient> for JsonRpcClient { | ||
| fn from(client: SubxtClient) -> Self { | ||
| (client.sender, client.receiver).into() | ||
| } | ||
| } | ||
|
|
||
| /// Role of the node. | ||
| #[derive(Clone, Copy, Debug)] | ||
| pub enum Role { | ||
| /// Light client. | ||
| Light, | ||
| /// A full node (mainly 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, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| 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> { | ||
| /// 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: DatabaseSource, | ||
| /// Keystore configuration. | ||
| pub keystore: KeystoreConfig, | ||
| /// Chain specification. | ||
| pub chain_spec: C, | ||
| /// Role of the node. | ||
| pub role: Role, | ||
| /// Enable telemetry on the given port. | ||
| pub telemetry: Option<u16>, | ||
| /// Wasm execution method | ||
| pub wasm_method: WasmExecutionMethod, | ||
| /// Handle to the tokio runtime. Will be used to spawn futures by the task manager. | ||
| pub tokio_handle: tokio::runtime::Handle, | ||
| } | ||
|
|
||
| impl<C: ChainSpec + 'static> SubxtClientConfig<C> { | ||
| /// Creates a service configuration. | ||
| pub fn into_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, | ||
| }; | ||
| let telemetry_endpoints = if let Some(port) = self.telemetry { | ||
| let endpoints = TelemetryEndpoints::new(vec![( | ||
| format!("/ip4/127.0.0.1/tcp/{}/ws", port), | ||
| 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(), | ||
| database: self.db, | ||
| keystore: self.keystore, | ||
| max_runtime_instances: 8, | ||
| announce_block: true, | ||
| dev_key_seed: self.role.into(), | ||
| telemetry_endpoints, | ||
| tokio_handle: self.tokio_handle, | ||
| default_heap_pages: Default::default(), | ||
| disable_grandpa: Default::default(), | ||
| execution_strategies: Default::default(), | ||
| force_authoring: Default::default(), | ||
| keep_blocks: KeepBlocks::All, | ||
| keystore_remote: Default::default(), | ||
| offchain_worker: Default::default(), | ||
| prometheus_config: 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: self.wasm_method, | ||
| base_path: Default::default(), | ||
| informant_output_format: Default::default(), | ||
| state_pruning: Default::default(), | ||
| transaction_storage: sc_client_db::TransactionStorageMode::BlockBody, | ||
| wasm_runtime_overrides: Default::default(), | ||
| rpc_max_payload: Default::default(), | ||
| ws_max_out_buffer_capacity: Default::default(), | ||
| }; | ||
|
|
||
| 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); | ||
|
|
||
| service_config | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.