From adc4902a5cebbdc90c0e0d8cd1d732f21394c331 Mon Sep 17 00:00:00 2001 From: gui Date: Thu, 21 Nov 2024 17:37:46 +0900 Subject: [PATCH 01/13] impl --- .../src/traits/transaction_extension/mod.rs | 7 + .../transaction_extension_pipeline.rs | 586 ++++++++++++++++++ 2 files changed, 593 insertions(+) create mode 100644 substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index f8c5dc6a724e..5f8577c8ee88 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -39,9 +39,13 @@ use super::{ mod as_transaction_extension; mod dispatch_transaction; +mod transaction_extension_pipeline; #[allow(deprecated)] pub use as_transaction_extension::AsTransactionExtension; pub use dispatch_transaction::DispatchTransaction; +pub use transaction_extension_pipeline::{ + TransactionExtensionPipeline, TransactionExtensionPipelineImplicit, +}; /// Shortcut for the result value of the `validate` function. pub type ValidateResult = @@ -610,9 +614,11 @@ impl TransactionExtension for () { } type Val = (); type Pre = (); + #[inline] fn weight(&self, _call: &Call) -> Weight { Weight::zero() } + #[inline] fn validate( &self, origin: ::RuntimeOrigin, @@ -628,6 +634,7 @@ impl TransactionExtension for () { > { Ok((ValidTransaction::default(), (), origin)) } + #[inline] fn prepare( self, _val: (), diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs new file mode 100644 index 000000000000..9b156ce9893a --- /dev/null +++ b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs @@ -0,0 +1,586 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The transaction extension pipeline struct. + +use crate::{ + scale_info::TypeInfo, + traits::{ + transaction_extension::{ + TransactionExtension, TransactionExtensionMetadata, ValidateResult, + }, + DispatchInfoOf, DispatchOriginOf, Dispatchable, PostDispatchInfoOf, + }, + transaction_validity::{ + TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, + }, + DispatchResult, +}; +use alloc::vec::Vec; +use codec::{Decode, Encode}; +use core::fmt::Debug; +use sp_weights::Weight; +use tuplex::PushBack; + +macro_rules! declare_pipeline { + ($( $num:tt: $generic:ident, { $( $basket_0:tt )* }, { $( $basket_1:tt )* }, { $( $basket_2:tt )* }, )*) => { + /// A pipeline of transaction extensions. Same as a tuple of transaction extensions, but + /// support up to 32 elements. + #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] + pub struct TransactionExtensionPipeline< + $( $generic = (), )* + >( + $( pub $generic, )* + ); + + paste::paste! { + $( + impl< $( [< E $basket_0 >], )* > + From<( $( [< E $basket_0 >], )* )> + for TransactionExtensionPipeline< $( [< E $basket_0 >], )* > + { + fn from(e: ($( [< E $basket_0 >], )*)) -> Self { + TransactionExtensionPipeline( + $( e.$basket_0, )* + $( { $basket_1; () }, )* + $( { $basket_2; () }, )* + ) + } + } + )* + } + + /// Implicit type for `TransactionExtensionPipeline`. + #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] + pub struct TransactionExtensionPipelineImplicit< + $( $generic = (), )* + >( + $( pub $generic, )* + ); + + paste::paste! { + $( + impl< $( [< E $basket_0 >], )* > + From<( $( [< E $basket_0 >], )* )> + for TransactionExtensionPipelineImplicit< $( [< E $basket_0 >], )* > + { + fn from(e: ($( [< E $basket_0 >], )*)) -> Self { + TransactionExtensionPipelineImplicit( + $( e.$basket_0, )* + $( { $basket_1; () }, )* + $( { $basket_2; () }, )* + ) + } + } + )* + } + + impl< + Call: Dispatchable, + $( $generic: TransactionExtension, )* + > TransactionExtension + for TransactionExtensionPipeline< + $( $generic, )* + > + { + const IDENTIFIER: &'static str = "TransactionExtensionPipeline"; + type Implicit = TransactionExtensionPipelineImplicit< + $( <$generic as TransactionExtension>::Implicit, )* + >; + fn implicit(&self) -> Result { + Ok(TransactionExtensionPipelineImplicit( + $( self.$num.implicit()?, )* + )) + } + fn metadata() -> Vec { + let mut ids = Vec::new(); + $( ids.extend($generic::metadata()); )* + ids + } + type Val = ( $( <$generic as TransactionExtension>::Val, )* ); + type Pre = ( $( <$generic as TransactionExtension>::Pre, )* ); + fn weight(&self, call: &Call) -> Weight { + Weight::zero() + $( .saturating_add(self.$num.weight(call)) )* + } + fn validate( + &self, + origin: DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + self_implicit: Self::Implicit, + inherited_implication: &impl Encode, + source: TransactionSource, + ) -> ValidateResult { + let valid = ValidTransaction::default(); + let val = (); + let explicit_implications = ( + $( &self.$num, )* + ); + let implicit_implications = self_implicit; + + $( + // Implication of this pipeline element not relevant for later items, so we pop it. + let item = explicit_implications.$num; + let item_implicit = implicit_implications.$num; + let (item_valid, item_val, origin) = { + let implications = ( + // The first is the implications born of the fact we return the mutated + // origin. + inherited_implication, + // This is the explicitly made implication born of the fact the new origin is + // passed into the next items in this pipeline-tuple. + ( + ( $( explicit_implications.$basket_1, )* ), + ( $( explicit_implications.$basket_2, )* ), + ), + // This is the implicitly made implication born of the fact the new origin is + // passed into the next items in this pipeline-tuple. + ( + ( $( &implicit_implications.$basket_1, )* ), + ( $( &implicit_implications.$basket_2, )* ), + ), + ); + $generic::validate(item, origin, call, info, len, item_implicit, &implications, source)? + }; + let valid = valid.combine_with(item_valid); + let val = val.push_back(item_val); + )* + + Ok((valid, val, origin)) + } + fn prepare( + self, + val: Self::Val, + origin: &DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + Ok(( + $( self.$num.prepare(val.$num, origin, call, info, len)?, )* + )) + } + fn post_dispatch_details( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + ) -> Result { + let mut total_unspent_weight = Weight::zero(); + + $( + let unspent_weight = $generic::post_dispatch_details(pre.$num, info, post_info, len, result)?; + total_unspent_weight = total_unspent_weight.saturating_add(unspent_weight); + )* + + Ok(total_unspent_weight) + + } + fn post_dispatch( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &mut PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + $( + $generic::post_dispatch(pre.$num, info, post_info, len, result)?; + )* + Ok(()) + } + fn bare_validate(call: &Call, info: &DispatchInfoOf, len: usize) -> TransactionValidity { + let valid = ValidTransaction::default(); + $( + let item_valid = $generic::bare_validate(call, info, len)?; + let valid = valid.combine_with(item_valid); + )* + Ok(valid) + } + + fn bare_validate_and_prepare( + call: &Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result<(), TransactionValidityError> { + $( $generic::bare_validate_and_prepare(call, info, len)?; )* + Ok(()) + } + + fn bare_post_dispatch( + info: &DispatchInfoOf, + post_info: &mut PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + $( $generic::bare_post_dispatch(info, post_info, len, result)?; )* + Ok(()) + } + } + }; +} + +declare_pipeline!( + 0: TransactionExtension0, { 0 }, { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 1: TransactionExtension1, { 0 1 }, { 2 3 4 5 6 7 8 9 10 11 12 13 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 2: TransactionExtension2, { 0 1 2 }, { 3 4 5 6 7 8 9 10 11 12 13 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 3: TransactionExtension3, { 0 1 2 3 }, { 4 5 6 7 8 9 10 11 12 13 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 4: TransactionExtension4, { 0 1 2 3 4 }, { 5 6 7 8 9 10 11 12 13 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 5: TransactionExtension5, { 0 1 2 3 4 5 }, { 6 7 8 9 10 11 12 13 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 6: TransactionExtension6, { 0 1 2 3 4 5 6 }, { 7 8 9 10 11 12 13 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 7: TransactionExtension7, { 0 1 2 3 4 5 6 7 }, { 8 9 10 11 12 13 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 8: TransactionExtension8, { 0 1 2 3 4 5 6 7 8 }, { 9 10 11 12 13 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 9: TransactionExtension9, { 0 1 2 3 4 5 6 7 8 9 }, { 10 11 12 13 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 10: TransactionExtension10, { 0 1 2 3 4 5 6 7 8 9 10 }, { 11 12 13 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 11: TransactionExtension11, { 0 1 2 3 4 5 6 7 8 9 10 11 }, { 12 13 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 12: TransactionExtension12, { 0 1 2 3 4 5 6 7 8 9 10 11 12 }, { 13 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 13: TransactionExtension13, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 }, { 14 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 14: TransactionExtension14, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 }, { 15 }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 15: TransactionExtension15, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 }, { }, { 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 16: TransactionExtension16, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 }, { }, { 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 17: TransactionExtension17, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 }, { }, { 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 18: TransactionExtension18, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 }, { }, { 19 20 21 22 23 24 25 26 27 28 29 30 31 }, + 19: TransactionExtension19, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 }, { }, { 20 21 22 23 24 25 26 27 28 29 30 31 }, + 20: TransactionExtension20, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 }, { }, { 21 22 23 24 25 26 27 28 29 30 31 }, + 21: TransactionExtension21, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 }, { }, { 22 23 24 25 26 27 28 29 30 31 }, + 22: TransactionExtension22, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 }, { }, { 23 24 25 26 27 28 29 30 31 }, + 23: TransactionExtension23, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 }, { }, { 24 25 26 27 28 29 30 31 }, + 24: TransactionExtension24, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 }, { }, { 25 26 27 28 29 30 31 }, + 25: TransactionExtension25, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 }, { }, { 26 27 28 29 30 31 }, + 26: TransactionExtension26, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 }, { }, { 27 28 29 30 31 }, + 27: TransactionExtension27, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 }, { }, { 28 29 30 31 }, + 28: TransactionExtension28, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 }, { }, { 29 30 31 }, + 29: TransactionExtension29, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 }, { }, { 30 31 }, + 30: TransactionExtension30, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 }, { }, { 31 }, + 31: TransactionExtension31, { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }, { }, { }, +); + +#[cfg(test)] +mod tests { + use super::*; + use std::cell::RefCell; + + const A_WEIGHT: Weight = Weight::from_all(3); + const A_POST_DISPATCH_WEIGHT: Weight = Weight::from_all(1); + const A_VAL: u32 = 4; + const A_PRE: u32 = 5; + const A_IMPLICIT: u64 = 6; + const A_EXPLICIT: u64 = 7; + #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] + struct TransactionExtensionA(u64); + impl TransactionExtension<()> for TransactionExtensionA { + const IDENTIFIER: &'static str = "TransactionExtensionA"; + type Implicit = u64; + fn implicit(&self) -> Result { + Ok(A_IMPLICIT) + } + type Val = u32; + type Pre = u32; + fn weight(&self, _call: &()) -> Weight { + A_WEIGHT + } + fn validate( + &self, + origin: DispatchOriginOf<()>, + _call: &(), + _info: &DispatchInfoOf<()>, + _len: usize, + self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + _source: TransactionSource, + ) -> ValidateResult { + assert_eq!(self_implicit, A_IMPLICIT); + assert_eq!(self.0, A_EXPLICIT); + Ok((ValidTransaction::default(), A_VAL, origin)) + } + fn prepare( + self, + val: Self::Val, + _origin: &DispatchOriginOf<()>, + _call: &(), + _info: &DispatchInfoOf<()>, + _len: usize, + ) -> Result { + assert_eq!(val, A_VAL); + Ok(A_PRE) + } + fn post_dispatch_details( + _pre: Self::Pre, + _info: &DispatchInfoOf<()>, + _post_info: &PostDispatchInfoOf<()>, + _len: usize, + _result: &DispatchResult, + ) -> Result { + Ok(A_POST_DISPATCH_WEIGHT) + } + } + + const B_WEIGHT: Weight = Weight::from_all(5); + const B_POST_DISPATCH_WEIGHT: Weight = Weight::from_all(2); + const B_VAL: u32 = 6; + const B_PRE: u32 = 7; + const B_IMPLICIT: u32 = 8; + const B_EXPLICIT: u32 = 9; + #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] + struct TransactionExtensionB(u32); + impl TransactionExtension<()> for TransactionExtensionB { + const IDENTIFIER: &'static str = "TransactionExtensionB"; + type Implicit = u32; + fn implicit(&self) -> Result { + Ok(B_IMPLICIT) + } + type Val = u32; + type Pre = u32; + fn weight(&self, _call: &()) -> Weight { + B_WEIGHT + } + fn validate( + &self, + origin: DispatchOriginOf<()>, + _call: &(), + _info: &DispatchInfoOf<()>, + _len: usize, + self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + _source: TransactionSource, + ) -> ValidateResult { + assert_eq!(self_implicit, B_IMPLICIT); + assert_eq!(self.0, B_EXPLICIT); + Ok((ValidTransaction::default(), B_VAL, origin)) + } + fn prepare( + self, + val: Self::Val, + _origin: &DispatchOriginOf<()>, + _call: &(), + _info: &DispatchInfoOf<()>, + _len: usize, + ) -> Result { + assert_eq!(val, B_VAL); + Ok(B_PRE) + } + fn post_dispatch_details( + _pre: Self::Pre, + _info: &DispatchInfoOf<()>, + _post_info: &PostDispatchInfoOf<()>, + _len: usize, + _result: &DispatchResult, + ) -> Result { + Ok(B_POST_DISPATCH_WEIGHT) + } + } + + thread_local! { + pub static INHERITED_IMPLICATION: RefCell> = RefCell::new(vec![]); + } + + #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] + struct TransactionExtensionCheck; + impl TransactionExtension<()> for TransactionExtensionCheck { + const IDENTIFIER: &'static str = "TransactionExtensionCheck"; + type Implicit = (); + fn implicit(&self) -> Result { + Ok(()) + } + type Val = u32; + type Pre = u32; + fn weight(&self, _call: &()) -> Weight { + Weight::zero() + } + fn validate( + &self, + origin: DispatchOriginOf<()>, + _call: &(), + _info: &DispatchInfoOf<()>, + _len: usize, + _self_implicit: Self::Implicit, + inherited_implication: &impl Encode, + _source: TransactionSource, + ) -> ValidateResult { + INHERITED_IMPLICATION.with_borrow(|i| assert_eq!(*i, inherited_implication.encode())); + Ok((ValidTransaction::default(), 0, origin)) + } + fn prepare( + self, + _val: Self::Val, + _origin: &DispatchOriginOf<()>, + _call: &(), + _info: &DispatchInfoOf<()>, + _len: usize, + ) -> Result { + Ok(0) + } + fn post_dispatch_details( + _pre: Self::Pre, + _info: &DispatchInfoOf<()>, + _post_info: &PostDispatchInfoOf<()>, + _len: usize, + _result: &DispatchResult, + ) -> Result { + Ok(Weight::zero()) + } + } + + #[test] + fn inherited_implications_at_the_end() { + let t1 = TransactionExtensionPipeline::from(( + TransactionExtensionA(A_EXPLICIT), + TransactionExtensionB(B_EXPLICIT), + TransactionExtensionCheck, + )); + + t1.validate( + (), + &(), + &(), + 0, + TransactionExtensionPipelineImplicit::from((A_IMPLICIT, B_IMPLICIT, ())), + &(), + TransactionSource::Local, + ) + .unwrap(); + } + + #[test] + fn inherited_implications_in_the_middle_1() { + INHERITED_IMPLICATION.with_borrow_mut(|i| { + *i = (B_EXPLICIT, B_IMPLICIT).encode(); + }); + + let t1 = TransactionExtensionPipeline::from(( + TransactionExtensionA(A_EXPLICIT), + TransactionExtensionCheck, + TransactionExtensionB(B_EXPLICIT), + )); + + t1.validate( + (), + &(), + &(), + 0, + TransactionExtensionPipelineImplicit::from((A_IMPLICIT, (), B_IMPLICIT)), + &(), + TransactionSource::Local, + ) + .unwrap(); + } + + #[test] + fn inherited_implications_in_the_middle_2() { + INHERITED_IMPLICATION.with_borrow_mut(|i| { + *i = (B_EXPLICIT, A_EXPLICIT, B_IMPLICIT, A_IMPLICIT).encode(); + }); + + let t2 = TransactionExtensionPipeline::from(( + TransactionExtensionA(A_EXPLICIT), + TransactionExtensionCheck, + TransactionExtensionB(B_EXPLICIT), + TransactionExtensionA(A_EXPLICIT), + )); + + t2.validate( + (), + &(), + &(), + 0, + TransactionExtensionPipelineImplicit::from((A_IMPLICIT, (), B_IMPLICIT, A_IMPLICIT)), + &(), + TransactionSource::Local, + ) + .unwrap(); + } + + #[test] + fn inherited_implications_in_the_middle_3() { + INHERITED_IMPLICATION.with_borrow_mut(|i| { + *i = ( + (B_EXPLICIT, A_EXPLICIT, B_EXPLICIT, A_EXPLICIT), + (B_EXPLICIT, A_EXPLICIT, B_EXPLICIT, A_EXPLICIT), + (B_EXPLICIT, A_EXPLICIT, B_EXPLICIT, A_EXPLICIT), + (B_EXPLICIT, A_EXPLICIT, B_EXPLICIT, A_EXPLICIT), + (B_EXPLICIT, B_EXPLICIT, B_EXPLICIT, B_EXPLICIT), + (B_IMPLICIT, A_IMPLICIT, B_IMPLICIT, A_IMPLICIT), + (B_IMPLICIT, A_IMPLICIT, B_IMPLICIT, A_IMPLICIT), + (B_IMPLICIT, A_IMPLICIT, B_IMPLICIT, A_IMPLICIT), + (B_IMPLICIT, A_IMPLICIT, B_IMPLICIT, A_IMPLICIT), + (B_IMPLICIT, B_IMPLICIT, B_IMPLICIT, B_IMPLICIT), + ) + .encode(); + }); + + let t3 = TransactionExtensionPipeline::from(( + TransactionExtensionA(A_EXPLICIT), + TransactionExtensionCheck, + TransactionExtensionB(B_EXPLICIT), + TransactionExtensionA(A_EXPLICIT), + TransactionExtensionB(B_EXPLICIT), + TransactionExtensionA(A_EXPLICIT), + TransactionExtensionB(B_EXPLICIT), + TransactionExtensionA(A_EXPLICIT), + TransactionExtensionB(B_EXPLICIT), + TransactionExtensionA(A_EXPLICIT), + TransactionExtensionB(B_EXPLICIT), + TransactionExtensionA(A_EXPLICIT), + TransactionExtensionB(B_EXPLICIT), + TransactionExtensionA(A_EXPLICIT), + TransactionExtensionB(B_EXPLICIT), + TransactionExtensionA(A_EXPLICIT), + TransactionExtensionB(B_EXPLICIT), + TransactionExtensionA(A_EXPLICIT), + TransactionExtensionB(B_EXPLICIT), + TransactionExtensionB(B_EXPLICIT), + TransactionExtensionB(B_EXPLICIT), + TransactionExtensionB(B_EXPLICIT), + )); + + t3.validate( + (), + &(), + &(), + 0, + TransactionExtensionPipelineImplicit::from(( + A_IMPLICIT, + (), + B_IMPLICIT, + A_IMPLICIT, + B_IMPLICIT, + A_IMPLICIT, + B_IMPLICIT, + A_IMPLICIT, + B_IMPLICIT, + A_IMPLICIT, + B_IMPLICIT, + A_IMPLICIT, + B_IMPLICIT, + A_IMPLICIT, + B_IMPLICIT, + A_IMPLICIT, + B_IMPLICIT, + A_IMPLICIT, + B_IMPLICIT, + B_IMPLICIT, + B_IMPLICIT, + B_IMPLICIT, + )), + &(), + TransactionSource::Local, + ) + .unwrap(); + } +} From e861c6f699f96a19286bc2224f7bcaf604304a8f Mon Sep 17 00:00:00 2001 From: gui Date: Fri, 6 Dec 2024 14:21:49 +0900 Subject: [PATCH 02/13] factorize tests --- .../src/traits/transaction_extension/mod.rs | 50 ++++ .../transaction_extension_pipeline.rs | 240 +++++++++++------- 2 files changed, 194 insertions(+), 96 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index 5f8577c8ee88..a908a4fc4dcd 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -609,6 +609,7 @@ impl TransactionExtension for Tuple { impl TransactionExtension for () { const IDENTIFIER: &'static str = "UnitTransactionExtension"; type Implicit = (); + #[inline] fn implicit(&self) -> sp_std::result::Result { Ok(()) } @@ -645,4 +646,53 @@ impl TransactionExtension for () { ) -> Result<(), TransactionValidityError> { Ok(()) } + #[inline] + fn metadata() -> Vec { + vec![] + } + #[inline] + fn post_dispatch( + _pre: Self::Pre, + _info: &DispatchInfoOf, + _post_info: &mut PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } + #[inline] + fn bare_validate( + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + Ok(ValidTransaction::default()) + } + #[inline] + fn bare_post_dispatch( + _info: &DispatchInfoOf, + _post_info: &mut PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } + #[inline] + fn post_dispatch_details( + _pre: Self::Pre, + _info: &DispatchInfoOf, + _post_info: &PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result { + Ok(Weight::zero()) + } + #[inline] + fn bare_validate_and_prepare( + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } } diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs index 9b156ce9893a..539715792352 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! The transaction extension pipeline struct. +//! The transaction extension pipeline struct, allowing to define a pipeline with many elements. use crate::{ scale_info::TypeInfo, @@ -40,6 +40,7 @@ macro_rules! declare_pipeline { ($( $num:tt: $generic:ident, { $( $basket_0:tt )* }, { $( $basket_1:tt )* }, { $( $basket_2:tt )* }, )*) => { /// A pipeline of transaction extensions. Same as a tuple of transaction extensions, but /// support up to 32 elements. + // NOTE: To extend beyond 32 elements we need to get rid of `push_back` usage. #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] pub struct TransactionExtensionPipeline< $( $generic = (), )* @@ -275,25 +276,30 @@ declare_pipeline!( mod tests { use super::*; use std::cell::RefCell; + use crate::transaction_validity::InvalidTransaction; - const A_WEIGHT: Weight = Weight::from_all(3); - const A_POST_DISPATCH_WEIGHT: Weight = Weight::from_all(1); - const A_VAL: u32 = 4; - const A_PRE: u32 = 5; - const A_IMPLICIT: u64 = 6; - const A_EXPLICIT: u64 = 7; #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] - struct TransactionExtensionA(u64); - impl TransactionExtension<()> for TransactionExtensionA { - const IDENTIFIER: &'static str = "TransactionExtensionA"; - type Implicit = u64; + struct TransactionExtensionN(u32); + + impl + TransactionExtensionN + { + fn new(explicit: u32) -> Self { + Self(explicit) + } + } + impl + TransactionExtension<()> for TransactionExtensionN + { + const IDENTIFIER: &'static str = "TransactionExtensionN"; + type Implicit = u32; fn implicit(&self) -> Result { - Ok(A_IMPLICIT) + Ok(IMPLICIT) } type Val = u32; type Pre = u32; fn weight(&self, _call: &()) -> Weight { - A_WEIGHT + WEIGHT.into() } fn validate( &self, @@ -305,9 +311,8 @@ mod tests { _inherited_implication: &impl Encode, _source: TransactionSource, ) -> ValidateResult { - assert_eq!(self_implicit, A_IMPLICIT); - assert_eq!(self.0, A_EXPLICIT); - Ok((ValidTransaction::default(), A_VAL, origin)) + assert_eq!(self_implicit, IMPLICIT); + Ok((ValidTransaction::default(), VAL, origin)) } fn prepare( self, @@ -317,8 +322,8 @@ mod tests { _info: &DispatchInfoOf<()>, _len: usize, ) -> Result { - assert_eq!(val, A_VAL); - Ok(A_PRE) + assert_eq!(val, VAL); + Ok(PRE) } fn post_dispatch_details( _pre: Self::Pre, @@ -327,65 +332,68 @@ mod tests { _len: usize, _result: &DispatchResult, ) -> Result { - Ok(A_POST_DISPATCH_WEIGHT) - } - } - - const B_WEIGHT: Weight = Weight::from_all(5); - const B_POST_DISPATCH_WEIGHT: Weight = Weight::from_all(2); - const B_VAL: u32 = 6; - const B_PRE: u32 = 7; - const B_IMPLICIT: u32 = 8; - const B_EXPLICIT: u32 = 9; - #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] - struct TransactionExtensionB(u32); - impl TransactionExtension<()> for TransactionExtensionB { - const IDENTIFIER: &'static str = "TransactionExtensionB"; - type Implicit = u32; - fn implicit(&self) -> Result { - Ok(B_IMPLICIT) - } - type Val = u32; - type Pre = u32; - fn weight(&self, _call: &()) -> Weight { - B_WEIGHT + Ok(POST_DISPATCH_WEIGHT.into()) } - fn validate( - &self, - origin: DispatchOriginOf<()>, - _call: &(), - _info: &DispatchInfoOf<()>, - _len: usize, - self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - _source: TransactionSource, - ) -> ValidateResult { - assert_eq!(self_implicit, B_IMPLICIT); - assert_eq!(self.0, B_EXPLICIT); - Ok((ValidTransaction::default(), B_VAL, origin)) + fn bare_validate(_call: &(), _info: &DispatchInfoOf<()>, _len: usize) -> TransactionValidity { + if BARE_VALIDATE { + Ok(ValidTransaction::default()) + } else { + Err(InvalidTransaction::Custom(0).into()) + } } - fn prepare( - self, - val: Self::Val, - _origin: &DispatchOriginOf<()>, - _call: &(), - _info: &DispatchInfoOf<()>, - _len: usize, - ) -> Result { - assert_eq!(val, B_VAL); - Ok(B_PRE) + fn bare_validate_and_prepare(_call: &(), _info: &DispatchInfoOf<()>, _len: usize) -> Result<(), TransactionValidityError> { + if BARE_VALIDATE { + Ok(()) + } else { + Err(InvalidTransaction::Custom(0).into()) + } } - fn post_dispatch_details( - _pre: Self::Pre, + fn bare_post_dispatch( _info: &DispatchInfoOf<()>, - _post_info: &PostDispatchInfoOf<()>, + _post_info: &mut PostDispatchInfoOf<()>, _len: usize, _result: &DispatchResult, - ) -> Result { - Ok(B_POST_DISPATCH_WEIGHT) + ) -> Result<(), TransactionValidityError> { + if BARE_POST_DISPATCH { + Ok(()) + } else { + Err(InvalidTransaction::Custom(0).into()) + } } } + #[test] + fn test_bare() { + type T1 = TransactionExtensionN<0, 0, 0, 0, 0, true, true>; + type T2 = TransactionExtensionN<0, 0, 0, 0, 0, false, false>; + + type P1 = TransactionExtensionPipeline; + P1::bare_validate_and_prepare(&(), &(), 0).expect("success"); + P1::bare_validate(&(), &(), 0).expect("success"); + P1::bare_post_dispatch(&(), &mut (), 0, &Ok(())).expect("success"); + + type P2 = TransactionExtensionPipeline; + assert_eq!(P2::bare_validate_and_prepare(&(), &(), 0).unwrap_err(), InvalidTransaction::Custom(0).into()); + assert_eq!(P2::bare_validate(&(), &(), 0).unwrap_err(), InvalidTransaction::Custom(0).into()); + assert_eq!(P2::bare_post_dispatch(&(), &mut (), 0, &Ok(())).unwrap_err(), InvalidTransaction::Custom(0).into()); + } + + const A_WEIGHT: u64 = 3; + const A_POST_DISPATCH_WEIGHT: u64 = 1; + const A_VAL: u32 = 4; + const A_PRE: u32 = 5; + const A_IMPLICIT: u32 = 6; + const A_EXPLICIT: u32 = 7; + type TransactionExtensionA = TransactionExtensionN; + + const B_WEIGHT: u64 = 5; + const B_POST_DISPATCH_WEIGHT: u64 = 2; + const B_VAL: u32 = 6; + const B_PRE: u32 = 7; + const B_IMPLICIT: u32 = 8; + const B_EXPLICIT: u32 = 9; + type TransactionExtensionB = TransactionExtensionN; + thread_local! { pub static INHERITED_IMPLICATION: RefCell> = RefCell::new(vec![]); } @@ -440,8 +448,8 @@ mod tests { #[test] fn inherited_implications_at_the_end() { let t1 = TransactionExtensionPipeline::from(( - TransactionExtensionA(A_EXPLICIT), - TransactionExtensionB(B_EXPLICIT), + TransactionExtensionA::new(A_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), TransactionExtensionCheck, )); @@ -464,9 +472,9 @@ mod tests { }); let t1 = TransactionExtensionPipeline::from(( - TransactionExtensionA(A_EXPLICIT), + TransactionExtensionA::new(A_EXPLICIT), TransactionExtensionCheck, - TransactionExtensionB(B_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), )); t1.validate( @@ -488,10 +496,10 @@ mod tests { }); let t2 = TransactionExtensionPipeline::from(( - TransactionExtensionA(A_EXPLICIT), + TransactionExtensionA::new(A_EXPLICIT), TransactionExtensionCheck, - TransactionExtensionB(B_EXPLICIT), - TransactionExtensionA(A_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), + TransactionExtensionA::new(A_EXPLICIT), )); t2.validate( @@ -525,28 +533,28 @@ mod tests { }); let t3 = TransactionExtensionPipeline::from(( - TransactionExtensionA(A_EXPLICIT), + TransactionExtensionA::new(A_EXPLICIT), TransactionExtensionCheck, - TransactionExtensionB(B_EXPLICIT), - TransactionExtensionA(A_EXPLICIT), - TransactionExtensionB(B_EXPLICIT), - TransactionExtensionA(A_EXPLICIT), - TransactionExtensionB(B_EXPLICIT), - TransactionExtensionA(A_EXPLICIT), - TransactionExtensionB(B_EXPLICIT), - TransactionExtensionA(A_EXPLICIT), - TransactionExtensionB(B_EXPLICIT), - TransactionExtensionA(A_EXPLICIT), - TransactionExtensionB(B_EXPLICIT), - TransactionExtensionA(A_EXPLICIT), - TransactionExtensionB(B_EXPLICIT), - TransactionExtensionA(A_EXPLICIT), - TransactionExtensionB(B_EXPLICIT), - TransactionExtensionA(A_EXPLICIT), - TransactionExtensionB(B_EXPLICIT), - TransactionExtensionB(B_EXPLICIT), - TransactionExtensionB(B_EXPLICIT), - TransactionExtensionB(B_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), + TransactionExtensionA::new(A_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), + TransactionExtensionA::new(A_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), + TransactionExtensionA::new(A_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), + TransactionExtensionA::new(A_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), + TransactionExtensionA::new(A_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), + TransactionExtensionA::new(A_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), + TransactionExtensionA::new(A_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), + TransactionExtensionA::new(A_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), )); t3.validate( @@ -583,4 +591,44 @@ mod tests { ) .unwrap(); } + + #[test] + fn full_test() { + type Pipeline = TransactionExtensionPipeline; + let p = Pipeline::from(( + TransactionExtensionA::new(A_EXPLICIT), + TransactionExtensionB::new(B_EXPLICIT), + )); + + let weight = p.weight(&()); + + assert_eq!(weight, (A_WEIGHT + B_WEIGHT).into()); + + let implicit = p.implicit().unwrap(); + + assert_eq!(implicit, (A_IMPLICIT, B_IMPLICIT).into()); + + let val = p.validate( + (), + &(), + &(), + 0, + TransactionExtensionPipelineImplicit::from((A_IMPLICIT, B_IMPLICIT)), + &(), + TransactionSource::Local, + ) + .unwrap(); + + assert_eq!(val.1.0, A_VAL); + assert_eq!(val.1.1, B_VAL); + + let pre = p.prepare(val.1, &(), &(), &(), 0).unwrap(); + + assert_eq!(pre.0, A_PRE); + assert_eq!(pre.1, B_PRE); + + let details = Pipeline::post_dispatch_details(pre, &(), &mut (), 0, &Ok(())).unwrap(); + + assert_eq!(details, (A_POST_DISPATCH_WEIGHT + B_POST_DISPATCH_WEIGHT).into()); + } } From 320ac119bdbf2a70ea930c46ab9e03d1f3da64fa Mon Sep 17 00:00:00 2001 From: gui Date: Fri, 6 Dec 2024 20:09:50 +0900 Subject: [PATCH 03/13] fmt tests --- .../transaction_extension_pipeline.rs | 134 ++++++++++++++---- 1 file changed, 104 insertions(+), 30 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs index 539715792352..27ef4d49bb0c 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs @@ -275,21 +275,61 @@ declare_pipeline!( #[cfg(test)] mod tests { use super::*; - use std::cell::RefCell; use crate::transaction_validity::InvalidTransaction; + use std::cell::RefCell; #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] - struct TransactionExtensionN(u32); - - impl - TransactionExtensionN - { - fn new(explicit: u32) -> Self { - Self(explicit) - } + struct TransactionExtensionN< + const WEIGHT: u64, + const POST_DISPATCH_WEIGHT: u64, + const VAL: u32, + const PRE: u32, + const IMPLICIT: u32, + const BARE_VALIDATE: bool, + const BARE_POST_DISPATCH: bool, + >(u32); + + impl< + const WEIGHT: u64, + const POST_DISPATCH_WEIGHT: u64, + const VAL: u32, + const PRE: u32, + const IMPLICIT: u32, + const BARE_VALIDATE: bool, + const BARE_POST_DISPATCH: bool, + > + TransactionExtensionN< + WEIGHT, + POST_DISPATCH_WEIGHT, + VAL, + PRE, + IMPLICIT, + BARE_VALIDATE, + BARE_POST_DISPATCH, + > + { + fn new(explicit: u32) -> Self { + Self(explicit) } - impl - TransactionExtension<()> for TransactionExtensionN + } + impl< + const WEIGHT: u64, + const POST_DISPATCH_WEIGHT: u64, + const VAL: u32, + const PRE: u32, + const IMPLICIT: u32, + const BARE_VALIDATE: bool, + const BARE_POST_DISPATCH: bool, + > TransactionExtension<()> + for TransactionExtensionN< + WEIGHT, + POST_DISPATCH_WEIGHT, + VAL, + PRE, + IMPLICIT, + BARE_VALIDATE, + BARE_POST_DISPATCH, + > { const IDENTIFIER: &'static str = "TransactionExtensionN"; type Implicit = u32; @@ -334,14 +374,22 @@ mod tests { ) -> Result { Ok(POST_DISPATCH_WEIGHT.into()) } - fn bare_validate(_call: &(), _info: &DispatchInfoOf<()>, _len: usize) -> TransactionValidity { + fn bare_validate( + _call: &(), + _info: &DispatchInfoOf<()>, + _len: usize, + ) -> TransactionValidity { if BARE_VALIDATE { Ok(ValidTransaction::default()) } else { Err(InvalidTransaction::Custom(0).into()) } } - fn bare_validate_and_prepare(_call: &(), _info: &DispatchInfoOf<()>, _len: usize) -> Result<(), TransactionValidityError> { + fn bare_validate_and_prepare( + _call: &(), + _info: &DispatchInfoOf<()>, + _len: usize, + ) -> Result<(), TransactionValidityError> { if BARE_VALIDATE { Ok(()) } else { @@ -373,9 +421,18 @@ mod tests { P1::bare_post_dispatch(&(), &mut (), 0, &Ok(())).expect("success"); type P2 = TransactionExtensionPipeline; - assert_eq!(P2::bare_validate_and_prepare(&(), &(), 0).unwrap_err(), InvalidTransaction::Custom(0).into()); - assert_eq!(P2::bare_validate(&(), &(), 0).unwrap_err(), InvalidTransaction::Custom(0).into()); - assert_eq!(P2::bare_post_dispatch(&(), &mut (), 0, &Ok(())).unwrap_err(), InvalidTransaction::Custom(0).into()); + assert_eq!( + P2::bare_validate_and_prepare(&(), &(), 0).unwrap_err(), + InvalidTransaction::Custom(0).into() + ); + assert_eq!( + P2::bare_validate(&(), &(), 0).unwrap_err(), + InvalidTransaction::Custom(0).into() + ); + assert_eq!( + P2::bare_post_dispatch(&(), &mut (), 0, &Ok(())).unwrap_err(), + InvalidTransaction::Custom(0).into() + ); } const A_WEIGHT: u64 = 3; @@ -384,7 +441,15 @@ mod tests { const A_PRE: u32 = 5; const A_IMPLICIT: u32 = 6; const A_EXPLICIT: u32 = 7; - type TransactionExtensionA = TransactionExtensionN; + type TransactionExtensionA = TransactionExtensionN< + A_WEIGHT, + A_POST_DISPATCH_WEIGHT, + A_VAL, + A_PRE, + A_IMPLICIT, + true, + true, + >; const B_WEIGHT: u64 = 5; const B_POST_DISPATCH_WEIGHT: u64 = 2; @@ -392,7 +457,15 @@ mod tests { const B_PRE: u32 = 7; const B_IMPLICIT: u32 = 8; const B_EXPLICIT: u32 = 9; - type TransactionExtensionB = TransactionExtensionN; + type TransactionExtensionB = TransactionExtensionN< + B_WEIGHT, + B_POST_DISPATCH_WEIGHT, + B_VAL, + B_PRE, + B_IMPLICIT, + true, + true, + >; thread_local! { pub static INHERITED_IMPLICATION: RefCell> = RefCell::new(vec![]); @@ -608,19 +681,20 @@ mod tests { assert_eq!(implicit, (A_IMPLICIT, B_IMPLICIT).into()); - let val = p.validate( - (), - &(), - &(), - 0, - TransactionExtensionPipelineImplicit::from((A_IMPLICIT, B_IMPLICIT)), - &(), - TransactionSource::Local, - ) - .unwrap(); + let val = p + .validate( + (), + &(), + &(), + 0, + TransactionExtensionPipelineImplicit::from((A_IMPLICIT, B_IMPLICIT)), + &(), + TransactionSource::Local, + ) + .unwrap(); - assert_eq!(val.1.0, A_VAL); - assert_eq!(val.1.1, B_VAL); + assert_eq!(val.1 .0, A_VAL); + assert_eq!(val.1 .1, B_VAL); let pre = p.prepare(val.1, &(), &(), &(), 0).unwrap(); From f1968a3712b50f0a22f082fb16b994da56c76300 Mon Sep 17 00:00:00 2001 From: gui Date: Fri, 6 Dec 2024 20:20:49 +0900 Subject: [PATCH 04/13] refactor --- .../transaction_extension/transaction_extension_pipeline.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs index 27ef4d49bb0c..08d47517812d 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs @@ -666,7 +666,7 @@ mod tests { } #[test] - fn full_test() { + fn general_tx_test() { type Pipeline = TransactionExtensionPipeline; let p = Pipeline::from(( TransactionExtensionA::new(A_EXPLICIT), @@ -701,7 +701,7 @@ mod tests { assert_eq!(pre.0, A_PRE); assert_eq!(pre.1, B_PRE); - let details = Pipeline::post_dispatch_details(pre, &(), &mut (), 0, &Ok(())).unwrap(); + let details = Pipeline::post_dispatch_details(pre, &(), &(), 0, &Ok(())).unwrap(); assert_eq!(details, (A_POST_DISPATCH_WEIGHT + B_POST_DISPATCH_WEIGHT).into()); } From a621615ce7eb239150a30ea31a0df2fbf0b4ccf3 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 6 Dec 2024 11:31:00 +0000 Subject: [PATCH 05/13] Update from gui1117 running command 'prdoc' --- prdoc/pr_6571.prdoc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 prdoc/pr_6571.prdoc diff --git a/prdoc/pr_6571.prdoc b/prdoc/pr_6571.prdoc new file mode 100644 index 000000000000..f5920218c5aa --- /dev/null +++ b/prdoc/pr_6571.prdoc @@ -0,0 +1,17 @@ +title: '[draft] Introduce `TransactionExtensionPipeline` to use instead of tuple for + pipeline with more than 12 elements' +doc: +- audience: Todo + description: |- + Fix https://github.com/paritytech/polkadot-sdk/issues/6569 + + Introduce a new type `TransactionExtensionPipeline` that has 32 generics that default to `()`. + This type accepts up to 32 transaction extensions which is better than the limit of 12 for a tuple. + + As stated in the linked issue, the issue with tuple is that tuple of tuple is not the same as a single tuple. The inherited implication is changing. But it is impossible to find out the order in the metadata because the metadata is just a vec of transaction extension metadata. + + TODO: + * additional test for weights. +crates: +- name: sp-runtime + bump: major From 281a226d2a2dcb397ae33d4648f887275b89d2bb Mon Sep 17 00:00:00 2001 From: gui Date: Fri, 6 Dec 2024 20:32:29 +0900 Subject: [PATCH 06/13] prdoc --- prdoc/pr_6571.prdoc | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/prdoc/pr_6571.prdoc b/prdoc/pr_6571.prdoc index f5920218c5aa..524c5199c7cf 100644 --- a/prdoc/pr_6571.prdoc +++ b/prdoc/pr_6571.prdoc @@ -1,17 +1,11 @@ -title: '[draft] Introduce `TransactionExtensionPipeline` to use instead of tuple for - pipeline with more than 12 elements' +title: 'Introduce `TransactionExtensionPipeline` to use instead of tuple for pipeline with more than 12 elements' doc: - audience: Todo description: |- - Fix https://github.com/paritytech/polkadot-sdk/issues/6569 - Introduce a new type `TransactionExtensionPipeline` that has 32 generics that default to `()`. - This type accepts up to 32 transaction extensions which is better than the limit of 12 for a tuple. - - As stated in the linked issue, the issue with tuple is that tuple of tuple is not the same as a single tuple. The inherited implication is changing. But it is impossible to find out the order in the metadata because the metadata is just a vec of transaction extension metadata. + This type accepts up to 32 transaction extensions. It can be used in place of tuple which is + limited to 12 transaction extensions. - TODO: - * additional test for weights. crates: - name: sp-runtime - bump: major + bump: minor From 56854f751b57958f2a4a51aef003cabcc946f85e Mon Sep 17 00:00:00 2001 From: gui Date: Fri, 6 Dec 2024 21:00:25 +0900 Subject: [PATCH 07/13] tests for post_dispatch and bare_post_dispatch weights --- .../transaction_extension_pipeline.rs | 147 +++++++++++------- 1 file changed, 95 insertions(+), 52 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs index 08d47517812d..9dacaf41a090 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs @@ -275,9 +275,48 @@ declare_pipeline!( #[cfg(test)] mod tests { use super::*; - use crate::transaction_validity::InvalidTransaction; + use crate::{ + traits::{ExtensionPostDispatchWeightHandler, Printable, RefundWeight}, + transaction_validity::InvalidTransaction, + }; use std::cell::RefCell; + struct MockCall; + + #[derive(Eq, PartialEq, Clone, Copy, Encode, Decode)] + struct MockPostInfo(sp_weights::Weight); + + impl Printable for MockPostInfo { + fn print(&self) { + self.0.print(); + } + } + + impl ExtensionPostDispatchWeightHandler<()> for MockPostInfo { + fn set_extension_weight(&mut self, _info: &()) { + unimplemented!(); + } + } + + impl RefundWeight for MockPostInfo { + fn refund(&mut self, weight: sp_weights::Weight) { + self.0 = self.0.saturating_sub(weight); + } + } + + impl Dispatchable for MockCall { + type RuntimeOrigin = (); + type Config = (); + type Info = (); + type PostInfo = MockPostInfo; + fn dispatch( + self, + _origin: Self::RuntimeOrigin, + ) -> crate::DispatchResultWithInfo { + panic!("This implementation should not be used for actual dispatch."); + } + } + #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] struct TransactionExtensionN< const WEIGHT: u64, @@ -312,6 +351,7 @@ mod tests { Self(explicit) } } + impl< const WEIGHT: u64, const POST_DISPATCH_WEIGHT: u64, @@ -320,7 +360,7 @@ mod tests { const IMPLICIT: u32, const BARE_VALIDATE: bool, const BARE_POST_DISPATCH: bool, - > TransactionExtension<()> + > TransactionExtension for TransactionExtensionN< WEIGHT, POST_DISPATCH_WEIGHT, @@ -338,14 +378,14 @@ mod tests { } type Val = u32; type Pre = u32; - fn weight(&self, _call: &()) -> Weight { + fn weight(&self, _call: &MockCall) -> Weight { WEIGHT.into() } fn validate( &self, - origin: DispatchOriginOf<()>, - _call: &(), - _info: &DispatchInfoOf<()>, + origin: (), + _call: &MockCall, + _info: &(), _len: usize, self_implicit: Self::Implicit, _inherited_implication: &impl Encode, @@ -357,9 +397,9 @@ mod tests { fn prepare( self, val: Self::Val, - _origin: &DispatchOriginOf<()>, - _call: &(), - _info: &DispatchInfoOf<()>, + _origin: &(), + _call: &MockCall, + _info: &(), _len: usize, ) -> Result { assert_eq!(val, VAL); @@ -367,18 +407,14 @@ mod tests { } fn post_dispatch_details( _pre: Self::Pre, - _info: &DispatchInfoOf<()>, - _post_info: &PostDispatchInfoOf<()>, + _info: &(), + _post_info: &MockPostInfo, _len: usize, _result: &DispatchResult, ) -> Result { Ok(POST_DISPATCH_WEIGHT.into()) } - fn bare_validate( - _call: &(), - _info: &DispatchInfoOf<()>, - _len: usize, - ) -> TransactionValidity { + fn bare_validate(_call: &MockCall, _info: &(), _len: usize) -> TransactionValidity { if BARE_VALIDATE { Ok(ValidTransaction::default()) } else { @@ -386,8 +422,8 @@ mod tests { } } fn bare_validate_and_prepare( - _call: &(), - _info: &DispatchInfoOf<()>, + _call: &MockCall, + _info: &(), _len: usize, ) -> Result<(), TransactionValidityError> { if BARE_VALIDATE { @@ -397,12 +433,13 @@ mod tests { } } fn bare_post_dispatch( - _info: &DispatchInfoOf<()>, - _post_info: &mut PostDispatchInfoOf<()>, + _info: &(), + post_info: &mut MockPostInfo, _len: usize, _result: &DispatchResult, ) -> Result<(), TransactionValidityError> { if BARE_POST_DISPATCH { + post_info.refund(POST_DISPATCH_WEIGHT.into()); Ok(()) } else { Err(InvalidTransaction::Custom(0).into()) @@ -412,27 +449,32 @@ mod tests { #[test] fn test_bare() { - type T1 = TransactionExtensionN<0, 0, 0, 0, 0, true, true>; + type T1 = TransactionExtensionN<0, 1, 0, 0, 0, true, true>; + type T1Bis = TransactionExtensionN<0, 2, 0, 0, 0, true, true>; type T2 = TransactionExtensionN<0, 0, 0, 0, 0, false, false>; - type P1 = TransactionExtensionPipeline; - P1::bare_validate_and_prepare(&(), &(), 0).expect("success"); - P1::bare_validate(&(), &(), 0).expect("success"); - P1::bare_post_dispatch(&(), &mut (), 0, &Ok(())).expect("success"); + type P1 = TransactionExtensionPipeline; + P1::bare_validate_and_prepare(&MockCall, &(), 0).expect("success"); + P1::bare_validate(&MockCall, &(), 0).expect("success"); + let mut post_info = MockPostInfo(100.into()); + P1::bare_post_dispatch(&(), &mut post_info, 0, &Ok(())).expect("success"); + assert_eq!(post_info.0, (100 - 1 - 2 - 1).into()); - type P2 = TransactionExtensionPipeline; + type P2 = TransactionExtensionPipeline; assert_eq!( - P2::bare_validate_and_prepare(&(), &(), 0).unwrap_err(), + P2::bare_validate_and_prepare(&MockCall, &(), 0).unwrap_err(), InvalidTransaction::Custom(0).into() ); assert_eq!( - P2::bare_validate(&(), &(), 0).unwrap_err(), + P2::bare_validate(&MockCall, &(), 0).unwrap_err(), InvalidTransaction::Custom(0).into() ); + let mut post_info = MockPostInfo(100.into()); assert_eq!( - P2::bare_post_dispatch(&(), &mut (), 0, &Ok(())).unwrap_err(), + P2::bare_post_dispatch(&(), &mut post_info, 0, &Ok(())).unwrap_err(), InvalidTransaction::Custom(0).into() ); + assert_eq!(post_info.0, (100 - 1 - 2).into()); } const A_WEIGHT: u64 = 3; @@ -473,7 +515,7 @@ mod tests { #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] struct TransactionExtensionCheck; - impl TransactionExtension<()> for TransactionExtensionCheck { + impl TransactionExtension for TransactionExtensionCheck { const IDENTIFIER: &'static str = "TransactionExtensionCheck"; type Implicit = (); fn implicit(&self) -> Result { @@ -481,14 +523,14 @@ mod tests { } type Val = u32; type Pre = u32; - fn weight(&self, _call: &()) -> Weight { + fn weight(&self, _call: &MockCall) -> Weight { Weight::zero() } fn validate( &self, - origin: DispatchOriginOf<()>, - _call: &(), - _info: &DispatchInfoOf<()>, + origin: (), + _call: &MockCall, + _info: &(), _len: usize, _self_implicit: Self::Implicit, inherited_implication: &impl Encode, @@ -500,17 +542,17 @@ mod tests { fn prepare( self, _val: Self::Val, - _origin: &DispatchOriginOf<()>, - _call: &(), - _info: &DispatchInfoOf<()>, + _origin: &(), + _call: &MockCall, + _info: &(), _len: usize, ) -> Result { Ok(0) } fn post_dispatch_details( _pre: Self::Pre, - _info: &DispatchInfoOf<()>, - _post_info: &PostDispatchInfoOf<()>, + _info: &(), + _post_info: &MockPostInfo, _len: usize, _result: &DispatchResult, ) -> Result { @@ -528,7 +570,7 @@ mod tests { t1.validate( (), - &(), + &MockCall, &(), 0, TransactionExtensionPipelineImplicit::from((A_IMPLICIT, B_IMPLICIT, ())), @@ -552,7 +594,7 @@ mod tests { t1.validate( (), - &(), + &MockCall, &(), 0, TransactionExtensionPipelineImplicit::from((A_IMPLICIT, (), B_IMPLICIT)), @@ -577,7 +619,7 @@ mod tests { t2.validate( (), - &(), + &MockCall, &(), 0, TransactionExtensionPipelineImplicit::from((A_IMPLICIT, (), B_IMPLICIT, A_IMPLICIT)), @@ -632,7 +674,7 @@ mod tests { t3.validate( (), - &(), + &MockCall, &(), 0, TransactionExtensionPipelineImplicit::from(( @@ -673,18 +715,16 @@ mod tests { TransactionExtensionB::new(B_EXPLICIT), )); - let weight = p.weight(&()); - + let weight = p.weight(&MockCall); assert_eq!(weight, (A_WEIGHT + B_WEIGHT).into()); let implicit = p.implicit().unwrap(); - assert_eq!(implicit, (A_IMPLICIT, B_IMPLICIT).into()); let val = p .validate( (), - &(), + &MockCall, &(), 0, TransactionExtensionPipelineImplicit::from((A_IMPLICIT, B_IMPLICIT)), @@ -692,17 +732,20 @@ mod tests { TransactionSource::Local, ) .unwrap(); - assert_eq!(val.1 .0, A_VAL); assert_eq!(val.1 .1, B_VAL); - let pre = p.prepare(val.1, &(), &(), &(), 0).unwrap(); - + let pre = p.prepare(val.1, &(), &MockCall, &(), 0).unwrap(); assert_eq!(pre.0, A_PRE); assert_eq!(pre.1, B_PRE); - let details = Pipeline::post_dispatch_details(pre, &(), &(), 0, &Ok(())).unwrap(); - + let details = + Pipeline::post_dispatch_details(pre, &(), &MockPostInfo(100.into()), 0, &Ok(())) + .unwrap(); assert_eq!(details, (A_POST_DISPATCH_WEIGHT + B_POST_DISPATCH_WEIGHT).into()); + + let mut post_info = MockPostInfo(100.into()); + Pipeline::post_dispatch(pre, &(), &mut post_info, 0, &Ok(())).unwrap(); + assert_eq!(post_info.0, (100 - A_POST_DISPATCH_WEIGHT - B_POST_DISPATCH_WEIGHT).into()); } } From 37942af24be0c328718c0c573ac8d2dc4d08e614 Mon Sep 17 00:00:00 2001 From: gui Date: Fri, 6 Dec 2024 21:04:07 +0900 Subject: [PATCH 08/13] clippy --- .../transaction_extension_pipeline.rs | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs index 9dacaf41a090..0fbe66d4abbe 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs @@ -57,8 +57,16 @@ macro_rules! declare_pipeline { fn from(e: ($( [< E $basket_0 >], )*)) -> Self { TransactionExtensionPipeline( $( e.$basket_0, )* - $( { $basket_1; () }, )* - $( { $basket_2; () }, )* + $( { + #[allow(clippy::no_effect)] + $basket_1; + () + }, )* + $( { + #[allow(clippy::no_effect)] + $basket_2; + () + }, )* ) } } @@ -82,8 +90,16 @@ macro_rules! declare_pipeline { fn from(e: ($( [< E $basket_0 >], )*)) -> Self { TransactionExtensionPipelineImplicit( $( e.$basket_0, )* - $( { $basket_1; () }, )* - $( { $basket_2; () }, )* + $( { + #[allow(clippy::no_effect)] + $basket_1; + () + }, )* + $( { + #[allow(clippy::no_effect)] + $basket_2; + () + }, )* ) } } From 89b3265b81c602d4d3f0399ba41b201f5df9c2b5 Mon Sep 17 00:00:00 2001 From: gui Date: Fri, 6 Dec 2024 21:06:25 +0900 Subject: [PATCH 09/13] prdoc --- prdoc/pr_6571.prdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prdoc/pr_6571.prdoc b/prdoc/pr_6571.prdoc index 524c5199c7cf..477aaa0d97d2 100644 --- a/prdoc/pr_6571.prdoc +++ b/prdoc/pr_6571.prdoc @@ -1,6 +1,6 @@ title: 'Introduce `TransactionExtensionPipeline` to use instead of tuple for pipeline with more than 12 elements' doc: -- audience: Todo +- audience: Runtime Dev description: |- Introduce a new type `TransactionExtensionPipeline` that has 32 generics that default to `()`. This type accepts up to 32 transaction extensions. It can be used in place of tuple which is From 1a20cea3b9ce0a80599af6204e8b828361c6eb1c Mon Sep 17 00:00:00 2001 From: gui Date: Sat, 7 Dec 2024 11:06:53 +0900 Subject: [PATCH 10/13] do not reuse () to avoid breaking change --- .../src/traits/transaction_extension/mod.rs | 54 +--------- .../transaction_extension_pipeline.rs | 101 +++++++++++++++++- 2 files changed, 99 insertions(+), 56 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index a908a4fc4dcd..76f735a1d852 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -44,7 +44,7 @@ mod transaction_extension_pipeline; pub use as_transaction_extension::AsTransactionExtension; pub use dispatch_transaction::DispatchTransaction; pub use transaction_extension_pipeline::{ - TransactionExtensionPipeline, TransactionExtensionPipelineImplicit, + TransactionExtensionPipeline, TransactionExtensionPipelineImplicit, NoTxExt, }; /// Shortcut for the result value of the `validate` function. @@ -615,11 +615,9 @@ impl TransactionExtension for () { } type Val = (); type Pre = (); - #[inline] fn weight(&self, _call: &Call) -> Weight { Weight::zero() } - #[inline] fn validate( &self, origin: ::RuntimeOrigin, @@ -635,7 +633,6 @@ impl TransactionExtension for () { > { Ok((ValidTransaction::default(), (), origin)) } - #[inline] fn prepare( self, _val: (), @@ -646,53 +643,4 @@ impl TransactionExtension for () { ) -> Result<(), TransactionValidityError> { Ok(()) } - #[inline] - fn metadata() -> Vec { - vec![] - } - #[inline] - fn post_dispatch( - _pre: Self::Pre, - _info: &DispatchInfoOf, - _post_info: &mut PostDispatchInfoOf, - _len: usize, - _result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - Ok(()) - } - #[inline] - fn bare_validate( - _call: &Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> TransactionValidity { - Ok(ValidTransaction::default()) - } - #[inline] - fn bare_post_dispatch( - _info: &DispatchInfoOf, - _post_info: &mut PostDispatchInfoOf, - _len: usize, - _result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - Ok(()) - } - #[inline] - fn post_dispatch_details( - _pre: Self::Pre, - _info: &DispatchInfoOf, - _post_info: &PostDispatchInfoOf, - _len: usize, - _result: &DispatchResult, - ) -> Result { - Ok(Weight::zero()) - } - #[inline] - fn bare_validate_and_prepare( - _call: &Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> Result<(), TransactionValidityError> { - Ok(()) - } } diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs index 0fbe66d4abbe..54f05b52e401 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs @@ -36,6 +36,101 @@ use core::fmt::Debug; use sp_weights::Weight; use tuplex::PushBack; +/// A no-op implementation of [`TransactionExtension`]. +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] +pub struct NoTxExt; + +impl TransactionExtension for NoTxExt { + const IDENTIFIER: &'static str = "NoTxExt"; + type Implicit = (); + #[inline] + fn implicit(&self) -> sp_std::result::Result { + Ok(()) + } + type Val = (); + type Pre = (); + #[inline] + fn weight(&self, _call: &Call) -> Weight { + Weight::zero() + } + #[inline] + fn validate( + &self, + origin: ::RuntimeOrigin, + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + _source: TransactionSource, + ) -> Result< + (ValidTransaction, (), ::RuntimeOrigin), + TransactionValidityError, + > { + Ok((ValidTransaction::default(), (), origin)) + } + #[inline] + fn prepare( + self, + _val: (), + _origin: &::RuntimeOrigin, + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } + #[inline] + fn metadata() -> Vec { + vec![] + } + #[inline] + fn post_dispatch( + _pre: Self::Pre, + _info: &DispatchInfoOf, + _post_info: &mut PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } + #[inline] + fn bare_validate( + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + Ok(ValidTransaction::default()) + } + #[inline] + fn bare_post_dispatch( + _info: &DispatchInfoOf, + _post_info: &mut PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } + #[inline] + fn post_dispatch_details( + _pre: Self::Pre, + _info: &DispatchInfoOf, + _post_info: &PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result { + Ok(Weight::zero()) + } + #[inline] + fn bare_validate_and_prepare( + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } +} + macro_rules! declare_pipeline { ($( $num:tt: $generic:ident, { $( $basket_0:tt )* }, { $( $basket_1:tt )* }, { $( $basket_2:tt )* }, )*) => { /// A pipeline of transaction extensions. Same as a tuple of transaction extensions, but @@ -43,7 +138,7 @@ macro_rules! declare_pipeline { // NOTE: To extend beyond 32 elements we need to get rid of `push_back` usage. #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] pub struct TransactionExtensionPipeline< - $( $generic = (), )* + $( $generic = NoTxExt, )* >( $( pub $generic, )* ); @@ -60,12 +155,12 @@ macro_rules! declare_pipeline { $( { #[allow(clippy::no_effect)] $basket_1; - () + NoTxExt }, )* $( { #[allow(clippy::no_effect)] $basket_2; - () + NoTxExt }, )* ) } From b3e450358ef74b0f9df798e65f2dbcad097d59a0 Mon Sep 17 00:00:00 2001 From: gui Date: Sat, 7 Dec 2024 17:48:22 +0900 Subject: [PATCH 11/13] add frame-support tests and also some reexport --- substrate/frame/support/src/dispatch.rs | 272 ++++++++++++++++++ .../primitives/runtime/src/traits/mod.rs | 3 +- .../src/traits/transaction_extension/mod.rs | 2 +- 3 files changed, 275 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 483a3dce77f6..362965e5ed45 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -1580,3 +1580,275 @@ mod extension_weight_tests { }); } } + +// Same tests as extension_weight_tests but using a pipeline instead of a tuple. +#[cfg(test)] +// Do not complain about unused `dispatch` and `dispatch_aux`. +#[allow(dead_code)] +mod extension_weight_tests_with_pipeline { + use crate::assert_ok; + + use super::*; + use sp_core::parameter_types; + use sp_runtime::{ + generic::{self, ExtrinsicFormat}, + traits::{ + Applyable, BlakeTwo256, DispatchTransaction, TransactionExtension, + TransactionExtensionPipeline, + }, + }; + use sp_weights::RuntimeDbWeight; + use test_extensions::{ActualWeightIs, FreeIfUnder, HalfCostIf}; + + use super::weight_tests::frame_system; + use frame_support::construct_runtime; + + pub type TxExtension = TransactionExtensionPipeline; + pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + pub type Header = generic::Header; + pub type Block = generic::Block; + pub type AccountId = u64; + pub type Balance = u32; + pub type BlockNumber = u32; + + construct_runtime!( + pub enum ExtRuntime { + System: frame_system, + } + ); + + impl frame_system::Config for ExtRuntime { + type Block = Block; + type AccountId = AccountId; + type Balance = Balance; + type BaseCallFilter = crate::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type DbWeight = DbWeight; + type PalletInfo = PalletInfo; + } + + parameter_types! { + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { + read: 100, + write: 1000, + }; + } + + pub struct ExtBuilder {} + + impl Default for ExtBuilder { + fn default() -> Self { + Self {} + } + } + + impl ExtBuilder { + pub fn build(self) -> sp_io::TestExternalities { + let mut ext = sp_io::TestExternalities::new(Default::default()); + ext.execute_with(|| {}); + ext + } + + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.build().execute_with(|| { + test(); + }) + } + } + + #[test] + fn no_post_dispatch_with_no_refund() { + ExtBuilder::default().build_and_execute(|| { + let call = RuntimeCall::System(frame_system::Call::::f99 {}); + let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(1500), ActualWeightIs(0)).into(); + let uxt = UncheckedExtrinsic::new_signed(call.clone(), 0, (), ext.clone()); + assert_eq!(uxt.extension_weight(), Weight::from_parts(600, 0)); + + let mut info = call.get_dispatch_info(); + assert_eq!(info.total_weight(), Weight::from_parts(1000, 0)); + info.extension_weight = ext.weight(&call); + let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap(); + let res = call.dispatch(Some(0).into()); + let mut post_info = res.unwrap(); + assert!(post_info.actual_weight.is_none()); + assert_ok!(>::post_dispatch( + pre, + &info, + &mut post_info, + 0, + &Ok(()), + )); + assert!(post_info.actual_weight.is_none()); + }); + } + + #[test] + fn no_post_dispatch_refunds_when_dispatched() { + ExtBuilder::default().build_and_execute(|| { + let call = RuntimeCall::System(frame_system::Call::::f99 {}); + let ext: TxExtension = (HalfCostIf(true), FreeIfUnder(100), ActualWeightIs(0)).into(); + let uxt = UncheckedExtrinsic::new_signed(call.clone(), 0, (), ext.clone()); + assert_eq!(uxt.extension_weight(), Weight::from_parts(600, 0)); + + let mut info = call.get_dispatch_info(); + assert_eq!(info.total_weight(), Weight::from_parts(1000, 0)); + info.extension_weight = ext.weight(&call); + let post_info = + ext.dispatch_transaction(Some(0).into(), call, &info, 0, 0).unwrap().unwrap(); + // 1000 call weight + 50 + 200 + 0 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1250, 0))); + }); + } + + #[test] + fn post_dispatch_with_refunds() { + ExtBuilder::default().build_and_execute(|| { + let call = RuntimeCall::System(frame_system::Call::::f100 {}); + // First testcase + let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(2000), ActualWeightIs(0)).into(); + let uxt = UncheckedExtrinsic::new_signed(call.clone(), 0, (), ext.clone()); + assert_eq!(uxt.extension_weight(), Weight::from_parts(600, 0)); + + let mut info = call.get_dispatch_info(); + assert_eq!(info.call_weight, Weight::from_parts(1000, 0)); + info.extension_weight = ext.weight(&call); + assert_eq!(info.total_weight(), Weight::from_parts(1600, 0)); + let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap(); + let res = call.clone().dispatch(Some(0).into()); + let mut post_info = res.unwrap(); + // 500 actual call weight + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0))); + // add the 600 worst case extension weight + post_info.set_extension_weight(&info); + // extension weight should be refunded + assert_ok!(>::post_dispatch( + pre, + &info, + &mut post_info, + 0, + &Ok(()), + )); + // 500 actual call weight + 100 + 0 + 0 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(600, 0))); + + // Second testcase + let ext: TxExtension = + (HalfCostIf(false), FreeIfUnder(1100), ActualWeightIs(200)).into(); + let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap(); + let res = call.clone().dispatch(Some(0).into()); + let mut post_info = res.unwrap(); + // 500 actual call weight + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0))); + // add the 600 worst case extension weight + post_info.set_extension_weight(&info); + // extension weight should be refunded + assert_ok!(>::post_dispatch( + pre, + &info, + &mut post_info, + 0, + &Ok(()), + )); + // 500 actual call weight + 100 + 200 + 200 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1000, 0))); + + // Third testcase + let ext: TxExtension = + (HalfCostIf(true), FreeIfUnder(1060), ActualWeightIs(200)).into(); + let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap(); + let res = call.clone().dispatch(Some(0).into()); + let mut post_info = res.unwrap(); + // 500 actual call weight + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0))); + // add the 600 worst case extension weight + post_info.set_extension_weight(&info); + // extension weight should be refunded + assert_ok!(>::post_dispatch( + pre, + &info, + &mut post_info, + 0, + &Ok(()), + )); + // 500 actual call weight + 50 + 0 + 200 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(750, 0))); + + // Fourth testcase + let ext: TxExtension = + (HalfCostIf(false), FreeIfUnder(100), ActualWeightIs(300)).into(); + let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap(); + let res = call.clone().dispatch(Some(0).into()); + let mut post_info = res.unwrap(); + // 500 actual call weight + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0))); + // add the 600 worst case extension weight + post_info.set_extension_weight(&info); + // extension weight should be refunded + assert_ok!(>::post_dispatch( + pre, + &info, + &mut post_info, + 0, + &Ok(()), + )); + // 500 actual call weight + 100 + 200 + 300 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1100, 0))); + }); + } + + #[test] + fn checked_extrinsic_apply() { + ExtBuilder::default().build_and_execute(|| { + let call = RuntimeCall::System(frame_system::Call::::f100 {}); + // First testcase + let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(2000), ActualWeightIs(0)).into(); + let xt = CheckedExtrinsic { + format: ExtrinsicFormat::Signed(0, ext.clone()), + function: call.clone(), + }; + assert_eq!(xt.extension_weight(), Weight::from_parts(600, 0)); + let mut info = call.get_dispatch_info(); + assert_eq!(info.call_weight, Weight::from_parts(1000, 0)); + info.extension_weight = ext.weight(&call); + assert_eq!(info.total_weight(), Weight::from_parts(1600, 0)); + let post_info = xt.apply::(&info, 0).unwrap().unwrap(); + // 500 actual call weight + 100 + 0 + 0 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(600, 0))); + + // Second testcase + let ext: TxExtension = + (HalfCostIf(false), FreeIfUnder(1100), ActualWeightIs(200)).into(); + let xt = CheckedExtrinsic { + format: ExtrinsicFormat::Signed(0, ext), + function: call.clone(), + }; + let post_info = xt.apply::(&info, 0).unwrap().unwrap(); + // 500 actual call weight + 100 + 200 + 200 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1000, 0))); + + // Third testcase + let ext: TxExtension = + (HalfCostIf(true), FreeIfUnder(1060), ActualWeightIs(200)).into(); + let xt = CheckedExtrinsic { + format: ExtrinsicFormat::Signed(0, ext), + function: call.clone(), + }; + let post_info = xt.apply::(&info, 0).unwrap().unwrap(); + // 500 actual call weight + 50 + 0 + 200 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(750, 0))); + + // Fourth testcase + let ext: TxExtension = + (HalfCostIf(false), FreeIfUnder(100), ActualWeightIs(300)).into(); + let xt = CheckedExtrinsic { + format: ExtrinsicFormat::Signed(0, ext), + function: call.clone(), + }; + let post_info = xt.apply::(&info, 0).unwrap().unwrap(); + // 500 actual call weight + 100 + 200 + 300 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1100, 0))); + }); + } +} diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs index 01bdcca86b6f..4d86250554bd 100644 --- a/substrate/primitives/runtime/src/traits/mod.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -55,7 +55,8 @@ use std::str::FromStr; pub mod transaction_extension; pub use transaction_extension::{ - DispatchTransaction, TransactionExtension, TransactionExtensionMetadata, ValidateResult, + DispatchTransaction, TransactionExtension, TransactionExtensionMetadata, + TransactionExtensionPipeline, TransactionExtensionPipelineImplicit, ValidateResult, }; /// A lazy value. diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs index 76f735a1d852..100c8c18c3dd 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -44,7 +44,7 @@ mod transaction_extension_pipeline; pub use as_transaction_extension::AsTransactionExtension; pub use dispatch_transaction::DispatchTransaction; pub use transaction_extension_pipeline::{ - TransactionExtensionPipeline, TransactionExtensionPipelineImplicit, NoTxExt, + NoTxExt, TransactionExtensionPipeline, TransactionExtensionPipelineImplicit, }; /// Shortcut for the result value of the `validate` function. From 34b606cc2a27053712119fb92114813ed23eefe3 Mon Sep 17 00:00:00 2001 From: gui Date: Sat, 7 Dec 2024 18:54:16 +0900 Subject: [PATCH 12/13] fix no std --- .../transaction_extension/transaction_extension_pipeline.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs index 54f05b52e401..fc6f50691414 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs @@ -30,7 +30,7 @@ use crate::{ }, DispatchResult, }; -use alloc::vec::Vec; +use alloc::vec::{self, Vec}; use codec::{Decode, Encode}; use core::fmt::Debug; use sp_weights::Weight; From 0174a49039a0be95ee3fa922d8eeb8a58af164ba Mon Sep 17 00:00:00 2001 From: gui Date: Sun, 8 Dec 2024 12:41:57 +0900 Subject: [PATCH 13/13] remove unused in std --- .../transaction_extension/transaction_extension_pipeline.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs index fc6f50691414..c69fddf62071 100644 --- a/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs +++ b/substrate/primitives/runtime/src/traits/transaction_extension/transaction_extension_pipeline.rs @@ -30,7 +30,7 @@ use crate::{ }, DispatchResult, }; -use alloc::vec::{self, Vec}; +use alloc::vec::Vec; use codec::{Decode, Encode}; use core::fmt::Debug; use sp_weights::Weight; @@ -82,7 +82,7 @@ impl TransactionExtension for NoTxExt { } #[inline] fn metadata() -> Vec { - vec![] + alloc::vec![] } #[inline] fn post_dispatch(