mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 00:01:09 +00:00
Support constructing and submitting V5 transactions (#1931)
* TransactionExtensions basic support for V5 VerifySignature and renames * WIP: subxt-core v5 transaction support * Subxt to support V5 extrinsics * WIP tests failing with wsm trap error * Actually encode mortality to fix tx encode issue * fmt * rename to sign_with_account_and_signature * Add explicit methods for v4 and v5 ext construction * clippy * fix wasm example and no mut self where not needed * fix doc example * another doc fix * Add tests for tx encoding and fix v5 encode issue * add copyright and todo * refactor APIs to have clear v4/v5 split in core and slightly nicer split in subxt proper * rename Partial/SubmittableExtrinsic to *Transaction * Remove SignerT::address since it's not needed * doc fixes * fmt * doc fixes * Fix comment number * Clarify panic behaviour of inject_signature * fmt
This commit is contained in:
@@ -16,7 +16,8 @@ use subxt_core::blocks::{ExtrinsicDetails as CoreExtrinsicDetails, Extrinsics as
|
||||
|
||||
// Re-export anything that's directly returned/used in the APIs below.
|
||||
pub use subxt_core::blocks::{
|
||||
ExtrinsicMetadataDetails, ExtrinsicSignedExtension, ExtrinsicSignedExtensions, StaticExtrinsic,
|
||||
ExtrinsicMetadataDetails, ExtrinsicTransactionExtension, ExtrinsicTransactionExtensions,
|
||||
StaticExtrinsic,
|
||||
};
|
||||
|
||||
/// The body of a block.
|
||||
@@ -191,14 +192,14 @@ where
|
||||
self.inner.signature_bytes()
|
||||
}
|
||||
|
||||
/// See [`subxt_core::blocks::ExtrinsicDetails::signed_extensions_bytes()`].
|
||||
pub fn signed_extensions_bytes(&self) -> Option<&[u8]> {
|
||||
self.inner.signed_extensions_bytes()
|
||||
/// See [`subxt_core::blocks::ExtrinsicDetails::transaction_extensions_bytes()`].
|
||||
pub fn transaction_extensions_bytes(&self) -> Option<&[u8]> {
|
||||
self.inner.transaction_extensions_bytes()
|
||||
}
|
||||
|
||||
/// See [`subxt_core::blocks::ExtrinsicDetails::signed_extensions()`].
|
||||
pub fn signed_extensions(&self) -> Option<ExtrinsicSignedExtensions<'_, T>> {
|
||||
self.inner.signed_extensions()
|
||||
/// See [`subxt_core::blocks::ExtrinsicDetails::transaction_extensions()`].
|
||||
pub fn transaction_extensions(&self) -> Option<ExtrinsicTransactionExtensions<'_, T>> {
|
||||
self.inner.transaction_extensions()
|
||||
}
|
||||
|
||||
/// See [`subxt_core::blocks::ExtrinsicDetails::pallet_index()`].
|
||||
|
||||
@@ -14,8 +14,8 @@ pub use crate::backend::BlockRef;
|
||||
pub use block_types::Block;
|
||||
pub use blocks_client::BlocksClient;
|
||||
pub use extrinsic_types::{
|
||||
ExtrinsicDetails, ExtrinsicEvents, ExtrinsicSignedExtension, ExtrinsicSignedExtensions,
|
||||
Extrinsics, FoundExtrinsic, StaticExtrinsic,
|
||||
ExtrinsicDetails, ExtrinsicEvents, ExtrinsicTransactionExtension,
|
||||
ExtrinsicTransactionExtensions, Extrinsics, FoundExtrinsic, StaticExtrinsic,
|
||||
};
|
||||
|
||||
// We get account nonce info in tx_client, too, so re-use the logic:
|
||||
|
||||
@@ -64,10 +64,10 @@
|
||||
//!
|
||||
//! ## ExtrinsicParams
|
||||
//!
|
||||
//! Chains each have a set of "signed extensions" configured. Signed extensions provide a means to extend how transactions
|
||||
//! work. Each signed extension can potentially encode some "extra" data which is sent along with a transaction, as well as some
|
||||
//! Chains each have a set of "transaction extensions" (formally called "signed extensions") configured. Transaction extensions provide
|
||||
//! a means to extend how transactions work. Each transaction extension can potentially encode some "extra" data which is sent along with a transaction, as well as some
|
||||
//! "additional" data which is included in the transaction signer payload, but not transmitted along with the transaction. On
|
||||
//! a node, signed extensions can then perform additional checks on the submitted transactions to ensure their validity.
|
||||
//! a node, transaction extensions can then perform additional checks on the submitted transactions to ensure their validity.
|
||||
//!
|
||||
//! The `ExtrinsicParams` config type expects to be given an implementation of the [`crate::config::ExtrinsicParams`] trait.
|
||||
//! Implementations of the [`crate::config::ExtrinsicParams`] trait are handed some parameters from Subxt itself, and can
|
||||
@@ -75,26 +75,26 @@
|
||||
//! via the required [`crate::config::ExtrinsicParamsEncoder`] impl.
|
||||
//!
|
||||
//! **In most cases, the default [crate::config::DefaultExtrinsicParams] type will work**: it understands the "standard"
|
||||
//! signed extensions that are in use, and allows the user to provide things like a tip, and set the extrinsic mortality via
|
||||
//! [`crate::config::DefaultExtrinsicParamsBuilder`]. It will use the chain metadata to decide which signed extensions to use
|
||||
//! and in which order. It will return an error if the chain uses a signed extension which it doesn't know how to handle.
|
||||
//! transaction extensions that are in use, and allows the user to provide things like a tip, and set the extrinsic mortality via
|
||||
//! [`crate::config::DefaultExtrinsicParamsBuilder`]. It will use the chain metadata to decide which transaction extensions to use
|
||||
//! and in which order. It will return an error if the chain uses a transaction extension which it doesn't know how to handle.
|
||||
//!
|
||||
//! If the chain uses novel signed extensions (or if you just wish to provide a different interface for users to configure
|
||||
//! If the chain uses novel transaction extensions (or if you just wish to provide a different interface for users to configure
|
||||
//! transactions), you can either:
|
||||
//!
|
||||
//! 1. Implement a new signed extension and add it to the list.
|
||||
//! 1. Implement a new transaction extension and add it to the list.
|
||||
//! 2. Implement [`crate::config::DefaultExtrinsicParams`] from scratch.
|
||||
//!
|
||||
//! See below for examples of each.
|
||||
//!
|
||||
//! ### Finding out which signed extensions a chain is using.
|
||||
//! ### Finding out which transaction extensions a chain is using.
|
||||
//!
|
||||
//! In either case, you'll want to find out which signed extensions a chain is using. This information can be obtained from
|
||||
//! the `SignedExtra` parameter of the `UncheckedExtrinsic` of your parachain, which will be a tuple of signed extensions.
|
||||
//! In either case, you'll want to find out which transaction extensions a chain is using. This information can be obtained from
|
||||
//! the `SignedExtra` parameter of the `UncheckedExtrinsic` of your parachain, which will be a tuple of transaction extensions.
|
||||
//! It can also be obtained from the metadata (see [`frame_metadata::v15::SignedExtensionMetadata`]).
|
||||
//!
|
||||
//! For statemint, the signed extensions look like
|
||||
//! [this](https://github.com/paritytech/cumulus/tree/master/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs#L779):
|
||||
//! For statemint, the transaction extensions look like
|
||||
//! [this](https://github.com/paritytech/cumulus/blob/d4bb2215bb28ee05159c4c7df1b3435177b5bf4e/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs#L786):
|
||||
//!
|
||||
//! ```rs
|
||||
//! pub type SignedExtra = (
|
||||
@@ -126,20 +126,20 @@
|
||||
//!
|
||||
//! All types in the `struct type` column make up the "extra" data that we're expected to provide. All types in the
|
||||
//! `AdditionalSigned` column make up the "additional" data that we're expected to provide. This information will be useful
|
||||
//! whether we want to implement [`crate::config::SignedExtension`] for a signed extension, or implement
|
||||
//! whether we want to implement [`crate::config::TransactionExtension`] for a transaction extension, or implement
|
||||
//! [`crate::config::ExtrinsicParams`] from scratch.
|
||||
//!
|
||||
//! As it happens, all of the signed extensions in the table are either already exported in [`crate::config::signed_extensions`],
|
||||
//! As it happens, all of the transaction extensions in the table are either already exported in [`crate::config::transaction_extensions`],
|
||||
//! or they hand back no "additional" or "extra" data. In both of these cases, the default `ExtrinsicParams` configuration will
|
||||
//! work out of the box.
|
||||
//!
|
||||
//! ### Implementing and adding new signed extensions to the config
|
||||
//! ### Implementing and adding new transaction extensions to the config
|
||||
//!
|
||||
//! If you do need to implement a novel signed extension, then you can implement [`crate::config::signed_extensions::SignedExtension`]
|
||||
//! on a custom type and place it into a new set of signed extensions, like so:
|
||||
//! If you do need to implement a novel transaction extension, then you can implement [`crate::config::transaction_extensions::TransactionExtension`]
|
||||
//! on a custom type and place it into a new set of transaction extensions, like so:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str ! ("../../../examples/setup_config_signed_extension.rs")]
|
||||
#![doc = include_str ! ("../../../examples/setup_config_transaction_extension.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ### Implementing [`crate::config::ExtrinsicParams`] from scratch
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
//!
|
||||
//! This example shows how to subscribe to blocks and decode the extrinsics in each block into the root extrinsic type.
|
||||
//! Once we get hold of the [ExtrinsicDetails](crate::blocks::ExtrinsicDetails), we can decode it statically or dynamically.
|
||||
//! We can also access details about the extrinsic, including the associated events and signed extensions.
|
||||
//! We can also access details about the extrinsic, including the associated events and transaction extensions.
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/blocks_subscribing.rs")]
|
||||
@@ -64,7 +64,8 @@
|
||||
//! get only [the first one](crate::blocks::Extrinsics::find_first), or [the last one](crate::blocks::Extrinsics::find_last).
|
||||
//!
|
||||
//! The following example monitors `TransferKeepAlive` extrinsics on the Polkadot network.
|
||||
//! We statically decode them and access the [tip](crate::blocks::ExtrinsicSignedExtensions::tip()) and [account nonce](crate::blocks::ExtrinsicSignedExtensions::nonce()) signed extensions.
|
||||
//! We statically decode them and access the [tip](crate::blocks::ExtrinsicTransactionExtensions::tip()) and [account nonce](crate::blocks::ExtrinsicTransactionExtensions::nonce())
|
||||
//! transaction extensions.
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/block_decoding_static.rs")]
|
||||
@@ -75,7 +76,7 @@
|
||||
//! Sometimes you might use subxt with metadata that is not known at compile time. In this case, you do not have access to a statically generated
|
||||
//! interface module that contains the relevant Rust types. You can [decode ExtrinsicDetails dynamically](crate::blocks::ExtrinsicDetails::field_values()),
|
||||
//! which gives you access to it's fields as a [scale value composite](scale_value::Composite).
|
||||
//! The following example looks for signed extrinsics on the Polkadot network and retrieves their pallet name, variant name, data fields and signed extensions dynamically.
|
||||
//! The following example looks for signed extrinsics on the Polkadot network and retrieves their pallet name, variant name, data fields and transaction extensions dynamically.
|
||||
//! Notice how we do not need to use code generation via the subxt macro. The only fixed component we provide is the [PolkadotConfig](crate::config::PolkadotConfig).
|
||||
//! Other than that it works in a chain-agnostic way:
|
||||
//!
|
||||
@@ -83,16 +84,16 @@
|
||||
#![doc = include_str!("../../../examples/block_decoding_dynamic.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ## Decoding signed extensions
|
||||
//! ## Decoding transaction extensions
|
||||
//!
|
||||
//! Extrinsics can contain signed extensions. The signed extensions can be different across chains.
|
||||
//! The [Config](crate::Config) implementation for your chain defines which signed extensions you expect.
|
||||
//! Extrinsics can contain transaction extensions. The transaction extensions can be different across chains.
|
||||
//! The [Config](crate::Config) implementation for your chain defines which transaction extensions you expect.
|
||||
//! Once you get hold of the [ExtrinsicDetails](crate::blocks::ExtrinsicDetails) for an extrinsic you are interested in,
|
||||
//! you can try to [get its signed extensions](crate::blocks::ExtrinsicDetails::signed_extensions()).
|
||||
//! These are only available on signed extrinsics. You can try to [find a specific signed extension](crate::blocks::ExtrinsicSignedExtensions::find),
|
||||
//! in the returned [signed extensions](crate::blocks::ExtrinsicSignedExtensions).
|
||||
//! you can try to [get its transaction extensions](crate::blocks::ExtrinsicDetails::transaction_extensions()).
|
||||
//! These are only available on V4 signed extrinsics or V5 general extrinsics. You can try to [find a specific transaction extension](crate::blocks::ExtrinsicTransactionExtensions::find),
|
||||
//! in the returned [transaction extensions](crate::blocks::ExtrinsicTransactionExtensions).
|
||||
//!
|
||||
//! Subxt also provides utility functions to get the [tip](crate::blocks::ExtrinsicSignedExtensions::tip()) and the
|
||||
//! [account nonce](crate::blocks::ExtrinsicSignedExtensions::tip()) associated with an extrinsic, given its signed extensions.
|
||||
//! If you prefer to do things dynamically you can get the data of the signed extension as a [scale value](crate::blocks::ExtrinsicSignedExtension::value()).
|
||||
//! Subxt also provides utility functions to get the [tip](crate::blocks::ExtrinsicTransactionExtensions::tip()) and the
|
||||
//! [account nonce](crate::blocks::ExtrinsicTransactionExtensions::tip()) associated with an extrinsic, given its transaction extensions.
|
||||
//! If you prefer to do things dynamically you can get the data of the transaction extension as a [scale value](crate::blocks::ExtrinsicTransactionExtension::value()).
|
||||
//!
|
||||
|
||||
@@ -113,8 +113,8 @@
|
||||
//! ]);
|
||||
//!
|
||||
//! // Construct the tx but don't sign it. The account nonce here defaults to 0.
|
||||
//! // You can use `create_partial_signed` to fetch the correct nonce.
|
||||
//! let partial_tx = client.tx().create_partial_signed_offline(
|
||||
//! // You can use `create_partial` to fetch the correct nonce.
|
||||
//! let mut partial_tx = client.tx().create_partial_offline(
|
||||
//! &payload,
|
||||
//! Default::default()
|
||||
//! )?;
|
||||
@@ -126,16 +126,16 @@
|
||||
//! // Ultimately we need to be given back a `signature` (or really, anything
|
||||
//! // that can be SCALE encoded) and an `address`:
|
||||
//! let signature;
|
||||
//! let address;
|
||||
//! let account_id;
|
||||
//! # use subxt::tx::Signer;
|
||||
//! # let signer = subxt_signer::sr25519::dev::alice();
|
||||
//! # signature = signer.sign(&signer_payload).into();
|
||||
//! # address = signer.public_key().to_address();
|
||||
//! # account_id = signer.public_key().to_account_id();
|
||||
//!
|
||||
//! // Now we can build an tx, which one can call `submit` or `submit_and_watch`
|
||||
//! // on to submit to a node and optionally watch the status.
|
||||
//! let tx = partial_tx.sign_with_address_and_signature(
|
||||
//! &address,
|
||||
//! let tx = partial_tx.sign_with_account_and_signature(
|
||||
//! &account_id,
|
||||
//! &signature
|
||||
//! );
|
||||
//! # Ok(())
|
||||
|
||||
@@ -21,7 +21,7 @@ pub use dispatch_error::{
|
||||
pub use crate::metadata::Metadata;
|
||||
pub use scale_decode::Error as DecodeError;
|
||||
pub use scale_encode::Error as EncodeError;
|
||||
pub use subxt_core::error::{ExtrinsicParamsError, MetadataError, StorageAddressError};
|
||||
pub use subxt_core::error::{ExtrinsicError, MetadataError, StorageAddressError};
|
||||
pub use subxt_metadata::TryFromError as MetadataTryFromError;
|
||||
|
||||
/// The underlying error enum, generic over the type held by the `Runtime`
|
||||
@@ -62,7 +62,7 @@ pub enum Error {
|
||||
Transaction(#[from] TransactionError),
|
||||
/// Error constructing the appropriate extrinsic params.
|
||||
#[error("Extrinsic params error: {0}")]
|
||||
ExtrinsicParams(#[from] ExtrinsicParamsError),
|
||||
Extrinsic(#[from] ExtrinsicError),
|
||||
/// Block related error.
|
||||
#[error("Block error: {0}")]
|
||||
Block(#[from] BlockError),
|
||||
@@ -90,7 +90,7 @@ impl From<CoreError> for Error {
|
||||
CoreError::StorageAddress(e) => Error::StorageAddress(e),
|
||||
CoreError::Decode(e) => Error::Decode(e),
|
||||
CoreError::Encode(e) => Error::Encode(e),
|
||||
CoreError::ExtrinsicParams(e) => Error::ExtrinsicParams(e),
|
||||
CoreError::Extrinsic(e) => Error::Extrinsic(e),
|
||||
CoreError::Block(e) => Error::Block(e.into()),
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -57,10 +57,10 @@ pub mod utils;
|
||||
/// Polkadot node.
|
||||
pub mod config {
|
||||
pub use subxt_core::config::{
|
||||
polkadot, signed_extensions, substrate, BlockHash, Config, DefaultExtrinsicParams,
|
||||
polkadot, substrate, transaction_extensions, BlockHash, Config, DefaultExtrinsicParams,
|
||||
DefaultExtrinsicParamsBuilder, ExtrinsicParams, ExtrinsicParamsEncoder, Hasher, Header,
|
||||
PolkadotConfig, PolkadotExtrinsicParams, RefineParams, RefineParamsData, SignedExtension,
|
||||
SubstrateConfig, SubstrateExtrinsicParams,
|
||||
PolkadotConfig, PolkadotExtrinsicParams, SubstrateConfig, SubstrateExtrinsicParams,
|
||||
TransactionExtension,
|
||||
};
|
||||
pub use subxt_core::error::ExtrinsicParamsError;
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ mod tx_progress;
|
||||
pub use subxt_core::tx::payload::{dynamic, DefaultPayload, DynamicPayload, Payload};
|
||||
pub use subxt_core::tx::signer::{self, Signer};
|
||||
pub use tx_client::{
|
||||
PartialExtrinsic, SubmittableExtrinsic, TransactionInvalid, TransactionUnknown, TxClient,
|
||||
PartialTransaction, SubmittableTransaction, TransactionInvalid, TransactionUnknown, TxClient,
|
||||
ValidationResult,
|
||||
};
|
||||
pub use tx_progress::{TxInBlock, TxProgress, TxStatus};
|
||||
|
||||
+276
-144
@@ -5,13 +5,14 @@
|
||||
use crate::{
|
||||
backend::{BackendExt, BlockRef, TransactionStatus},
|
||||
client::{OfflineClientT, OnlineClientT},
|
||||
config::{Config, ExtrinsicParams, Header, RefineParams, RefineParamsData},
|
||||
config::{Config, ExtrinsicParams, Header},
|
||||
error::{BlockError, Error},
|
||||
tx::{Payload, Signer as SignerT, TxProgress},
|
||||
utils::PhantomDataSendSync,
|
||||
};
|
||||
use codec::{Compact, Decode, Encode};
|
||||
use derive_where::derive_where;
|
||||
use subxt_core::tx::TransactionVersion;
|
||||
|
||||
/// A client for working with transactions.
|
||||
#[derive_where(Clone; Client)]
|
||||
@@ -31,7 +32,7 @@ impl<T: Config, Client> TxClient<T, Client> {
|
||||
}
|
||||
|
||||
impl<T: Config, C: OfflineClientT<T>> TxClient<T, C> {
|
||||
/// Run the validation logic against some extrinsic you'd like to submit. Returns `Ok(())`
|
||||
/// Run the validation logic against some transaction you'd like to submit. Returns `Ok(())`
|
||||
/// if the call is valid (or if it's not possible to check since the call has no validation hash).
|
||||
/// Return an error if the call was not valid or something went wrong trying to validate it (ie
|
||||
/// the pallet or call in question do not exist at all).
|
||||
@@ -50,59 +51,143 @@ impl<T: Config, C: OfflineClientT<T>> TxClient<T, C> {
|
||||
subxt_core::tx::call_data(call, &self.client.metadata()).map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Creates an unsigned extrinsic without submitting it.
|
||||
pub fn create_unsigned<Call>(&self, call: &Call) -> Result<SubmittableExtrinsic<T, C>, Error>
|
||||
/// Creates an unsigned transaction without submitting it. Depending on the metadata, we might end
|
||||
/// up constructing either a v4 or v5 transaction. See [`Self::create_v4_unsigned`] or
|
||||
/// [`Self::create_v5_bare`] if you'd like to explicitly create an unsigned transaction of a certain version.
|
||||
pub fn create_unsigned<Call>(&self, call: &Call) -> Result<SubmittableTransaction<T, C>, Error>
|
||||
where
|
||||
Call: Payload,
|
||||
{
|
||||
subxt_core::tx::create_unsigned(call, &self.client.metadata())
|
||||
.map(|tx| SubmittableExtrinsic {
|
||||
client: self.client.clone(),
|
||||
inner: tx,
|
||||
})
|
||||
.map_err(Into::into)
|
||||
let metadata = self.client.metadata();
|
||||
let tx = match subxt_core::tx::suggested_version(&metadata)? {
|
||||
TransactionVersion::V4 => subxt_core::tx::create_v4_unsigned(call, &metadata),
|
||||
TransactionVersion::V5 => subxt_core::tx::create_v5_bare(call, &metadata),
|
||||
}?;
|
||||
|
||||
Ok(SubmittableTransaction {
|
||||
client: self.client.clone(),
|
||||
inner: tx,
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a partial extrinsic.
|
||||
/// Creates a v4 unsigned (no signature or transaction extensions) transaction without submitting it.
|
||||
///
|
||||
/// Prefer [`Self::create_unsigned()`] if you don't know which version to create; this will pick the
|
||||
/// most suitable one for the given chain.
|
||||
pub fn create_v4_unsigned<Call>(
|
||||
&self,
|
||||
call: &Call,
|
||||
) -> Result<SubmittableTransaction<T, C>, Error>
|
||||
where
|
||||
Call: Payload,
|
||||
{
|
||||
let metadata = self.client.metadata();
|
||||
let tx = subxt_core::tx::create_v4_unsigned(call, &metadata)?;
|
||||
|
||||
Ok(SubmittableTransaction {
|
||||
client: self.client.clone(),
|
||||
inner: tx,
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a v5 "bare" (no signature or transaction extensions) transaction without submitting it.
|
||||
///
|
||||
/// Prefer [`Self::create_unsigned()`] if you don't know which version to create; this will pick the
|
||||
/// most suitable one for the given chain.
|
||||
pub fn create_v5_bare<Call>(&self, call: &Call) -> Result<SubmittableTransaction<T, C>, Error>
|
||||
where
|
||||
Call: Payload,
|
||||
{
|
||||
let metadata = self.client.metadata();
|
||||
let tx = subxt_core::tx::create_v5_bare(call, &metadata)?;
|
||||
|
||||
Ok(SubmittableTransaction {
|
||||
client: self.client.clone(),
|
||||
inner: tx,
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a partial transaction. Depending on the metadata, we might end up constructing either a v4 or
|
||||
/// v5 transaction. See [`subxt_core::tx`] if you'd like to manually pick the version to construct
|
||||
///
|
||||
/// Note: if not provided, the default account nonce will be set to 0 and the default mortality will be _immortal_.
|
||||
/// This is because this method runs offline, and so is unable to fetch the data needed for more appropriate values.
|
||||
pub fn create_partial_signed_offline<Call>(
|
||||
pub fn create_partial_offline<Call>(
|
||||
&self,
|
||||
call: &Call,
|
||||
params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
) -> Result<PartialExtrinsic<T, C>, Error>
|
||||
) -> Result<PartialTransaction<T, C>, Error>
|
||||
where
|
||||
Call: Payload,
|
||||
{
|
||||
subxt_core::tx::create_partial_signed(call, &self.client.client_state(), params)
|
||||
.map(|tx| PartialExtrinsic {
|
||||
client: self.client.clone(),
|
||||
inner: tx,
|
||||
})
|
||||
.map_err(Into::into)
|
||||
let metadata = self.client.metadata();
|
||||
let tx = match subxt_core::tx::suggested_version(&metadata)? {
|
||||
TransactionVersion::V4 => PartialTransactionInner::V4(
|
||||
subxt_core::tx::create_v4_signed(call, &self.client.client_state(), params)?,
|
||||
),
|
||||
TransactionVersion::V5 => PartialTransactionInner::V5(
|
||||
subxt_core::tx::create_v5_general(call, &self.client.client_state(), params)?,
|
||||
),
|
||||
};
|
||||
|
||||
Ok(PartialTransaction {
|
||||
client: self.client.clone(),
|
||||
inner: tx,
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a signed extrinsic without submitting it.
|
||||
/// Create a v4 partial transaction, ready to sign.
|
||||
///
|
||||
/// Note: if not provided, the default account nonce will be set to 0 and the default mortality will be _immortal_.
|
||||
/// This is because this method runs offline, and so is unable to fetch the data needed for more appropriate values.
|
||||
pub fn create_signed_offline<Call, Signer>(
|
||||
///
|
||||
/// Prefer [`Self::create_partial_offline()`] if you don't know which version to create; this will pick the
|
||||
/// most suitable one for the given chain.
|
||||
pub fn create_v4_partial_offline<Call>(
|
||||
&self,
|
||||
call: &Call,
|
||||
signer: &Signer,
|
||||
params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
) -> Result<SubmittableExtrinsic<T, C>, Error>
|
||||
) -> Result<PartialTransaction<T, C>, Error>
|
||||
where
|
||||
Call: Payload,
|
||||
Signer: SignerT<T>,
|
||||
{
|
||||
subxt_core::tx::create_signed(call, &self.client.client_state(), signer, params)
|
||||
.map(|tx| SubmittableExtrinsic {
|
||||
client: self.client.clone(),
|
||||
inner: tx,
|
||||
})
|
||||
.map_err(Into::into)
|
||||
let tx = PartialTransactionInner::V4(subxt_core::tx::create_v4_signed(
|
||||
call,
|
||||
&self.client.client_state(),
|
||||
params,
|
||||
)?);
|
||||
|
||||
Ok(PartialTransaction {
|
||||
client: self.client.clone(),
|
||||
inner: tx,
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a v5 partial transaction, ready to sign.
|
||||
///
|
||||
/// Note: if not provided, the default account nonce will be set to 0 and the default mortality will be _immortal_.
|
||||
/// This is because this method runs offline, and so is unable to fetch the data needed for more appropriate values.
|
||||
///
|
||||
/// Prefer [`Self::create_partial_offline()`] if you don't know which version to create; this will pick the
|
||||
/// most suitable one for the given chain.
|
||||
pub fn create_v5_partial_offline<Call>(
|
||||
&self,
|
||||
call: &Call,
|
||||
params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
) -> Result<PartialTransaction<T, C>, Error>
|
||||
where
|
||||
Call: Payload,
|
||||
{
|
||||
let tx = PartialTransactionInner::V5(subxt_core::tx::create_v5_general(
|
||||
call,
|
||||
&self.client.client_state(),
|
||||
params,
|
||||
)?);
|
||||
|
||||
Ok(PartialTransaction {
|
||||
client: self.client.clone(),
|
||||
inner: tx,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,84 +196,85 @@ where
|
||||
T: Config,
|
||||
C: OnlineClientT<T>,
|
||||
{
|
||||
/// Fetch the latest block header and account nonce from the backend and use them to refine [`ExtrinsicParams::Params`].
|
||||
async fn refine_params(
|
||||
&self,
|
||||
account_id: &T::AccountId,
|
||||
params: &mut <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
) -> Result<(), Error> {
|
||||
let block_ref = self.client.backend().latest_finalized_block_ref().await?;
|
||||
let block_header = self
|
||||
.client
|
||||
.backend()
|
||||
.block_header(block_ref.hash())
|
||||
.await?
|
||||
.ok_or_else(|| Error::Block(BlockError::not_found(block_ref.hash())))?;
|
||||
let account_nonce =
|
||||
crate::blocks::get_account_nonce(&self.client, account_id, block_ref.hash()).await?;
|
||||
|
||||
params.refine(&RefineParamsData::new(
|
||||
account_nonce,
|
||||
block_header.number().into(),
|
||||
block_header.hash(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the account nonce for a given account ID.
|
||||
pub async fn account_nonce(&self, account_id: &T::AccountId) -> Result<u64, Error> {
|
||||
let block_ref = self.client.backend().latest_finalized_block_ref().await?;
|
||||
crate::blocks::get_account_nonce(&self.client, account_id, block_ref.hash()).await
|
||||
}
|
||||
|
||||
/// Creates a partial signed extrinsic, without submitting it.
|
||||
pub async fn create_partial_signed<Call>(
|
||||
/// Creates a partial transaction, without submitting it. This can then be signed and submitted.
|
||||
pub async fn create_partial<Call>(
|
||||
&self,
|
||||
call: &Call,
|
||||
account_id: &T::AccountId,
|
||||
mut params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
) -> Result<PartialExtrinsic<T, C>, Error>
|
||||
) -> Result<PartialTransaction<T, C>, Error>
|
||||
where
|
||||
Call: Payload,
|
||||
{
|
||||
// Refine the params by adding account nonce and latest block information:
|
||||
self.refine_params(account_id, &mut params).await?;
|
||||
// Create the partial extrinsic with the refined params:
|
||||
self.create_partial_signed_offline(call, params)
|
||||
inject_account_nonce_and_block(&self.client, account_id, &mut params).await?;
|
||||
self.create_partial_offline(call, params)
|
||||
}
|
||||
|
||||
/// Creates a signed extrinsic, without submitting it.
|
||||
pub async fn create_signed<Call, Signer>(
|
||||
/// Creates a partial V4 transaction, without submitting it. This can then be signed and submitted.
|
||||
///
|
||||
/// Prefer [`Self::create_partial()`] if you don't know which version to create; this will pick the
|
||||
/// most suitable one for the given chain.
|
||||
pub async fn create_v4_partial<Call>(
|
||||
&self,
|
||||
call: &Call,
|
||||
account_id: &T::AccountId,
|
||||
mut params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
) -> Result<PartialTransaction<T, C>, Error>
|
||||
where
|
||||
Call: Payload,
|
||||
{
|
||||
inject_account_nonce_and_block(&self.client, account_id, &mut params).await?;
|
||||
self.create_v4_partial_offline(call, params)
|
||||
}
|
||||
|
||||
/// Creates a partial V5 transaction, without submitting it. This can then be signed and submitted.
|
||||
///
|
||||
/// Prefer [`Self::create_partial()`] if you don't know which version to create; this will pick the
|
||||
/// most suitable one for the given chain.
|
||||
pub async fn create_v5_partial<Call>(
|
||||
&self,
|
||||
call: &Call,
|
||||
account_id: &T::AccountId,
|
||||
mut params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
) -> Result<PartialTransaction<T, C>, Error>
|
||||
where
|
||||
Call: Payload,
|
||||
{
|
||||
inject_account_nonce_and_block(&self.client, account_id, &mut params).await?;
|
||||
self.create_v5_partial_offline(call, params)
|
||||
}
|
||||
|
||||
/// Creates a signed transaction, without submitting it.
|
||||
pub async fn create_signed<Call, Signer>(
|
||||
&mut self,
|
||||
call: &Call,
|
||||
signer: &Signer,
|
||||
params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
) -> Result<SubmittableExtrinsic<T, C>, Error>
|
||||
) -> Result<SubmittableTransaction<T, C>, Error>
|
||||
where
|
||||
Call: Payload,
|
||||
Signer: SignerT<T>,
|
||||
{
|
||||
// 1. Validate this call against the current node metadata if the call comes
|
||||
// with a hash allowing us to do so.
|
||||
self.validate(call)?;
|
||||
|
||||
// 2. Gather the "additional" and "extra" params along with the encoded call data,
|
||||
// ready to be signed.
|
||||
let partial_signed = self
|
||||
.create_partial_signed(call, &signer.account_id(), params)
|
||||
let mut partial = self
|
||||
.create_partial(call, &signer.account_id(), params)
|
||||
.await?;
|
||||
|
||||
// 3. Sign and construct an extrinsic from these details.
|
||||
Ok(partial_signed.sign(signer))
|
||||
Ok(partial.sign(signer))
|
||||
}
|
||||
|
||||
/// Creates and signs an extrinsic and submits it to the chain. Passes default parameters
|
||||
/// to construct the "signed extra" and "additional" payloads needed by the extrinsic.
|
||||
/// Creates and signs an transaction and submits it to the chain. Passes default parameters
|
||||
/// to construct the "signed extra" and "additional" payloads needed by the transaction.
|
||||
///
|
||||
/// Returns a [`TxProgress`], which can be used to track the status of the transaction
|
||||
/// and obtain details about it, once it has made it into a block.
|
||||
pub async fn sign_and_submit_then_watch_default<Call, Signer>(
|
||||
&self,
|
||||
&mut self,
|
||||
call: &Call,
|
||||
signer: &Signer,
|
||||
) -> Result<TxProgress<T, C>, Error>
|
||||
@@ -201,12 +287,12 @@ where
|
||||
.await
|
||||
}
|
||||
|
||||
/// Creates and signs an extrinsic and submits it to the chain.
|
||||
/// Creates and signs an transaction and submits it to the chain.
|
||||
///
|
||||
/// Returns a [`TxProgress`], which can be used to track the status of the transaction
|
||||
/// and obtain details about it, once it has made it into a block.
|
||||
pub async fn sign_and_submit_then_watch<Call, Signer>(
|
||||
&self,
|
||||
&mut self,
|
||||
call: &Call,
|
||||
signer: &Signer,
|
||||
params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
@@ -221,18 +307,18 @@ where
|
||||
.await
|
||||
}
|
||||
|
||||
/// Creates and signs an extrinsic and submits to the chain for block inclusion. Passes
|
||||
/// Creates and signs an transaction and submits to the chain for block inclusion. Passes
|
||||
/// default parameters to construct the "signed extra" and "additional" payloads needed
|
||||
/// by the extrinsic.
|
||||
/// by the transaction.
|
||||
///
|
||||
/// Returns `Ok` with the extrinsic hash if it is valid extrinsic.
|
||||
/// Returns `Ok` with the transaction hash if it is valid transaction.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// Success does not mean the extrinsic has been included in the block, just that it is valid
|
||||
/// Success does not mean the transaction has been included in the block, just that it is valid
|
||||
/// and has been included in the transaction pool.
|
||||
pub async fn sign_and_submit_default<Call, Signer>(
|
||||
&self,
|
||||
&mut self,
|
||||
call: &Call,
|
||||
signer: &Signer,
|
||||
) -> Result<T::Hash, Error>
|
||||
@@ -244,16 +330,16 @@ where
|
||||
self.sign_and_submit(call, signer, Default::default()).await
|
||||
}
|
||||
|
||||
/// Creates and signs an extrinsic and submits to the chain for block inclusion.
|
||||
/// Creates and signs an transaction and submits to the chain for block inclusion.
|
||||
///
|
||||
/// Returns `Ok` with the extrinsic hash if it is valid extrinsic.
|
||||
/// Returns `Ok` with the transaction hash if it is valid transaction.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// Success does not mean the extrinsic has been included in the block, just that it is valid
|
||||
/// Success does not mean the transaction has been included in the block, just that it is valid
|
||||
/// and has been included in the transaction pool.
|
||||
pub async fn sign_and_submit<Call, Signer>(
|
||||
&self,
|
||||
&mut self,
|
||||
call: &Call,
|
||||
signer: &Signer,
|
||||
params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
@@ -269,76 +355,99 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// This payload contains the information needed to produce an extrinsic.
|
||||
pub struct PartialExtrinsic<T: Config, C> {
|
||||
/// This payload contains the information needed to produce an transaction.
|
||||
pub struct PartialTransaction<T: Config, C> {
|
||||
client: C,
|
||||
inner: subxt_core::tx::PartialTransaction<T>,
|
||||
inner: PartialTransactionInner<T>,
|
||||
}
|
||||
|
||||
impl<T, C> PartialExtrinsic<T, C>
|
||||
enum PartialTransactionInner<T: Config> {
|
||||
V4(subxt_core::tx::PartialTransactionV4<T>),
|
||||
V5(subxt_core::tx::PartialTransactionV5<T>),
|
||||
}
|
||||
|
||||
impl<T, C> PartialTransaction<T, C>
|
||||
where
|
||||
T: Config,
|
||||
C: OfflineClientT<T>,
|
||||
{
|
||||
/// Return the signer payload for this extrinsic. These are the bytes that must
|
||||
/// be signed in order to produce a valid signature for the extrinsic.
|
||||
/// Return the signer payload for this transaction. These are the bytes that must
|
||||
/// be signed in order to produce a valid signature for the transaction.
|
||||
pub fn signer_payload(&self) -> Vec<u8> {
|
||||
self.inner.signer_payload()
|
||||
}
|
||||
|
||||
/// Return the bytes representing the call data for this partially constructed
|
||||
/// extrinsic.
|
||||
pub fn call_data(&self) -> &[u8] {
|
||||
self.inner.call_data()
|
||||
}
|
||||
|
||||
/// Convert this [`PartialExtrinsic`] into a [`SubmittableExtrinsic`], ready to submit.
|
||||
/// The provided `signer` is responsible for providing the "from" address for the transaction,
|
||||
/// as well as providing a signature to attach to it.
|
||||
pub fn sign<Signer>(&self, signer: &Signer) -> SubmittableExtrinsic<T, C>
|
||||
where
|
||||
Signer: SignerT<T>,
|
||||
{
|
||||
SubmittableExtrinsic {
|
||||
client: self.client.clone(),
|
||||
inner: self.inner.sign(signer),
|
||||
match &self.inner {
|
||||
PartialTransactionInner::V4(tx) => tx.signer_payload(),
|
||||
PartialTransactionInner::V5(tx) => tx.signer_payload().to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert this [`PartialExtrinsic`] into a [`SubmittableExtrinsic`], ready to submit.
|
||||
/// Return the bytes representing the call data for this partially constructed
|
||||
/// transaction.
|
||||
pub fn call_data(&self) -> &[u8] {
|
||||
match &self.inner {
|
||||
PartialTransactionInner::V4(tx) => tx.call_data(),
|
||||
PartialTransactionInner::V5(tx) => tx.call_data(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert this [`PartialTransaction`] into a [`SubmittableTransaction`], ready to submit.
|
||||
/// The provided `signer` is responsible for providing the "from" address for the transaction,
|
||||
/// as well as providing a signature to attach to it.
|
||||
pub fn sign<Signer>(&mut self, signer: &Signer) -> SubmittableTransaction<T, C>
|
||||
where
|
||||
Signer: SignerT<T>,
|
||||
{
|
||||
let tx = match &mut self.inner {
|
||||
PartialTransactionInner::V4(tx) => tx.sign(signer),
|
||||
PartialTransactionInner::V5(tx) => tx.sign(signer),
|
||||
};
|
||||
|
||||
SubmittableTransaction {
|
||||
client: self.client.clone(),
|
||||
inner: tx,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert this [`PartialTransaction`] into a [`SubmittableTransaction`], ready to submit.
|
||||
/// An address, and something representing a signature that can be SCALE encoded, are both
|
||||
/// needed in order to construct it. If you have a `Signer` to hand, you can use
|
||||
/// [`PartialExtrinsic::sign()`] instead.
|
||||
pub fn sign_with_address_and_signature(
|
||||
&self,
|
||||
address: &T::Address,
|
||||
/// [`PartialTransaction::sign()`] instead.
|
||||
pub fn sign_with_account_and_signature(
|
||||
&mut self,
|
||||
account_id: &T::AccountId,
|
||||
signature: &T::Signature,
|
||||
) -> SubmittableExtrinsic<T, C> {
|
||||
SubmittableExtrinsic {
|
||||
) -> SubmittableTransaction<T, C> {
|
||||
let tx = match &mut self.inner {
|
||||
PartialTransactionInner::V4(tx) => {
|
||||
tx.sign_with_account_and_signature(account_id.clone(), signature)
|
||||
}
|
||||
PartialTransactionInner::V5(tx) => {
|
||||
tx.sign_with_account_and_signature(account_id, signature)
|
||||
}
|
||||
};
|
||||
|
||||
SubmittableTransaction {
|
||||
client: self.client.clone(),
|
||||
inner: self
|
||||
.inner
|
||||
.sign_with_address_and_signature(address, signature),
|
||||
inner: tx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This represents an extrinsic that has been signed and is ready to submit.
|
||||
pub struct SubmittableExtrinsic<T, C> {
|
||||
/// This represents an transaction that has been signed and is ready to submit.
|
||||
pub struct SubmittableTransaction<T, C> {
|
||||
client: C,
|
||||
inner: subxt_core::tx::Transaction<T>,
|
||||
}
|
||||
|
||||
impl<T, C> SubmittableExtrinsic<T, C>
|
||||
impl<T, C> SubmittableTransaction<T, C>
|
||||
where
|
||||
T: Config,
|
||||
C: OfflineClientT<T>,
|
||||
{
|
||||
/// Create a [`SubmittableExtrinsic`] from some already-signed and prepared
|
||||
/// extrinsic bytes, and some client (anything implementing [`OfflineClientT`]
|
||||
/// Create a [`SubmittableTransaction`] from some already-signed and prepared
|
||||
/// transaction bytes, and some client (anything implementing [`OfflineClientT`]
|
||||
/// or [`OnlineClientT`]).
|
||||
///
|
||||
/// Prefer to use [`TxClient`] to create and sign extrinsics. This is simply
|
||||
/// Prefer to use [`TxClient`] to create and sign transactions. This is simply
|
||||
/// exposed in case you want to skip this process and submit something you've
|
||||
/// already created.
|
||||
pub fn from_bytes(client: C, tx_bytes: Vec<u8>) -> Self {
|
||||
@@ -348,34 +457,34 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate and return the hash of the extrinsic, based on the configured hasher.
|
||||
/// Calculate and return the hash of the transaction, based on the configured hasher.
|
||||
pub fn hash(&self) -> T::Hash {
|
||||
self.inner.hash()
|
||||
}
|
||||
|
||||
/// Returns the SCALE encoded extrinsic bytes.
|
||||
/// Returns the SCALE encoded transaction bytes.
|
||||
pub fn encoded(&self) -> &[u8] {
|
||||
self.inner.encoded()
|
||||
}
|
||||
|
||||
/// Consumes [`SubmittableExtrinsic`] and returns the SCALE encoded
|
||||
/// extrinsic bytes.
|
||||
/// Consumes [`SubmittableTransaction`] and returns the SCALE encoded
|
||||
/// transaction bytes.
|
||||
pub fn into_encoded(self) -> Vec<u8> {
|
||||
self.inner.into_encoded()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> SubmittableExtrinsic<T, C>
|
||||
impl<T, C> SubmittableTransaction<T, C>
|
||||
where
|
||||
T: Config,
|
||||
C: OnlineClientT<T>,
|
||||
{
|
||||
/// Submits the extrinsic to the chain.
|
||||
/// Submits the transaction to the chain.
|
||||
///
|
||||
/// Returns a [`TxProgress`], which can be used to track the status of the transaction
|
||||
/// and obtain details about it, once it has made it into a block.
|
||||
pub async fn submit_and_watch(&self) -> Result<TxProgress<T, C>, Error> {
|
||||
// Get a hash of the extrinsic (we'll need this later).
|
||||
// Get a hash of the transaction (we'll need this later).
|
||||
let ext_hash = self.hash();
|
||||
|
||||
// Submit and watch for transaction progress.
|
||||
@@ -388,7 +497,7 @@ where
|
||||
Ok(TxProgress::new(sub, self.client.clone(), ext_hash))
|
||||
}
|
||||
|
||||
/// Submits the extrinsic to the chain for block inclusion.
|
||||
/// Submits the transaction to the chain for block inclusion.
|
||||
///
|
||||
/// It's usually better to call `submit_and_watch` to get an idea of the progress of the
|
||||
/// submission and whether it's eventually successful or not. This call does not guarantee
|
||||
@@ -429,7 +538,7 @@ where
|
||||
/// Validate a transaction by submitting it to the relevant Runtime API. A transaction that is
|
||||
/// valid can be added to a block, but may still end up in an error state.
|
||||
///
|
||||
/// Returns `Ok` with a [`ValidationResult`], which is the result of attempting to dry run the extrinsic.
|
||||
/// Returns `Ok` with a [`ValidationResult`], which is the result of attempting to dry run the transaction.
|
||||
pub async fn validate(&self) -> Result<ValidationResult, Error> {
|
||||
let latest_block_ref = self.client.backend().latest_finalized_block_ref().await?;
|
||||
self.validate_at(latest_block_ref).await
|
||||
@@ -438,7 +547,7 @@ where
|
||||
/// Validate a transaction by submitting it to the relevant Runtime API. A transaction that is
|
||||
/// valid can be added to a block, but may still end up in an error state.
|
||||
///
|
||||
/// Returns `Ok` with a [`ValidationResult`], which is the result of attempting to dry run the extrinsic.
|
||||
/// Returns `Ok` with a [`ValidationResult`], which is the result of attempting to dry run the transaction.
|
||||
pub async fn validate_at(
|
||||
&self,
|
||||
at: impl Into<BlockRef<T::Hash>>,
|
||||
@@ -464,7 +573,7 @@ where
|
||||
ValidationResult::try_from_bytes(res)
|
||||
}
|
||||
|
||||
/// This returns an estimate for what the extrinsic is expected to cost to execute, less any tips.
|
||||
/// This returns an estimate for what the transaction 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<u128, Error> {
|
||||
let mut params = self.encoded().to_vec();
|
||||
@@ -486,6 +595,29 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch the latest block header and account nonce from the backend and use them to refine [`ExtrinsicParams::Params`].
|
||||
async fn inject_account_nonce_and_block<T: Config, Client: OnlineClientT<T>>(
|
||||
client: &Client,
|
||||
account_id: &T::AccountId,
|
||||
params: &mut <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
) -> Result<(), Error> {
|
||||
use subxt_core::config::transaction_extensions::Params;
|
||||
|
||||
let block_ref = client.backend().latest_finalized_block_ref().await?;
|
||||
let block_header = client
|
||||
.backend()
|
||||
.block_header(block_ref.hash())
|
||||
.await?
|
||||
.ok_or_else(|| Error::Block(BlockError::not_found(block_ref.hash())))?;
|
||||
let account_nonce =
|
||||
crate::blocks::get_account_nonce(client, account_id, block_ref.hash()).await?;
|
||||
|
||||
params.inject_account_nonce(account_nonce);
|
||||
params.inject_block(block_header.number().into(), block_header.hash());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl ValidationResult {
|
||||
#[allow(clippy::get_first)]
|
||||
fn try_from_bytes(bytes: Vec<u8>) -> Result<ValidationResult, crate::Error> {
|
||||
@@ -512,7 +644,7 @@ impl ValidationResult {
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of performing [`SubmittableExtrinsic::validate()`].
|
||||
/// The result of performing [`SubmittableTransaction::validate()`].
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ValidationResult {
|
||||
/// The transaction is valid
|
||||
@@ -611,12 +743,12 @@ pub enum TransactionInvalid {
|
||||
ExhaustsResources,
|
||||
/// Any other custom invalid validity that is not covered by this enum.
|
||||
Custom(u8),
|
||||
/// An extrinsic with a Mandatory dispatch resulted in Error. This is indicative of either a
|
||||
/// An transaction with a Mandatory dispatch resulted in Error. This is indicative of either a
|
||||
/// malicious validator or a buggy `provide_inherent`. In any case, it can result in
|
||||
/// dangerously overweight blocks and therefore if found, invalidates the block.
|
||||
BadMandatory,
|
||||
/// An extrinsic with a mandatory dispatch tried to be validated.
|
||||
/// This is invalid; only inherent extrinsics are allowed to have mandatory dispatches.
|
||||
/// An transaction with a mandatory dispatch tried to be validated.
|
||||
/// This is invalid; only inherent transactions are allowed to have mandatory dispatches.
|
||||
MandatoryValidation,
|
||||
/// The sending address is disabled or known to be invalid.
|
||||
BadSigner,
|
||||
|
||||
Reference in New Issue
Block a user