From 6f97ca70419b6ce54ecc6cb8fd3e1880e50b478e Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Tue, 20 Feb 2024 18:22:13 +0100 Subject: [PATCH] rework signed extensions --- Cargo.lock | 1 - subxt/Cargo.toml | 18 +-- subxt/examples/setup_config_custom.rs | 6 +- .../examples/setup_config_signed_extension.rs | 6 +- subxt/src/blocks/block_types.rs | 5 + subxt/src/client/mod.rs | 38 ++++++ subxt/src/client/offline_client.rs | 30 ++-- subxt/src/client/online_client.rs | 28 ++-- subxt/src/config/default_extrinsic_params.rs | 13 +- subxt/src/config/extrinsic_params.rs | 43 +++--- subxt/src/config/mod.rs | 4 +- subxt/src/config/signed_extensions.rs | 128 ++++++++++-------- subxt/src/tx/tx_client.rs | 72 +++++----- 13 files changed, 227 insertions(+), 165 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6fe5bf2575..6e82bf79b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4531,7 +4531,6 @@ dependencies = [ "subxt-lightclient", "subxt-macro", "subxt-metadata", - "subxt-signer", "thiserror", "tokio", "tokio-stream", diff --git a/subxt/Cargo.toml b/subxt/Cargo.toml index 4a18bb2b41..e910eff407 100644 --- a/subxt/Cargo.toml +++ b/subxt/Cargo.toml @@ -24,23 +24,11 @@ default = ["jsonrpsee", "native"] # Enable this for native (ie non web/wasm builds). # Exactly 1 of "web" and "native" is expected. -native = [ - "jsonrpsee?/async-client", - "jsonrpsee?/client-ws-transport-native-tls", - "subxt-lightclient?/native", - "tokio-util" -] +native = ["jsonrpsee?/async-client", "jsonrpsee?/client-ws-transport-native-tls", "subxt-lightclient?/native", "tokio-util"] # Enable this for web/wasm builds. # Exactly 1 of "web" and "native" is expected. -web = [ - "jsonrpsee?/async-wasm-client", - "jsonrpsee?/client-web-transport", - "getrandom/js", - "subxt-lightclient?/web", - "subxt-macro/web", - "instant/wasm-bindgen" -] +web = ["jsonrpsee?/async-wasm-client", "jsonrpsee?/client-web-transport", "getrandom/js", "subxt-lightclient?/web", "subxt-macro/web", "instant/wasm-bindgen"] # Enable this to use the reconnecting rpc client unstable-reconnecting-rpc-client = ["dep:reconnecting-jsonrpsee-ws-client"] @@ -127,7 +115,7 @@ sp-core = { workspace = true } sp-keyring = { workspace = true } sp-runtime = { workspace = true } assert_matches = { workspace = true } -subxt-signer = { path = "../signer" } +# subxt-signer = { path = "../signer" } // todo!() revert this, but rust analyzer blows up on cyclic dep # Tracing subscriber is useful for light-client examples to ensure that # the `bootNodes` and chain spec are configured correctly. If all is fine, then # the light-client wlll emit INFO logs with diff --git a/subxt/examples/setup_config_custom.rs b/subxt/examples/setup_config_custom.rs index 4748202e1f..1c556971b9 100644 --- a/subxt/examples/setup_config_custom.rs +++ b/subxt/examples/setup_config_custom.rs @@ -53,13 +53,13 @@ impl CustomExtrinsicParamsBuilder { // Describe how to fetch and then encode the params: impl ExtrinsicParams for CustomExtrinsicParams { - type OtherParams = CustomExtrinsicParamsBuilder; + type Params = CustomExtrinsicParamsBuilder; // Gather together all of the params we will need to encode: fn new>( _nonce: u64, client: Client, - other_params: Self::OtherParams, + other_params: Self::Params, ) -> Result { Ok(Self { genesis_hash: client.genesis_hash(), @@ -86,7 +86,7 @@ async fn main() { let tx_payload = runtime::tx().system().remark(b"Hello".to_vec()); - // Build your custom "OtherParams": + // Build your custom "Params": let tx_config = CustomExtrinsicParamsBuilder::new().tip(1234).enable_foo(); // And provide them when submitting a transaction: diff --git a/subxt/examples/setup_config_signed_extension.rs b/subxt/examples/setup_config_signed_extension.rs index 2442de629b..e1f7e33acf 100644 --- a/subxt/examples/setup_config_signed_extension.rs +++ b/subxt/examples/setup_config_signed_extension.rs @@ -58,12 +58,12 @@ impl signed_extensions::SignedExtension for CustomSignedExtension // Gather together any params we need for our signed extension, here none. impl ExtrinsicParams for CustomSignedExtension { - type OtherParams = (); + type Params = (); fn new>( _nonce: u64, _client: Client, - _other_params: Self::OtherParams, + _other_params: Self::Params, ) -> Result { Ok(CustomSignedExtension) } @@ -86,7 +86,7 @@ impl ExtrinsicParamsEncoder for CustomSignedExtension { // to construct an entirely new interface to provide the relevant `OtherParams`. pub fn custom( params: DefaultExtrinsicParamsBuilder, -) -> <::ExtrinsicParams as ExtrinsicParams>::OtherParams { +) -> <::ExtrinsicParams as ExtrinsicParams>::Params { let (a, b, c, d, e, f, g) = params.build(); (a, b, c, d, e, f, g, ()) } diff --git a/subxt/src/blocks/block_types.rs b/subxt/src/blocks/block_types.rs index a1cb01ec25..9908ca1eee 100644 --- a/subxt/src/blocks/block_types.rs +++ b/subxt/src/blocks/block_types.rs @@ -65,6 +65,11 @@ where pub fn header(&self) -> &T::Header { &self.header } + + /// Return the entire block header. Consumes the block itself + pub fn into_header(self) -> T::Header { + self.header + } } impl Block diff --git a/subxt/src/client/mod.rs b/subxt/src/client/mod.rs index c764af4b59..a139fcf2d2 100644 --- a/subxt/src/client/mod.rs +++ b/subxt/src/client/mod.rs @@ -19,7 +19,45 @@ crate::macros::cfg_unstable_light_client! { }; } +use derivative::Derivative; pub use offline_client::{OfflineClient, OfflineClientT}; pub use online_client::{ ClientRuntimeUpdater, OnlineClient, OnlineClientT, RuntimeUpdaterStream, Update, UpgradeError, }; + +use crate::{backend::RuntimeVersion, Config, Metadata}; + +/// The inner values, any client should contain. +#[derive(Derivative)] +#[derivative(Debug(bound = ""), Clone(bound = ""))] +pub struct BaseClient { + genesis_hash: T::Hash, + runtime_version: RuntimeVersion, + metadata: Metadata, +} + +impl BaseClient { + /// Create a new [`BaseClient`]. + pub fn new(genesis_hash: T::Hash, runtime_version: RuntimeVersion, metadata: Metadata) -> Self { + Self { + genesis_hash, + runtime_version, + metadata, + } + } + + /// Return the genesis hash. + pub fn genesis_hash(&self) -> T::Hash { + self.genesis_hash + } + + /// Return the runtime version. + pub fn runtime_version(&self) -> RuntimeVersion { + self.runtime_version.clone() + } + + /// Return the [`Metadata`] used in this client. + pub fn metadata(&self) -> Metadata { + self.metadata.clone() + } +} diff --git a/subxt/src/client/offline_client.rs b/subxt/src/client/offline_client.rs index 4477e21b7a..9809f3a23e 100644 --- a/subxt/src/client/offline_client.rs +++ b/subxt/src/client/offline_client.rs @@ -2,6 +2,7 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. +use super::BaseClient; use crate::custom_values::CustomValuesClient; use crate::{ backend::RuntimeVersion, blocks::BlocksClient, constants::ConstantsClient, @@ -9,7 +10,6 @@ use crate::{ Config, Metadata, }; use derivative::Derivative; - use std::sync::Arc; /// A trait representing a client that can perform @@ -21,6 +21,8 @@ pub trait OfflineClientT: Clone + Send + Sync + 'static { fn genesis_hash(&self) -> T::Hash; /// Return the provided [`RuntimeVersion`]. fn runtime_version(&self) -> RuntimeVersion; + /// Return the inner [`BaseClient`]. + fn base_client(&self) -> BaseClient; /// Work with transactions. fn tx(&self) -> TxClient { @@ -63,15 +65,7 @@ pub trait OfflineClientT: Clone + Send + Sync + 'static { #[derive(Derivative)] #[derivative(Debug(bound = ""), Clone(bound = ""))] pub struct OfflineClient { - inner: Arc>, -} - -#[derive(Derivative)] -#[derivative(Debug(bound = ""), Clone(bound = ""))] -struct Inner { - genesis_hash: T::Hash, - runtime_version: RuntimeVersion, - metadata: Metadata, + inner: Arc>, } impl OfflineClient { @@ -83,11 +77,11 @@ impl OfflineClient { metadata: impl Into, ) -> OfflineClient { OfflineClient { - inner: Arc::new(Inner { + inner: Arc::new(BaseClient::new( genesis_hash, runtime_version, - metadata: metadata.into(), - }), + metadata.into(), + )), } } @@ -106,6 +100,12 @@ impl OfflineClient { self.inner.metadata.clone() } + /// Return the inner [`BaseClient`]. + pub fn base_client(&self) -> BaseClient { + // Note: this clone should be cheap because metadata is arced up. + (*self.inner).clone() + } + // Just a copy of the most important trait methods so that people // don't need to import the trait for most things: @@ -145,6 +145,10 @@ impl OfflineClientT for OfflineClient { fn metadata(&self) -> Metadata { self.metadata() } + + fn base_client(&self) -> BaseClient { + self.base_client() + } } // For ergonomics; cloning a client is deliberately fairly cheap (via Arc), diff --git a/subxt/src/client/online_client.rs b/subxt/src/client/online_client.rs index f4e2f8c723..b7d38838c3 100644 --- a/subxt/src/client/online_client.rs +++ b/subxt/src/client/online_client.rs @@ -2,7 +2,7 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use super::{OfflineClient, OfflineClientT}; +use super::{BaseClient, OfflineClient, OfflineClientT}; use crate::custom_values::CustomValuesClient; use crate::{ backend::{ @@ -33,18 +33,10 @@ pub trait OnlineClientT: OfflineClientT { #[derive(Derivative)] #[derivative(Clone(bound = ""))] pub struct OnlineClient { - inner: Arc>>, + inner: Arc>>, backend: Arc>, } -#[derive(Derivative)] -#[derivative(Debug(bound = ""))] -struct Inner { - genesis_hash: T::Hash, - runtime_version: RuntimeVersion, - metadata: Metadata, -} - impl std::fmt::Debug for OnlineClient { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Client") @@ -146,11 +138,11 @@ impl OnlineClient { backend: Arc, ) -> Result, Error> { Ok(OnlineClient { - inner: Arc::new(RwLock::new(Inner { + inner: Arc::new(RwLock::new(BaseClient::new( genesis_hash, runtime_version, - metadata: metadata.into(), - })), + metadata.into(), + ))), backend, }) } @@ -268,6 +260,12 @@ impl OnlineClient { inner.genesis_hash } + /// Return the inner [`BaseClient`]. + pub fn base_client(&self) -> BaseClient { + let inner = self.inner.read().expect("shouldn't be poisoned"); + inner.clone() + } + /// Change the genesis hash used in this client. /// /// # Warning @@ -360,6 +358,10 @@ impl OfflineClientT for OnlineClient { fn runtime_version(&self) -> RuntimeVersion { self.runtime_version() } + + fn base_client(&self) -> BaseClient { + self.base_client() + } } impl OnlineClientT for OnlineClient { diff --git a/subxt/src/config/default_extrinsic_params.rs b/subxt/src/config/default_extrinsic_params.rs index dce83853bf..26531964ff 100644 --- a/subxt/src/config/default_extrinsic_params.rs +++ b/subxt/src/config/default_extrinsic_params.rs @@ -20,12 +20,14 @@ pub type DefaultExtrinsicParams = signed_extensions::AnyOf< ), >; -/// A builder that outputs the set of [`super::ExtrinsicParams::OtherParams`] required for +/// A builder that outputs the set of [`super::ExtrinsicParams::Params`] required for /// [`DefaultExtrinsicParams`]. This may expose methods that aren't applicable to the current /// chain; such values will simply be ignored if so. pub struct DefaultExtrinsicParamsBuilder { /// `None` means the tx will be immortal. mortality: Option>, + /// The account nonce has to be set explicitly when creating extrinsic params. + nonce: Option, /// `None` means we'll use the native token. tip_of_asset_id: Option, tip: u128, @@ -36,7 +38,7 @@ struct Mortality { /// Block hash that mortality starts from checkpoint_hash: Hash, /// Block number that mortality starts from (must - // point to the same block as the hash above) + /// point to the same block as the hash above) checkpoint_number: u64, /// How many blocks the tx is mortal for period: u64, @@ -46,6 +48,7 @@ impl Default for DefaultExtrinsicParamsBuilder { fn default() -> Self { Self { mortality: None, + nonce: None, tip: 0, tip_of: 0, tip_of_asset_id: None, @@ -111,7 +114,7 @@ impl DefaultExtrinsicParamsBuilder { } /// Build the extrinsic parameters. - pub fn build(self) -> as ExtrinsicParams>::OtherParams { + pub fn build(self) -> as ExtrinsicParams>::Params { let check_mortality_params = if let Some(mortality) = self.mortality { signed_extensions::CheckMortalityParams::mortal( mortality.period, @@ -128,13 +131,15 @@ impl DefaultExtrinsicParamsBuilder { signed_extensions::ChargeAssetTxPaymentParams::tip(self.tip) }; + let check_nonce_params = signed_extensions::CheckNonceParams(self.nonce); + let charge_transaction_params = signed_extensions::ChargeTransactionPaymentParams::tip(self.tip); ( (), (), - (), + check_nonce_params, (), check_mortality_params, charge_asset_tx_params, diff --git a/subxt/src/config/extrinsic_params.rs b/subxt/src/config/extrinsic_params.rs index f0971b5caa..73a8a1ed80 100644 --- a/subxt/src/config/extrinsic_params.rs +++ b/subxt/src/config/extrinsic_params.rs @@ -7,7 +7,7 @@ //! [`crate::config::DefaultExtrinsicParams`] provides a general-purpose //! implementation of this that will work in many cases. -use crate::{client::OfflineClientT, Config}; +use crate::{client::BaseClient, Config}; use core::fmt::Debug; /// An error that can be emitted when trying to construct an instance of [`ExtrinsicParams`], @@ -53,14 +53,11 @@ pub trait ExtrinsicParams: ExtrinsicParamsEncoder + Sized + 'static { /// These parameters can be provided to the constructor along with /// some default parameters that `subxt` understands, in order to /// help construct your [`ExtrinsicParams`] object. - type OtherParams; + type Params: FromBaseParams; /// Construct a new instance of our [`ExtrinsicParams`]. - fn new>( - nonce: u64, - client: Client, - other_params: Self::OtherParams, - ) -> Result; + fn new(base_params: &BaseParams, params: Self::Params) + -> Result; } /// This trait is expected to be implemented for any [`ExtrinsicParams`], and @@ -80,26 +77,36 @@ pub trait ExtrinsicParamsEncoder: 'static { fn encode_additional_to(&self, _v: &mut Vec) {} } -/// Like the `From` trait, if value is Some(_), but it lets us circumvent the orphan rule, because we want to implement -/// `DefaultOrFrom
` for `()`, such that DefaultOrFrom
is implemented by `((),(),(),CheckMortalityParams)`, if `CheckMortalityParams` implements `DefaultFrom
` -pub trait DefaultOrFrom { - /// If value is None, Self is constructed as some default value. Otherwise it takes the value of `T` into account. - fn default_or_from(value: Option<&T>) -> Self; +/// Params that always need to be known to construct the Params of an extrinsic. +pub struct BaseParams { + /// [`BaseClient`] containing the metadata, genesis hash and runtime version. + pub client: BaseClient, + /// Latest hash of a finalized block. Not always known (None), e.g. if only a [`crate::OfflineClient`] is available. + pub latest_block_header: Option, + /// Account nonce for the account submitting the extrinsic. + pub nonce: u64, } -impl DefaultOrFrom for () { - fn default_or_from(_value: Option<&T>) {} +/// Types implementing this trait can be constructed from a minimal set of data provided by the client. +/// Implementing this trait is similar to implementing Default, only that we pass in some prior information here. +pub trait FromBaseParams { + /// Constructs the value from the given mandatory params. + fn from_base_params(params: &BaseParams) -> Self; +} + +impl FromBaseParams for () { + fn from_base_params(_params: &BaseParams) {} } macro_rules! impl_default_from_tuples { ($($ident:ident),+) => { - impl DefaultOrFrom for ($($ident,)+) + impl FromBaseParams for ($($ident,)+) where - $($ident: DefaultOrFrom,)+ + $($ident: FromBaseParams,)+ { - fn default_or_from(value: Option<&T>) -> Self { + fn from_base_params(params: &BaseParams) -> Self { ($( - (<$ident as DefaultOrFrom>::default_or_from(value)), + (<$ident as FromBaseParams>::from_base_params(params)), )+) } } diff --git a/subxt/src/config/mod.rs b/subxt/src/config/mod.rs index b028d0b77c..e4ac47bd9a 100644 --- a/subxt/src/config/mod.rs +++ b/subxt/src/config/mod.rs @@ -24,7 +24,7 @@ use serde::{de::DeserializeOwned, Serialize}; pub use default_extrinsic_params::{DefaultExtrinsicParams, DefaultExtrinsicParamsBuilder}; pub use extrinsic_params::{ - DefaultOrFrom, ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError, + BaseParams, ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError, FromBaseParams, }; pub use polkadot::{PolkadotConfig, PolkadotExtrinsicParams, PolkadotExtrinsicParamsBuilder}; pub use signed_extensions::SignedExtension; @@ -62,7 +62,7 @@ pub trait Config: Sized + Send + Sync + 'static { } /// given some [`Config`], this return the other params needed for its `ExtrinsicParams`. -pub type OtherParamsFor = <::ExtrinsicParams as ExtrinsicParams>::OtherParams; +pub type ParamsFor = <::ExtrinsicParams as ExtrinsicParams>::Params; /// Block hashes must conform to a bunch of things to be used in Subxt. pub trait BlockHash: diff --git a/subxt/src/config/signed_extensions.rs b/subxt/src/config/signed_extensions.rs index 9751a57f0c..a170e3d88b 100644 --- a/subxt/src/config/signed_extensions.rs +++ b/subxt/src/config/signed_extensions.rs @@ -7,9 +7,8 @@ //! [`AnyOf`] to configure the set of signed extensions which are known about //! when interacting with a chain. -use super::extrinsic_params::{ - DefaultOrFrom, ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError, -}; +use super::extrinsic_params::{ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError}; +use super::{BaseParams, FromBaseParams}; use crate::config::Header; use crate::utils::Era; use crate::{client::OfflineClientT, Config}; @@ -40,14 +39,15 @@ pub trait SignedExtension: ExtrinsicParams { pub struct CheckSpecVersion(u32); impl ExtrinsicParams for CheckSpecVersion { - type OtherParams = (); + type Params = (); - fn new>( - _nonce: u64, - client: Client, - _other_params: Self::OtherParams, + fn new( + base_params: &BaseParams, + params: Self::Params, ) -> Result { - Ok(CheckSpecVersion(client.runtime_version().spec_version)) + Ok(CheckSpecVersion( + base_params.client.runtime_version().spec_version, + )) } } @@ -68,13 +68,13 @@ impl SignedExtension for CheckSpecVersion { pub struct CheckNonce(Compact); impl ExtrinsicParams for CheckNonce { - type OtherParams = (); + type Params = CheckNonceParams; - fn new>( - nonce: u64, - _client: Client, - _other_params: Self::OtherParams, + fn new( + base_params: &BaseParams, + params: Self::Params, ) -> Result { + let nonce = params.0.unwrap_or_else(|| base_params.nonce); Ok(CheckNonce(Compact(nonce))) } } @@ -92,18 +92,29 @@ impl SignedExtension for CheckNonce { } } +/// The nonce can be explicitly set to `Some(_)` or left empty with `None`. In this case it will be taken from the base params. +#[derive(Debug, Clone, Default)] +pub struct CheckNonceParams(pub Option); + +impl FromBaseParams for CheckNonceParams { + fn from_base_params(params: &BaseParams) -> Self { + CheckNonceParams(Some(params.nonce)) + } +} + /// The [`CheckTxVersion`] signed extension. pub struct CheckTxVersion(u32); impl ExtrinsicParams for CheckTxVersion { - type OtherParams = (); + type Params = (); - fn new>( - _nonce: u64, - client: Client, - _other_params: Self::OtherParams, + fn new( + base_params: &BaseParams, + params: Self::Params, ) -> Result { - Ok(CheckTxVersion(client.runtime_version().transaction_version)) + Ok(CheckTxVersion( + base_params.client.runtime_version().transaction_version, + )) } } @@ -124,14 +135,13 @@ impl SignedExtension for CheckTxVersion { pub struct CheckGenesis(T::Hash); impl ExtrinsicParams for CheckGenesis { - type OtherParams = (); + type Params = (); - fn new>( - _nonce: u64, - client: Client, - _other_params: Self::OtherParams, + fn new( + base_params: &BaseParams, + params: Self::Params, ) -> Result { - Ok(CheckGenesis(client.genesis_hash())) + Ok(CheckGenesis(base_params.client.genesis_hash())) } } @@ -169,9 +179,9 @@ impl Default for CheckMortalityParams { } } -impl DefaultOrFrom for CheckMortalityParams { - fn default_or_from(value: Option<&T::Header>) -> Self { - if let Some(header) = value { +impl FromBaseParams for CheckMortalityParams { + fn from_base_params(params: &BaseParams) -> Self { + if let Some(header) = ¶ms.latest_block_header { const FOR_N_BLOCKS: u64 = 32; CheckMortalityParams::mortal(FOR_N_BLOCKS, header.number().into(), header.hash()) } else { @@ -201,16 +211,17 @@ impl CheckMortalityParams { } impl ExtrinsicParams for CheckMortality { - type OtherParams = CheckMortalityParams; + type Params = CheckMortalityParams; - fn new>( - _nonce: u64, - client: Client, - other_params: Self::OtherParams, + fn new( + base_params: &BaseParams, + params: Self::Params, ) -> Result { Ok(CheckMortality { - era: other_params.era, - checkpoint: other_params.checkpoint.unwrap_or(client.genesis_hash()), + era: params.era, + checkpoint: params + .checkpoint + .unwrap_or(base_params.client.genesis_hash()), }) } } @@ -267,8 +278,8 @@ impl Default for ChargeAssetTxPaymentParams { } } -impl DefaultOrFrom for ChargeAssetTxPaymentParams { - fn default_or_from(_value: Option<&T::Header>) -> Self { +impl FromBaseParams for ChargeAssetTxPaymentParams { + fn from_base_params(params: &BaseParams) -> Self { Default::default() } } @@ -298,16 +309,15 @@ impl ChargeAssetTxPaymentParams { } impl ExtrinsicParams for ChargeAssetTxPayment { - type OtherParams = ChargeAssetTxPaymentParams; + type Params = ChargeAssetTxPaymentParams; - fn new>( - _nonce: u64, - _client: Client, - other_params: Self::OtherParams, + fn new( + base_params: &BaseParams, + params: Self::Params, ) -> Result { Ok(ChargeAssetTxPayment { - tip: Compact(other_params.tip), - asset_id: other_params.asset_id, + tip: Compact(params.tip), + asset_id: params.asset_id, }) } } @@ -344,8 +354,8 @@ pub struct ChargeTransactionPaymentParams { tip: u128, } -impl DefaultOrFrom for ChargeTransactionPaymentParams { - fn default_or_from(_value: Option<&T>) -> Self { +impl FromBaseParams for ChargeTransactionPaymentParams { + fn from_base_params(params: &BaseParams) -> Self { Default::default() } } @@ -362,15 +372,14 @@ impl ChargeTransactionPaymentParams { } impl ExtrinsicParams for ChargeTransactionPayment { - type OtherParams = ChargeTransactionPaymentParams; + type Params = ChargeTransactionPaymentParams; - fn new>( - _nonce: u64, - _client: Client, - other_params: Self::OtherParams, + fn new( + base_params: &BaseParams, + params: Self::Params, ) -> Result { Ok(ChargeTransactionPayment { - tip: Compact(other_params.tip), + tip: Compact(params.tip), }) } } @@ -406,14 +415,13 @@ macro_rules! impl_tuples { T: Config, $($ident: SignedExtension,)+ { - type OtherParams = ($($ident::OtherParams,)+); + type Params = ($($ident::Params,)+); - fn new>( - nonce: u64, - client: Client, - other_params: Self::OtherParams, + fn new( + base_params: &BaseParams, + params: Self::Params, ) -> Result { - let metadata = client.metadata(); + let metadata = base_params.client.metadata(); let types = metadata.types(); // For each signed extension in the tuple, find the matching index in the metadata, if @@ -427,7 +435,7 @@ macro_rules! impl_tuples { } // Break and record as soon as we find a match: if $ident::matches(e.identifier(), e.extra_ty(), types) { - let ext = $ident::new(nonce, client.clone(), other_params.$index)?; + let ext = $ident::new(base_params, params.$index)?; let boxed_ext: Box = Box::new(ext); exts_by_index.insert(idx, boxed_ext); break diff --git a/subxt/src/tx/tx_client.rs b/subxt/src/tx/tx_client.rs index dd40567087..2293f6070f 100644 --- a/subxt/src/tx/tx_client.rs +++ b/subxt/src/tx/tx_client.rs @@ -7,7 +7,7 @@ use std::borrow::Cow; use crate::{ backend::{BackendExt, BlockRef, TransactionStatus}, client::{OfflineClientT, OnlineClientT}, - config::{Config, DefaultOrFrom, ExtrinsicParams, ExtrinsicParamsEncoder, Hasher}, + config::{BaseParams, Config, ExtrinsicParams, ExtrinsicParamsEncoder, FromBaseParams, Hasher}, error::{Error, MetadataError}, tx::{Signer as SignerT, TxPayload, TxProgress}, utils::{Encoded, PhantomDataSendSync}, @@ -103,11 +103,11 @@ impl> TxClient { } /// Create a partial extrinsic. - pub fn create_partial_signed_with_nonce( + fn create_partial_signed_with_base_params( &self, call: &Call, - account_nonce: u64, - other_params: >::OtherParams, + base_params: BaseParams, + other_params: >::Params, ) -> Result, Error> where Call: TxPayload, @@ -120,11 +120,8 @@ impl> TxClient { let call_data = self.call_data(call)?; // 3. Construct our custom additional/extra params. - let additional_and_extra_params = >::new( - account_nonce, - self.client.clone(), - other_params, - )?; + let additional_and_extra_params = + >::new(&base_params, other_params)?; // Return these details, ready to construct a signed extrinsic from. Ok(PartialExtrinsic { @@ -135,12 +132,12 @@ impl> TxClient { } /// Creates a signed extrinsic without submitting it. - pub fn create_signed_with_nonce( + fn create_signed_with_base_params( &self, call: &Call, signer: &Signer, - account_nonce: u64, - other_params: >::OtherParams, + base_params: BaseParams, + params: >::Params, ) -> Result, Error> where Call: TxPayload, @@ -153,7 +150,7 @@ impl> TxClient { // 2. Gather the "additional" and "extra" params along with the encoded call data, // ready to be signed. let partial_signed = - self.create_partial_signed_with_nonce(call, account_nonce, other_params)?; + self.create_partial_signed_with_base_params(call, base_params, params)?; // 3. Sign and construct an extrinsic from these details. Ok(partial_signed.sign(signer)) @@ -171,18 +168,30 @@ where crate::blocks::get_account_nonce(&self.client, account_id, block_ref.hash()).await } + async fn base_params(&self, account_id: &T::AccountId) -> Result, Error> { + let nonce = self.account_nonce(account_id).await?; + let latest_block = self.client.blocks().at_latest().await.ok(); + let latest_block_header = latest_block.map(|b| b.into_header()); + let base_params = BaseParams:: { + client: self.client.base_client(), + latest_block_header, + nonce, + }; + Ok(base_params) + } + /// Creates a partial signed extrinsic, without submitting it. pub async fn create_partial_signed( &self, call: &Call, account_id: &T::AccountId, - other_params: >::OtherParams, + other_params: >::Params, ) -> Result, Error> where Call: TxPayload, { - let account_nonce = self.account_nonce(account_id).await?; - self.create_partial_signed_with_nonce(call, account_nonce, other_params) + let base_params = self.base_params(account_id).await?; + self.create_partial_signed_with_base_params(call, base_params, other_params) } /// Creates a signed extrinsic, without submitting it. @@ -190,14 +199,14 @@ where &self, call: &Call, signer: &Signer, - other_params: >::OtherParams, + other_params: >::Params, ) -> Result, Error> where Call: TxPayload, Signer: SignerT, { - let account_nonce = self.account_nonce(&signer.account_id()).await?; - self.create_signed_with_nonce(call, signer, account_nonce, other_params) + let base_params = self.base_params(&signer.account_id()).await?; + self.create_signed_with_base_params(call, signer, base_params, other_params) } /// Creates and signs an extrinsic and submits it to the chain. Passes default parameters @@ -213,13 +222,12 @@ where where Call: TxPayload, Signer: SignerT, - >::OtherParams: DefaultOrFrom, { - let latest_block = self.client.blocks().at_latest().await.ok(); - let latest_header = latest_block.as_ref().map(|b| b.header()); - let other_params = - >::OtherParams::default_or_from(latest_header); - self.sign_and_submit_then_watch(call, signer, other_params) + let base_params = self.base_params(&signer.account_id()).await?; + let params = + >::Params::from_base_params(&base_params); + self.create_signed_with_base_params(call, signer, base_params, params)? + .submit_and_watch() .await } @@ -231,14 +239,14 @@ where &self, call: &Call, signer: &Signer, - other_params: >::OtherParams, + other_params: >::Params, ) -> Result, Error> where Call: TxPayload, Signer: SignerT, { - self.create_signed(call, signer, other_params) - .await? + let base_params = self.base_params(&signer.account_id()).await?; + self.create_signed_with_base_params(call, signer, base_params, other_params)? .submit_and_watch() .await } @@ -261,12 +269,10 @@ where where Call: TxPayload, Signer: SignerT, - >::OtherParams: DefaultOrFrom, { - let latest_block = self.client.blocks().at_latest().await.ok(); - let latest_header = latest_block.as_ref().map(|b| b.header()); + let base_params = self.base_params(&signer.account_id()).await?; let other_params = - >::OtherParams::default_or_from(latest_header); + >::Params::from_base_params(&base_params); self.sign_and_submit(call, signer, other_params).await } @@ -282,7 +288,7 @@ where &self, call: &Call, signer: &Signer, - other_params: >::OtherParams, + other_params: >::Params, ) -> Result where Call: TxPayload,