Revert "FRAME: Create TransactionExtension as a replacement for SignedExtension (#2280)" (#3665)

This PR reverts #2280 which introduced `TransactionExtension` to replace
`SignedExtension`.

As a result of the discussion
[here](https://github.com/paritytech/polkadot-sdk/pull/3623#issuecomment-1986789700),
the changes will be reverted for now with plans to reintroduce the
concept in the future.

---------

Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
This commit is contained in:
georgepisaltu
2024-03-13 16:10:59 +02:00
committed by GitHub
parent 60ac5a723c
commit bbd51ce867
350 changed files with 15826 additions and 24304 deletions
+40 -36
View File
@@ -46,10 +46,9 @@
//! use the [`Config::WeightInfo`] trait to calculate call weights. This can also be overridden,
//! as demonstrated by [`Call::set_dummy`].
//! - A private function that performs a storage update.
//! - A simple transaction extension implementation (see:
//! [`sp_runtime::traits::TransactionExtension`]) which increases the priority of the
//! [`Call::set_dummy`] if it's present and drops any transaction with an encoded length higher
//! than 200 bytes.
//! - A simple signed extension implementation (see: [`sp_runtime::traits::SignedExtension`]) which
//! increases the priority of the [`Call::set_dummy`] if it's present and drops any transaction
//! with an encoded length higher than 200 bytes.
// Ensure we're `no_std` when compiling for Wasm.
#![cfg_attr(not(feature = "std"), no_std)]
@@ -65,12 +64,10 @@ use frame_system::ensure_signed;
use log::info;
use scale_info::TypeInfo;
use sp_runtime::{
impl_tx_ext_default,
traits::{
Bounded, DispatchInfoOf, OriginOf, SaturatedConversion, Saturating, TransactionExtension,
TransactionExtensionBase, ValidateResult,
traits::{Bounded, DispatchInfoOf, SaturatedConversion, Saturating, SignedExtension},
transaction_validity::{
InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,
},
transaction_validity::{InvalidTransaction, ValidTransaction},
};
use sp_std::vec::Vec;
@@ -443,8 +440,8 @@ impl<T: Config> Pallet<T> {
// Similar to other FRAME pallets, your pallet can also define a signed extension and perform some
// checks and [pre/post]processing [before/after] the transaction. A signed extension can be any
// decodable type that implements `TransactionExtension`. See the trait definition for the full list
// of bounds. As a convention, you can follow this approach to create an extension for your pallet:
// decodable type that implements `SignedExtension`. See the trait definition for the full list of
// bounds. As a convention, you can follow this approach to create an extension for your pallet:
// - If the extension does not carry any data, then use a tuple struct with just a `marker`
// (needed for the compiler to accept `T: Config`) will suffice.
// - Otherwise, create a tuple struct which contains the external data. Of course, for the entire
@@ -458,18 +455,18 @@ impl<T: Config> Pallet<T> {
//
// Using the extension, you can add some hooks to the life cycle of each transaction. Note that by
// default, an extension is applied to all `Call` functions (i.e. all transactions). the `Call` enum
// variant is given to each function of `TransactionExtension`. Hence, you can filter based on
// pallet or a particular call if needed.
// variant is given to each function of `SignedExtension`. Hence, you can filter based on pallet or
// a particular call if needed.
//
// Some extra information, such as encoded length, some static dispatch info like weight and the
// sender of the transaction (if signed) are also provided.
//
// The full list of hooks that can be added to a signed extension can be found
// [here](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/traits/trait.TransactionExtension.html).
// [here](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/traits/trait.SignedExtension.html).
//
// The signed extensions are aggregated in the runtime file of a substrate chain. All extensions
// should be aggregated in a tuple and passed to the `CheckedExtrinsic` and `UncheckedExtrinsic`
// types defined in the runtime. Lookup `pub type TxExtension = (...)` in `node/runtime` and
// types defined in the runtime. Lookup `pub type SignedExtra = (...)` in `node/runtime` and
// `node-template` for an example of this.
/// A simple signed extension that checks for the `set_dummy` call. In that case, it increases the
@@ -487,45 +484,52 @@ impl<T: Config + Send + Sync> core::fmt::Debug for WatchDummy<T> {
}
}
impl<T: Config + Send + Sync> TransactionExtensionBase for WatchDummy<T> {
const IDENTIFIER: &'static str = "WatchDummy";
type Implicit = ();
}
impl<T: Config + Send + Sync, Context>
TransactionExtension<<T as frame_system::Config>::RuntimeCall, Context> for WatchDummy<T>
impl<T: Config + Send + Sync> SignedExtension for WatchDummy<T>
where
<T as frame_system::Config>::RuntimeCall: IsSubType<Call<T>>,
{
const IDENTIFIER: &'static str = "WatchDummy";
type AccountId = T::AccountId;
type Call = <T as frame_system::Config>::RuntimeCall;
type AdditionalSigned = ();
type Pre = ();
type Val = ();
fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> {
Ok(())
}
fn pre_dispatch(
self,
who: &Self::AccountId,
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
self.validate(who, call, info, len).map(|_| ())
}
fn validate(
&self,
origin: OriginOf<<T as frame_system::Config>::RuntimeCall>,
call: &<T as frame_system::Config>::RuntimeCall,
_info: &DispatchInfoOf<<T as frame_system::Config>::RuntimeCall>,
_who: &Self::AccountId,
call: &Self::Call,
_info: &DispatchInfoOf<Self::Call>,
len: usize,
_context: &mut Context,
_self_implicit: Self::Implicit,
_inherited_implication: &impl Encode,
) -> ValidateResult<Self::Val, <T as frame_system::Config>::RuntimeCall> {
) -> TransactionValidity {
// if the transaction is too big, just drop it.
if len > 200 {
return Err(InvalidTransaction::ExhaustsResources.into())
return InvalidTransaction::ExhaustsResources.into()
}
// check for `set_dummy`
let validity = match call.is_sub_type() {
match call.is_sub_type() {
Some(Call::set_dummy { .. }) => {
sp_runtime::print("set_dummy was received.");
let valid_tx =
ValidTransaction { priority: Bounded::max_value(), ..Default::default() };
valid_tx
Ok(valid_tx)
},
_ => Default::default(),
};
Ok((validity, (), origin))
_ => Ok(Default::default()),
}
}
impl_tx_ext_default!(<T as frame_system::Config>::RuntimeCall; Context; prepare);
}
+3 -6
View File
@@ -27,7 +27,7 @@ use sp_core::H256;
// The testing primitives are very useful for avoiding having to work with signatures
// or public keys. `u64` is used as the `AccountId` and no `Signature`s are required.
use sp_runtime::{
traits::{BlakeTwo256, DispatchTransaction, IdentityLookup},
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
};
// Reexport crate as its pallet name for construct_runtime.
@@ -158,16 +158,13 @@ fn signed_ext_watch_dummy_works() {
assert_eq!(
WatchDummy::<Test>(PhantomData)
.validate_only(Some(1).into(), &call, &info, 150)
.validate(&1, &call, &info, 150)
.unwrap()
.0
.priority,
u64::MAX,
);
assert_eq!(
WatchDummy::<Test>(PhantomData)
.validate_only(Some(1).into(), &call, &info, 250)
.unwrap_err(),
WatchDummy::<Test>(PhantomData).validate(&1, &call, &info, 250),
InvalidTransaction::ExhaustsResources.into(),
);
})
@@ -30,7 +30,7 @@ use sp_core::{
use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt};
use sp_runtime::{
generic::UncheckedExtrinsic,
testing::TestXt,
traits::{BlakeTwo256, Extrinsic as ExtrinsicT, IdentifyAccount, IdentityLookup, Verify},
RuntimeAppPublic,
};
@@ -73,7 +73,7 @@ impl frame_system::Config for Test {
type MaxConsumers = ConstU32<16>;
}
type Extrinsic = UncheckedExtrinsic<u64, RuntimeCall, (), ()>;
type Extrinsic = TestXt<RuntimeCall, ()>;
type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
impl frame_system::offchain::SigningTypes for Test {
@@ -99,7 +99,7 @@ where
_account: AccountId,
nonce: u64,
) -> Option<(RuntimeCall, <Extrinsic as ExtrinsicT>::SignaturePayload)> {
Some((call, (nonce, (), ())))
Some((call, (nonce, ())))
}
}
@@ -219,8 +219,8 @@ fn should_submit_signed_transaction_on_chain() {
let tx = pool_state.write().transactions.pop().unwrap();
assert!(pool_state.read().transactions.is_empty());
let tx = Extrinsic::decode(&mut &*tx).unwrap();
assert!(matches!(tx.preamble, sp_runtime::generic::Preamble::Signed(0, (), ())));
assert_eq!(tx.function, RuntimeCall::Example(crate::Call::submit_price { price: 15523 }));
assert_eq!(tx.signature.unwrap().0, 0);
assert_eq!(tx.call, RuntimeCall::Example(crate::Call::submit_price { price: 15523 }));
});
}
@@ -259,11 +259,11 @@ fn should_submit_unsigned_transaction_on_chain_for_any_account() {
// then
let tx = pool_state.write().transactions.pop().unwrap();
let tx = Extrinsic::decode(&mut &*tx).unwrap();
assert!(tx.is_inherent());
assert_eq!(tx.signature, None);
if let RuntimeCall::Example(crate::Call::submit_price_unsigned_with_signed_payload {
price_payload: body,
signature,
}) = tx.function
}) = tx.call
{
assert_eq!(body, price_payload);
@@ -313,11 +313,11 @@ fn should_submit_unsigned_transaction_on_chain_for_all_accounts() {
// then
let tx = pool_state.write().transactions.pop().unwrap();
let tx = Extrinsic::decode(&mut &*tx).unwrap();
assert!(tx.is_inherent());
assert_eq!(tx.signature, None);
if let RuntimeCall::Example(crate::Call::submit_price_unsigned_with_signed_payload {
price_payload: body,
signature,
}) = tx.function
}) = tx.call
{
assert_eq!(body, price_payload);
@@ -353,9 +353,9 @@ fn should_submit_raw_unsigned_transaction_on_chain() {
let tx = pool_state.write().transactions.pop().unwrap();
assert!(pool_state.read().transactions.is_empty());
let tx = Extrinsic::decode(&mut &*tx).unwrap();
assert!(tx.is_inherent());
assert_eq!(tx.signature, None);
assert_eq!(
tx.function,
tx.call,
RuntimeCall::Example(crate::Call::submit_price_unsigned {
block_number: 1,
price: 15523
+36 -42
View File
@@ -15,31 +15,30 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! Autogenerated weights for `tasks_example`
//! Autogenerated weights for `pallet_example_tasks`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2024-03-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-06-02, STEPS: `20`, REPEAT: `10`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024`
//! HOSTNAME: `MacBook.local`, CPU: `<UNKNOWN>`
//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
// Executed Command:
// ./target/production/substrate-node
// ./target/release/node-template
// benchmark
// pallet
// --chain=dev
// --steps=50
// --repeat=20
// --pallet=tasks_example
// --no-storage-info
// --no-median-slopes
// --no-min-squares
// --extrinsic=*
// --wasm-execution=compiled
// --heap-pages=4096
// --output=./substrate/frame/examples/tasks/src/weights.rs
// --header=./substrate/HEADER-APACHE2
// --template=./substrate/.maintain/frame-weight-template.hbs
// --chain
// dev
// --pallet
// pallet_example_tasks
// --extrinsic
// *
// --steps
// 20
// --repeat
// 10
// --output
// frame/examples/tasks/src/weights.rs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
@@ -49,42 +48,37 @@
use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
use core::marker::PhantomData;
/// Weight functions needed for `tasks_example`.
/// Weight functions needed for pallet_template.
pub trait WeightInfo {
fn add_number_into_total() -> Weight;
}
/// Weights for `tasks_example` using the Substrate node and recommended hardware.
/// Weight functions for `pallet_example_kitchensink`.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Storage: `TasksExample::Numbers` (r:1 w:1)
/// Proof: `TasksExample::Numbers` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `TasksExample::Total` (r:1 w:1)
/// Proof: `TasksExample::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Kitchensink OtherFoo (r:0 w:1)
/// Proof Skipped: Kitchensink OtherFoo (max_values: Some(1), max_size: None, mode: Measured)
fn add_number_into_total() -> Weight {
// Proof Size summary in bytes:
// Measured: `149`
// Estimated: `3614`
// Minimum execution time: 5_776_000 picoseconds.
Weight::from_parts(6_178_000, 3614)
.saturating_add(T::DbWeight::get().reads(2_u64))
.saturating_add(T::DbWeight::get().writes(2_u64))
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 1_000_000 picoseconds.
Weight::from_parts(1_000_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
}
// For backwards compatibility and tests.
impl WeightInfo for () {
/// Storage: `TasksExample::Numbers` (r:1 w:1)
/// Proof: `TasksExample::Numbers` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `TasksExample::Total` (r:1 w:1)
/// Proof: `TasksExample::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Kitchensink OtherFoo (r:0 w:1)
/// Proof Skipped: Kitchensink OtherFoo (max_values: Some(1), max_size: None, mode: Measured)
fn add_number_into_total() -> Weight {
// Proof Size summary in bytes:
// Measured: `149`
// Estimated: `3614`
// Minimum execution time: 5_776_000 picoseconds.
Weight::from_parts(6_178_000, 3614)
.saturating_add(RocksDbWeight::get().reads(2_u64))
.saturating_add(RocksDbWeight::get().writes(2_u64))
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 1_000_000 picoseconds.
Weight::from_parts(1_000_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(RocksDbWeight::get().writes(1))
}
}