rework signed extensions

This commit is contained in:
Tadeo hepperle
2024-02-20 18:22:13 +01:00
parent 81c145db1e
commit 6f97ca7041
13 changed files with 227 additions and 165 deletions
Generated
-1
View File
@@ -4531,7 +4531,6 @@ dependencies = [
"subxt-lightclient",
"subxt-macro",
"subxt-metadata",
"subxt-signer",
"thiserror",
"tokio",
"tokio-stream",
+3 -15
View File
@@ -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
+3 -3
View File
@@ -53,13 +53,13 @@ impl CustomExtrinsicParamsBuilder {
// Describe how to fetch and then encode the params:
impl<T: Config> ExtrinsicParams<T> for CustomExtrinsicParams<T> {
type OtherParams = CustomExtrinsicParamsBuilder;
type Params = CustomExtrinsicParamsBuilder;
// Gather together all of the params we will need to encode:
fn new<Client: OfflineClientT<T>>(
_nonce: u64,
client: Client,
other_params: Self::OtherParams,
other_params: Self::Params,
) -> Result<Self, ExtrinsicParamsError> {
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:
@@ -58,12 +58,12 @@ impl<T: Config> signed_extensions::SignedExtension<T> for CustomSignedExtension
// Gather together any params we need for our signed extension, here none.
impl<T: Config> ExtrinsicParams<T> for CustomSignedExtension {
type OtherParams = ();
type Params = ();
fn new<Client: OfflineClientT<T>>(
_nonce: u64,
_client: Client,
_other_params: Self::OtherParams,
_other_params: Self::Params,
) -> Result<Self, ExtrinsicParamsError> {
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<CustomConfig>,
) -> <<CustomConfig as Config>::ExtrinsicParams as ExtrinsicParams<CustomConfig>>::OtherParams {
) -> <<CustomConfig as Config>::ExtrinsicParams as ExtrinsicParams<CustomConfig>>::Params {
let (a, b, c, d, e, f, g) = params.build();
(a, b, c, d, e, f, g, ())
}
+5
View File
@@ -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<T, C> Block<T, C>
+38
View File
@@ -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<T: Config> {
genesis_hash: T::Hash,
runtime_version: RuntimeVersion,
metadata: Metadata,
}
impl<T: Config> BaseClient<T> {
/// 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()
}
}
+17 -13
View File
@@ -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<T: Config>: 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<T>;
/// Work with transactions.
fn tx(&self) -> TxClient<T, Self> {
@@ -63,15 +65,7 @@ pub trait OfflineClientT<T: Config>: Clone + Send + Sync + 'static {
#[derive(Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""))]
pub struct OfflineClient<T: Config> {
inner: Arc<Inner<T>>,
}
#[derive(Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""))]
struct Inner<T: Config> {
genesis_hash: T::Hash,
runtime_version: RuntimeVersion,
metadata: Metadata,
inner: Arc<BaseClient<T>>,
}
impl<T: Config> OfflineClient<T> {
@@ -83,11 +77,11 @@ impl<T: Config> OfflineClient<T> {
metadata: impl Into<Metadata>,
) -> OfflineClient<T> {
OfflineClient {
inner: Arc::new(Inner {
inner: Arc::new(BaseClient::new(
genesis_hash,
runtime_version,
metadata: metadata.into(),
}),
metadata.into(),
)),
}
}
@@ -106,6 +100,12 @@ impl<T: Config> OfflineClient<T> {
self.inner.metadata.clone()
}
/// Return the inner [`BaseClient`].
pub fn base_client(&self) -> BaseClient<T> {
// 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<T: Config> OfflineClientT<T> for OfflineClient<T> {
fn metadata(&self) -> Metadata {
self.metadata()
}
fn base_client(&self) -> BaseClient<T> {
self.base_client()
}
}
// For ergonomics; cloning a client is deliberately fairly cheap (via Arc),
+15 -13
View File
@@ -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<T: Config>: OfflineClientT<T> {
#[derive(Derivative)]
#[derivative(Clone(bound = ""))]
pub struct OnlineClient<T: Config> {
inner: Arc<RwLock<Inner<T>>>,
inner: Arc<RwLock<BaseClient<T>>>,
backend: Arc<dyn Backend<T>>,
}
#[derive(Derivative)]
#[derivative(Debug(bound = ""))]
struct Inner<T: Config> {
genesis_hash: T::Hash,
runtime_version: RuntimeVersion,
metadata: Metadata,
}
impl<T: Config> std::fmt::Debug for OnlineClient<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Client")
@@ -146,11 +138,11 @@ impl<T: Config> OnlineClient<T> {
backend: Arc<B>,
) -> Result<OnlineClient<T>, 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<T: Config> OnlineClient<T> {
inner.genesis_hash
}
/// Return the inner [`BaseClient`].
pub fn base_client(&self) -> BaseClient<T> {
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<T: Config> OfflineClientT<T> for OnlineClient<T> {
fn runtime_version(&self) -> RuntimeVersion {
self.runtime_version()
}
fn base_client(&self) -> BaseClient<T> {
self.base_client()
}
}
impl<T: Config> OnlineClientT<T> for OnlineClient<T> {
+9 -4
View File
@@ -20,12 +20,14 @@ pub type DefaultExtrinsicParams<T> = 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<T: Config> {
/// `None` means the tx will be immortal.
mortality: Option<Mortality<T::Hash>>,
/// The account nonce has to be set explicitly when creating extrinsic params.
nonce: Option<u64>,
/// `None` means we'll use the native token.
tip_of_asset_id: Option<T::AssetId>,
tip: u128,
@@ -36,7 +38,7 @@ struct Mortality<Hash> {
/// 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<T: Config> Default for DefaultExtrinsicParamsBuilder<T> {
fn default() -> Self {
Self {
mortality: None,
nonce: None,
tip: 0,
tip_of: 0,
tip_of_asset_id: None,
@@ -111,7 +114,7 @@ impl<T: Config> DefaultExtrinsicParamsBuilder<T> {
}
/// Build the extrinsic parameters.
pub fn build(self) -> <DefaultExtrinsicParams<T> as ExtrinsicParams<T>>::OtherParams {
pub fn build(self) -> <DefaultExtrinsicParams<T> as ExtrinsicParams<T>>::Params {
let check_mortality_params = if let Some(mortality) = self.mortality {
signed_extensions::CheckMortalityParams::mortal(
mortality.period,
@@ -128,13 +131,15 @@ impl<T: Config> DefaultExtrinsicParamsBuilder<T> {
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,
+25 -18
View File
@@ -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<T: Config>: 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<T>;
/// Construct a new instance of our [`ExtrinsicParams`].
fn new<Client: OfflineClientT<T>>(
nonce: u64,
client: Client,
other_params: Self::OtherParams,
) -> Result<Self, ExtrinsicParamsError>;
fn new(base_params: &BaseParams<T>, params: Self::Params)
-> Result<Self, ExtrinsicParamsError>;
}
/// 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<u8>) {}
}
/// Like the `From<T>` trait, if value is Some(_), but it lets us circumvent the orphan rule, because we want to implement
/// `DefaultOrFrom<Header>` for `()`, such that DefaultOrFrom<Header> is implemented by `((),(),(),CheckMortalityParams)`, if `CheckMortalityParams` implements `DefaultFrom<Header>`
pub trait DefaultOrFrom<T> {
/// 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<T: Config> {
/// [`BaseClient`] containing the metadata, genesis hash and runtime version.
pub client: BaseClient<T>,
/// Latest hash of a finalized block. Not always known (None), e.g. if only a [`crate::OfflineClient`] is available.
pub latest_block_header: Option<T::Header>,
/// Account nonce for the account submitting the extrinsic.
pub nonce: u64,
}
impl<T> DefaultOrFrom<T> 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<T: Config> {
/// Constructs the value from the given mandatory params.
fn from_base_params(params: &BaseParams<T>) -> Self;
}
impl<T: Config> FromBaseParams<T> for () {
fn from_base_params(_params: &BaseParams<T>) {}
}
macro_rules! impl_default_from_tuples {
($($ident:ident),+) => {
impl <T, $($ident),+> DefaultOrFrom<T> for ($($ident,)+)
impl <T: Config, $($ident),+> FromBaseParams<T> for ($($ident,)+)
where
$($ident: DefaultOrFrom<T>,)+
$($ident: FromBaseParams<T>,)+
{
fn default_or_from(value: Option<&T>) -> Self {
fn from_base_params(params: &BaseParams<T>) -> Self {
($(
(<$ident as DefaultOrFrom<T>>::default_or_from(value)),
(<$ident as FromBaseParams<T>>::from_base_params(params)),
)+)
}
}
+2 -2
View File
@@ -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<T> = <<T as Config>::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams;
pub type ParamsFor<T> = <<T as Config>::ExtrinsicParams as ExtrinsicParams<T>>::Params;
/// Block hashes must conform to a bunch of things to be used in Subxt.
pub trait BlockHash:
+68 -60
View File
@@ -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<T: Config>: ExtrinsicParams<T> {
pub struct CheckSpecVersion(u32);
impl<T: Config> ExtrinsicParams<T> for CheckSpecVersion {
type OtherParams = ();
type Params = ();
fn new<Client: OfflineClientT<T>>(
_nonce: u64,
client: Client,
_other_params: Self::OtherParams,
fn new(
base_params: &BaseParams<T>,
params: Self::Params,
) -> Result<Self, ExtrinsicParamsError> {
Ok(CheckSpecVersion(client.runtime_version().spec_version))
Ok(CheckSpecVersion(
base_params.client.runtime_version().spec_version,
))
}
}
@@ -68,13 +68,13 @@ impl<T: Config> SignedExtension<T> for CheckSpecVersion {
pub struct CheckNonce(Compact<u64>);
impl<T: Config> ExtrinsicParams<T> for CheckNonce {
type OtherParams = ();
type Params = CheckNonceParams;
fn new<Client: OfflineClientT<T>>(
nonce: u64,
_client: Client,
_other_params: Self::OtherParams,
fn new(
base_params: &BaseParams<T>,
params: Self::Params,
) -> Result<Self, ExtrinsicParamsError> {
let nonce = params.0.unwrap_or_else(|| base_params.nonce);
Ok(CheckNonce(Compact(nonce)))
}
}
@@ -92,18 +92,29 @@ impl<T: Config> SignedExtension<T> 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<u64>);
impl<T: Config> FromBaseParams<T> for CheckNonceParams {
fn from_base_params(params: &BaseParams<T>) -> Self {
CheckNonceParams(Some(params.nonce))
}
}
/// The [`CheckTxVersion`] signed extension.
pub struct CheckTxVersion(u32);
impl<T: Config> ExtrinsicParams<T> for CheckTxVersion {
type OtherParams = ();
type Params = ();
fn new<Client: OfflineClientT<T>>(
_nonce: u64,
client: Client,
_other_params: Self::OtherParams,
fn new(
base_params: &BaseParams<T>,
params: Self::Params,
) -> Result<Self, ExtrinsicParamsError> {
Ok(CheckTxVersion(client.runtime_version().transaction_version))
Ok(CheckTxVersion(
base_params.client.runtime_version().transaction_version,
))
}
}
@@ -124,14 +135,13 @@ impl<T: Config> SignedExtension<T> for CheckTxVersion {
pub struct CheckGenesis<T: Config>(T::Hash);
impl<T: Config> ExtrinsicParams<T> for CheckGenesis<T> {
type OtherParams = ();
type Params = ();
fn new<Client: OfflineClientT<T>>(
_nonce: u64,
client: Client,
_other_params: Self::OtherParams,
fn new(
base_params: &BaseParams<T>,
params: Self::Params,
) -> Result<Self, ExtrinsicParamsError> {
Ok(CheckGenesis(client.genesis_hash()))
Ok(CheckGenesis(base_params.client.genesis_hash()))
}
}
@@ -169,9 +179,9 @@ impl<T: Config> Default for CheckMortalityParams<T> {
}
}
impl<T: Config> DefaultOrFrom<T::Header> for CheckMortalityParams<T> {
fn default_or_from(value: Option<&T::Header>) -> Self {
if let Some(header) = value {
impl<T: Config> FromBaseParams<T> for CheckMortalityParams<T> {
fn from_base_params(params: &BaseParams<T>) -> Self {
if let Some(header) = &params.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<T: Config> CheckMortalityParams<T> {
}
impl<T: Config> ExtrinsicParams<T> for CheckMortality<T> {
type OtherParams = CheckMortalityParams<T>;
type Params = CheckMortalityParams<T>;
fn new<Client: OfflineClientT<T>>(
_nonce: u64,
client: Client,
other_params: Self::OtherParams,
fn new(
base_params: &BaseParams<T>,
params: Self::Params,
) -> Result<Self, ExtrinsicParamsError> {
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<T: Config> Default for ChargeAssetTxPaymentParams<T> {
}
}
impl<T: Config> DefaultOrFrom<T::Header> for ChargeAssetTxPaymentParams<T> {
fn default_or_from(_value: Option<&T::Header>) -> Self {
impl<T: Config> FromBaseParams<T> for ChargeAssetTxPaymentParams<T> {
fn from_base_params(params: &BaseParams<T>) -> Self {
Default::default()
}
}
@@ -298,16 +309,15 @@ impl<T: Config> ChargeAssetTxPaymentParams<T> {
}
impl<T: Config> ExtrinsicParams<T> for ChargeAssetTxPayment<T> {
type OtherParams = ChargeAssetTxPaymentParams<T>;
type Params = ChargeAssetTxPaymentParams<T>;
fn new<Client: OfflineClientT<T>>(
_nonce: u64,
_client: Client,
other_params: Self::OtherParams,
fn new(
base_params: &BaseParams<T>,
params: Self::Params,
) -> Result<Self, ExtrinsicParamsError> {
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<T> DefaultOrFrom<T> for ChargeTransactionPaymentParams {
fn default_or_from(_value: Option<&T>) -> Self {
impl<T: Config> FromBaseParams<T> for ChargeTransactionPaymentParams {
fn from_base_params(params: &BaseParams<T>) -> Self {
Default::default()
}
}
@@ -362,15 +372,14 @@ impl ChargeTransactionPaymentParams {
}
impl<T: Config> ExtrinsicParams<T> for ChargeTransactionPayment {
type OtherParams = ChargeTransactionPaymentParams;
type Params = ChargeTransactionPaymentParams;
fn new<Client: OfflineClientT<T>>(
_nonce: u64,
_client: Client,
other_params: Self::OtherParams,
fn new(
base_params: &BaseParams<T>,
params: Self::Params,
) -> Result<Self, ExtrinsicParamsError> {
Ok(ChargeTransactionPayment {
tip: Compact(other_params.tip),
tip: Compact(params.tip),
})
}
}
@@ -406,14 +415,13 @@ macro_rules! impl_tuples {
T: Config,
$($ident: SignedExtension<T>,)+
{
type OtherParams = ($($ident::OtherParams,)+);
type Params = ($($ident::Params,)+);
fn new<Client: OfflineClientT<T>>(
nonce: u64,
client: Client,
other_params: Self::OtherParams,
fn new(
base_params: &BaseParams<T>,
params: Self::Params,
) -> Result<Self, ExtrinsicParamsError> {
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<dyn ExtrinsicParamsEncoder> = Box::new(ext);
exts_by_index.insert(idx, boxed_ext);
break
+39 -33
View File
@@ -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<T: Config, C: OfflineClientT<T>> TxClient<T, C> {
}
/// Create a partial extrinsic.
pub fn create_partial_signed_with_nonce<Call>(
fn create_partial_signed_with_base_params<Call>(
&self,
call: &Call,
account_nonce: u64,
other_params: <T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams,
base_params: BaseParams<T>,
other_params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
) -> Result<PartialExtrinsic<T, C>, Error>
where
Call: TxPayload,
@@ -120,11 +120,8 @@ impl<T: Config, C: OfflineClientT<T>> TxClient<T, C> {
let call_data = self.call_data(call)?;
// 3. Construct our custom additional/extra params.
let additional_and_extra_params = <T::ExtrinsicParams as ExtrinsicParams<T>>::new(
account_nonce,
self.client.clone(),
other_params,
)?;
let additional_and_extra_params =
<T::ExtrinsicParams as ExtrinsicParams<T>>::new(&base_params, other_params)?;
// Return these details, ready to construct a signed extrinsic from.
Ok(PartialExtrinsic {
@@ -135,12 +132,12 @@ impl<T: Config, C: OfflineClientT<T>> TxClient<T, C> {
}
/// Creates a signed extrinsic without submitting it.
pub fn create_signed_with_nonce<Call, Signer>(
fn create_signed_with_base_params<Call, Signer>(
&self,
call: &Call,
signer: &Signer,
account_nonce: u64,
other_params: <T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams,
base_params: BaseParams<T>,
params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
) -> Result<SubmittableExtrinsic<T, C>, Error>
where
Call: TxPayload,
@@ -153,7 +150,7 @@ impl<T: Config, C: OfflineClientT<T>> TxClient<T, C> {
// 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<BaseParams<T>, 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::<T> {
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<Call>(
&self,
call: &Call,
account_id: &T::AccountId,
other_params: <T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams,
other_params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
) -> Result<PartialExtrinsic<T, C>, 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: <T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams,
other_params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
) -> Result<SubmittableExtrinsic<T, C>, Error>
where
Call: TxPayload,
Signer: SignerT<T>,
{
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<T>,
<T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams: DefaultOrFrom<T::Header>,
{
let latest_block = self.client.blocks().at_latest().await.ok();
let latest_header = latest_block.as_ref().map(|b| b.header());
let other_params =
<T::ExtrinsicParams as ExtrinsicParams<T>>::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 =
<T::ExtrinsicParams as ExtrinsicParams<T>>::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: <T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams,
other_params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
) -> Result<TxProgress<T, C>, Error>
where
Call: TxPayload,
Signer: SignerT<T>,
{
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<T>,
<T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams: DefaultOrFrom<T::Header>,
{
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 =
<T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams::default_or_from(latest_header);
<T::ExtrinsicParams as ExtrinsicParams<T>>::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: <T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams,
other_params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
) -> Result<T::Hash, Error>
where
Call: TxPayload,