diff --git a/subxt/Cargo.toml b/subxt/Cargo.toml index 6dec5b7c90..d5f800db26 100644 --- a/subxt/Cargo.toml +++ b/subxt/Cargo.toml @@ -20,7 +20,7 @@ chameleon = "0.1.0" scale-info = { version = "1.0.0", features = ["bit-vec"] } futures = "0.3.13" hex = "0.4.3" -jsonrpsee = { version = "0.8.0", features = ["macros", "async-client", "client-ws-transport"] } +jsonrpsee = { git = "https://github.com/paritytech/jsonrpsee", branch = "696_trait_bounds", features = ["macros", "async-client", "client-ws-transport"] } log = "0.4.14" num-traits = { version = "0.2.14", default-features = false } serde = { version = "1.0.124", features = ["derive"] } diff --git a/subxt/src/client.rs b/subxt/src/client.rs index ad52ddbcf9..477b0971b3 100644 --- a/subxt/src/client.rs +++ b/subxt/src/client.rs @@ -94,17 +94,10 @@ impl ClientBuilder { }; let rpc = Rpc::new(client); let (metadata_bytes, genesis_hash, runtime_version, properties) = future::join4( - SubxtRpcApiClient::::metadata(rpc.inner()), - SubxtRpcApiClient::::genesis_hash( - rpc.inner(), - ), - SubxtRpcApiClient::::runtime_version( - rpc.inner(), - None, - ), - SubxtRpcApiClient::::system_properties( - rpc.inner(), - ), + SubxtRpcApiClient::::metadata(rpc.inner()), + SubxtRpcApiClient::::genesis_hash(rpc.inner()), + SubxtRpcApiClient::::runtime_version(rpc.inner(), None), + SubxtRpcApiClient::::system_properties(rpc.inner()), ) .await; let metadata_bytes = metadata_bytes?; @@ -247,11 +240,9 @@ where let bytes = extrinsic.encode().into(); // Submit and watch for transaction progress. - let sub = SubxtRpcApiClient::::watch_extrinsic( - self.client.rpc().inner(), - bytes, - ) - .await?; + let sub = + SubxtRpcApiClient::::watch_extrinsic(self.client.rpc().inner(), bytes) + .await?; Ok(TransactionProgress::new(sub, self.client, ext_hash)) } @@ -280,12 +271,9 @@ where .encode() .into(); - SubxtRpcApiClient::::submit_extrinsic( - self.client.rpc().inner(), - bytes, - ) - .await - .map_err(Into::into) + SubxtRpcApiClient::::submit_extrinsic(self.client.rpc().inner(), bytes) + .await + .map_err(Into::into) } /// Creates a signed extrinsic. diff --git a/subxt/src/config.rs b/subxt/src/config.rs index eec63f128e..dd7b727790 100644 --- a/subxt/src/config.rs +++ b/subxt/src/config.rs @@ -78,14 +78,7 @@ pub trait Config: 'static { type Signature: Verify + Encode + Send + Sync + 'static; /// Extrinsic type within blocks. - // TODO(niklasad1): I have no idea if this ok or not ^^ => won't work otherwise - // because `jsonrpsee` requires `Deserialize + Send + Sync` for the return types. - type Extrinsic: Parameter - + Extrinsic - + Debug - + MaybeSerializeDeserialize - + Send - + Sync; + type Extrinsic: Parameter + Extrinsic + Debug + MaybeSerializeDeserialize; } /// Parameter trait copied from `substrate::frame_support` diff --git a/subxt/src/rpc.rs b/subxt/src/rpc.rs index e105ddcf69..1ce5d76143 100644 --- a/subxt/src/rpc.rs +++ b/subxt/src/rpc.rs @@ -79,14 +79,18 @@ use sp_runtime::generic::{ }; /// subxt RPC API. -#[rpc(client)] -pub trait SubxtRpcApi { +#[rpc( + client, + client_bounds( + C::Hash: DeserializeOwned + Serialize, C::Header: Serialize, C::Extrinsic: Serialize) +)] +pub trait SubxtRpcApi { /// Fetch a storage key #[method(name = "state_getStorage")] async fn storage( &self, key: &StorageKey, - hash: Option, + hash: Option, ) -> RpcResult>; /// Returns the keys with prefix with pagination support. @@ -98,7 +102,7 @@ pub trait SubxtRpcApi { prefix: Option, count: u32, start_key: Option, - hash: Option, + hash: Option, ) -> RpcResult>; /// Query historical storage entries @@ -106,21 +110,21 @@ pub trait SubxtRpcApi { async fn query_storage( &self, keys: Vec, - from: Hash, - to: Option, - ) -> RpcResult>>; + from: C::Hash, + to: Option, + ) -> RpcResult>>; /// Query historical storage entries #[method(name = "state_queryStorageAt")] async fn query_storage_at( &self, keys: &[StorageKey], - at: Option, - ) -> RpcResult>>; + at: Option, + ) -> RpcResult>>; /// Fetch the genesis hash #[method(name = "chain_getBlockHash")] - async fn genesis_hash(&self) -> RpcResult; + async fn genesis_hash(&self) -> RpcResult; /// Fetch the metadata as bytes. #[method(name = "state_getMetadata")] @@ -144,37 +148,37 @@ pub trait SubxtRpcApi { /// Fetch the runtime version #[method(name = "state_getRuntimeVersion")] - async fn runtime_version(&self, at: Option) -> RpcResult; + async fn runtime_version(&self, at: Option) -> RpcResult; /// Get a header #[method(name = "state_getRuntimeVersion")] - async fn header(&self, hash: Option) -> RpcResult>; + async fn header(&self, hash: Option) -> RpcResult>; /// Get a block hash, returns hash of latest block by default #[method(name = "chain_getBlockHash")] async fn block_hash( &self, block_number: Option, - ) -> RpcResult>; + ) -> RpcResult>; /// Get a block hash of the latest finalized block #[method(name = "chain_getFinalizedHead")] - async fn finalized_head(&self) -> RpcResult; + async fn finalized_head(&self) -> RpcResult; /// Get proof of storage entries at a specific block's state. #[method(name = "state_getReadProof")] async fn read_proof( &self, keys: Vec, - hash: Option, - ) -> RpcResult>; + hash: Option, + ) -> RpcResult>; /// Get a Block #[method(name = "chain_getBlock")] async fn block( &self, - hash: Option, - ) -> RpcResult>>>; + hash: Option, + ) -> RpcResult>>>; /// Insert a key into the keystore. #[method(name = "author_insertKey")] @@ -205,30 +209,41 @@ pub trait SubxtRpcApi { /// Create and submit an extrinsic and return corresponding Hash if successful #[method(name = "author_submitExtrinsic")] - async fn submit_extrinsic(&self, extrinsic: Bytes) -> RpcResult; + async fn submit_extrinsic(&self, extrinsic: Bytes) -> RpcResult; /// Subscribe to System Events that are imported into blocks. /// /// *WARNING* these may not be included in the finalized chain, use /// `subscribe_finalized_events` to ensure events are finalized. - #[subscription(name = "state_subscribeStorage", item = StorageChangeSet)] - fn subscribe_events(&self) -> RpcResult<()>; + #[subscription( + name = "state_subscribeStorage", + unsubscribe = "state_unsubscribeStorage", + item = StorageChangeSet + )] + fn subscribe_events(&self); /// Subscribe to blocks. - #[subscription(name = "chain_subscribeNewHeads", item = Header)] - fn subscribe_blocks(&self) -> RpcResult<()>; + #[subscription( + name = "chain_subscribeNewHeads", + unsubscribe = "chain_unsubscribeNewHeads", + item = C::Header)] + fn subscribe_blocks(&self); /// Subscribe to finalized blocks. - #[subscription(name = "chain_subscribeFinalizedHeads", item = Header)] - fn subscribe_finalized_blocks(&self) -> RpcResult<()>; + #[subscription( + name = "chain_subscribeFinalizedHeads", + unsubscribe = "chain_unsubscribeFinalizedHeads", + item = C::Header + )] + fn subscribe_finalized_blocks(&self); /// Create and submit an extrinsic and return a subscription to the events triggered. #[subscription( name = "author_submitAndWatchExtrinsic", - unsubscribe_aliases = ["author_unwatchExtrinsic"], - item = SubstrateTransactionStatus + unsubscribe = "author_unwatchExtrinsic", + item = SubstrateTransactionStatus )] - fn watch_extrinsic(&self, xt: Bytes) -> RpcResult<()>; + fn watch_extrinsic(&self, xt: Bytes); } /// A number type that can be serialized both as a number or a string that encodes a number in a @@ -393,7 +408,7 @@ impl Rpc { Ok(EventStorageSubscription::Finalized( FinalizedEventStorageSubscription::new( self.clone(), - SubxtRpcApiClient::::subscribe_finalized_blocks(&*self.client).await?, + SubxtRpcApiClient::::subscribe_finalized_blocks(&*self.client).await?, ), )) } @@ -404,7 +419,7 @@ pub async fn ws_client(url: &str) -> Result { let (sender, receiver) = ws_transport(url).await?; Ok(RpcClientBuilder::default() .max_notifs_per_subscription(4096) - .build(sender, receiver)) + .build_with_tokio(sender, receiver)) } async fn ws_transport(url: &str) -> Result<(WsSender, WsReceiver), RpcError> { diff --git a/subxt/src/storage.rs b/subxt/src/storage.rs index 3995c39669..23340c88a6 100644 --- a/subxt/src/storage.rs +++ b/subxt/src/storage.rs @@ -168,12 +168,7 @@ impl<'a, T: Config> StorageClient<'a, T> { hash: Option, ) -> Result, BasicError> { if let Some(data) = - SubxtRpcApiClient::::storage( - &*self.rpc.client, - &key, - hash, - ) - .await? + SubxtRpcApiClient::::storage(&*self.rpc.client, &key, hash).await? { Ok(Some(Decode::decode(&mut &data.0[..])?)) } else { @@ -187,13 +182,9 @@ impl<'a, T: Config> StorageClient<'a, T> { key: StorageKey, hash: Option, ) -> Result, BasicError> { - SubxtRpcApiClient::::storage( - &*self.rpc.client, - &key, - hash, - ) - .await - .map_err(Into::into) + SubxtRpcApiClient::::storage(&*self.rpc.client, &key, hash) + .await + .map_err(Into::into) } /// Fetch a StorageKey with an optional block hash. @@ -231,14 +222,9 @@ impl<'a, T: Config> StorageClient<'a, T> { from: T::Hash, to: Option, ) -> Result>, BasicError> { - SubxtRpcApiClient::::query_storage( - &*self.rpc.client, - keys, - from, - to, - ) - .await - .map_err(Into::into) + SubxtRpcApiClient::::query_storage(&*self.rpc.client, keys, from, to) + .await + .map_err(Into::into) } /// Fetch up to `count` keys for a storage map in lexicographic order. @@ -251,15 +237,14 @@ impl<'a, T: Config> StorageClient<'a, T> { hash: Option, ) -> Result, BasicError> { let prefix = StorageKeyPrefix::new::().to_storage_key(); - let keys = - SubxtRpcApiClient::::storage_keys_paged( - &*self.rpc.client, - Some(prefix), - count, - start_key, - hash, - ) - .await?; + let keys = SubxtRpcApiClient::::storage_keys_paged( + &*self.rpc.client, + Some(prefix), + count, + start_key, + hash, + ) + .await?; Ok(keys) } @@ -271,12 +256,9 @@ impl<'a, T: Config> StorageClient<'a, T> { let hash = if let Some(hash) = hash { hash } else { - SubxtRpcApiClient::::block_hash( - &*self.rpc.client, - None, - ) - .await? - .expect("didn't pass a block number; qed") + SubxtRpcApiClient::::block_hash(&*self.rpc.client, None) + .await? + .expect("didn't pass a block number; qed") }; Ok(KeyIter { client: self.clone(), @@ -317,13 +299,12 @@ impl<'a, T: Config, F: StorageEntry> KeyIter<'a, T, F> { self.start_key = keys.last().cloned(); - let change_sets = - SubxtRpcApiClient::::query_storage_at( - &*self.client.rpc.client, - &keys, - Some(self.hash), - ) - .await?; + let change_sets = SubxtRpcApiClient::::query_storage_at( + &*self.client.rpc.client, + &keys, + Some(self.hash), + ) + .await?; for change_set in change_sets { for (k, v) in change_set.changes { if let Some(v) = v { diff --git a/subxt/src/subscription.rs b/subxt/src/subscription.rs index 6ff706a15a..d075c85c18 100644 --- a/subxt/src/subscription.rs +++ b/subxt/src/subscription.rs @@ -248,7 +248,7 @@ impl FinalizedEventStorageSubscription { read_subscription_response("HeaderSubscription", &mut self.subscription) .await?; self.storage_changes.extend( - SubxtRpcApiClient::::query_storage_at( + SubxtRpcApiClient::::query_storage_at( &*self.rpc.client, &[self.storage_key.clone()], Some(header.hash()), diff --git a/subxt/src/transaction.rs b/subxt/src/transaction.rs index 568f1e680a..66dd9c0e75 100644 --- a/subxt/src/transaction.rs +++ b/subxt/src/transaction.rs @@ -392,7 +392,7 @@ impl<'client, T: Config, E: Decode> TransactionInBlock<'client, T, E> { /// **Note:** This has to download block details from the node and decode events /// from them. pub async fn fetch_events(&self) -> Result, BasicError> { - let block = SubxtRpcApiClient::::block( + let block = SubxtRpcApiClient::::block( &*self.client.rpc().client, Some(self.block_hash), ) @@ -409,7 +409,7 @@ impl<'client, T: Config, E: Decode> TransactionInBlock<'client, T, E> { // extrinsic, the extrinsic should be in there somewhere.. .ok_or(BasicError::Transaction(TransactionError::BlockHashNotFound))?; - let raw_events = SubxtRpcApiClient::::storage( + let raw_events = SubxtRpcApiClient::::storage( &*self.client.rpc().client, &StorageKey::from(SystemEvents::new()), Some(self.block_hash),