diff --git a/sube/Cargo.toml b/sube/Cargo.toml index 84ababb..d07bf61 100644 --- a/sube/Cargo.toml +++ b/sube/Cargo.toml @@ -9,7 +9,6 @@ repository = "https://github.com/valibre-org/virto-dk/sube" [dependencies] async-once-cell = "0.4.4" -async-trait = "0.1.53" blake2 = { version = "0.10.5", default-features = false } codec = { version = "3.1.2", package = "parity-scale-codec", default-features = false } frame-metadata = { version = "16.0.0", default-features = false, features = ["serde_full", "decode"] } @@ -28,7 +27,6 @@ url = "2.5.0" surf = { version = "2.3.2", default-features = false, optional = true } # ws backend -async-tungstenite = { version = "0.17.2", features = ["async-std-runtime"], optional = true } futures-channel = { version = "0.3.21", default-features = false, features = ["alloc"], optional = true } futures-util = { version = "0.3.21", default-features = false, features = ["sink"], optional = true } async-mutex = { version = "1.4.0", optional = true } @@ -52,7 +50,7 @@ libwallet = { path = "../libwallet", default-features=false, features=["substrat rand_core = "0.6.3" [features] -default = ["v14", "wss", "http"] +default = ["v14"] test = ["std", "wss", "http", "json", "v14", "dep:async-std", "dep:rand_core"] http = ["dep:jsonrpc", "surf/h1-client-rustls"] http-web = ["dep:jsonrpc", "dep:wasm-bindgen", "surf?/wasm-client"] diff --git a/sube/justfile b/sube/justfile index 0735fa2..99baaa3 100644 --- a/sube/justfile +++ b/sube/justfile @@ -1,7 +1,7 @@ default: check check: - cargo check + cargo check --features http,wss lint: cargo clippy --features http,wss -- -D warnings diff --git a/sube/src/builder.rs b/sube/src/builder.rs index d8efae0..16c0749 100644 --- a/sube/src/builder.rs +++ b/sube/src/builder.rs @@ -1,5 +1,7 @@ #[cfg(any(feature = "http", feature = "http-web"))] use crate::http::Backend as HttpBackend; +#[cfg(any(feature = "http", feature = "http-web", feature = "ws", feature = "js"))] +use crate::rpc::RpcClient; #[cfg(feature = "ws")] use crate::ws::Backend as WSBackend; use crate::{ @@ -8,7 +10,6 @@ use crate::{ }; use crate::{prelude::*, Offline, StorageChangeSet}; -use async_trait::async_trait; use core::future::{Future, IntoFuture}; use url::Url; @@ -205,25 +206,23 @@ fn chain_string_to_url(chain: &str) -> SubeResult { async fn get_backend_by_url(url: Url) -> SubeResult { match url.scheme() { #[cfg(feature = "ws")] - "ws" | "wss" => Ok(AnyBackend::Ws( - #[cfg(feature = "ws")] + "ws" | "wss" => Ok(AnyBackend::Ws(RpcClient( WSBackend::new_ws2(url.to_string().as_str()).await?, - )), + ))), #[cfg(any(feature = "http", feature = "http-web"))] - "http" | "https" => Ok(AnyBackend::Http(HttpBackend::new(url))), + "http" | "https" => Ok(AnyBackend::Http(RpcClient(HttpBackend::new(url)))), _ => Err(Error::BadInput), } } enum AnyBackend { #[cfg(any(feature = "http", feature = "http-web"))] - Http(HttpBackend), + Http(RpcClient), #[cfg(feature = "ws")] - Ws(WSBackend), + Ws(RpcClient), _Offline(Offline), } -#[async_trait] impl Backend for &AnyBackend { async fn query_storage_at( &self, @@ -264,7 +263,7 @@ impl Backend for &AnyBackend { } } - async fn submit + Send>(&self, ext: U) -> SubeResult<()> { + async fn submit(&self, ext: impl AsRef<[u8]>) -> SubeResult<()> { match self { #[cfg(any(feature = "http", feature = "http-web"))] AnyBackend::Http(b) => b.submit(ext).await, diff --git a/sube/src/http.rs b/sube/src/http.rs index 6a54f88..d485de0 100644 --- a/sube/src/http.rs +++ b/sube/src/http.rs @@ -1,11 +1,10 @@ use crate::prelude::*; -use async_trait::async_trait; -use serde::Deserialize; use core::{convert::TryInto, fmt}; use jsonrpc::{ error::{standard_error, StandardError}, serde_json::{to_string, value::to_raw_value}, }; +use serde::Deserialize; pub use surf::Url; use crate::rpc::{self, Rpc, RpcResult}; @@ -23,10 +22,12 @@ impl Backend { } } -#[async_trait] impl Rpc for Backend { /// HTTP based JSONRpc request expecting an hex encoded result - async fn rpc Deserialize<'a>>(&self, method: &str, params: &[&str]) -> RpcResult { + async fn rpc(&self, method: &str, params: &[&str]) -> RpcResult + where + T: for<'de> Deserialize<'de>, + { log::info!("RPC `{}` to {}", method, &self.0); let req = surf::post(&self.0).content_type("application/json").body( to_string(&rpc::Request { diff --git a/sube/src/lib.rs b/sube/src/lib.rs index 3d41d88..f4e7f7b 100644 --- a/sube/src/lib.rs +++ b/sube/src/lib.rs @@ -1,9 +1,5 @@ -// #![feature(async_closure)] -// #![feature(trait_alias)] -// #![feature(async_fn_traits)] -// #![feature(impl_trait_in_assoc_type)] #![cfg_attr(not(feature = "std"), no_std)] - +#![allow(async_fn_in_trait)] /*! Sube is a lightweight blockchain client to query and submit extrinsics to Substrate based blockchains. @@ -19,20 +15,16 @@ compile_error!("Enable one of the metadata versions"); #[macro_use] extern crate alloc; -pub use builder::SubeBuilder; -pub use signer::SignerFn; - pub use codec; use codec::Encode; pub use core::fmt::Display; pub use frame_metadata::RuntimeMetadataPrefixed; -pub use signer::Signer; +pub use signer::{Signer, SignerFn}; pub use meta::Metadata; #[cfg(feature = "v14")] pub use scales::{Serializer, Value}; -use async_trait::async_trait; use codec::Compact; use core::fmt; use hasher::hash; @@ -72,8 +64,8 @@ pub mod util; /// The batteries included way to query or submit extrinsics to a Substrate based blockchain /// /// Returns a builder that implments `IntoFuture` so it can be `.await`ed on. -pub async fn sube(url: &str) -> SubeBuilder<(), ()> { - SubeBuilder::default().with_url(url) +pub fn sube(url: &str) -> builder::SubeBuilder<(), ()> { + builder::SubeBuilder::default().with_url(url) } pub type Result = core::result::Result; @@ -400,18 +392,16 @@ pub struct StorageChangeSet { /// Generic definition of a blockchain backend /// /// ```rust,ignore -/// #[async_trait] /// pub trait Backend { /// async fn query_bytes(&self, key: &StorageKey) -> Result>; /// /// async fn submit(&self, ext: T) -> Result<()> /// where -/// T: AsRef<[u8]> + Send; +/// T: AsRef<[u8]>; /// /// async fn metadata(&self) -> Result; /// } /// ``` -#[async_trait] pub trait Backend { async fn query_storage_at( &self, @@ -425,13 +415,12 @@ pub trait Backend { size: u16, to: Option<&StorageKey>, ) -> crate::Result>; + /// Get raw storage items form the blockchain async fn query_storage(&self, key: &StorageKey) -> Result>; /// Send a signed extrinsic to the blockchain - async fn submit(&self, ext: T) -> Result<()> - where - T: AsRef<[u8]> + Send; + async fn submit(&self, ext: impl AsRef<[u8]>) -> Result<()>; async fn metadata(&self) -> Result; @@ -441,7 +430,6 @@ pub trait Backend { /// A Dummy backend for offline querying of metadata pub struct Offline(pub Metadata); -#[async_trait] impl Backend for Offline { async fn query_storage_at( &self, @@ -465,10 +453,7 @@ impl Backend for Offline { } /// Send a signed extrinsic to the blockchain - async fn submit(&self, _ext: T) -> Result<()> - where - T: AsRef<[u8]> + Send, - { + async fn submit(&self, _ext: impl AsRef<[u8]>) -> Result<()> { Err(Error::ChainUnavailable) } diff --git a/sube/src/rpc.rs b/sube/src/rpc.rs index f1b44c2..969eb7c 100644 --- a/sube/src/rpc.rs +++ b/sube/src/rpc.rs @@ -1,6 +1,4 @@ use core::convert::TryInto; - -use async_trait::async_trait; use jsonrpc::serde_json::value::RawValue; pub use jsonrpc::{error, Error, Request, Response}; use serde::Deserialize; @@ -12,9 +10,10 @@ use crate::{Backend, StorageKey}; pub type RpcResult = Result; /// Rpc defines types of backends that are remote and talk JSONRpc -#[async_trait] -pub trait Rpc: Backend + Send + Sync { - async fn rpc Deserialize<'a>>(&self, method: &str, params: &[&str]) -> RpcResult; +pub trait Rpc { + async fn rpc(&self, method: &str, params: &[&str]) -> RpcResult + where + T: for<'de> Deserialize<'de>; fn convert_params(params: &[&str]) -> Vec> { params @@ -26,8 +25,9 @@ pub trait Rpc: Backend + Send + Sync { } } -#[async_trait] -impl Backend for R { +pub struct RpcClient(pub R); + +impl Backend for RpcClient { async fn query_storage_at( &self, keys: Vec, @@ -40,19 +40,20 @@ impl Backend for R { vec![keys] }; - self.rpc( - "state_queryStorageAt", - params - .iter() - .map(|s| s.as_ref()) - .collect::>() - .as_slice(), - ) - .await - .map_err(|err| { - log::info!("error {:?}", err); - crate::Error::StorageKeyNotFound - }) + self.0 + .rpc( + "state_queryStorageAt", + params + .iter() + .map(|s| s.as_ref()) + .collect::>() + .as_slice(), + ) + .await + .map_err(|err| { + log::info!("error {:?}", err); + crate::Error::StorageKeyNotFound + }) } async fn get_keys_paged( @@ -62,6 +63,7 @@ impl Backend for R { to: Option<&StorageKey>, ) -> crate::Result> { let r: Vec = self + .0 .rpc( "state_getKeysPaged", &[ @@ -84,6 +86,7 @@ impl Backend for R { log::debug!("StorageKey encoded: {}", key); let res: String = self + .0 .rpc("state_getStorage", &[&format!("\"{}\"", &key)]) .await .map_err(|e| { @@ -97,23 +100,20 @@ impl Backend for R { Ok(response) } - async fn submit(&self, ext: T) -> crate::Result<()> - where - T: AsRef<[u8]> + Send, - { + async fn submit(&self, ext: impl AsRef<[u8]>) -> crate::Result<()> { let extrinsic = format!("0x{}", hex::encode(ext.as_ref())); log::debug!("Extrinsic: {}", extrinsic); - let res = self + self.0 .rpc("author_submitExtrinsic", &[&format!("\"{}\"", &extrinsic)]) .await .map_err(|e| crate::Error::Node(e.to_string()))?; - log::debug!("Extrinsic {:x?}", res); Ok(()) } async fn metadata(&self) -> crate::Result { let res: String = self + .0 .rpc("state_getMetadata", &[]) .await .map_err(|e| crate::Error::Node(e.to_string()))?; @@ -125,10 +125,8 @@ impl Backend for R { } async fn block_info(&self, at: Option) -> crate::Result { - async fn block_info(s: &R, params: &[&str]) -> crate::Result> - where - R: Rpc, - { + #[inline] + async fn block_info(s: &impl Rpc, params: &[&str]) -> crate::Result> { s.rpc("chain_getBlockHash", params) .await .map_err(|e| crate::Error::Node(e.to_string())) @@ -136,9 +134,9 @@ impl Backend for R { let block_hash = if let Some(block_number) = at { let block_number = block_number.to_string(); - block_info(self, &[&block_number]).await? + block_info(&self.0, &[&block_number]).await? } else { - block_info(self, &[]).await? + block_info(&self.0, &[]).await? }; Ok(meta::BlockInfo { diff --git a/sube/src/ws.rs b/sube/src/ws.rs index 9e466f5..ce94db4 100644 --- a/sube/src/ws.rs +++ b/sube/src/ws.rs @@ -1,7 +1,6 @@ -use alloc::{boxed::Box, collections::BTreeMap, sync::Arc}; +use alloc::{collections::BTreeMap, sync::Arc}; use async_mutex::Mutex; -use async_trait::async_trait; use ewebsock::{WsEvent, WsMessage as Message, WsReceiver as Rx, WsSender as Tx}; use futures_channel::{mpsc, oneshot}; use futures_util::StreamExt as _; @@ -33,9 +32,11 @@ pub struct Backend { unsafe impl Send for Backend {} unsafe impl Sync for Backend {} -#[async_trait] impl Rpc for Backend { - async fn rpc Deserialize<'a>>(&self, method: &str, params: &[&str]) -> RpcResult { + async fn rpc(&self, method: &str, params: &[&str]) -> RpcResult + where + T: for<'a> Deserialize<'a>, + { let id = self.next_id().await; info!("RPC `{}` (ID={})", method, id);