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
@@ -15,19 +15,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{AccountInfo, Config};
use crate::Config;
use codec::{Decode, Encode};
use frame_support::dispatch::DispatchInfo;
use scale_info::TypeInfo;
use sp_runtime::{
traits::{
AsSystemOriginSigner, DispatchInfoOf, Dispatchable, One, TransactionExtension,
TransactionExtensionBase, ValidateResult, Zero,
},
traits::{DispatchInfoOf, Dispatchable, One, SignedExtension, Zero},
transaction_validity::{
InvalidTransaction, TransactionLongevity, TransactionValidityError, ValidTransaction,
InvalidTransaction, TransactionLongevity, TransactionValidity, TransactionValidityError,
ValidTransaction,
},
Saturating,
};
use sp_std::vec;
@@ -61,78 +58,75 @@ impl<T: Config> sp_std::fmt::Debug for CheckNonce<T> {
}
}
impl<T: Config> TransactionExtensionBase for CheckNonce<T> {
const IDENTIFIER: &'static str = "CheckNonce";
type Implicit = ();
fn weight(&self) -> sp_weights::Weight {
<T::ExtensionsWeightInfo as super::WeightInfo>::check_nonce()
}
}
impl<T: Config, Context> TransactionExtension<T::RuntimeCall, Context> for CheckNonce<T>
impl<T: Config> SignedExtension for CheckNonce<T>
where
T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
<T::RuntimeCall as Dispatchable>::RuntimeOrigin: AsSystemOriginSigner<T::AccountId> + Clone,
{
type Val = Option<(T::AccountId, AccountInfo<T::Nonce, T::AccountData>)>;
type AccountId = T::AccountId;
type Call = T::RuntimeCall;
type AdditionalSigned = ();
type Pre = ();
const IDENTIFIER: &'static str = "CheckNonce";
fn validate(
&self,
origin: <T as Config>::RuntimeOrigin,
_call: &T::RuntimeCall,
_info: &DispatchInfoOf<T::RuntimeCall>,
fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {
Ok(())
}
fn pre_dispatch(
self,
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::RuntimeCall> {
let Some(who) = origin.as_system_origin_signer() else {
return Ok((Default::default(), None, origin))
};
let account = crate::Account::<T>::get(who);
) -> Result<(), TransactionValidityError> {
let mut account = crate::Account::<T>::get(who);
if account.providers.is_zero() && account.sufficients.is_zero() {
// Nonce storage not paid for
return Err(InvalidTransaction::Payment.into())
}
if self.0 != account.nonce {
return Err(if self.0 < account.nonce {
InvalidTransaction::Stale
} else {
InvalidTransaction::Future
}
.into())
}
account.nonce += T::Nonce::one();
crate::Account::<T>::insert(who, account);
Ok(())
}
fn validate(
&self,
who: &Self::AccountId,
_call: &Self::Call,
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> TransactionValidity {
let account = crate::Account::<T>::get(who);
if account.providers.is_zero() && account.sufficients.is_zero() {
// Nonce storage not paid for
return InvalidTransaction::Payment.into()
}
if self.0 < account.nonce {
return Err(InvalidTransaction::Stale.into())
return InvalidTransaction::Stale.into()
}
let provides = vec![Encode::encode(&(who.clone(), self.0))];
let provides = vec![Encode::encode(&(who, self.0))];
let requires = if account.nonce < self.0 {
vec![Encode::encode(&(who.clone(), self.0.saturating_sub(One::one())))]
vec![Encode::encode(&(who, self.0 - One::one()))]
} else {
vec![]
};
let validity = ValidTransaction {
Ok(ValidTransaction {
priority: 0,
requires,
provides,
longevity: TransactionLongevity::max_value(),
propagate: true,
};
Ok((validity, Some((who.clone(), account)), origin))
}
fn prepare(
self,
val: Self::Val,
_origin: &T::RuntimeOrigin,
_call: &T::RuntimeCall,
_info: &DispatchInfoOf<T::RuntimeCall>,
_len: usize,
_context: &Context,
) -> Result<Self::Pre, TransactionValidityError> {
let Some((who, mut account)) = val else { return Ok(()) };
// `self.0 < account.nonce` already checked in `validate`.
if self.0 > account.nonce {
return Err(InvalidTransaction::Future.into())
}
account.nonce.saturating_inc();
crate::Account::<T>::insert(who, account);
Ok(())
})
}
}
@@ -140,8 +134,7 @@ where
mod tests {
use super::*;
use crate::mock::{new_test_ext, Test, CALL};
use frame_support::assert_ok;
use sp_runtime::traits::DispatchTransaction;
use frame_support::{assert_noop, assert_ok};
#[test]
fn signed_ext_check_nonce_works() {
@@ -159,33 +152,22 @@ mod tests {
let info = DispatchInfo::default();
let len = 0_usize;
// stale
assert_eq!(
CheckNonce::<Test>(0)
.validate_only(Some(1).into(), CALL, &info, len,)
.unwrap_err(),
TransactionValidityError::Invalid(InvalidTransaction::Stale)
assert_noop!(
CheckNonce::<Test>(0).validate(&1, CALL, &info, len),
InvalidTransaction::Stale
);
assert_eq!(
CheckNonce::<Test>(0)
.validate_and_prepare(Some(1).into(), CALL, &info, len)
.unwrap_err(),
InvalidTransaction::Stale.into()
assert_noop!(
CheckNonce::<Test>(0).pre_dispatch(&1, CALL, &info, len),
InvalidTransaction::Stale
);
// correct
assert_ok!(CheckNonce::<Test>(1).validate_only(Some(1).into(), CALL, &info, len));
assert_ok!(CheckNonce::<Test>(1).validate_and_prepare(
Some(1).into(),
CALL,
&info,
len
));
assert_ok!(CheckNonce::<Test>(1).validate(&1, CALL, &info, len));
assert_ok!(CheckNonce::<Test>(1).pre_dispatch(&1, CALL, &info, len));
// future
assert_ok!(CheckNonce::<Test>(5).validate_only(Some(1).into(), CALL, &info, len));
assert_eq!(
CheckNonce::<Test>(5)
.validate_and_prepare(Some(1).into(), CALL, &info, len)
.unwrap_err(),
InvalidTransaction::Future.into()
assert_ok!(CheckNonce::<Test>(5).validate(&1, CALL, &info, len));
assert_noop!(
CheckNonce::<Test>(5).pre_dispatch(&1, CALL, &info, len),
InvalidTransaction::Future
);
})
}
@@ -216,44 +198,20 @@ mod tests {
let info = DispatchInfo::default();
let len = 0_usize;
// Both providers and sufficients zero
assert_eq!(
CheckNonce::<Test>(1)
.validate_only(Some(1).into(), CALL, &info, len)
.unwrap_err(),
TransactionValidityError::Invalid(InvalidTransaction::Payment)
assert_noop!(
CheckNonce::<Test>(1).validate(&1, CALL, &info, len),
InvalidTransaction::Payment
);
assert_eq!(
CheckNonce::<Test>(1)
.validate_and_prepare(Some(1).into(), CALL, &info, len)
.unwrap_err(),
TransactionValidityError::Invalid(InvalidTransaction::Payment)
assert_noop!(
CheckNonce::<Test>(1).pre_dispatch(&1, CALL, &info, len),
InvalidTransaction::Payment
);
// Non-zero providers
assert_ok!(CheckNonce::<Test>(1).validate_only(Some(2).into(), CALL, &info, len));
assert_ok!(CheckNonce::<Test>(1).validate_and_prepare(
Some(2).into(),
CALL,
&info,
len
));
assert_ok!(CheckNonce::<Test>(1).validate(&2, CALL, &info, len));
assert_ok!(CheckNonce::<Test>(1).pre_dispatch(&2, CALL, &info, len));
// Non-zero sufficients
assert_ok!(CheckNonce::<Test>(1).validate_only(Some(3).into(), CALL, &info, len));
assert_ok!(CheckNonce::<Test>(1).validate_and_prepare(
Some(3).into(),
CALL,
&info,
len
));
})
}
#[test]
fn unsigned_check_nonce_works() {
new_test_ext().execute_with(|| {
let info = DispatchInfo::default();
let len = 0_usize;
assert_ok!(CheckNonce::<Test>(1).validate_only(None.into(), CALL, &info, len));
assert_ok!(CheckNonce::<Test>(1).validate_and_prepare(None.into(), CALL, &info, len));
assert_ok!(CheckNonce::<Test>(1).validate(&3, CALL, &info, len));
assert_ok!(CheckNonce::<Test>(1).pre_dispatch(&3, CALL, &info, len));
})
}
}