mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 13:21:10 +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:
@@ -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(())
|
||||
|
||||
Reference in New Issue
Block a user