From d12416ab149aca60e595a2c5881fc9ca8b4dc654 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 13 Apr 2023 16:37:49 +0200 Subject: [PATCH 01/11] add partial_fee estimation to submittable extrinsic --- subxt/src/rpc/rpc.rs | 45 ++++++++++----------- subxt/src/rpc/types.rs | 66 +++++++++++++++++++++++++++++- subxt/src/tx/tx_client.rs | 85 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 166 insertions(+), 30 deletions(-) diff --git a/subxt/src/rpc/rpc.rs b/subxt/src/rpc/rpc.rs index 64f146de5d..0e4cada834 100644 --- a/subxt/src/rpc/rpc.rs +++ b/subxt/src/rpc/rpc.rs @@ -31,16 +31,19 @@ //! # } //! ``` +use std::sync::Arc; + +use codec::{Decode, Encode}; +use frame_metadata::RuntimeMetadataPrefixed; +use serde::Serialize; + +use crate::{error::Error, utils::PhantomDataSendSync, Config, Metadata}; + use super::{ rpc_params, types::{self, ChainHeadEvent, FollowEvent}, RpcClient, RpcClientT, Subscription, }; -use crate::{error::Error, utils::PhantomDataSendSync, Config, Metadata}; -use codec::{Decode, Encode}; -use frame_metadata::RuntimeMetadataPrefixed; -use serde::Serialize; -use std::sync::Arc; /// Client for substrate rpc interfaces pub struct Rpc { @@ -151,25 +154,6 @@ impl Rpc { Ok(metadata) } - /// Execute a runtime API call. - pub async fn call( - &self, - function: String, - call_parameters: Option<&[u8]>, - at: Option, - ) -> Result { - let call_parameters = call_parameters.unwrap_or_default(); - - let bytes: types::Bytes = self - .client - .request( - "state_call", - rpc_params![function, to_hex(call_parameters), at], - ) - .await?; - Ok(bytes) - } - /// Fetch system properties pub async fn system_properties(&self) -> Result { self.client @@ -382,6 +366,19 @@ impl Rpc { Ok(bytes) } + /// Execute a runtime API call. + pub async fn state_call_decoded( + &self, + function: &str, + call_parameters: Option<&[u8]>, + at: Option, + ) -> Result { + let bytes = self.state_call(function, call_parameters, at).await?; + let cursor = &mut &bytes[..]; + let res: Res = Decode::decode(cursor)?; + Ok(res) + } + /// Create and submit an extrinsic and return a subscription to the events triggered. pub async fn watch_extrinsic( &self, diff --git a/subxt/src/rpc/types.rs b/subxt/src/rpc/types.rs index 2500507da0..93e01715a9 100644 --- a/subxt/src/rpc/types.rs +++ b/subxt/src/rpc/types.rs @@ -59,7 +59,7 @@ impl DryRunResultBytes { /// /// The primary motivation for having this type is to avoid overflows when using big integers in /// JavaScript (which we consider as an important RPC API consumer). -#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] +#[derive(Encode, Decode, Copy, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] #[serde(untagged)] pub enum NumberOrHex { /// The number represented directly. @@ -233,6 +233,70 @@ into_block_number!(u8 u16 u32 u64); /// Arbitrary properties defined in the chain spec as a JSON object. pub type SystemProperties = serde_json::Map; +/// taken from original type [`pallet_transaction_payment::types::FeeDetails`] +#[derive(Encode, Decode, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct FeeDetails { + /// The minimum fee for a transaction to be included in a block. + pub inclusion_fee: Option, + /// tip + pub tip: u128, +} + +/// taken from original type [`pallet_transaction_payment::types::InclusionFee`] +/// The base fee and adjusted weight and length fees constitute the _inclusion fee_. +#[derive(Encode, Decode, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct InclusionFee { + /// minimum amount a user pays for a transaction. + pub base_fee: u128, + /// amount paid for the encoded length (in bytes) of the transaction. + pub len_fee: u128, + /// + /// - `targeted_fee_adjustment`: This is a multiplier that can tune the final fee based on the + /// congestion of the network. + /// - `weight_fee`: This amount is computed based on the weight of the transaction. Weight + /// accounts for the execution time of a transaction. + /// + /// adjusted_weight_fee = targeted_fee_adjustment * weight_fee + pub adjusted_weight_fee: u128, +} + +/// taken from original type [`pallet_transaction_payment::types::RuntimeDispatchInfo`] +#[derive(Debug, Encode, Decode, Eq, PartialEq, Copy, Clone)] +pub struct RuntimeDispatchInfo { + /// Weight of this dispatch. + pub weight: Weight, + /// Class of this dispatch. + pub class: DispatchClass, + /// The inclusion fee of this dispatch. + /// + /// This does not include a tip or anything else + pub partial_fee: u128, +} + +/// taken from original type [`sp_weights::weight_v2::Weight`] +#[derive(Debug, Encode, Decode, Eq, PartialEq, Copy, Clone, Default)] +pub struct Weight { + #[codec(compact)] + /// The weight of computational time used based on some reference hardware. + pub ref_time: u64, + #[codec(compact)] + /// The weight of storage space used by proof of validity. + pub proof_size: u64, +} + +/// taken from original type [`frame_support::dispatch::DispatchClass`] +#[derive(Debug, Encode, Decode, Eq, PartialEq, Copy, Clone)] +pub enum DispatchClass { + /// A normal dispatch. + Normal, + /// An operational dispatch. + Operational, + /// A mandatory dispatch. + Mandatory, +} + /// Possible transaction status events. /// /// # Note diff --git a/subxt/src/tx/tx_client.rs b/subxt/src/tx/tx_client.rs index 9eb9fa279a..d0ba080a16 100644 --- a/subxt/src/tx/tx_client.rs +++ b/subxt/src/tx/tx_client.rs @@ -2,21 +2,26 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use super::TxPayload; +use std::borrow::Cow; + +use codec::{Compact, Decode, Encode}; +use derivative::Derivative; +use futures::try_join; +use serde::{Deserialize, Serialize}; + use crate::{ client::{OfflineClientT, OnlineClientT}, config::{Config, ExtrinsicParams, Hasher}, error::Error, + rpc::types::{FeeDetails, InclusionFee, RuntimeDispatchInfo, Weight}, tx::{Signer as SignerT, TxProgress}, utils::{Encoded, PhantomDataSendSync}, }; -use codec::{Compact, Encode}; -use derivative::Derivative; -use std::borrow::Cow; - // This is returned from an API below, so expose it here. pub use crate::rpc::types::DryRunResult; +use super::TxPayload; + /// A client for working with transactions. #[derive(Derivative)] #[derivative(Clone(bound = "Client: Clone"))] @@ -425,6 +430,15 @@ where pub fn into_encoded(self) -> Vec { self.encoded.0 } + + /// Returns the SCALE encoded extrinsic bytes with the length attached to the end. + /// Useful for certain RPC-calls that expect this format. + /// + /// *Example*: let self.encoded.0 be [10, 20, 10, 20, 10], then encoded_with_len() will be [10, 20, 10, 20, 10, 5, 0, 0, 0]. So there are always 4 bytes appended representing the length of the extrinsic in bytes in little endian notation. + pub fn encoded_with_len(&self) -> Vec { + let b: [u8; 4] = (self.encoded.0.len() as u32).to_le_bytes(); + [&self.encoded()[..], &b[..]].concat() + } } impl SubmittableExtrinsic @@ -465,4 +479,65 @@ where let dry_run_bytes = self.client.rpc().dry_run(self.encoded(), at).await?; dry_run_bytes.into_dry_run_result(&self.client.metadata()) } + + /// returns an estimate for the partial fee. There are two ways of obtaining this, method I is used here in practice. Both methods should give the exact same result though. + /// ## Method I: TransactionPaymentApi_query_info + /// + /// ``` + /// + /// let encoded_with_len = self.encoded_with_len(); + /// let RuntimeDispatchInfo{ partial_fee, ..} = self.client + /// .rpc() + /// .state_call_decoded::( + /// "TransactionPaymentApi_query_info", + /// Some(&encoded_with_len), + /// None, + /// ).await?; + /// ``` + /// + /// Here the `partial_fee` is already the result we are looking for. + /// + /// ## Method II: TransactionPaymentApi_query_fee_details + /// + /// Make a state call to "TransactionPaymentApi_query_fee_details": + /// ``` + /// let encoded_with_len = self.encoded_with_len(); + /// let InclusionFee { + /// base_fee, + /// len_fee, + /// adjusted_weight_fee, + /// } = self.client.rpc().state_call_decoded::( + /// "TransactionPaymentApi_query_fee_details", + /// Some(&encoded_with_len), + /// None, + /// ).await?; + /// ``` + /// + /// Referring to this [this stackexchange answer by jsdw](https://substrate.stackexchange.com/questions/2637/determining-the-final-fee-from-a-client/4224#4224) the formula for the _partial_fee_ is: + /// + /// ```txt + /// partial_fee = base_fee + len_fee + (adjusted_weight_fee/estimated_weight*actual_weight) + /// ``` + /// We assume here, that _estimated_weight == actual_weight_. + /// + /// So this should hold and give the same result as Method I: + /// ```txt + /// partial_fee = base_fee + len_fee + adjusted_weight_fee + /// ``` + pub async fn partial_fee_estimate(&self) -> Result { + let encoded_with_len = self.encoded_with_len(); + let RuntimeDispatchInfo { partial_fee, .. } = self + .client + .rpc() + .state_call_decoded::( + "TransactionPaymentApi_query_info", + Some(&encoded_with_len), + None, + ) + .await?; + Ok(partial_fee) + } } + +#[derive(Eq, Encode, PartialEq, Debug, Decode, Serialize, Deserialize)] +pub struct DataPrefixed(pub u32, pub Data); From 6976e7fbec71de144e37ab22ca437944c9dc41fd Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 13 Apr 2023 16:54:38 +0200 Subject: [PATCH 02/11] add integration test --- subxt/src/tx/tx_client.rs | 3 +- testing/integration-tests/src/client/mod.rs | 48 ++++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/subxt/src/tx/tx_client.rs b/subxt/src/tx/tx_client.rs index d0ba080a16..986e0a3207 100644 --- a/subxt/src/tx/tx_client.rs +++ b/subxt/src/tx/tx_client.rs @@ -510,7 +510,8 @@ where /// "TransactionPaymentApi_query_fee_details", /// Some(&encoded_with_len), /// None, - /// ).await?; + /// ).await?.inclusion_fee.unwrap(); + /// let partial_fee_2 = base_fee + len_fee + adjusted_weight_fee; /// ``` /// /// Referring to this [this stackexchange answer by jsdw](https://substrate.stackexchange.com/questions/2637/determining-the-final-fee-from-a-client/4224#4224) the formula for the _partial_fee_ is: diff --git a/testing/integration-tests/src/client/mod.rs b/testing/integration-tests/src/client/mod.rs index 7b4fdb0d45..5d7d5c9a77 100644 --- a/testing/integration-tests/src/client/mod.rs +++ b/testing/integration-tests/src/client/mod.rs @@ -15,8 +15,8 @@ use sp_keyring::AccountKeyring; use subxt::{ error::{DispatchError, Error, TokenError}, rpc::types::{ - ChainHeadEvent, DryRunResult, DryRunResultBytes, FollowEvent, Initialized, RuntimeEvent, - RuntimeVersionEvent, + ChainHeadEvent, DryRunResult, DryRunResultBytes, FeeDetails, FollowEvent, InclusionFee, + Initialized, RuntimeEvent, RuntimeVersionEvent, }, tx::Signer, utils::AccountId32, @@ -582,3 +582,47 @@ async fn chainhead_unstable_unpin() { .await .is_err()); } + +#[tokio::test] +async fn partial_fee_estimate_correct() { + let ctx = test_context().await; + let api = ctx.client(); + + let alice = pair_signer(AccountKeyring::Alice.pair()); + let hans = pair_signer(Sr25519Pair::generate().0); + + let tx = node_runtime::tx() + .balances() + .transfer(hans.account_id().clone().into(), 1_000_000_000_000); + + let signed_extrinsic = api + .tx() + .create_signed(&tx, &alice, Default::default()) + .await + .unwrap(); + + // Method I: TransactionPaymentApi_query_info + let partial_fee_1 = signed_extrinsic.partial_fee_estimate().await.unwrap(); + + // Method II: TransactionPaymentApi_query_fee_details + calculations + let encoded_with_len = signed_extrinsic.encoded_with_len(); + let InclusionFee { + base_fee, + len_fee, + adjusted_weight_fee, + } = api + .rpc() + .state_call_decoded::( + "TransactionPaymentApi_query_fee_details", + Some(&encoded_with_len), + None, + ) + .await + .unwrap() + .inclusion_fee + .unwrap(); + let partial_fee_2 = base_fee + len_fee + adjusted_weight_fee; + + /// Both methods should yield the same fee + assert_eq!(partial_fee_1, partial_fee_2); +} From 15caf365f59ac9a59a5a3a16f8c38e53b7558ec7 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 13 Apr 2023 17:19:04 +0200 Subject: [PATCH 03/11] make functions immune to doctest --- subxt/src/rpc/types.rs | 2 +- subxt/src/tx/tx_client.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/subxt/src/rpc/types.rs b/subxt/src/rpc/types.rs index 93e01715a9..f7a6f98c1e 100644 --- a/subxt/src/rpc/types.rs +++ b/subxt/src/rpc/types.rs @@ -59,7 +59,7 @@ impl DryRunResultBytes { /// /// The primary motivation for having this type is to avoid overflows when using big integers in /// JavaScript (which we consider as an important RPC API consumer). -#[derive(Encode, Decode, Copy, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] #[serde(untagged)] pub enum NumberOrHex { /// The number represented directly. diff --git a/subxt/src/tx/tx_client.rs b/subxt/src/tx/tx_client.rs index 986e0a3207..e78d264852 100644 --- a/subxt/src/tx/tx_client.rs +++ b/subxt/src/tx/tx_client.rs @@ -6,14 +6,13 @@ use std::borrow::Cow; use codec::{Compact, Decode, Encode}; use derivative::Derivative; -use futures::try_join; use serde::{Deserialize, Serialize}; use crate::{ client::{OfflineClientT, OnlineClientT}, config::{Config, ExtrinsicParams, Hasher}, error::Error, - rpc::types::{FeeDetails, InclusionFee, RuntimeDispatchInfo, Weight}, + rpc::types::RuntimeDispatchInfo, tx::{Signer as SignerT, TxProgress}, utils::{Encoded, PhantomDataSendSync}, }; @@ -483,8 +482,8 @@ where /// returns an estimate for the partial fee. There are two ways of obtaining this, method I is used here in practice. Both methods should give the exact same result though. /// ## Method I: TransactionPaymentApi_query_info /// + #[cfg_attr(doctest, doc = " ````no_test")] /// ``` - /// /// let encoded_with_len = self.encoded_with_len(); /// let RuntimeDispatchInfo{ partial_fee, ..} = self.client /// .rpc() @@ -500,6 +499,7 @@ where /// ## Method II: TransactionPaymentApi_query_fee_details /// /// Make a state call to "TransactionPaymentApi_query_fee_details": + #[cfg_attr(doctest, doc = " ````no_test")] /// ``` /// let encoded_with_len = self.encoded_with_len(); /// let InclusionFee { From 60277bba5d912ad91222c14c7a603e16660f1cb9 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 13 Apr 2023 23:11:56 +0200 Subject: [PATCH 04/11] add doc test --- subxt/src/rpc/types.rs | 64 --------------------- subxt/src/tx/tx_client.rs | 36 +++++++++--- subxt/src/tx/tx_progress.rs | 25 ++++---- testing/integration-tests/src/client/mod.rs | 29 ++++++++++ 4 files changed, 71 insertions(+), 83 deletions(-) diff --git a/subxt/src/rpc/types.rs b/subxt/src/rpc/types.rs index f7a6f98c1e..2500507da0 100644 --- a/subxt/src/rpc/types.rs +++ b/subxt/src/rpc/types.rs @@ -233,70 +233,6 @@ into_block_number!(u8 u16 u32 u64); /// Arbitrary properties defined in the chain spec as a JSON object. pub type SystemProperties = serde_json::Map; -/// taken from original type [`pallet_transaction_payment::types::FeeDetails`] -#[derive(Encode, Decode, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct FeeDetails { - /// The minimum fee for a transaction to be included in a block. - pub inclusion_fee: Option, - /// tip - pub tip: u128, -} - -/// taken from original type [`pallet_transaction_payment::types::InclusionFee`] -/// The base fee and adjusted weight and length fees constitute the _inclusion fee_. -#[derive(Encode, Decode, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct InclusionFee { - /// minimum amount a user pays for a transaction. - pub base_fee: u128, - /// amount paid for the encoded length (in bytes) of the transaction. - pub len_fee: u128, - /// - /// - `targeted_fee_adjustment`: This is a multiplier that can tune the final fee based on the - /// congestion of the network. - /// - `weight_fee`: This amount is computed based on the weight of the transaction. Weight - /// accounts for the execution time of a transaction. - /// - /// adjusted_weight_fee = targeted_fee_adjustment * weight_fee - pub adjusted_weight_fee: u128, -} - -/// taken from original type [`pallet_transaction_payment::types::RuntimeDispatchInfo`] -#[derive(Debug, Encode, Decode, Eq, PartialEq, Copy, Clone)] -pub struct RuntimeDispatchInfo { - /// Weight of this dispatch. - pub weight: Weight, - /// Class of this dispatch. - pub class: DispatchClass, - /// The inclusion fee of this dispatch. - /// - /// This does not include a tip or anything else - pub partial_fee: u128, -} - -/// taken from original type [`sp_weights::weight_v2::Weight`] -#[derive(Debug, Encode, Decode, Eq, PartialEq, Copy, Clone, Default)] -pub struct Weight { - #[codec(compact)] - /// The weight of computational time used based on some reference hardware. - pub ref_time: u64, - #[codec(compact)] - /// The weight of storage space used by proof of validity. - pub proof_size: u64, -} - -/// taken from original type [`frame_support::dispatch::DispatchClass`] -#[derive(Debug, Encode, Decode, Eq, PartialEq, Copy, Clone)] -pub enum DispatchClass { - /// A normal dispatch. - Normal, - /// An operational dispatch. - Operational, - /// A mandatory dispatch. - Mandatory, -} - /// Possible transaction status events. /// /// # Note diff --git a/subxt/src/tx/tx_client.rs b/subxt/src/tx/tx_client.rs index e78d264852..2b52ccb2b9 100644 --- a/subxt/src/tx/tx_client.rs +++ b/subxt/src/tx/tx_client.rs @@ -6,13 +6,11 @@ use std::borrow::Cow; use codec::{Compact, Decode, Encode}; use derivative::Derivative; -use serde::{Deserialize, Serialize}; use crate::{ client::{OfflineClientT, OnlineClientT}, config::{Config, ExtrinsicParams, Hasher}, error::Error, - rpc::types::RuntimeDispatchInfo, tx::{Signer as SignerT, TxProgress}, utils::{Encoded, PhantomDataSendSync}, }; @@ -433,10 +431,23 @@ where /// Returns the SCALE encoded extrinsic bytes with the length attached to the end. /// Useful for certain RPC-calls that expect this format. /// - /// *Example*: let self.encoded.0 be [10, 20, 10, 20, 10], then encoded_with_len() will be [10, 20, 10, 20, 10, 5, 0, 0, 0]. So there are always 4 bytes appended representing the length of the extrinsic in bytes in little endian notation. + /// ``` + /// use subxt::{SubstrateConfig, client::OfflineClientT, tx::SubmittableExtrinsic}; + /// #[derive(Clone)] + /// struct MockClient; + /// impl OfflineClientT for MockClient { + /// fn metadata(&self) -> subxt::Metadata { panic!() } + /// fn genesis_hash(&self) -> ::Hash { panic!() } + /// fn runtime_version(&self) -> subxt::rpc::types::RuntimeVersion { panic!() } + /// } + /// let bytes = vec![4, 2, 0]; + /// let extrinsic = SubmittableExtrinsic::::from_bytes(MockClient, bytes); + /// // extrinsic.encoded().len() is 3 and is encoded as [3, 0, 0, 0]: + /// assert_eq!(extrinsic.encoded_with_len(), vec![4, 2, 0, 3, 0, 0, 0]); + /// ``` pub fn encoded_with_len(&self) -> Vec { let b: [u8; 4] = (self.encoded.0.len() as u32).to_le_bytes(); - [&self.encoded()[..], &b[..]].concat() + [self.encoded(), &b[..]].concat() } } @@ -526,6 +537,20 @@ where /// partial_fee = base_fee + len_fee + adjusted_weight_fee /// ``` pub async fn partial_fee_estimate(&self) -> Result { + /// adapted from original type + #[derive(Debug, Encode, Decode, Eq, PartialEq, Copy, Clone)] + pub struct RuntimeDispatchInfo { + /// Weight of this dispatch. Adapted from original type + #[codec(compact)] + weight_ref_time: u64, + #[codec(compact)] + weight_proof_size: u64, + /// Class of this dispatch; an enum variant index. Adapted from original type + class: u8, + /// The inclusion fee of this dispatch; what we want: + partial_fee: u128, + } + let encoded_with_len = self.encoded_with_len(); let RuntimeDispatchInfo { partial_fee, .. } = self .client @@ -539,6 +564,3 @@ where Ok(partial_fee) } } - -#[derive(Eq, Encode, PartialEq, Debug, Decode, Serialize, Deserialize)] -pub struct DataPrefixed(pub u32, pub Data); diff --git a/subxt/src/tx/tx_progress.rs b/subxt/src/tx/tx_progress.rs index 09a5a40119..8f23259239 100644 --- a/subxt/src/tx/tx_progress.rs +++ b/subxt/src/tx/tx_progress.rs @@ -415,7 +415,7 @@ mod test { use futures::Stream; use crate::{ - client::{OfflineClientT, OnlineClientT}, + client::{MockClient, OfflineClientT, OnlineClientT}, config::{ extrinsic_params::BaseExtrinsicParams, polkadot::{PlainTip, PolkadotConfig}, @@ -429,15 +429,23 @@ mod test { use serde_json::value::RawValue; + type MockTxProgress = TxProgress; + type MockHash = , + > as Config>::Hash; + type MockSubstrateTxStatus = SubstrateTxStatus; + + /// a mock client to satisfy trait bounds in tests #[derive(Clone, Debug)] struct MockClient; - impl OfflineClientT for MockClient { + impl OfflineClientT for MockClient { fn metadata(&self) -> crate::Metadata { panic!("just a mock impl to satisfy trait bounds") } - fn genesis_hash(&self) -> ::Hash { + fn genesis_hash(&self) -> ::Hash { panic!("just a mock impl to satisfy trait bounds") } @@ -446,15 +454,8 @@ mod test { } } - type MockTxProgress = TxProgress; - type MockHash = , - > as Config>::Hash; - type MockSubstrateTxStatus = SubstrateTxStatus; - - impl OnlineClientT for MockClient { - fn rpc(&self) -> &crate::rpc::Rpc { + impl OnlineClientT for MockClient { + fn rpc(&self) -> &crate::rpc::Rpc { panic!("just a mock impl to satisfy trait bounds") } } diff --git a/testing/integration-tests/src/client/mod.rs b/testing/integration-tests/src/client/mod.rs index 5d7d5c9a77..c42796f6ad 100644 --- a/testing/integration-tests/src/client/mod.rs +++ b/testing/integration-tests/src/client/mod.rs @@ -583,6 +583,35 @@ async fn chainhead_unstable_unpin() { .is_err()); } +/// taken from original type +#[derive(Encode, Decode, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct FeeDetails { + /// The minimum fee for a transaction to be included in a block. + pub inclusion_fee: Option, + /// tip + pub tip: u128, +} + +/// taken from original type +/// The base fee and adjusted weight and length fees constitute the _inclusion fee_. +#[derive(Encode, Decode, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct InclusionFee { + /// minimum amount a user pays for a transaction. + pub base_fee: u128, + /// amount paid for the encoded length (in bytes) of the transaction. + pub len_fee: u128, + /// + /// - `targeted_fee_adjustment`: This is a multiplier that can tune the final fee based on the + /// congestion of the network. + /// - `weight_fee`: This amount is computed based on the weight of the transaction. Weight + /// accounts for the execution time of a transaction. + /// + /// adjusted_weight_fee = targeted_fee_adjustment * weight_fee + pub adjusted_weight_fee: u128, +} + #[tokio::test] async fn partial_fee_estimate_correct() { let ctx = test_context().await; From 42437e2e644d662213ab3a9c116b3a9db7d343de Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Fri, 14 Apr 2023 00:10:00 +0200 Subject: [PATCH 05/11] inline encoded_with_len, fix tests --- subxt/src/client/online_client.rs | 9 ++- subxt/src/rpc/rpc.rs | 16 +---- subxt/src/runtime_api/runtime_types.rs | 13 ++-- subxt/src/tx/tx_client.rs | 75 ++------------------- subxt/src/tx/tx_progress.rs | 2 +- testing/integration-tests/src/client/mod.rs | 21 +++--- 6 files changed, 29 insertions(+), 107 deletions(-) diff --git a/subxt/src/client/online_client.rs b/subxt/src/client/online_client.rs index 0d264681c9..703777f26a 100644 --- a/subxt/src/client/online_client.rs +++ b/subxt/src/client/online_client.rs @@ -17,7 +17,7 @@ use crate::{ tx::TxClient, Config, Metadata, }; -use codec::{Compact, Decode}; +use codec::Compact; use derivative::Derivative; use frame_metadata::RuntimeMetadataPrefixed; use futures::future; @@ -136,10 +136,9 @@ impl OnlineClient { /// Fetch the metadata from substrate using the runtime API. async fn fetch_metadata(rpc: &Rpc) -> Result { - let bytes = rpc.state_call("Metadata_metadata", None, None).await?; - let cursor = &mut &*bytes; - let _ = >::decode(cursor)?; - let meta: RuntimeMetadataPrefixed = Decode::decode(cursor)?; + let (_, meta) = rpc + .state_call::<(Compact, RuntimeMetadataPrefixed)>("Metadata_metadata", None, None) + .await?; Ok(meta.try_into()?) } diff --git a/subxt/src/rpc/rpc.rs b/subxt/src/rpc/rpc.rs index 0e4cada834..b21b9d4311 100644 --- a/subxt/src/rpc/rpc.rs +++ b/subxt/src/rpc/rpc.rs @@ -348,14 +348,13 @@ impl Rpc { } /// Execute a runtime API call. - pub async fn state_call( + pub async fn state_call( &self, function: &str, call_parameters: Option<&[u8]>, at: Option, - ) -> Result { + ) -> Result { let call_parameters = call_parameters.unwrap_or_default(); - let bytes: types::Bytes = self .client .request( @@ -363,17 +362,6 @@ impl Rpc { rpc_params![function, to_hex(call_parameters), at], ) .await?; - Ok(bytes) - } - - /// Execute a runtime API call. - pub async fn state_call_decoded( - &self, - function: &str, - call_parameters: Option<&[u8]>, - at: Option, - ) -> Result { - let bytes = self.state_call(function, call_parameters, at).await?; let cursor = &mut &bytes[..]; let res: Res = Decode::decode(cursor)?; Ok(res) diff --git a/subxt/src/runtime_api/runtime_types.rs b/subxt/src/runtime_api/runtime_types.rs index 70162e4f08..5d8253e5a9 100644 --- a/subxt/src/runtime_api/runtime_types.rs +++ b/subxt/src/runtime_api/runtime_types.rs @@ -2,7 +2,7 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use crate::{client::OnlineClientT, error::Error, Config}; +use crate::{client::OnlineClientT, error::Error, rpc::types, rpc_params, Config}; use derivative::Derivative; use std::{future::Future, marker::PhantomData}; @@ -42,11 +42,16 @@ where // Ensure that the returned future doesn't have a lifetime tied to api.runtime_api(), // which is a temporary thing we'll be throwing away quickly: async move { - let data = client + let call_parameters = call_parameters.unwrap_or_default(); + let hex_encoded_call_params = format!("0x{}", hex::encode(call_parameters)); + let bytes: types::Bytes = client .rpc() - .state_call(function, call_parameters, Some(block_hash)) + .request( + "state_call", + rpc_params![function, hex_encoded_call_params, Some(block_hash)], + ) .await?; - Ok(data.0) + Ok(bytes.0) } } } diff --git a/subxt/src/tx/tx_client.rs b/subxt/src/tx/tx_client.rs index 2b52ccb2b9..22c06f8529 100644 --- a/subxt/src/tx/tx_client.rs +++ b/subxt/src/tx/tx_client.rs @@ -427,28 +427,6 @@ where pub fn into_encoded(self) -> Vec { self.encoded.0 } - - /// Returns the SCALE encoded extrinsic bytes with the length attached to the end. - /// Useful for certain RPC-calls that expect this format. - /// - /// ``` - /// use subxt::{SubstrateConfig, client::OfflineClientT, tx::SubmittableExtrinsic}; - /// #[derive(Clone)] - /// struct MockClient; - /// impl OfflineClientT for MockClient { - /// fn metadata(&self) -> subxt::Metadata { panic!() } - /// fn genesis_hash(&self) -> ::Hash { panic!() } - /// fn runtime_version(&self) -> subxt::rpc::types::RuntimeVersion { panic!() } - /// } - /// let bytes = vec![4, 2, 0]; - /// let extrinsic = SubmittableExtrinsic::::from_bytes(MockClient, bytes); - /// // extrinsic.encoded().len() is 3 and is encoded as [3, 0, 0, 0]: - /// assert_eq!(extrinsic.encoded_with_len(), vec![4, 2, 0, 3, 0, 0, 0]); - /// ``` - pub fn encoded_with_len(&self) -> Vec { - let b: [u8; 4] = (self.encoded.0.len() as u32).to_le_bytes(); - [self.encoded(), &b[..]].concat() - } } impl SubmittableExtrinsic @@ -490,52 +468,8 @@ where dry_run_bytes.into_dry_run_result(&self.client.metadata()) } - /// returns an estimate for the partial fee. There are two ways of obtaining this, method I is used here in practice. Both methods should give the exact same result though. - /// ## Method I: TransactionPaymentApi_query_info - /// - #[cfg_attr(doctest, doc = " ````no_test")] - /// ``` - /// let encoded_with_len = self.encoded_with_len(); - /// let RuntimeDispatchInfo{ partial_fee, ..} = self.client - /// .rpc() - /// .state_call_decoded::( - /// "TransactionPaymentApi_query_info", - /// Some(&encoded_with_len), - /// None, - /// ).await?; - /// ``` - /// - /// Here the `partial_fee` is already the result we are looking for. - /// - /// ## Method II: TransactionPaymentApi_query_fee_details - /// - /// Make a state call to "TransactionPaymentApi_query_fee_details": - #[cfg_attr(doctest, doc = " ````no_test")] - /// ``` - /// let encoded_with_len = self.encoded_with_len(); - /// let InclusionFee { - /// base_fee, - /// len_fee, - /// adjusted_weight_fee, - /// } = self.client.rpc().state_call_decoded::( - /// "TransactionPaymentApi_query_fee_details", - /// Some(&encoded_with_len), - /// None, - /// ).await?.inclusion_fee.unwrap(); - /// let partial_fee_2 = base_fee + len_fee + adjusted_weight_fee; - /// ``` - /// - /// Referring to this [this stackexchange answer by jsdw](https://substrate.stackexchange.com/questions/2637/determining-the-final-fee-from-a-client/4224#4224) the formula for the _partial_fee_ is: - /// - /// ```txt - /// partial_fee = base_fee + len_fee + (adjusted_weight_fee/estimated_weight*actual_weight) - /// ``` - /// We assume here, that _estimated_weight == actual_weight_. - /// - /// So this should hold and give the same result as Method I: - /// ```txt - /// partial_fee = base_fee + len_fee + adjusted_weight_fee - /// ``` + /// This returns an estimate for what the extrinsic is expected to cost to execute, less any tips. + /// The actual amount paid can vary from block to block based on node traffic and other factors. pub async fn partial_fee_estimate(&self) -> Result { /// adapted from original type #[derive(Debug, Encode, Decode, Eq, PartialEq, Copy, Clone)] @@ -551,11 +485,12 @@ where partial_fee: u128, } - let encoded_with_len = self.encoded_with_len(); + let len_bytes: [u8; 4] = (self.encoded.0.len() as u32).to_le_bytes(); + let encoded_with_len = [self.encoded(), &len_bytes[..]].concat(); let RuntimeDispatchInfo { partial_fee, .. } = self .client .rpc() - .state_call_decoded::( + .state_call::( "TransactionPaymentApi_query_info", Some(&encoded_with_len), None, diff --git a/subxt/src/tx/tx_progress.rs b/subxt/src/tx/tx_progress.rs index 8f23259239..79c99ada26 100644 --- a/subxt/src/tx/tx_progress.rs +++ b/subxt/src/tx/tx_progress.rs @@ -415,7 +415,7 @@ mod test { use futures::Stream; use crate::{ - client::{MockClient, OfflineClientT, OnlineClientT}, + client::{OfflineClientT, OnlineClientT}, config::{ extrinsic_params::BaseExtrinsicParams, polkadot::{PlainTip, PolkadotConfig}, diff --git a/testing/integration-tests/src/client/mod.rs b/testing/integration-tests/src/client/mod.rs index c42796f6ad..3f870136a8 100644 --- a/testing/integration-tests/src/client/mod.rs +++ b/testing/integration-tests/src/client/mod.rs @@ -15,7 +15,7 @@ use sp_keyring::AccountKeyring; use subxt::{ error::{DispatchError, Error, TokenError}, rpc::types::{ - ChainHeadEvent, DryRunResult, DryRunResultBytes, FeeDetails, FollowEvent, InclusionFee, + ChainHeadEvent, DryRunResult, DryRunResultBytes, FollowEvent, Initialized, RuntimeEvent, RuntimeVersionEvent, }, tx::Signer, @@ -388,15 +388,11 @@ async fn rpc_state_call() { let api = ctx.client(); // Call into the runtime of the chain to get the Metadata. - let metadata_bytes = api + let (_, meta) = api .rpc() - .state_call("Metadata_metadata", None, None) + .state_call::<(Compact, RuntimeMetadataPrefixed)>("Metadata_metadata", None, None) .await .unwrap(); - - let cursor = &mut &*metadata_bytes; - let _ = >::decode(cursor).unwrap(); - let meta: RuntimeMetadataPrefixed = Decode::decode(cursor).unwrap(); let metadata_call = match meta.1 { frame_metadata::RuntimeMetadata::V14(metadata) => metadata, _ => panic!("Metadata V14 unavailable"), @@ -584,8 +580,7 @@ async fn chainhead_unstable_unpin() { } /// taken from original type -#[derive(Encode, Decode, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] +#[derive(Encode, Decode, Debug, Clone, Eq, PartialEq)] pub struct FeeDetails { /// The minimum fee for a transaction to be included in a block. pub inclusion_fee: Option, @@ -595,8 +590,7 @@ pub struct FeeDetails { /// taken from original type /// The base fee and adjusted weight and length fees constitute the _inclusion fee_. -#[derive(Encode, Decode, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] +#[derive(Encode, Decode, Debug, Clone, Eq, PartialEq)] pub struct InclusionFee { /// minimum amount a user pays for a transaction. pub base_fee: u128, @@ -634,14 +628,15 @@ async fn partial_fee_estimate_correct() { let partial_fee_1 = signed_extrinsic.partial_fee_estimate().await.unwrap(); // Method II: TransactionPaymentApi_query_fee_details + calculations - let encoded_with_len = signed_extrinsic.encoded_with_len(); + let len_bytes: [u8; 4] = (signed_extrinsic.encoded().len() as u32).to_le_bytes(); + let encoded_with_len = [signed_extrinsic.encoded(), &len_bytes[..]].concat(); let InclusionFee { base_fee, len_fee, adjusted_weight_fee, } = api .rpc() - .state_call_decoded::( + .state_call::( "TransactionPaymentApi_query_fee_details", Some(&encoded_with_len), None, From 3f47e47368c34ec6c8f827fd873e00460f2b8714 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Fri, 14 Apr 2023 09:51:18 +0200 Subject: [PATCH 06/11] fix test fmt --- testing/integration-tests/src/client/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/integration-tests/src/client/mod.rs b/testing/integration-tests/src/client/mod.rs index 3f870136a8..2dee4a2c66 100644 --- a/testing/integration-tests/src/client/mod.rs +++ b/testing/integration-tests/src/client/mod.rs @@ -15,8 +15,8 @@ use sp_keyring::AccountKeyring; use subxt::{ error::{DispatchError, Error, TokenError}, rpc::types::{ - ChainHeadEvent, DryRunResult, DryRunResultBytes, FollowEvent, - Initialized, RuntimeEvent, RuntimeVersionEvent, + ChainHeadEvent, DryRunResult, DryRunResultBytes, FollowEvent, Initialized, RuntimeEvent, + RuntimeVersionEvent, }, tx::Signer, utils::AccountId32, @@ -647,6 +647,6 @@ async fn partial_fee_estimate_correct() { .unwrap(); let partial_fee_2 = base_fee + len_fee + adjusted_weight_fee; - /// Both methods should yield the same fee + // Both methods should yield the same fee assert_eq!(partial_fee_1, partial_fee_2); } From edb86f916c5a23ebbd21ec1d4e99b821b012f8b8 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Fri, 14 Apr 2023 12:04:26 +0200 Subject: [PATCH 07/11] remove unused imoort --- subxt/src/tx/tx_progress.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/subxt/src/tx/tx_progress.rs b/subxt/src/tx/tx_progress.rs index 79c99ada26..97aa77e8c3 100644 --- a/subxt/src/tx/tx_progress.rs +++ b/subxt/src/tx/tx_progress.rs @@ -416,11 +416,7 @@ mod test { use crate::{ client::{OfflineClientT, OnlineClientT}, - config::{ - extrinsic_params::BaseExtrinsicParams, - polkadot::{PlainTip, PolkadotConfig}, - WithExtrinsicParams, - }, + config::{extrinsic_params::BaseExtrinsicParams, polkadot::PlainTip, WithExtrinsicParams}, error::RpcError, rpc::{types::SubstrateTxStatus, RpcSubscription, Subscription}, tx::TxProgress, From 0c7677381013e63156db3227948656b5210639f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Apr 2023 09:58:31 +0100 Subject: [PATCH 08/11] Bump h2 from 0.3.16 to 0.3.17 (#911) Bumps [h2](https://github.com/hyperium/h2) from 0.3.16 to 0.3.17. - [Release notes](https://github.com/hyperium/h2/releases) - [Changelog](https://github.com/hyperium/h2/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/h2/compare/v0.3.16...v0.3.17) --- updated-dependencies: - dependency-name: h2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 970c2c424c..8b3f7e4987 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1309,9 +1309,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" dependencies = [ "bytes", "fnv", From b1303ee08a10317b41b3c1074cc7de342c18e59b Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Sat, 15 Apr 2023 10:26:32 +0200 Subject: [PATCH 09/11] call_raw returns Res: Decode --- subxt/src/runtime_api/runtime_types.rs | 18 +++++++----------- subxt/src/tx/tx_client.rs | 11 +++++------ testing/integration-tests/src/blocks/mod.rs | 7 +++---- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/subxt/src/runtime_api/runtime_types.rs b/subxt/src/runtime_api/runtime_types.rs index 5d8253e5a9..7bcd3436b9 100644 --- a/subxt/src/runtime_api/runtime_types.rs +++ b/subxt/src/runtime_api/runtime_types.rs @@ -2,7 +2,8 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use crate::{client::OnlineClientT, error::Error, rpc::types, rpc_params, Config}; +use crate::{client::OnlineClientT, error::Error, Config}; +use codec::Decode; use derivative::Derivative; use std::{future::Future, marker::PhantomData}; @@ -32,26 +33,21 @@ where Client: OnlineClientT, { /// Execute a raw runtime API call. - pub fn call_raw<'a>( + pub fn call_raw<'a, Res: Decode>( &self, function: &'a str, call_parameters: Option<&'a [u8]>, - ) -> impl Future, Error>> + 'a { + ) -> impl Future> + 'a { let client = self.client.clone(); let block_hash = self.block_hash; // Ensure that the returned future doesn't have a lifetime tied to api.runtime_api(), // which is a temporary thing we'll be throwing away quickly: async move { - let call_parameters = call_parameters.unwrap_or_default(); - let hex_encoded_call_params = format!("0x{}", hex::encode(call_parameters)); - let bytes: types::Bytes = client + let data: Res = client .rpc() - .request( - "state_call", - rpc_params![function, hex_encoded_call_params, Some(block_hash)], - ) + .state_call(function, call_parameters, Some(block_hash)) .await?; - Ok(bytes.0) + Ok(data) } } } diff --git a/subxt/src/tx/tx_client.rs b/subxt/src/tx/tx_client.rs index 22c06f8529..5a5a79adcf 100644 --- a/subxt/src/tx/tx_client.rs +++ b/subxt/src/tx/tx_client.rs @@ -11,14 +11,13 @@ use crate::{ client::{OfflineClientT, OnlineClientT}, config::{Config, ExtrinsicParams, Hasher}, error::Error, - tx::{Signer as SignerT, TxProgress}, + tx::{Signer as SignerT, TxPayload, TxProgress}, utils::{Encoded, PhantomDataSendSync}, }; + // This is returned from an API below, so expose it here. pub use crate::rpc::types::DryRunResult; -use super::TxPayload; - /// A client for working with transactions. #[derive(Derivative)] #[derivative(Clone(bound = "Client: Clone"))] @@ -485,14 +484,14 @@ where partial_fee: u128, } - let len_bytes: [u8; 4] = (self.encoded.0.len() as u32).to_le_bytes(); - let encoded_with_len = [self.encoded(), &len_bytes[..]].concat(); + let mut params = self.encoded().to_vec(); + (self.encoded().len() as u32).encode_to(&mut params); let RuntimeDispatchInfo { partial_fee, .. } = self .client .rpc() .state_call::( "TransactionPaymentApi_query_info", - Some(&encoded_with_len), + Some(¶ms), None, ) .await?; diff --git a/testing/integration-tests/src/blocks/mod.rs b/testing/integration-tests/src/blocks/mod.rs index ed3fb4b5e5..2e097ecf46 100644 --- a/testing/integration-tests/src/blocks/mod.rs +++ b/testing/integration-tests/src/blocks/mod.rs @@ -101,10 +101,9 @@ async fn runtime_api_call() -> Result<(), subxt::Error> { let block = sub.next().await.unwrap()?; let rt = block.runtime_api().await?; - let bytes = rt.call_raw("Metadata_metadata", None).await?; - let cursor = &mut &*bytes; - let _ = >::decode(cursor)?; - let meta: RuntimeMetadataPrefixed = Decode::decode(cursor)?; + let (_, meta) = rt + .call_raw::<(Compact, RuntimeMetadataPrefixed)>("Metadata_metadata", None) + .await?; let metadata_call = match meta.1 { frame_metadata::RuntimeMetadata::V14(metadata) => metadata, _ => panic!("Metadata V14 unavailable"), From 4413618844a602420a9458538e00442190bd42c6 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Sat, 15 Apr 2023 12:44:05 +0200 Subject: [PATCH 10/11] remove import --- testing/integration-tests/src/blocks/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/integration-tests/src/blocks/mod.rs b/testing/integration-tests/src/blocks/mod.rs index 2e097ecf46..f0943e1675 100644 --- a/testing/integration-tests/src/blocks/mod.rs +++ b/testing/integration-tests/src/blocks/mod.rs @@ -3,7 +3,7 @@ // see LICENSE for license details. use crate::test_context; -use codec::{Compact, Decode}; +use codec::{Compact}; use frame_metadata::RuntimeMetadataPrefixed; use futures::StreamExt; From d3a3a018a81b1afd2985bdfe5059977804903af5 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Sat, 15 Apr 2023 19:11:10 +0200 Subject: [PATCH 11/11] remove struct --- subxt/src/tx/tx_client.rs | 22 +++++---------------- testing/integration-tests/src/blocks/mod.rs | 2 +- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/subxt/src/tx/tx_client.rs b/subxt/src/tx/tx_client.rs index 5a5a79adcf..0b73a964e1 100644 --- a/subxt/src/tx/tx_client.rs +++ b/subxt/src/tx/tx_client.rs @@ -4,7 +4,7 @@ use std::borrow::Cow; -use codec::{Compact, Decode, Encode}; +use codec::{Compact, Encode}; use derivative::Derivative; use crate::{ @@ -470,26 +470,14 @@ where /// This returns an estimate for what the extrinsic is expected to cost to execute, less any tips. /// The actual amount paid can vary from block to block based on node traffic and other factors. pub async fn partial_fee_estimate(&self) -> Result { - /// adapted from original type - #[derive(Debug, Encode, Decode, Eq, PartialEq, Copy, Clone)] - pub struct RuntimeDispatchInfo { - /// Weight of this dispatch. Adapted from original type - #[codec(compact)] - weight_ref_time: u64, - #[codec(compact)] - weight_proof_size: u64, - /// Class of this dispatch; an enum variant index. Adapted from original type - class: u8, - /// The inclusion fee of this dispatch; what we want: - partial_fee: u128, - } - let mut params = self.encoded().to_vec(); (self.encoded().len() as u32).encode_to(&mut params); - let RuntimeDispatchInfo { partial_fee, .. } = self + // destructuring RuntimeDispatchInfo, see type information + // data layout: {weight_ref_time: Compact, weight_proof_size: Compact, class: u8, partial_fee: u128} + let (_, _, _, partial_fee) = self .client .rpc() - .state_call::( + .state_call::<(Compact, Compact, u8, u128)>( "TransactionPaymentApi_query_info", Some(¶ms), None, diff --git a/testing/integration-tests/src/blocks/mod.rs b/testing/integration-tests/src/blocks/mod.rs index f0943e1675..d9c37c2e73 100644 --- a/testing/integration-tests/src/blocks/mod.rs +++ b/testing/integration-tests/src/blocks/mod.rs @@ -3,7 +3,7 @@ // see LICENSE for license details. use crate::test_context; -use codec::{Compact}; +use codec::Compact; use frame_metadata::RuntimeMetadataPrefixed; use futures::StreamExt;