Skip to content

Commit

Permalink
Remove async_trait in favor of native support (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
olanod authored Jun 20, 2024
1 parent 98c96e6 commit 57af797
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 76 deletions.
4 changes: 1 addition & 3 deletions sube/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand All @@ -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 }
Expand All @@ -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"]
Expand Down
2 changes: 1 addition & 1 deletion sube/justfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
default: check

check:
cargo check
cargo check --features http,wss

lint:
cargo clippy --features http,wss -- -D warnings
17 changes: 8 additions & 9 deletions sube/src/builder.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand All @@ -8,7 +10,6 @@ use crate::{
};
use crate::{prelude::*, Offline, StorageChangeSet};

use async_trait::async_trait;
use core::future::{Future, IntoFuture};
use url::Url;

Expand Down Expand Up @@ -205,25 +206,23 @@ fn chain_string_to_url(chain: &str) -> SubeResult<Url> {
async fn get_backend_by_url(url: Url) -> SubeResult<AnyBackend> {
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<HttpBackend>),
#[cfg(feature = "ws")]
Ws(WSBackend),
Ws(RpcClient<WSBackend>),
_Offline(Offline),
}

#[async_trait]
impl Backend for &AnyBackend {
async fn query_storage_at(
&self,
Expand Down Expand Up @@ -264,7 +263,7 @@ impl Backend for &AnyBackend {
}
}

async fn submit<U: AsRef<[u8]> + 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,
Expand Down
9 changes: 5 additions & 4 deletions sube/src/http.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -23,10 +22,12 @@ impl Backend {
}
}

#[async_trait]
impl Rpc for Backend {
/// HTTP based JSONRpc request expecting an hex encoded result
async fn rpc<T: for<'a> Deserialize<'a>>(&self, method: &str, params: &[&str]) -> RpcResult<T> {
async fn rpc<T>(&self, method: &str, params: &[&str]) -> RpcResult<T>
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 {
Expand Down
31 changes: 8 additions & 23 deletions sube/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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;
Expand Down Expand Up @@ -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<T> = core::result::Result<T, Error>;
Expand Down Expand Up @@ -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<Vec<u8>>;
///
/// async fn submit<T>(&self, ext: T) -> Result<()>
/// where
/// T: AsRef<[u8]> + Send;
/// T: AsRef<[u8]>;
///
/// async fn metadata(&self) -> Result<Metadata>;
/// }
/// ```
#[async_trait]
pub trait Backend {
async fn query_storage_at(
&self,
Expand All @@ -425,13 +415,12 @@ pub trait Backend {
size: u16,
to: Option<&StorageKey>,
) -> crate::Result<Vec<String>>;

/// Get raw storage items form the blockchain
async fn query_storage(&self, key: &StorageKey) -> Result<Vec<u8>>;

/// Send a signed extrinsic to the blockchain
async fn submit<T>(&self, ext: T) -> Result<()>
where
T: AsRef<[u8]> + Send;
async fn submit(&self, ext: impl AsRef<[u8]>) -> Result<()>;

async fn metadata(&self) -> Result<Metadata>;

Expand All @@ -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,
Expand All @@ -465,10 +453,7 @@ impl Backend for Offline {
}

/// Send a signed extrinsic to the blockchain
async fn submit<T>(&self, _ext: T) -> Result<()>
where
T: AsRef<[u8]> + Send,
{
async fn submit(&self, _ext: impl AsRef<[u8]>) -> Result<()> {
Err(Error::ChainUnavailable)
}

Expand Down
62 changes: 30 additions & 32 deletions sube/src/rpc.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -12,9 +10,10 @@ use crate::{Backend, StorageKey};
pub type RpcResult<T> = Result<T, error::Error>;

/// Rpc defines types of backends that are remote and talk JSONRpc
#[async_trait]
pub trait Rpc: Backend + Send + Sync {
async fn rpc<T: for<'a> Deserialize<'a>>(&self, method: &str, params: &[&str]) -> RpcResult<T>;
pub trait Rpc {
async fn rpc<T>(&self, method: &str, params: &[&str]) -> RpcResult<T>
where
T: for<'de> Deserialize<'de>;

fn convert_params(params: &[&str]) -> Vec<Box<RawValue>> {
params
Expand All @@ -26,8 +25,9 @@ pub trait Rpc: Backend + Send + Sync {
}
}

#[async_trait]
impl<R: Rpc> Backend for R {
pub struct RpcClient<R>(pub R);

impl<R: Rpc> Backend for RpcClient<R> {
async fn query_storage_at(
&self,
keys: Vec<String>,
Expand All @@ -40,19 +40,20 @@ impl<R: Rpc> Backend for R {
vec![keys]
};

self.rpc(
"state_queryStorageAt",
params
.iter()
.map(|s| s.as_ref())
.collect::<Vec<_>>()
.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::<Vec<_>>()
.as_slice(),
)
.await
.map_err(|err| {
log::info!("error {:?}", err);
crate::Error::StorageKeyNotFound
})
}

async fn get_keys_paged(
Expand All @@ -62,6 +63,7 @@ impl<R: Rpc> Backend for R {
to: Option<&StorageKey>,
) -> crate::Result<Vec<String>> {
let r: Vec<String> = self
.0
.rpc(
"state_getKeysPaged",
&[
Expand All @@ -84,6 +86,7 @@ impl<R: Rpc> Backend for R {
log::debug!("StorageKey encoded: {}", key);

let res: String = self
.0
.rpc("state_getStorage", &[&format!("\"{}\"", &key)])
.await
.map_err(|e| {
Expand All @@ -97,23 +100,20 @@ impl<R: Rpc> Backend for R {
Ok(response)
}

async fn submit<T>(&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<Metadata> {
let res: String = self
.0
.rpc("state_getMetadata", &[])
.await
.map_err(|e| crate::Error::Node(e.to_string()))?;
Expand All @@ -125,20 +125,18 @@ impl<R: Rpc> Backend for R {
}

async fn block_info(&self, at: Option<u32>) -> crate::Result<meta::BlockInfo> {
async fn block_info<R>(s: &R, params: &[&str]) -> crate::Result<Vec<u8>>
where
R: Rpc,
{
#[inline]
async fn block_info(s: &impl Rpc, params: &[&str]) -> crate::Result<Vec<u8>> {
s.rpc("chain_getBlockHash", params)
.await
.map_err(|e| crate::Error::Node(e.to_string()))
}

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 {
Expand Down
9 changes: 5 additions & 4 deletions sube/src/ws.rs
Original file line number Diff line number Diff line change
@@ -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 _;
Expand Down Expand Up @@ -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<T: for<'a> Deserialize<'a>>(&self, method: &str, params: &[&str]) -> RpcResult<T> {
async fn rpc<T>(&self, method: &str, params: &[&str]) -> RpcResult<T>
where
T: for<'a> Deserialize<'a>,
{
let id = self.next_id().await;
info!("RPC `{}` (ID={})", method, id);

Expand Down

0 comments on commit 57af797

Please sign in to comment.