Skip to content

Commit

Permalink
Merge pull request #404 from opentensor/junius/fix-pays-no
Browse files Browse the repository at this point in the history
fix pays no check
  • Loading branch information
sam0x17 committed May 10, 2024
2 parents 18c520d + f765321 commit 833364b
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 2 deletions.
3 changes: 2 additions & 1 deletion node/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use crate::service::FullClient;

use node_subtensor_runtime as runtime;
use node_subtensor_runtime::check_nonce;
use node_subtensor_runtime::pallet_subtensor;
use runtime::{AccountId, Balance, BalancesCall, SystemCall};
use sc_cli::Result;
Expand Down Expand Up @@ -130,7 +131,7 @@ pub fn create_benchmark_extrinsic(
period,
best_block.saturated_into(),
)),
frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
check_nonce::CheckNonce::<runtime::Runtime>::from(nonce),
frame_system::CheckWeight::<runtime::Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(0),
pallet_subtensor::SubtensorSignedExtension::<runtime::Runtime>::new(),
Expand Down
127 changes: 127 additions & 0 deletions runtime/src/check_nonce.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use codec::{Decode, Encode};
use frame_support::dispatch::{DispatchInfo, Pays};
use frame_system::Config;
use scale_info::TypeInfo;
use sp_runtime::{
traits::{DispatchInfoOf, Dispatchable, One, SignedExtension, Zero},
transaction_validity::{
InvalidTransaction, TransactionLongevity, TransactionValidity, TransactionValidityError,
ValidTransaction,
},
};
use sp_std::vec;

/// 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.
#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct CheckNonce<T: Config>(#[codec(compact)] pub T::Nonce);

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

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

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

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

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);
match info.pays_fee {
Pays::Yes => {
if account.providers.is_zero() && account.sufficients.is_zero() {
// Nonce storage not paid for
return Err(InvalidTransaction::Payment.into());
}
}
// not check providers and sufficients for Pays::No extrinsic
Pays::No => {}
}

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);
match info.pays_fee {
Pays::Yes => {
if account.providers.is_zero() && account.sufficients.is_zero() {
// Nonce storage not paid for
return Err(InvalidTransaction::Payment.into());
}
}
// not check providers and sufficients for Pays::No extrinsic
Pays::No => {}
}
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,
})
}
}
3 changes: 2 additions & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));

pub mod check_nonce;
mod migrations;

use codec::{Decode, Encode, MaxEncodedLen};
Expand Down Expand Up @@ -1177,7 +1178,7 @@ pub type SignedExtra = (
frame_system::CheckTxVersion<Runtime>,
frame_system::CheckGenesis<Runtime>,
frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>,
check_nonce::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
pallet_subtensor::SubtensorSignedExtension<Runtime>,
Expand Down

0 comments on commit 833364b

Please sign in to comment.