mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-12 01:45:45 +00:00
Address some issues around tx mortality (#2025)
* Clarify mortality config * Fix EncodeAsType / DecodeAsType impls for Era to be proper ones * Fix test now that txs are mortal by default * clippy * missing imports * allow Era decoding from CheckMortality * tweak a comment * fmt * Add more explicit tests for mortality
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use super::Config;
|
||||
use crate::config::transaction_extensions::CheckMortalityParams;
|
||||
|
||||
use super::{Config, HashFor};
|
||||
use super::{ExtrinsicParams, transaction_extensions};
|
||||
|
||||
/// The default [`super::ExtrinsicParams`] implementation understands common signed extensions
|
||||
@@ -26,8 +28,8 @@ pub type DefaultExtrinsicParams<T> = transaction_extensions::AnyOf<
|
||||
/// [`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, else it's mortal for N blocks (if possible).
|
||||
mortality: Option<u64>,
|
||||
/// `None` means the tx will be immortal, else it's mortality is described.
|
||||
mortality: transaction_extensions::CheckMortalityParams<T>,
|
||||
/// `None` means the nonce will be automatically set.
|
||||
nonce: Option<u64>,
|
||||
/// `None` means we'll use the native token.
|
||||
@@ -39,7 +41,7 @@ pub struct DefaultExtrinsicParamsBuilder<T: Config> {
|
||||
impl<T: Config> Default for DefaultExtrinsicParamsBuilder<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mortality: None,
|
||||
mortality: CheckMortalityParams::default(),
|
||||
tip: 0,
|
||||
tip_of: 0,
|
||||
tip_of_asset_id: None,
|
||||
@@ -55,10 +57,43 @@ impl<T: Config> DefaultExtrinsicParamsBuilder<T> {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Make the transaction immortal, meaning it will never expire. This means that it could, in
|
||||
/// theory, be pending for a long time and only be included many blocks into the future.
|
||||
pub fn immortal(mut self) -> Self {
|
||||
self.mortality = transaction_extensions::CheckMortalityParams::immortal();
|
||||
self
|
||||
}
|
||||
|
||||
/// Make the transaction mortal, given a number of blocks it will be mortal for from
|
||||
/// the current block at the time of submission.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// This will ultimately return an error if used for creating extrinsic offline, because we need
|
||||
/// additional information in order to set the mortality properly.
|
||||
///
|
||||
/// When creating offline transactions, you must use [`Self::mortal_from_unchecked`] instead to set
|
||||
/// the mortality. This provides all of the necessary information which we must otherwise be online
|
||||
/// in order to obtain.
|
||||
pub fn mortal(mut self, for_n_blocks: u64) -> Self {
|
||||
self.mortality = Some(for_n_blocks);
|
||||
self.mortality = transaction_extensions::CheckMortalityParams::mortal(for_n_blocks);
|
||||
self
|
||||
}
|
||||
|
||||
/// Configure a transaction that will be mortal for the number of blocks given, and from the
|
||||
/// block details provided. Prefer to use [`Self::mortal()`] where possible, which prevents
|
||||
/// the block number and hash from being misaligned.
|
||||
pub fn mortal_from_unchecked(
|
||||
mut self,
|
||||
for_n_blocks: u64,
|
||||
from_block_n: u64,
|
||||
from_block_hash: HashFor<T>,
|
||||
) -> Self {
|
||||
self.mortality = transaction_extensions::CheckMortalityParams::mortal_from_unchecked(
|
||||
for_n_blocks,
|
||||
from_block_n,
|
||||
from_block_hash,
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
@@ -88,11 +123,7 @@ impl<T: Config> DefaultExtrinsicParamsBuilder<T> {
|
||||
|
||||
/// Build the extrinsic parameters.
|
||||
pub fn build(self) -> <DefaultExtrinsicParams<T> as ExtrinsicParams<T>>::Params {
|
||||
let check_mortality_params = if let Some(for_n_blocks) = self.mortality {
|
||||
transaction_extensions::CheckMortalityParams::mortal(for_n_blocks)
|
||||
} else {
|
||||
transaction_extensions::CheckMortalityParams::immortal()
|
||||
};
|
||||
let check_mortality_params = self.mortality;
|
||||
|
||||
let charge_asset_tx_params = if let Some(asset_id) = self.tip_of_asset_id {
|
||||
transaction_extensions::ChargeAssetTxPaymentParams::tip_of(self.tip, asset_id)
|
||||
|
||||
@@ -295,6 +295,15 @@ impl<T: Config> ExtrinsicParams<T> for CheckMortality<T> {
|
||||
type Params = CheckMortalityParams<T>;
|
||||
|
||||
fn new(client: &ClientState<T>, params: Self::Params) -> Result<Self, ExtrinsicParamsError> {
|
||||
// If a user has explicitly configured the transaction to be mortal for n blocks, but we get
|
||||
// to this stage and no injected information was able to turn this into MortalFromBlock{..},
|
||||
// then we hit an error as we are unable to construct a mortal transaction here.
|
||||
if matches!(¶ms.0, CheckMortalityParamsInner::MortalForBlocks(_)) {
|
||||
return Err(ExtrinsicParamsError::custom(
|
||||
"CheckMortality: We cannot construct an offline extrinsic with only the number of blocks it is mortal for. Use mortal_from_unchecked instead.",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(CheckMortality {
|
||||
// if nothing has been explicitly configured, we will have a mortal transaction
|
||||
// valid for 32 blocks if block info is available.
|
||||
@@ -347,8 +356,15 @@ impl<T: Config> TransactionExtension<T> for CheckMortality<T> {
|
||||
pub struct CheckMortalityParams<T: Config>(CheckMortalityParamsInner<T>);
|
||||
|
||||
enum CheckMortalityParamsInner<T: Config> {
|
||||
/// The transaction will be immortal.
|
||||
Immortal,
|
||||
/// The transaction is mortal for N blocks. This must be "upgraded" into
|
||||
/// [`CheckMortalityParamsInner::MortalFromBlock`] to ultimately work.
|
||||
MortalForBlocks(u64),
|
||||
/// The transaction is mortal for N blocks, but if it cannot be "upgraded",
|
||||
/// then it will be set to immortal instead. This is the default if unset.
|
||||
MortalForBlocksOrImmortalIfNotPossible(u64),
|
||||
/// The transaction is mortal and all of the relevant information is provided.
|
||||
MortalFromBlock {
|
||||
for_n_blocks: u64,
|
||||
from_block_n: u64,
|
||||
@@ -358,8 +374,8 @@ enum CheckMortalityParamsInner<T: Config> {
|
||||
|
||||
impl<T: Config> Default for CheckMortalityParams<T> {
|
||||
fn default() -> Self {
|
||||
// default to being mortal for 32 blocks if possible:
|
||||
CheckMortalityParams(CheckMortalityParamsInner::MortalForBlocks(32))
|
||||
// default to being mortal for 32 blocks if possible, else immortal:
|
||||
CheckMortalityParams(CheckMortalityParamsInner::MortalForBlocksOrImmortalIfNotPossible(32))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,7 +408,8 @@ impl<T: Config> CheckMortalityParams<T> {
|
||||
impl<T: Config> Params<T> for CheckMortalityParams<T> {
|
||||
fn inject_block(&mut self, from_block_n: u64, from_block_hash: HashFor<T>) {
|
||||
match &self.0 {
|
||||
CheckMortalityParamsInner::MortalForBlocks(n) => {
|
||||
CheckMortalityParamsInner::MortalForBlocks(n)
|
||||
| CheckMortalityParamsInner::MortalForBlocksOrImmortalIfNotPossible(n) => {
|
||||
self.0 = CheckMortalityParamsInner::MortalFromBlock {
|
||||
for_n_blocks: *n,
|
||||
from_block_n,
|
||||
|
||||
Reference in New Issue
Block a user