Skip to content

Commit

Permalink
fix(runtime): Fix inability to use vouchers with no balance (#3967)
Browse files Browse the repository at this point in the history
  • Loading branch information
breathx committed May 26, 2024
1 parent 5adfb9b commit a25a431
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 15 deletions.
9 changes: 2 additions & 7 deletions gsdk/src/metadata/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,6 @@ pub mod runtime_types {
)]
pub struct CheckNonZeroSender;
}
pub mod check_nonce {
use super::runtime_types;
#[derive(
Debug, crate::gp::Decode, crate::gp::DecodeAsType, crate::gp::Encode,
)]
pub struct CheckNonce(#[codec(compact)] pub ::core::primitive::u32);
}
pub mod check_spec_version {
use super::runtime_types;
#[derive(
Expand Down Expand Up @@ -7459,6 +7452,8 @@ pub mod runtime_types {
}
}
#[derive(Debug, crate::gp::Decode, crate::gp::DecodeAsType, crate::gp::Encode)]
pub struct CustomCheckNonce(#[codec(compact)] pub ::core::primitive::u32);
#[derive(Debug, crate::gp::Decode, crate::gp::DecodeAsType, crate::gp::Encode)]
pub struct NposSolution16 {
pub votes1: ::std::vec::Vec<(
::subxt::ext::codec::Compact<::core::primitive::u32>,
Expand Down
2 changes: 1 addition & 1 deletion node/cli/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ macro_rules! with_signed_payload {
frame_system::CheckMortality::<runtime::Runtime>::from(
sp_runtime::generic::Era::mortal($period, $current_block),
),
frame_system::CheckNonce::<runtime::Runtime>::from($nonce),
runtime::CustomCheckNonce::<runtime::Runtime>::from($nonce),
frame_system::CheckWeight::<runtime::Runtime>::new(),
pallet_gear_payment::CustomChargeTransactionPayment::<runtime::Runtime>::from($tip),
);
Expand Down
6 changes: 3 additions & 3 deletions node/testing/src/keyring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use runtime_primitives::{AccountId, Nonce};
use sp_keyring::{AccountKeyring, Ed25519Keyring, Sr25519Keyring};
use sp_runtime::generic::Era;
use vara_runtime::{
CustomChargeTransactionPayment, RuntimeCall, SessionKeys, SignedExtra, StakingBlackList,
UncheckedExtrinsic,
CustomChargeTransactionPayment, CustomCheckNonce, RuntimeCall, SessionKeys, SignedExtra,
StakingBlackList, UncheckedExtrinsic,
};

pub type CheckedExtrinsic =
Expand Down Expand Up @@ -82,7 +82,7 @@ pub fn signed_extra(nonce: Nonce) -> SignedExtra {
frame_system::CheckTxVersion::new(),
frame_system::CheckGenesis::new(),
frame_system::CheckEra::from(Era::mortal(256, 0)),
frame_system::CheckNonce::from(nonce),
CustomCheckNonce::from(nonce),
frame_system::CheckWeight::new(),
CustomChargeTransactionPayment::from(0),
)
Expand Down
115 changes: 111 additions & 4 deletions runtime/vara/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ use frame_election_provider_support::{
bounds::ElectionBoundsBuilder, onchain, ElectionDataProvider, NposSolution, SequentialPhragmen,
VoteWeight,
};
use frame_support::weights::ConstantMultiplier;
pub use frame_support::{
construct_runtime,
dispatch::{DispatchClass, WeighData},
Expand All @@ -52,6 +51,13 @@ pub use frame_support::{
},
PalletId, StorageValue,
};
use frame_support::{
dispatch::DispatchInfo,
pallet_prelude::{
InvalidTransaction, TransactionLongevity, TransactionValidityError, ValidTransaction,
},
weights::ConstantMultiplier,
};
use frame_system::{
limits::{BlockLength, BlockWeights},
EnsureRoot,
Expand Down Expand Up @@ -81,6 +87,7 @@ pub use runtime_common::{
};
pub use runtime_primitives::{AccountId, Signature, VARA_SS58_PREFIX};
use runtime_primitives::{Balance, BlockNumber, Hash, Moment, Nonce};
use scale_info::TypeInfo;
use sp_api::impl_runtime_apis;
#[cfg(any(feature = "std", test))]
use sp_api::{CallApiAt, CallContext, Extensions, OverlayedChanges, ProofRecorder};
Expand All @@ -91,8 +98,8 @@ use sp_runtime::{
codec::{Decode, Encode, MaxEncodedLen},
create_runtime_str, generic, impl_opaque_keys,
traits::{
AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, IdentityLookup, NumberFor,
OpaqueKeys,
AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, DispatchInfoOf, Dispatchable,
IdentityLookup, NumberFor, One, OpaqueKeys, SignedExtension,
},
transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity},
ApplyExtrinsicResult, FixedU128, Perbill, Percent, Permill, Perquintill, RuntimeDebug,
Expand Down Expand Up @@ -1303,7 +1310,7 @@ pub type SignedExtra = (
frame_system::CheckTxVersion<Runtime>,
frame_system::CheckGenesis<Runtime>,
frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>,
CustomCheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
CustomChargeTransactionPayment<Runtime>,
);
Expand Down Expand Up @@ -1554,3 +1561,103 @@ where
}
}
}

/// Nonce check and increment to give replay protection for transactions.
///
/// # Transaction Validity
///
/// This extension affects `requires` and `provides` tags of validity, but DOES NOT
/// set the `priority` field. Make sure that AT LEAST one of the signed extension sets
/// some kind of priority upon validating transactions.
///
/// NOTE: Copy-paste from substrate/frame/system/src/extensions/check_nonce.rs,
/// but without providers and sufficients checks, so contains revert of changes
/// from substrate v1.3.0 https://github.com/paritytech/polkadot-sdk/pull/1578.
#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct CustomCheckNonce<T: frame_system::Config>(#[codec(compact)] pub T::Nonce);

impl<T: frame_system::Config> CustomCheckNonce<T> {
/// utility constructor. Used only in client/factory code.
pub fn from(nonce: T::Nonce) -> Self {
Self(nonce)
}
}

impl<T: frame_system::Config> sp_std::fmt::Debug for CustomCheckNonce<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
write!(f, "CustomCheckNonce({})", self.0)
}

#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
Ok(())
}
}

impl<T: frame_system::Config> SignedExtension for CustomCheckNonce<T>
where
T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
{
type AccountId = <frame_system::CheckNonce<T> as SignedExtension>::AccountId;
type Call = <frame_system::CheckNonce<T> as SignedExtension>::Call;
type AdditionalSigned = <frame_system::CheckNonce<T> as SignedExtension>::AdditionalSigned;
type Pre = <frame_system::CheckNonce<T> as SignedExtension>::Pre;
const IDENTIFIER: &'static str = <frame_system::CheckNonce<T> as SignedExtension>::IDENTIFIER;

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,
) -> Result<(), TransactionValidityError> {
let mut account = frame_system::Account::<T>::get(who);

if self.0 != account.nonce {
return Err(if self.0 < account.nonce {
InvalidTransaction::Stale
} else {
InvalidTransaction::Future
}
.into());
}
account.nonce += T::Nonce::one();
frame_system::Account::<T>::insert(who, account);
Ok(())
}

fn validate(
&self,
who: &Self::AccountId,
_call: &Self::Call,
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> TransactionValidity {
let account = frame_system::Account::<T>::get(who);

if self.0 < account.nonce {
return InvalidTransaction::Stale.into();
}

let provides = vec![Encode::encode(&(who, self.0))];
let requires = if account.nonce < self.0 {
vec![Encode::encode(&(who, self.0 - One::one()))]
} else {
vec![]
};

Ok(ValidTransaction {
priority: 0,
requires,
provides,
longevity: TransactionLongevity::max_value(),
propagate: true,
})
}
}

0 comments on commit a25a431

Please sign in to comment.