diff --git a/Cargo.toml b/Cargo.toml index 64c8871b0..dd559248c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ serde = { version = "1.0.136", default-features = false, features = ["derive"] } serde_json = { version = "1.0.79", default-features = false } thiserror = { version = "1.0.30", optional = true } tungstenite = { version = "0.18.0", optional = true, features = ["native-tls"] } -url = { verson = "2.0.0", optional = true } +url = { version = "2.0.0", optional = true } ws = { version = "0.9.2", optional = true, features = ["ssl"] } diff --git a/compose-macros/src/lib.rs b/compose-macros/src/lib.rs index 96cdd8aa0..4b650af8a 100644 --- a/compose-macros/src/lib.rs +++ b/compose-macros/src/lib.rs @@ -68,7 +68,7 @@ macro_rules! compose_extrinsic_offline { $params: expr) => {{ use $crate::{ primitives::{ExtrinsicParams, GenericAddress, SignedPayload, UncheckedExtrinsicV4}, - sp_core::crypto::Pair, + sp_core::{crypto::Pair, Public}, sp_runtime::{generic::Era, traits::IdentifyAccount, MultiSigner}, }; diff --git a/examples/batch_payout.rs b/examples/batch_payout.rs index e86883f0c..790983d71 100644 --- a/examples/batch_payout.rs +++ b/examples/batch_payout.rs @@ -11,7 +11,9 @@ use sp_keyring::AccountKeyring; #[cfg(feature = "staking-xt")] use sp_runtime::{app_crypto::Ss58Codec, AccountId32}; #[cfg(feature = "staking-xt")] -use substrate_api_client::{rpc::JsonrpseeClient, Api, PlainTipExtrinsicParams, XtStatus}; +use substrate_api_client::{ + rpc::JsonrpseeClient, Api, GetStorage, PlainTipExtrinsicParams, SubmitAndWatch, XtStatus, +}; #[cfg(feature = "staking-xt")] #[tokio::main] diff --git a/examples/benchmark_bulk_xt.rs b/examples/benchmark_bulk_xt.rs index f788bd4ff..34f8cb640 100644 --- a/examples/benchmark_bulk_xt.rs +++ b/examples/benchmark_bulk_xt.rs @@ -21,7 +21,8 @@ use kitchensink_runtime::{BalancesCall, Runtime, RuntimeCall}; use sp_keyring::AccountKeyring; use substrate_api_client::{ - compose_extrinsic_offline, Api, AssetTipExtrinsicParams, JsonrpseeClient, UncheckedExtrinsicV4, + compose_extrinsic_offline, Api, AssetTipExtrinsicParams, JsonrpseeClient, SubmitExtrinsic, + UncheckedExtrinsicV4, }; #[tokio::main] diff --git a/examples/compose_extrinsic_offline.rs b/examples/compose_extrinsic_offline.rs index 8dd9a2038..5c2ccfd68 100644 --- a/examples/compose_extrinsic_offline.rs +++ b/examples/compose_extrinsic_offline.rs @@ -21,8 +21,8 @@ use kitchensink_runtime::{BalancesCall, Header, Runtime, RuntimeCall}; use sp_keyring::AccountKeyring; use sp_runtime::{generic::Era, MultiAddress}; use substrate_api_client::{ - compose_extrinsic_offline, rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, - UncheckedExtrinsicV4, XtStatus, + compose_extrinsic_offline, rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, GetHeader, + SubmitAndWatch, UncheckedExtrinsicV4, XtStatus, }; #[tokio::main] diff --git a/examples/contract_instantiate_with_code.rs b/examples/contract_instantiate_with_code.rs index f18623521..89c1e1868 100644 --- a/examples/contract_instantiate_with_code.rs +++ b/examples/contract_instantiate_with_code.rs @@ -19,7 +19,8 @@ use codec::Decode; use kitchensink_runtime::Runtime; use sp_keyring::AccountKeyring; use substrate_api_client::{ - rpc::JsonrpseeClient, AccountId, Api, PlainTipExtrinsicParams, StaticEvent, XtStatus, + rpc::JsonrpseeClient, AccountId, Api, PlainTipExtrinsicParams, StaticEvent, SubmitAndWatch, + SubscribeEvents, SubscribeFrameSystem, XtStatus, }; #[allow(unused)] @@ -55,7 +56,7 @@ async fn main() { "#; let wasm = wabt::wat2wasm(CONTRACT).expect("invalid wabt"); - let mut subscription = api.subscribe_events().expect("cannot subscribe to events"); + let mut subscription = api.subscribe_system_events().expect("cannot subscribe to events"); let xt = api.contract_instantiate_with_code( 1_000_000_000_000_000, diff --git a/examples/custom_nonce.rs b/examples/custom_nonce.rs index 2844467ea..d5c271a66 100644 --- a/examples/custom_nonce.rs +++ b/examples/custom_nonce.rs @@ -21,8 +21,8 @@ use kitchensink_runtime::{BalancesCall, Runtime, RuntimeCall}; use sp_keyring::AccountKeyring; use sp_runtime::{generic::Era, MultiAddress}; use substrate_api_client::{ - compose_extrinsic_offline, rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, - UncheckedExtrinsicV4, XtStatus, + compose_extrinsic_offline, rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, GetHeader, + SubmitAndWatch, UncheckedExtrinsicV4, XtStatus, }; #[tokio::main] diff --git a/examples/event_callback.rs b/examples/event_callback.rs index f88534fec..f3771075a 100644 --- a/examples/event_callback.rs +++ b/examples/event_callback.rs @@ -19,9 +19,9 @@ use codec::Decode; use kitchensink_runtime::Runtime; use log::debug; use sp_core::{sr25519, H256 as Hash}; -use substrate_api_client::HandleSubscription; - -use substrate_api_client::{rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams}; +use substrate_api_client::{ + rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, HandleSubscription, SubscribeFrameSystem, +}; // This module depends on node_runtime. // To avoid dependency collisions, node_runtime has been removed from the substrate-api-client library. @@ -38,7 +38,7 @@ async fn main() { Api::, Runtime>::new(client).unwrap(); println!("Subscribe to events"); - let mut subscription = api.subscribe_events().unwrap(); + let mut subscription = api.subscribe_system_events().unwrap(); for _ in 0..5 { let event_bytes = subscription.next().unwrap().unwrap().changes[0].1.clone().unwrap().0; diff --git a/examples/event_error_details.rs b/examples/event_error_details.rs index 77f44ae8d..b2afc788c 100644 --- a/examples/event_error_details.rs +++ b/examples/event_error_details.rs @@ -19,7 +19,8 @@ use sp_core::crypto::Pair; use sp_keyring::AccountKeyring; use sp_runtime::{AccountId32 as AccountId, MultiAddress}; use substrate_api_client::{ - rpc::JsonrpseeClient, Api, ApiResult, AssetTipExtrinsicParams, StaticEvent, XtStatus, + rpc::JsonrpseeClient, Api, ApiResult, AssetTipExtrinsicParams, GetAccountInformation, + StaticEvent, SubmitAndWatch, SubscribeEvents, SubscribeFrameSystem, XtStatus, }; #[derive(Decode)] @@ -81,7 +82,7 @@ async fn main() { println!("[+] Transaction got included into the TxPool."); // Transfer should fail as Alice wants to transfer all her balance. She does not have enough money to pay the fees. - let mut subscription = api.subscribe_events().unwrap(); + let mut subscription = api.subscribe_system_events().unwrap(); let args: ApiResult = api.wait_for_event(&mut subscription); match args { Ok(_transfer) => { diff --git a/examples/generic_event_callback.rs b/examples/generic_event_callback.rs index 27f73e663..c31a29764 100644 --- a/examples/generic_event_callback.rs +++ b/examples/generic_event_callback.rs @@ -22,7 +22,8 @@ use sp_keyring::AccountKeyring; use sp_runtime::{AccountId32 as AccountId, MultiAddress}; use std::thread; use substrate_api_client::{ - rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, StaticEvent, XtStatus, + rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, StaticEvent, SubmitAndWatch, + SubscribeEvents, SubscribeFrameSystem, XtStatus, }; // Look at the how the transfer event looks like in in the metadata @@ -52,7 +53,7 @@ async fn main() { let api2 = api.clone(); let thread_output = thread::spawn(move || { - let mut subscription = api2.subscribe_events().unwrap(); + let mut subscription = api2.subscribe_system_events().unwrap(); let args: TransferEventArgs = api2.wait_for_event::(&mut subscription).unwrap(); args diff --git a/examples/generic_extrinsic.rs b/examples/generic_extrinsic.rs index b54524950..6000bbe58 100644 --- a/examples/generic_extrinsic.rs +++ b/examples/generic_extrinsic.rs @@ -20,7 +20,7 @@ use kitchensink_runtime::Runtime; use sp_keyring::AccountKeyring; use substrate_api_client::{ compose_extrinsic, rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, GenericAddress, - UncheckedExtrinsicV4, XtStatus, + SubmitAndWatch, UncheckedExtrinsicV4, XtStatus, }; #[tokio::main] diff --git a/examples/get_account_identity.rs b/examples/get_account_identity.rs index 218936b9c..d7c9c752e 100644 --- a/examples/get_account_identity.rs +++ b/examples/get_account_identity.rs @@ -21,8 +21,8 @@ use pallet_identity::{Data, IdentityInfo, Registration}; use sp_core::{crypto::Pair, H256}; use sp_keyring::AccountKeyring; use substrate_api_client::{ - compose_extrinsic, rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, UncheckedExtrinsicV4, - XtStatus, + compose_extrinsic, rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, GetStorage, + SubmitAndWatch, UncheckedExtrinsicV4, XtStatus, }; type BalanceOf = <::Currency as Currency< diff --git a/examples/get_blocks.rs b/examples/get_blocks.rs index 423245600..cc3b2d08d 100644 --- a/examples/get_blocks.rs +++ b/examples/get_blocks.rs @@ -19,7 +19,8 @@ use kitchensink_runtime::Runtime; use sp_core::sr25519; use substrate_api_client::{ - rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, HandleSubscription, + rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, GetBlock, GetHeader, HandleSubscription, + SubscribeChain, }; #[tokio::main] diff --git a/examples/get_existential_deposit.rs b/examples/get_existential_deposit.rs index 0d0138a09..be0195a7e 100644 --- a/examples/get_existential_deposit.rs +++ b/examples/get_existential_deposit.rs @@ -17,7 +17,7 @@ limitations under the License. use kitchensink_runtime::Runtime; use sp_runtime::app_crypto::sp_core::sr25519; -use substrate_api_client::{rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams}; +use substrate_api_client::{rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, GetBalance}; #[tokio::main] async fn main() { diff --git a/examples/get_storage.rs b/examples/get_storage.rs index a418af8e3..5ca53fd39 100644 --- a/examples/get_storage.rs +++ b/examples/get_storage.rs @@ -18,7 +18,7 @@ use frame_system::AccountInfo as GenericAccountInfo; use kitchensink_runtime::Runtime; use sp_keyring::AccountKeyring; -use substrate_api_client::{rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams}; +use substrate_api_client::{rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, GetStorage}; type IndexFor = ::Index; type AccountDataFor = ::AccountData; diff --git a/examples/staking_payout.rs b/examples/staking_payout.rs index 472608afb..fdbb5365e 100644 --- a/examples/staking_payout.rs +++ b/examples/staking_payout.rs @@ -7,7 +7,9 @@ use sp_keyring::AccountKeyring; #[cfg(feature = "staking-xt")] use sp_runtime::{app_crypto::Ss58Codec, AccountId32}; #[cfg(feature = "staking-xt")] -use substrate_api_client::{rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, XtStatus}; +use substrate_api_client::{ + rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, GetStorage, SubmitAndWatch, XtStatus, +}; #[cfg(feature = "staking-xt")] #[tokio::main] diff --git a/examples/sudo.rs b/examples/sudo.rs index 16443a77e..9e5fe55b2 100644 --- a/examples/sudo.rs +++ b/examples/sudo.rs @@ -21,7 +21,7 @@ use kitchensink_runtime::Runtime; use sp_keyring::AccountKeyring; use substrate_api_client::{ compose_call, compose_extrinsic, rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, - GenericAddress, UncheckedExtrinsicV4, XtStatus, + GenericAddress, SubmitAndWatch, UncheckedExtrinsicV4, XtStatus, }; #[tokio::main] diff --git a/examples/transfer_using_seed.rs b/examples/transfer_using_seed.rs index b59b8862f..61959b18b 100755 --- a/examples/transfer_using_seed.rs +++ b/examples/transfer_using_seed.rs @@ -21,7 +21,10 @@ use sp_core::{ sr25519, }; use sp_runtime::MultiAddress; -use substrate_api_client::{rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, XtStatus}; +use substrate_api_client::{ + rpc::JsonrpseeClient, Api, AssetTipExtrinsicParams, GetAccountInformation, SubmitAndWatch, + XtStatus, +}; #[tokio::main] async fn main() { diff --git a/examples/transfer_with_tungstenite_client.rs b/examples/transfer_with_tungstenite_client.rs index 23f591f12..51673ab7f 100755 --- a/examples/transfer_with_tungstenite_client.rs +++ b/examples/transfer_with_tungstenite_client.rs @@ -21,7 +21,10 @@ use sp_core::{ sr25519, }; use sp_runtime::MultiAddress; -use substrate_api_client::{rpc::TungsteniteRpcClient, Api, AssetTipExtrinsicParams, XtStatus}; +use substrate_api_client::{ + rpc::TungsteniteRpcClient, Api, AssetTipExtrinsicParams, GetAccountInformation, SubmitAndWatch, + XtStatus, +}; fn main() { env_logger::init(); diff --git a/examples/transfer_with_ws_client.rs b/examples/transfer_with_ws_client.rs index d0f69d7ae..baeef4ecd 100755 --- a/examples/transfer_with_ws_client.rs +++ b/examples/transfer_with_ws_client.rs @@ -21,7 +21,9 @@ use sp_core::{ sr25519, }; use sp_runtime::MultiAddress; -use substrate_api_client::{rpc::WsRpcClient, Api, AssetTipExtrinsicParams, XtStatus}; +use substrate_api_client::{ + rpc::WsRpcClient, Api, AssetTipExtrinsicParams, GetAccountInformation, SubmitAndWatch, XtStatus, +}; fn main() { env_logger::init(); diff --git a/node-api/src/metadata.rs b/node-api/src/metadata.rs index f82351b7b..c1d108916 100644 --- a/node-api/src/metadata.rs +++ b/node-api/src/metadata.rs @@ -10,7 +10,7 @@ //! //! This file is mostly subxt. -use crate::{alloc::borrow::ToOwned, storage::GetStorage, Encoded}; +use crate::{alloc::borrow::ToOwned, storage::GetStorageTypes, Encoded}; use codec::{Decode, Encode, Error as CodecError}; use frame_metadata::{ PalletConstantMetadata, RuntimeMetadata, RuntimeMetadataLastVersion, RuntimeMetadataPrefixed, diff --git a/node-api/src/storage.rs b/node-api/src/storage.rs index ca928174f..f3d1cee0e 100644 --- a/node-api/src/storage.rs +++ b/node-api/src/storage.rs @@ -75,7 +75,7 @@ impl StorageDoubleMap { } /// trait to extract the storage based on the [`StorageEntryMetadata`]. -pub trait GetStorage { +pub trait GetStorageTypes { fn get_double_map( &self, pallet_prefix: &str, @@ -85,7 +85,7 @@ pub trait GetStorage { fn get_value(&self, pallet_prefix: &str) -> Result; } -impl GetStorage for StorageEntryMetadata { +impl GetStorageTypes for StorageEntryMetadata { fn get_double_map( &self, pallet_prefix: &str, diff --git a/primitives/src/pallet_traits/frame_system_config.rs b/primitives/src/pallet_traits/frame_system_config.rs index b73ff9265..b32a69eda 100644 --- a/primitives/src/pallet_traits/frame_system_config.rs +++ b/primitives/src/pallet_traits/frame_system_config.rs @@ -14,7 +14,7 @@ limitations under the License. */ -use codec::{Codec, EncodeLike, FullCodec, MaxEncodedLen}; +use codec::{Codec, Decode, EncodeLike, FullCodec, MaxEncodedLen}; use core::fmt::Debug; use scale_info::TypeInfo; use sp_runtime::traits::{ @@ -37,18 +37,13 @@ pub trait FrameSystemConfig { + TypeInfo + Dispatchable + Debug; - type Index: Codec - + EncodeLike - + Clone - + Eq - + Debug - + TypeInfo - + MaybeSerializeDeserialize + type Index: MaybeSerializeDeserialize + Debug + Default + AtLeast32Bit + Copy - + MaxEncodedLen; + + MaxEncodedLen + + Decode; type BlockNumber: Codec + EncodeLike + Clone diff --git a/src/api/api_client.rs b/src/api/api_client.rs index ad3667513..b1deef585 100644 --- a/src/api/api_client.rs +++ b/src/api/api_client.rs @@ -1,18 +1,14 @@ /* Copyright 2019 Supercomputing Systems AG - Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - */ pub use crate::{ @@ -26,43 +22,37 @@ pub use frame_metadata::RuntimeMetadataPrefixed; pub use serde_json::Value; pub use sp_core::{crypto::Pair, storage::StorageKey}; pub use sp_runtime::{ - generic::{Block, SignedBlock}, - traits::{GetRuntimeBlockType, Header, IdentifyAccount}, + generic::SignedBlock, + traits::{Block, Header, IdentifyAccount}, AccountId32, MultiSignature, MultiSigner, }; pub use sp_std::prelude::*; -use crate::{rpc::Request, ReadProof}; +use crate::{rpc::Request, GetAccountInformation}; use ac_compose_macros::rpc_params; -use ac_node_api::metadata::{Metadata, MetadataError}; -use ac_primitives::{ - AccountInfo, BalancesConfig, ExtrinsicParams, FeeDetails, InclusionFee, RpcParams, - RuntimeDispatchInfo, -}; -use codec::{Decode, Encode}; -use core::{ - convert::{TryFrom, TryInto}, - str::FromStr, -}; +use ac_node_api::metadata::Metadata; +use ac_primitives::{ExtrinsicParams, FrameSystemConfig}; +use codec::Decode; +use core::convert::TryFrom; use log::{debug, info}; -use serde::de::DeserializeOwned; -use sp_core::{storage::StorageData, Bytes}; -use sp_rpc::number::NumberOrHex; +use sp_core::Bytes; use sp_version::RuntimeVersion; + /// Api to talk with substrate-nodes /// -/// It is generic over the `RpcClient` trait, so you can use any rpc-backend you like. +/// It is generic over the `Request` trait, so you can use any rpc-backend you like. /// /// # Custom Client Example /// /// ```no_run /// use substrate_api_client::{ -/// Api, ApiClientError, ApiResult, FromHexString, Request, rpc::Error as RpcClientError, XtStatus, PlainTipExtrinsicParams, rpc::Result as RpcResult +/// Api, ApiClientError, ApiResult, FromHexString, Request, rpc::Error as RpcClientError, XtStatus, PlainTipExtrinsicParams, rpc::Result as RpcResult /// }; /// use serde::de::DeserializeOwned; /// use ac_primitives::RpcParams; -/// use kitchensink_runtime::Runtime; /// use serde_json::{Value, json}; +/// use kitchensink_runtime::Runtime; +/// /// struct MyClient { /// // pick any request crate, such as ureq::Agent /// _inner: (), @@ -71,7 +61,6 @@ use sp_version::RuntimeVersion; /// impl MyClient { /// pub fn new() -> Self { /// Self { -/// // ureq::agent() /// _inner: (), /// } /// } @@ -107,10 +96,8 @@ use sp_version::RuntimeVersion; #[derive(Clone)] pub struct Api where + Runtime: FrameSystemConfig, Params: ExtrinsicParams, - Runtime: BalancesConfig, - Runtime::Hash: FromHexString, - Runtime::Balance: TryFrom, { signer: Option, genesis_hash: Runtime::Hash, @@ -122,27 +109,31 @@ where impl Api where - Signer: Pair, - MultiSigner: From, - Client: Request, + Runtime: FrameSystemConfig, Params: ExtrinsicParams, - Runtime: BalancesConfig, - Runtime::Hash: FromHexString, - Runtime::Index: From, - Runtime::Balance: TryFrom + FromStr, { + /// Create a new api instance without any node interaction. + pub fn new_offline( + genesis_hash: Runtime::Hash, + metadata: Metadata, + runtime_version: RuntimeVersion, + client: Client, + ) -> Self { + Self { + signer: None, + genesis_hash, + metadata, + runtime_version, + client, + extrinsic_params_builder: None, + } + } + /// Set the api signer account. pub fn set_signer(&mut self, signer: Signer) { self.signer = Some(signer); } - /// Get the public part of the api signer account. - pub fn signer_account(&self) -> Option { - let pair = self.signer.as_ref()?; - let multi_signer = MultiSigner::from(pair.public()); - Some(multi_signer.into_account()) - } - /// Get the private key pair of the api signer. pub fn signer(&self) -> Option<&Signer> { self.signer.as_ref() @@ -193,72 +184,12 @@ where impl Api where - Signer: Pair, - MultiSigner: From, Client: Request, Params: ExtrinsicParams, - Runtime: GetRuntimeBlockType + BalancesConfig, + Runtime: FrameSystemConfig, Runtime::Hash: FromHexString, - Runtime::Index: From, - Runtime::Balance: TryFrom + FromStr, - Runtime::Header: DeserializeOwned, - Runtime::RuntimeBlock: DeserializeOwned, -{ - /// Get nonce of signer account. - pub fn get_nonce(&self) -> ApiResult { - if self.signer.is_none() { - return Err(ApiClientError::NoSigner) - } - - self.get_account_info(&self.signer_account().ok_or(ApiClientError::NoSigner)?) - .map(|acc_opt| acc_opt.map_or_else(|| 0u32.into(), |acc| acc.nonce)) - } -} - -/// Private node query methods. They should be used internally only, because the user should retrieve the data from the struct cache. -/// If an up-to-date query is necessary, cache should be updated beforehand. -impl Api -where - Client: Request, - Params: ExtrinsicParams, - Runtime: BalancesConfig, - Runtime::Hash: FromHexString, - Runtime::Balance: TryFrom + FromStr, - Runtime::Header: DeserializeOwned, -{ - fn get_genesis_hash(client: &Client) -> ApiResult { - let genesis: Option = - client.request("chain_getBlockHash", rpc_params![Some(0)])?; - genesis.ok_or(ApiClientError::Genesis) - } - - /// Get runtime version from node via websocket query. - fn get_runtime_version(client: &Client) -> ApiResult { - let version: RuntimeVersion = client.request("state_getRuntimeVersion", rpc_params![])?; - Ok(version) - } - - /// Get metadata from node via websocket query. - fn get_metadata(client: &Client) -> ApiResult { - let metadata_bytes: Bytes = client.request("state_getMetadata", rpc_params![])?; - - let metadata = RuntimeMetadataPrefixed::decode(&mut metadata_bytes.0.as_slice())?; - Metadata::try_from(metadata).map_err(|e| e.into()) - } -} - -/// Substrate node calls via websocket. -impl Api -where - Client: Request, - Params: ExtrinsicParams, - Runtime: GetRuntimeBlockType + BalancesConfig, - Runtime::Hash: FromHexString, - Runtime::Index: From, - Runtime::Balance: TryFrom + FromStr, - Runtime::Header: DeserializeOwned, - Runtime::RuntimeBlock: DeserializeOwned, { + /// Create a new Api client with call to the node to retrieve metadata. pub fn new(client: Client) -> ApiResult { let genesis_hash = Self::get_genesis_hash(&client)?; info!("Got genesis hash: {:?}", genesis_hash); @@ -269,14 +200,7 @@ where let runtime_version = Self::get_runtime_version(&client)?; info!("Runtime Version: {:?}", runtime_version); - Ok(Self { - signer: None, - genesis_hash, - metadata, - runtime_version, - client, - extrinsic_params_builder: None, - }) + Ok(Self::new_offline(genesis_hash, metadata, runtime_version, client)) } /// Updates the runtime and metadata of the api via node query. @@ -292,287 +216,58 @@ where self.runtime_version = runtime_version; Ok(()) } +} - pub fn get_account_info( - &self, - address: &AccountId, - ) -> ApiResult>> { - let storagekey: sp_core::storage::StorageKey = - self.metadata - .storage_map_key::("System", "Account", address.clone())?; - - info!("storage key is: 0x{}", hex::encode(&storagekey)); - self.get_storage_by_key_hash(storagekey, None) - } - - pub fn get_account_data( - &self, - address: &Runtime::AccountId, - ) -> ApiResult> { - self.get_account_info(address).map(|info| info.map(|i| i.data)) - } - - pub fn get_finalized_head(&self) -> ApiResult> { - let finalized_block_hash = self.request("chain_getFinalizedHead", rpc_params![])?; - Ok(finalized_block_hash) - } - - pub fn get_header(&self, hash: Option) -> ApiResult> { - let block_hash = self.request("chain_getHeader", rpc_params![hash])?; - Ok(block_hash) - } - - pub fn get_block_hash( - &self, - number: Option, - ) -> ApiResult> { - let block_hash = self.request("chain_getBlockHash", rpc_params![number])?; - Ok(block_hash) - } - - pub fn get_block( - &self, - hash: Option, - ) -> ApiResult> { - Self::get_signed_block(self, hash).map(|sb_opt| sb_opt.map(|sb| sb.block)) - } - - pub fn get_block_by_num( - &self, - number: Option, - ) -> ApiResult> { - Self::get_signed_block_by_num(self, number).map(|sb_opt| sb_opt.map(|sb| sb.block)) - } - - /// A signed block is a block with Justification ,i.e., a Grandpa finality proof. - /// The interval at which finality proofs are provided is set via the - /// the `GrandpaConfig.justification_period` in a node's service.rs. - /// The Justification may be none. - pub fn get_signed_block( - &self, - hash: Option, - ) -> ApiResult>> { - let block = self.request("chain_getBlock", rpc_params![hash])?; - Ok(block) - } - - pub fn get_signed_block_by_num( - &self, - number: Option, - ) -> ApiResult>> { - self.get_block_hash(number).map(|h| self.get_signed_block(h))? - } - - pub fn request(&self, method: &str, params: RpcParams) -> ApiResult { - self.client.request(method, params).map_err(ApiClientError::RpcClient) - } - - pub fn get_storage_value( - &self, - storage_prefix: &'static str, - storage_key_name: &'static str, - at_block: Option, - ) -> ApiResult> { - let storagekey = self.metadata.storage_value_key(storage_prefix, storage_key_name)?; - info!("storage key is: 0x{}", hex::encode(&storagekey)); - self.get_storage_by_key_hash(storagekey, at_block) - } - - pub fn get_storage_map( - &self, - storage_prefix: &'static str, - storage_key_name: &'static str, - map_key: K, - at_block: Option, - ) -> ApiResult> { - let storagekey = - self.metadata.storage_map_key::(storage_prefix, storage_key_name, map_key)?; - info!("storage key is: 0x{}", hex::encode(&storagekey)); - self.get_storage_by_key_hash(storagekey, at_block) - } - - pub fn get_storage_map_key_prefix( - &self, - storage_prefix: &'static str, - storage_key_name: &'static str, - ) -> ApiResult { - self.metadata - .storage_map_key_prefix(storage_prefix, storage_key_name) - .map_err(|e| e.into()) - } - - pub fn get_storage_double_map( - &self, - storage_prefix: &'static str, - storage_key_name: &'static str, - first: K, - second: Q, - at_block: Option, - ) -> ApiResult> { - let storagekey = self.metadata.storage_double_map_key::( - storage_prefix, - storage_key_name, - first, - second, - )?; - info!("storage key is: 0x{}", hex::encode(&storagekey)); - self.get_storage_by_key_hash(storagekey, at_block) - } - - pub fn get_storage_by_key_hash( - &self, - key: StorageKey, - at_block: Option, - ) -> ApiResult> { - let s = self.get_opaque_storage_by_key_hash(key, at_block)?; - match s { - Some(storage) => Ok(Some(Decode::decode(&mut storage.as_slice())?)), - None => Ok(None), - } - } - - pub fn get_opaque_storage_by_key_hash( - &self, - key: StorageKey, - at_block: Option, - ) -> ApiResult>> { - let storage: Option = - self.request("state_getStorage", rpc_params![key, at_block])?; - Ok(storage.map(|storage_data| storage_data.0)) - } - - pub fn get_storage_value_proof( - &self, - storage_prefix: &'static str, - storage_key_name: &'static str, - at_block: Option, - ) -> ApiResult>> { - let storagekey = self.metadata.storage_value_key(storage_prefix, storage_key_name)?; - info!("storage key is: 0x{}", hex::encode(&storagekey)); - self.get_storage_proof_by_keys(vec![storagekey], at_block) - } - - pub fn get_storage_map_proof( - &self, - storage_prefix: &'static str, - storage_key_name: &'static str, - map_key: K, - at_block: Option, - ) -> ApiResult>> { - let storagekey = - self.metadata.storage_map_key::(storage_prefix, storage_key_name, map_key)?; - info!("storage key is: 0x{}", hex::encode(&storagekey)); - self.get_storage_proof_by_keys(vec![storagekey], at_block) - } - - pub fn get_storage_double_map_proof( - &self, - storage_prefix: &'static str, - storage_key_name: &'static str, - first: K, - second: Q, - at_block: Option, - ) -> ApiResult>> { - let storagekey = self.metadata.storage_double_map_key::( - storage_prefix, - storage_key_name, - first, - second, - )?; - info!("storage key is: 0x{}", hex::encode(&storagekey)); - self.get_storage_proof_by_keys(vec![storagekey], at_block) - } - - pub fn get_storage_proof_by_keys( - &self, - keys: Vec, - at_block: Option, - ) -> ApiResult>> { - let proof = self.request("state_getReadProof", rpc_params![keys, at_block])?; - Ok(proof) - } - - pub fn get_keys( - &self, - key: StorageKey, - at_block: Option, - ) -> ApiResult>> { - let keys = self.request("state_getKeys", rpc_params![key, at_block])?; - Ok(keys) +impl Api +where + Signer: Pair, + MultiSignature: From, + Client: Request, + Params: ExtrinsicParams, + Runtime: FrameSystemConfig, + Runtime::AccountId: From, +{ + /// Get the public part of the api signer account. + pub fn signer_account(&self) -> Option { + let pair = self.signer.as_ref()?; + Some(pair.public().into()) } - pub fn get_fee_details( - &self, - xthex_prefixed: &str, - at_block: Option, - ) -> ApiResult>> { - let details: Option> = - self.request("payment_queryFeeDetails", rpc_params![xthex_prefixed, at_block])?; - - let details = match details { - Some(details) => Some(convert_fee_details(details)?), - None => None, - }; - Ok(details) + /// Get nonce of self signer account. + pub fn get_nonce(&self) -> ApiResult { + let account = self.signer_account().ok_or(ApiClientError::NoSigner)?; + self.get_account_info(&account) + .map(|acc_opt| acc_opt.map_or_else(|| 0u32.into(), |acc| acc.nonce)) } +} - pub fn get_payment_info( - &self, - xthex_prefixed: &str, - at_block: Option, - ) -> ApiResult>> { - let res = self.request("payment_queryInfo", rpc_params![xthex_prefixed, at_block])?; - Ok(res) +/// Private node query methods. They should be used internally only, because the user should retrieve the data from the struct cache. +/// If an up-to-date query is necessary, cache should be updated beforehand. +impl Api +where + Client: Request, + Params: ExtrinsicParams, + Runtime: FrameSystemConfig, + Runtime::Hash: FromHexString, +{ + /// Get the genesis hash from node via websocket query. + fn get_genesis_hash(client: &Client) -> ApiResult { + let genesis: Option = + client.request("chain_getBlockHash", rpc_params![Some(0)])?; + genesis.ok_or(ApiClientError::Genesis) } - pub fn get_constant( - &self, - pallet: &'static str, - constant: &'static str, - ) -> ApiResult { - let c = self - .metadata - .pallet(pallet)? - .constants - .get(constant) - .ok_or(MetadataError::ConstantNotFound(constant))?; - - Ok(Decode::decode(&mut c.value.as_slice())?) + /// Get runtime version from node via websocket query. + fn get_runtime_version(client: &Client) -> ApiResult { + let version: RuntimeVersion = client.request("state_getRuntimeVersion", rpc_params![])?; + Ok(version) } - pub fn get_existential_deposit(&self) -> ApiResult { - self.get_constant("Balances", "ExistentialDeposit") - } + /// Get metadata from node via websocket query. + fn get_metadata(client: &Client) -> ApiResult { + let metadata_bytes: Bytes = client.request("state_getMetadata", rpc_params![])?; - /// Submit an extrsinic to the substrate node, without watching. - pub fn submit_extrinsic(&self, xthex_prefixed: String) -> ApiResult { - debug!("sending extrinsic: {:?}", xthex_prefixed); - let xt_hash = self.client.request("author_submitExtrinsic", rpc_params![xthex_prefixed])?; - Ok(xt_hash) + let metadata = RuntimeMetadataPrefixed::decode(&mut metadata_bytes.0.as_slice())?; + Metadata::try_from(metadata).map_err(|e| e.into()) } } - -fn convert_fee_details>( - details: FeeDetails, -) -> ApiResult> { - let inclusion_fee = if let Some(inclusion_fee) = details.inclusion_fee { - Some(inclusion_fee_with_balance(inclusion_fee)?) - } else { - None - }; - let tip = details.tip.try_into().map_err(|_| ApiClientError::TryFromIntError)?; - Ok(FeeDetails { inclusion_fee, tip }) -} - -fn inclusion_fee_with_balance>( - inclusion_fee: InclusionFee, -) -> ApiResult> { - Ok(InclusionFee { - base_fee: inclusion_fee.base_fee.try_into().map_err(|_| ApiClientError::TryFromIntError)?, - len_fee: inclusion_fee.len_fee.try_into().map_err(|_| ApiClientError::TryFromIntError)?, - adjusted_weight_fee: inclusion_fee - .adjusted_weight_fee - .try_into() - .map_err(|_| ApiClientError::TryFromIntError)?, - }) -} diff --git a/src/api/error.rs b/src/api/error.rs index 13ea3df2a..18399d24d 100644 --- a/src/api/error.rs +++ b/src/api/error.rs @@ -41,7 +41,6 @@ pub enum Error { Metadata(MetadataError), #[error("InvalidMetadata: {0:?}")] InvalidMetadata(InvalidMetadataError), - #[cfg(any(feature = "ws-client", feature = "tungstenite-client"))] #[error("Events Error: {0:?}")] NodeApi(ac_node_api::error::Error), #[error("Error decoding storage value: {0}")] @@ -76,7 +75,6 @@ impl From for Error { } } -#[cfg(any(feature = "ws-client", feature = "tungstenite-client"))] impl From for Error { fn from(error: ac_node_api::error::Error) -> Self { Error::NodeApi(error) diff --git a/src/api/mod.rs b/src/api/mod.rs index dba04f7e6..933d32411 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -22,6 +22,7 @@ pub use crate::{ pub use ac_primitives::FeeDetails; pub use api_client::Api; pub use frame_metadata::RuntimeMetadataPrefixed; +pub use rpc_api::*; pub use serde_json::Value; pub use sp_core::{crypto::Pair, storage::StorageKey}; pub use sp_runtime::{ @@ -36,12 +37,7 @@ use serde::{Deserialize, Serialize}; pub mod api_client; pub mod error; - -#[cfg(any(feature = "ws-client", feature = "tungstenite-client"))] -pub mod subscription; - -#[cfg(any(feature = "ws-client", feature = "tungstenite-client"))] -pub use subscription::*; +pub mod rpc_api; /// Simplified TransactionStatus to allow the user to choose until when to watch /// an extrinsic. diff --git a/src/api/rpc_api/author.rs b/src/api/rpc_api/author.rs new file mode 100644 index 000000000..baad4931f --- /dev/null +++ b/src/api/rpc_api/author.rs @@ -0,0 +1,132 @@ +/* + Copyright 2019 Supercomputing Systems AG + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +//! Interface to common frame system pallet information. + +use crate::{ + api::{error::Error, ApiResult}, + rpc::HandleSubscription, + Api, Request, Subscribe, TransactionStatus, XtStatus, +}; +use ac_compose_macros::rpc_params; +use ac_primitives::{ExtrinsicParams, FrameSystemConfig}; +use log::*; +use serde::de::DeserializeOwned; + +pub type TransactionSubscriptionFor = + ::Subscription>; + +/// Simple extrinsic submission without any subscription. +pub trait SubmitExtrinsic { + type Hash; + + /// Submit an extrsinic to the substrate node, without watching. + /// Retruns the extrinsic hash. + fn submit_extrinsic(&self, xthex_prefixed: String) -> ApiResult; +} + +impl SubmitExtrinsic for Api +where + Client: Request, + Params: ExtrinsicParams, + Runtime: FrameSystemConfig, +{ + type Hash = Runtime::Hash; + + fn submit_extrinsic(&self, xthex_prefixed: String) -> ApiResult { + debug!("sending extrinsic: {:?}", xthex_prefixed); + let xt_hash = + self.client().request("author_submitExtrinsic", rpc_params![xthex_prefixed])?; + Ok(xt_hash) + } +} + +pub trait SubmitAndWatch +where + Client: Subscribe, + Hash: DeserializeOwned, +{ + /// Submit an extrinsic an return a websocket Subscription to watch the + /// extrinsic progress. + fn submit_and_watch_extrinsic( + &self, + xthex_prefixed: &str, + ) -> ApiResult>; + + /// Submit an extrinsic and watch in until the desired status is reached, + /// if no error is encountered previously. This method is blocking. + fn submit_and_watch_extrinsic_until( + &self, + xthex_prefixed: &str, + watch_until: XtStatus, + ) -> ApiResult>; +} + +impl SubmitAndWatch + for Api +where + Client: Subscribe, + Params: ExtrinsicParams, + Runtime: FrameSystemConfig, +{ + fn submit_and_watch_extrinsic( + &self, + xthex_prefixed: &str, + ) -> ApiResult> { + self.client() + .subscribe( + "author_submitAndWatchExtrinsic", + rpc_params![xthex_prefixed], + "author_unsubmitAndWatchExtrinsic", + ) + .map_err(|e| e.into()) + } + + fn submit_and_watch_extrinsic_until( + &self, + xthex_prefixed: &str, + watch_until: XtStatus, + ) -> ApiResult> { + let mut subscription: TransactionSubscriptionFor = + self.submit_and_watch_extrinsic(xthex_prefixed)?; + while let Some(transaction_status) = subscription.next() { + let transaction_status = transaction_status?; + if transaction_status.is_supported() { + if transaction_status.as_u8() >= watch_until as u8 { + subscription.unsubscribe()?; + return Ok(return_block_hash_if_available(transaction_status)) + } + } else { + subscription.unsubscribe()?; + let error = Error::Extrinsic(format!( + "Unsupported transaction status: {:?}, stopping watch process.", + transaction_status + )); + return Err(error) + } + } + Err(Error::NoStream) + } +} + +fn return_block_hash_if_available( + transcation_status: TransactionStatus, +) -> Option { + match transcation_status { + TransactionStatus::InBlock(block_hash) => Some(block_hash), + TransactionStatus::Retracted(block_hash) => Some(block_hash), + TransactionStatus::FinalityTimeout(block_hash) => Some(block_hash), + TransactionStatus::Finalized(block_hash) => Some(block_hash), + _ => None, + } +} diff --git a/src/api/rpc_api/chain.rs b/src/api/rpc_api/chain.rs new file mode 100644 index 000000000..ab886fcdb --- /dev/null +++ b/src/api/rpc_api/chain.rs @@ -0,0 +1,157 @@ +/* + Copyright 2019 Supercomputing Systems AG + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +use crate::{ + api::{Api, ApiResult}, + rpc::{Request, Subscribe}, + FromHexString, +}; +use ac_compose_macros::rpc_params; +pub use ac_node_api::{events::EventDetails, StaticEvent}; +use ac_primitives::{ExtrinsicParams, FrameSystemConfig}; +use log::*; +use serde::de::DeserializeOwned; +use sp_core::Pair; +use sp_runtime::{generic::SignedBlock, traits::GetRuntimeBlockType, MultiSignature}; + +pub trait GetHeader { + type Header; + + fn get_finalized_head(&self) -> ApiResult>; + + fn get_header(&self, hash: Option) -> ApiResult>; +} + +impl GetHeader + for Api +where + Client: Request, + Runtime: FrameSystemConfig, + Params: ExtrinsicParams, + Runtime::Header: DeserializeOwned, + Runtime::Hash: FromHexString, +{ + type Header = Runtime::Header; + + fn get_finalized_head(&self) -> ApiResult> { + let finalized_block_hash = + self.client().request("chain_getFinalizedHead", rpc_params![])?; + Ok(finalized_block_hash) + } + + fn get_header(&self, hash: Option) -> ApiResult> { + let block_hash = self.client().request("chain_getHeader", rpc_params![hash])?; + Ok(block_hash) + } +} + +pub trait GetBlock { + type Block; + + fn get_block_hash(&self, number: Option) -> ApiResult>; + + fn get_block(&self, hash: Option) -> ApiResult>; + + fn get_block_by_num(&self, number: Option) -> ApiResult>; + + /// A signed block is a block with Justification ,i.e., a Grandpa finality proof. + /// The interval at which finality proofs are provided is set via the + /// the `GrandpaConfig.justification_period` in a node's service.rs. + /// The Justification may be None. + fn get_signed_block(&self, hash: Option) -> ApiResult>>; + + fn get_signed_block_by_num( + &self, + number: Option, + ) -> ApiResult>>; +} + +impl GetBlock + for Api +where + Signer: Pair, + MultiSignature: From, + Client: Request, + Runtime: FrameSystemConfig + GetRuntimeBlockType, + Params: ExtrinsicParams, + Runtime::RuntimeBlock: DeserializeOwned, + Runtime::Hash: FromHexString, +{ + type Block = Runtime::RuntimeBlock; + + fn get_block_hash( + &self, + number: Option, + ) -> ApiResult> { + let block_hash = self.client().request("chain_getBlockHash", rpc_params![number])?; + Ok(block_hash) + } + + fn get_block(&self, hash: Option) -> ApiResult> { + Self::get_signed_block(self, hash).map(|sb_opt| sb_opt.map(|sb| sb.block)) + } + + fn get_block_by_num( + &self, + number: Option, + ) -> ApiResult> { + Self::get_signed_block_by_num(self, number).map(|sb_opt| sb_opt.map(|sb| sb.block)) + } + + fn get_signed_block( + &self, + hash: Option, + ) -> ApiResult>> { + let block = self.client().request("chain_getBlock", rpc_params![hash])?; + Ok(block) + } + + fn get_signed_block_by_num( + &self, + number: Option, + ) -> ApiResult>> { + self.get_block_hash(number).map(|h| self.get_signed_block(h))? + } +} + +pub trait SubscribeChain +where + Client: Subscribe, + Hash: DeserializeOwned, +{ + type Header: DeserializeOwned; + + fn subscribe_finalized_heads(&self) -> ApiResult>; +} + +impl SubscribeChain + for Api +where + Client: Subscribe, + Params: ExtrinsicParams, + Runtime: FrameSystemConfig, + Runtime::Header: DeserializeOwned, +{ + type Header = Runtime::Header; + + fn subscribe_finalized_heads(&self) -> ApiResult> { + debug!("subscribing to finalized heads"); + self.client() + .subscribe( + "chain_subscribeFinalizedHeads", + rpc_params![], + "chain_unsubscribeFinalizedHeads", + ) + .map_err(|e| e.into()) + } +} diff --git a/src/api/rpc_api/frame_system.rs b/src/api/rpc_api/frame_system.rs new file mode 100644 index 000000000..4c88cc753 --- /dev/null +++ b/src/api/rpc_api/frame_system.rs @@ -0,0 +1,102 @@ +/* + Copyright 2019 Supercomputing Systems AG + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +//! Interface to common frame system pallet information. + +use crate::{ + api::{Api, ApiResult, GetStorage}, + rpc::Subscribe, + utils, Request, +}; +use ac_compose_macros::rpc_params; +pub use ac_node_api::{events::EventDetails, StaticEvent}; +use ac_primitives::{AccountInfo, ExtrinsicParams, FrameSystemConfig}; +use log::*; +use serde::de::DeserializeOwned; +use sp_core::{ + storage::{StorageChangeSet, StorageKey}, + Pair, +}; +use sp_runtime::MultiSignature; + +pub trait GetAccountInformation { + type Index; + type AccountData; + + fn get_account_info( + &self, + address: &AccountId, + ) -> ApiResult>>; + + fn get_account_data(&self, address: &AccountId) -> ApiResult>; +} + +impl GetAccountInformation + for Api +where + Signer: Pair, + MultiSignature: From, + Client: Request, + Runtime: FrameSystemConfig, + Params: ExtrinsicParams, +{ + type Index = Runtime::Index; + type AccountData = Runtime::AccountData; + + fn get_account_info( + &self, + address: &Runtime::AccountId, + ) -> ApiResult>> { + let storagekey: StorageKey = self.metadata().storage_map_key::( + "System", + "Account", + address.clone(), + )?; + + info!("storage key is: 0x{}", hex::encode(&storagekey)); + self.get_storage_by_key_hash(storagekey, None) + } + + fn get_account_data( + &self, + address: &Runtime::AccountId, + ) -> ApiResult> { + self.get_account_info(address).map(|info| info.map(|i| i.data)) + } +} + +pub trait SubscribeFrameSystem +where + Client: Subscribe, + Hash: DeserializeOwned, +{ + fn subscribe_system_events(&self) -> ApiResult>>; +} + +impl SubscribeFrameSystem + for Api +where + Client: Subscribe, + Params: ExtrinsicParams, + Runtime: FrameSystemConfig, +{ + fn subscribe_system_events( + &self, + ) -> ApiResult>> { + debug!("subscribing to events"); + let key = utils::storage_key("System", "Events"); + self.client() + .subscribe("state_subscribeStorage", rpc_params![vec![key]], "state_unsubscribeStorage") + .map_err(|e| e.into()) + } +} diff --git a/src/api/rpc_api/mod.rs b/src/api/rpc_api/mod.rs new file mode 100644 index 000000000..6af891d78 --- /dev/null +++ b/src/api/rpc_api/mod.rs @@ -0,0 +1,25 @@ +/* + Copyright 2019 Supercomputing Systems AG + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +pub use self::{ + author::*, chain::*, frame_system::*, pallet_balances::*, pallet_transaction_payment::*, + state::*, subscribe_events::*, +}; + +pub mod author; +pub mod chain; +pub mod frame_system; +pub mod pallet_balances; +pub mod pallet_transaction_payment; +pub mod state; +pub mod subscribe_events; diff --git a/src/api/rpc_api/pallet_balances.rs b/src/api/rpc_api/pallet_balances.rs new file mode 100644 index 000000000..a435bcc0c --- /dev/null +++ b/src/api/rpc_api/pallet_balances.rs @@ -0,0 +1,39 @@ +/* + Copyright 2019 Supercomputing Systems AG + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +use crate::{ + api::{Api, ApiResult, GetStorage}, + rpc::Request, + ExtrinsicParams, +}; +use ac_primitives::BalancesConfig; + +/// Interface to common calls of the substrate balances pallet. +pub trait GetBalance { + type Balance; + + fn get_existential_deposit(&self) -> ApiResult; +} + +impl GetBalance + for Api +where + Client: Request, + Runtime: BalancesConfig, + Params: ExtrinsicParams, +{ + type Balance = Runtime::Balance; + + fn get_existential_deposit(&self) -> ApiResult { + self.get_constant("Balances", "ExistentialDeposit") + } +} diff --git a/src/api/rpc_api/pallet_transaction_payment.rs b/src/api/rpc_api/pallet_transaction_payment.rs new file mode 100644 index 000000000..e04db6b95 --- /dev/null +++ b/src/api/rpc_api/pallet_transaction_payment.rs @@ -0,0 +1,100 @@ +/* + Copyright 2019 Supercomputing Systems AG + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +use crate::{ + api::{Api, ApiClientError, ApiResult}, + rpc::Request, + ExtrinsicParams, +}; +use ac_compose_macros::rpc_params; +use ac_primitives::{BalancesConfig, FeeDetails, InclusionFee, RuntimeDispatchInfo}; +use sp_rpc::number::NumberOrHex; + +/// Interface to common calls of the substrate transaction payment pallet. +pub trait GetTransactionPayment { + type Balance; + + fn get_fee_details( + &self, + xthex_prefixed: &str, + at_block: Option, + ) -> ApiResult>>; + + fn get_payment_info( + &self, + xthex_prefixed: &str, + at_block: Option, + ) -> ApiResult>>; +} + +impl GetTransactionPayment + for Api +where + Client: Request, + Runtime: BalancesConfig, + Params: ExtrinsicParams, + Runtime::Balance: TryFrom, +{ + type Balance = Runtime::Balance; + + fn get_fee_details( + &self, + xthex_prefixed: &str, + at_block: Option, + ) -> ApiResult>> { + let details: Option> = self + .client() + .request("payment_queryFeeDetails", rpc_params![xthex_prefixed, at_block])?; + + let details = match details { + Some(details) => Some(convert_fee_details(details)?), + None => None, + }; + Ok(details) + } + + fn get_payment_info( + &self, + xthex_prefixed: &str, + at_block: Option, + ) -> ApiResult>> { + let res = self + .client() + .request("payment_queryInfo", rpc_params![xthex_prefixed, at_block])?; + Ok(res) + } +} + +fn convert_fee_details>( + details: FeeDetails, +) -> ApiResult> { + let inclusion_fee = if let Some(inclusion_fee) = details.inclusion_fee { + Some(inclusion_fee_with_balance(inclusion_fee)?) + } else { + None + }; + let tip = details.tip.try_into().map_err(|_| ApiClientError::TryFromIntError)?; + Ok(FeeDetails { inclusion_fee, tip }) +} + +fn inclusion_fee_with_balance>( + inclusion_fee: InclusionFee, +) -> ApiResult> { + Ok(InclusionFee { + base_fee: inclusion_fee.base_fee.try_into().map_err(|_| ApiClientError::TryFromIntError)?, + len_fee: inclusion_fee.len_fee.try_into().map_err(|_| ApiClientError::TryFromIntError)?, + adjusted_weight_fee: inclusion_fee + .adjusted_weight_fee + .try_into() + .map_err(|_| ApiClientError::TryFromIntError)?, + }) +} diff --git a/src/api/rpc_api/state.rs b/src/api/rpc_api/state.rs new file mode 100644 index 000000000..315bfde5a --- /dev/null +++ b/src/api/rpc_api/state.rs @@ -0,0 +1,291 @@ +/* + Copyright 2019 Supercomputing Systems AG + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +use crate::{api::ApiResult, rpc::Subscribe, utils, Api, MetadataError, ReadProof, Request}; +use ac_compose_macros::rpc_params; +pub use ac_node_api::{events::EventDetails, StaticEvent}; +use ac_primitives::{ExtrinsicParams, FrameSystemConfig}; +use codec::{Decode, Encode}; +use log::*; +use serde::de::DeserializeOwned; +use sp_core::storage::{StorageChangeSet, StorageData, StorageKey}; + +/// Generic interface to substrate storage. +pub trait GetStorage { + fn get_storage_value( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + at_block: Option, + ) -> ApiResult>; + + fn get_storage_map( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + map_key: K, + at_block: Option, + ) -> ApiResult>; + + fn get_storage_map_key_prefix( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + ) -> ApiResult; + + fn get_storage_double_map( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + first: K, + second: Q, + at_block: Option, + ) -> ApiResult>; + + fn get_storage_by_key_hash( + &self, + key: StorageKey, + at_block: Option, + ) -> ApiResult>; + + fn get_opaque_storage_by_key_hash( + &self, + key: StorageKey, + at_block: Option, + ) -> ApiResult>>; + + fn get_storage_value_proof( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + at_block: Option, + ) -> ApiResult>>; + + fn get_storage_map_proof( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + map_key: K, + at_block: Option, + ) -> ApiResult>>; + + fn get_storage_double_map_proof( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + first: K, + second: Q, + at_block: Option, + ) -> ApiResult>>; + + fn get_storage_proof_by_keys( + &self, + keys: Vec, + at_block: Option, + ) -> ApiResult>>; + + fn get_keys(&self, key: StorageKey, at_block: Option) -> ApiResult>>; + + fn get_constant(&self, pallet: &'static str, constant: &'static str) + -> ApiResult; +} + +impl GetStorage + for Api +where + Client: Request, + Runtime: FrameSystemConfig, + Params: ExtrinsicParams, +{ + fn get_storage_value( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + at_block: Option, + ) -> ApiResult> { + let storagekey = self.metadata().storage_value_key(storage_prefix, storage_key_name)?; + info!("storage key is: 0x{}", hex::encode(&storagekey)); + self.get_storage_by_key_hash(storagekey, at_block) + } + + fn get_storage_map( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + map_key: K, + at_block: Option, + ) -> ApiResult> { + let storagekey = + self.metadata() + .storage_map_key::(storage_prefix, storage_key_name, map_key)?; + info!("storage key is: 0x{}", hex::encode(&storagekey)); + self.get_storage_by_key_hash(storagekey, at_block) + } + + fn get_storage_map_key_prefix( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + ) -> ApiResult { + self.metadata() + .storage_map_key_prefix(storage_prefix, storage_key_name) + .map_err(|e| e.into()) + } + + fn get_storage_double_map( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + first: K, + second: Q, + at_block: Option, + ) -> ApiResult> { + let storagekey = self.metadata().storage_double_map_key::( + storage_prefix, + storage_key_name, + first, + second, + )?; + info!("storage key is: 0x{}", hex::encode(&storagekey)); + self.get_storage_by_key_hash(storagekey, at_block) + } + + fn get_storage_by_key_hash( + &self, + key: StorageKey, + at_block: Option, + ) -> ApiResult> { + let s = self.get_opaque_storage_by_key_hash(key, at_block)?; + match s { + Some(storage) => Ok(Some(Decode::decode(&mut storage.as_slice())?)), + None => Ok(None), + } + } + + fn get_opaque_storage_by_key_hash( + &self, + key: StorageKey, + at_block: Option, + ) -> ApiResult>> { + let storage: Option = + self.client().request("state_getStorage", rpc_params![key, at_block])?; + Ok(storage.map(|storage_data| storage_data.0)) + } + + fn get_storage_value_proof( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + at_block: Option, + ) -> ApiResult>> { + let storagekey = self.metadata().storage_value_key(storage_prefix, storage_key_name)?; + info!("storage key is: 0x{}", hex::encode(&storagekey)); + self.get_storage_proof_by_keys(vec![storagekey], at_block) + } + + fn get_storage_map_proof( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + map_key: K, + at_block: Option, + ) -> ApiResult>> { + let storagekey = + self.metadata() + .storage_map_key::(storage_prefix, storage_key_name, map_key)?; + info!("storage key is: 0x{}", hex::encode(&storagekey)); + self.get_storage_proof_by_keys(vec![storagekey], at_block) + } + + fn get_storage_double_map_proof( + &self, + storage_prefix: &'static str, + storage_key_name: &'static str, + first: K, + second: Q, + at_block: Option, + ) -> ApiResult>> { + let storagekey = self.metadata().storage_double_map_key::( + storage_prefix, + storage_key_name, + first, + second, + )?; + info!("storage key is: 0x{}", hex::encode(&storagekey)); + self.get_storage_proof_by_keys(vec![storagekey], at_block) + } + + fn get_storage_proof_by_keys( + &self, + keys: Vec, + at_block: Option, + ) -> ApiResult>> { + let proof = self.client().request("state_getReadProof", rpc_params![keys, at_block])?; + Ok(proof) + } + + fn get_keys( + &self, + key: StorageKey, + at_block: Option, + ) -> ApiResult>> { + let keys = self.client().request("state_getKeys", rpc_params![key, at_block])?; + Ok(keys) + } + + fn get_constant( + &self, + pallet: &'static str, + constant: &'static str, + ) -> ApiResult { + let c = self + .metadata() + .pallet(pallet)? + .constants + .get(constant) + .ok_or(MetadataError::ConstantNotFound(constant))?; + + Ok(Decode::decode(&mut c.value.as_slice())?) + } +} + +pub trait SubscribeState +where + Client: Subscribe, + Hash: DeserializeOwned, +{ + fn subscribe_state( + &self, + pallet: &str, + storage_key: &str, + ) -> ApiResult>>; +} + +impl SubscribeState + for Api +where + Client: Subscribe, + Params: ExtrinsicParams, + Runtime: FrameSystemConfig, +{ + fn subscribe_state( + &self, + pallet: &str, + storage_key_name: &str, + ) -> ApiResult>> { + debug!("subscribing to events"); + let key = utils::storage_key(pallet, storage_key_name); + self.client() + .subscribe("state_subscribeStorage", rpc_params![vec![key]], "state_unsubscribeStorage") + .map_err(|e| e.into()) + } +} diff --git a/src/api/rpc_api/subscribe_events.rs b/src/api/rpc_api/subscribe_events.rs new file mode 100644 index 000000000..9d466a231 --- /dev/null +++ b/src/api/rpc_api/subscribe_events.rs @@ -0,0 +1,104 @@ +/* + Copyright 2019 Supercomputing Systems AG + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +use crate::{ + api::{error::Error, Api, ApiResult}, + rpc::{HandleSubscription, Subscribe}, +}; +pub use ac_node_api::{events::EventDetails, StaticEvent}; +use ac_node_api::{DispatchError, Events}; +use ac_primitives::{ExtrinsicParams, FrameSystemConfig}; +use log::*; +use serde::de::DeserializeOwned; +use sp_core::storage::StorageChangeSet; + +// FIXME: This should rather be implemented directly on the +// Subscription return value, rather than the api. Or directly +// subcribe. Should be looked at in #288 +// https://github.com/scs/substrate-api-client/issues/288#issuecomment-1346221653 +pub trait SubscribeEvents +where + Client: Subscribe, + Hash: DeserializeOwned, +{ + fn wait_for_event( + &self, + subscription: &mut Client::Subscription>, + ) -> ApiResult; + + fn wait_for_event_details( + &self, + subscription: &mut Client::Subscription>, + ) -> ApiResult; +} + +impl SubscribeEvents + for Api +where + Client: Subscribe, + Params: ExtrinsicParams, + Runtime: FrameSystemConfig, +{ + fn wait_for_event( + &self, + subscription: &mut Client::Subscription>, + ) -> ApiResult { + let maybe_event_details = self.wait_for_event_details::(subscription)?; + maybe_event_details + .as_event()? + .ok_or(Error::Other("Could not find the specific event".into())) + } + + fn wait_for_event_details( + &self, + subscription: &mut Client::Subscription>, + ) -> ApiResult { + while let Some(change_set) = subscription.next() { + let event_bytes = change_set?.changes[0].1.as_ref().unwrap().0.clone(); + let events = Events::::new( + self.metadata().clone(), + Default::default(), + event_bytes, + ); + for maybe_event_details in events.iter() { + let event_details = maybe_event_details?; + + // Check for failed xt and return as Dispatch Error in case we find one. + // Careful - this reports the first one encountered. This event may belong to another extrinsic + // than the one that is being waited for. + if extrinsic_has_failed(&event_details) { + let dispatch_error = + DispatchError::decode_from(event_details.field_bytes(), self.metadata()); + return Err(Error::Dispatch(dispatch_error)) + } + + let event_metadata = event_details.event_metadata(); + trace!( + "Found extrinsic: {:?}, {:?}", + event_metadata.pallet(), + event_metadata.event() + ); + if event_metadata.pallet() == Ev::PALLET && event_metadata.event() == Ev::EVENT { + return Ok(event_details) + } else { + trace!("Not the event we are looking for, skipping.") + } + } + } + Err(Error::NoStream) + } +} + +fn extrinsic_has_failed(event_details: &EventDetails) -> bool { + event_details.pallet_name() == "System" && event_details.variant_name() == "ExtrinsicFailed" +} diff --git a/src/api/subscription.rs b/src/api/subscription.rs deleted file mode 100644 index 31f46dc3e..000000000 --- a/src/api/subscription.rs +++ /dev/null @@ -1,176 +0,0 @@ -/* - Copyright 2019 Supercomputing Systems AG - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -use crate::{ - api::{error::Error, Api, ApiResult, TransactionStatus}, - rpc::{HandleSubscription, Request, Subscribe}, - utils, FromHexString, XtStatus, -}; -use ac_compose_macros::rpc_params; -pub use ac_node_api::{events::EventDetails, StaticEvent}; -use ac_node_api::{DispatchError, Events}; -use ac_primitives::{BalancesConfig, ExtrinsicParams}; -use core::str::FromStr; -use log::*; -use serde::de::DeserializeOwned; -use sp_core::{storage::StorageChangeSet, Pair}; -use sp_rpc::number::NumberOrHex; -use sp_runtime::MultiSigner; - -pub type TransactionSubscriptionFor = - ::Subscription>; - -impl Api -where - Signer: Pair, - MultiSigner: From, - Client: Subscribe + Request, - Params: ExtrinsicParams, - Runtime: BalancesConfig, - Runtime::Hash: FromHexString, - Runtime::Balance: TryFrom + FromStr, - Runtime::Header: DeserializeOwned, -{ - /// Submit an extrinsic an return a websocket Subscription to watch the - /// extrinsic progress. - pub fn submit_and_watch_extrinsic( - &self, - xthex_prefixed: &str, - ) -> ApiResult> { - self.client() - .subscribe( - "author_submitAndWatchExtrinsic", - rpc_params![xthex_prefixed], - "author_unsubmitAndWatchExtrinsic", - ) - .map_err(|e| e.into()) - } - - /// Submit an extrinsic and watch in until the desired status is reached, - /// if no error is encountered previously. This method is blocking. - pub fn submit_and_watch_extrinsic_until( - &self, - xthex_prefixed: &str, - watch_until: XtStatus, - ) -> ApiResult> { - let mut subscription: TransactionSubscriptionFor = - self.submit_and_watch_extrinsic(xthex_prefixed)?; - while let Some(transaction_status) = subscription.next() { - let transaction_status = transaction_status?; - if transaction_status.is_supported() { - if transaction_status.as_u8() >= watch_until as u8 { - subscription.unsubscribe()?; - return Ok(return_block_hash_if_available(transaction_status)) - } - } else { - subscription.unsubscribe()?; - let error = Error::Extrinsic(format!( - "Unsupported transaction status: {:?}, stopping watch process.", - transaction_status - )); - return Err(error) - } - } - Err(Error::NoStream) - } - - pub fn subscribe_events( - &self, - ) -> ApiResult>> { - debug!("subscribing to events"); - let key = utils::storage_key("System", "Events"); - self.client() - .subscribe("state_subscribeStorage", rpc_params![vec![key]], "state_unsubscribeStorage") - .map_err(|e| e.into()) - } - - pub fn subscribe_finalized_heads(&self) -> ApiResult> { - debug!("subscribing to finalized heads"); - self.client() - .subscribe( - "chain_subscribeFinalizedHeads", - rpc_params![], - "chain_unsubscribeFinalizedHeads", - ) - .map_err(|e| e.into()) - } - - pub fn wait_for_event( - &self, - subscription: &mut Client::Subscription>, - ) -> ApiResult { - let maybe_event_details = self.wait_for_event_details::(subscription)?; - maybe_event_details - .as_event()? - .ok_or(Error::Other("Could not find the specific event".into())) - } - - pub fn wait_for_event_details( - &self, - subscription: &mut Client::Subscription>, - ) -> ApiResult { - while let Some(change_set) = subscription.next() { - let event_bytes = change_set?.changes[0].1.as_ref().unwrap().0.clone(); - let events = Events::::new( - self.metadata().clone(), - Default::default(), - event_bytes, - ); - for maybe_event_details in events.iter() { - let event_details = maybe_event_details?; - - // Check for failed xt and return as Dispatch Error in case we find one. - // Careful - this reports the first one encountered. This event may belong to another extrinsic - // than the one that is being waited for. - if extrinsic_has_failed(&event_details) { - let dispatch_error = - DispatchError::decode_from(event_details.field_bytes(), self.metadata()); - return Err(Error::Dispatch(dispatch_error)) - } - - let event_metadata = event_details.event_metadata(); - trace!( - "Found extrinsic: {:?}, {:?}", - event_metadata.pallet(), - event_metadata.event() - ); - if event_metadata.pallet() == Ev::PALLET && event_metadata.event() == Ev::EVENT { - return Ok(event_details) - } else { - trace!("Not the event we are looking for, skipping.") - } - } - } - Err(Error::NoStream) - } -} - -fn extrinsic_has_failed(event_details: &EventDetails) -> bool { - event_details.pallet_name() == "System" && event_details.variant_name() == "ExtrinsicFailed" -} - -fn return_block_hash_if_available( - transcation_status: TransactionStatus, -) -> Option { - match transcation_status { - TransactionStatus::InBlock(block_hash) => Some(block_hash), - TransactionStatus::Retracted(block_hash) => Some(block_hash), - TransactionStatus::FinalityTimeout(block_hash) => Some(block_hash), - TransactionStatus::Finalized(block_hash) => Some(block_hash), - _ => None, - } -} diff --git a/src/extrinsic/balances.rs b/src/extrinsic/balances.rs index 4e28e70d8..8ea3b7b51 100644 --- a/src/extrinsic/balances.rs +++ b/src/extrinsic/balances.rs @@ -17,16 +17,14 @@ //! Extrinsics for `pallet-balances`. -use crate::{api::Api, rpc::Request, FromHexString}; +use crate::{api::Api, rpc::Request}; use ac_compose_macros::compose_extrinsic; use ac_primitives::{ BalancesConfig, CallIndex, ExtrinsicParams, GenericAddress, UncheckedExtrinsicV4, }; use codec::{Compact, Encode}; -use core::str::FromStr; use serde::de::DeserializeOwned; use sp_core::crypto::Pair; -use sp_rpc::number::NumberOrHex; use sp_runtime::{traits::GetRuntimeBlockType, MultiSignature, MultiSigner}; pub const BALANCES_MODULE: &str = "Balances"; @@ -49,13 +47,12 @@ where MultiSignature: From, MultiSigner: From, Client: Request, - Params: ExtrinsicParams, Runtime: GetRuntimeBlockType + BalancesConfig, - Runtime::Hash: FromHexString, - Runtime::Balance: TryFrom + FromStr, + Params: ExtrinsicParams, Compact: Encode, Runtime::Header: DeserializeOwned, Runtime::RuntimeBlock: DeserializeOwned, + Runtime::AccountId: From, { pub fn balance_transfer( &self, diff --git a/src/extrinsic/contracts.rs b/src/extrinsic/contracts.rs index d98abcbd1..6cc43f549 100644 --- a/src/extrinsic/contracts.rs +++ b/src/extrinsic/contracts.rs @@ -18,17 +18,15 @@ //! Extrinsics for `pallet-contract`. //! Contracts module is community maintained and not CI tested, therefore it may not work as is. -use crate::{api::Api, rpc::Request, FromHexString}; +use crate::{api::Api, rpc::Request}; use ac_compose_macros::compose_extrinsic; use ac_primitives::{ BalancesConfig, CallIndex, ContractsConfig, ExtrinsicParams, FrameSystemConfig, GenericAddress, UncheckedExtrinsicV4, }; use codec::{Compact, Encode}; -use core::str::FromStr; use serde::de::DeserializeOwned; use sp_core::crypto::Pair; -use sp_rpc::number::NumberOrHex; use sp_runtime::{traits::GetRuntimeBlockType, MultiSignature, MultiSigner}; use sp_std::prelude::*; @@ -77,9 +75,8 @@ where Client: Request, Params: ExtrinsicParams, Runtime: GetRuntimeBlockType + ContractsConfig + BalancesConfig, - Runtime::Hash: FromHexString, - Runtime::Balance: TryFrom + FromStr, Compact>: Encode + Clone, + Runtime::AccountId: From, Runtime::Currency: frame_support::traits::Currency, Runtime::Header: DeserializeOwned, Runtime::RuntimeBlock: DeserializeOwned, diff --git a/src/extrinsic/staking.rs b/src/extrinsic/staking.rs index 17be5cd9c..75e6a8a25 100644 --- a/src/extrinsic/staking.rs +++ b/src/extrinsic/staking.rs @@ -18,17 +18,15 @@ //! Extrinsics for `pallet-staking`. use super::common::*; -use crate::{rpc::Request, Api, FromHexString}; +use crate::{rpc::Request, Api}; use ac_compose_macros::compose_extrinsic; use ac_primitives::{ BalancesConfig, CallIndex, ExtrinsicParams, GenericAddress, RewardDestination, StakingConfig, UncheckedExtrinsicV4, }; use codec::{Compact, Encode}; -use core::str::FromStr; use serde::de::DeserializeOwned; use sp_core::Pair; -use sp_rpc::number::NumberOrHex; use sp_runtime::{traits::GetRuntimeBlockType, AccountId32, MultiSignature, MultiSigner}; const STAKING_MODULE: &str = "Staking"; @@ -92,13 +90,12 @@ pub type StakingSetValidatorCountXt = impl Api where Signer: Pair, - MultiSigner: From, MultiSignature: From, + MultiSigner: From, Client: Request, Params: ExtrinsicParams, Runtime: GetRuntimeBlockType + BalancesConfig + StakingConfig, - Runtime::Hash: FromHexString, - Runtime::Balance: TryFrom + FromStr, + Runtime::AccountId: From, Compact: Encode, Runtime::Header: DeserializeOwned, Runtime::RuntimeBlock: DeserializeOwned, diff --git a/src/extrinsic/utility.rs b/src/extrinsic/utility.rs index 188876dad..d33d041e9 100644 --- a/src/extrinsic/utility.rs +++ b/src/extrinsic/utility.rs @@ -18,14 +18,11 @@ //! Extrinsics for `pallet-utility`. use super::common::Batch; -use crate::{rpc::Request, Api, FromHexString}; +use crate::{rpc::Request, Api}; use ac_compose_macros::compose_extrinsic; use ac_primitives::{BalancesConfig, CallIndex, ExtrinsicParams, UncheckedExtrinsicV4}; use codec::Encode; -use core::str::FromStr; -use serde::de::DeserializeOwned; use sp_core::Pair; -use sp_rpc::number::NumberOrHex; use sp_runtime::{traits::GetRuntimeBlockType, MultiSignature, MultiSigner}; const UTILITY_MODULE: &str = "Utility"; @@ -44,10 +41,7 @@ where Client: Request, Params: ExtrinsicParams, Runtime: GetRuntimeBlockType + BalancesConfig, - Runtime::Hash: FromHexString, - Runtime::Balance: TryFrom + FromStr, - Runtime::Header: DeserializeOwned, - Runtime::RuntimeBlock: DeserializeOwned, + Runtime::AccountId: From, { pub fn batch( &self,