From 35e4c6e78be183550dcab7961a0a4ddf30820979 Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 20 May 2025 14:37:59 +0800 Subject: [PATCH 01/22] udpate readme --- evm-tests/README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/evm-tests/README.md b/evm-tests/README.md index 7d01034bd8..83dc8f326f 100644 --- a/evm-tests/README.md +++ b/evm-tests/README.md @@ -1,15 +1,30 @@ # type-test -test with ts +The evm-tests folder includes all typescript code to test the basic EVM function +like token transfer, and all precompile contracts in Subtensor. It is +implemented in typescript, use both ethers and viem lib to interact with +contracts. The polkadot API is used to call extrinsic, get storage in Subtensor +. The developers can use it to verify the code change in precompile contracts. + +It is also included in the CI process, all test cases are executed for new +commit. CI flow can get catch any failed test cases. The polkadot API get the +latest metadata from the runtime, the case also can find out any incompatibility +between runtime and precompile contracts. ## polkadot api +To get the metadata, you need start the localnet via run +`./scripts/localnet.sh`. then run following command to get metadata, a folder +name .papi will be created, which include the metadata and type definitions. + ```bash -npx papi add devnet -w ws://10.0.0.11:9944 +npx papi add devnet -w ws://localhost:9944 ``` ## get the new metadata +If the runtime is upgrade, need to get the metadata again. + ```bash sh get-metadata.sh ``` From 9ffd3e01bbfd911dbd0c1477ac8196134a5f64ea Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 20 May 2025 20:00:43 -0400 Subject: [PATCH 02/22] add filter --- pallets/subtensor/src/tests/batch_tx.rs | 30 ++++++++++++++++++++++++- pallets/subtensor/src/tests/mock.rs | 27 ++++++++++++++++++++-- runtime/src/lib.rs | 28 ++++++++++++++++++++--- 3 files changed, 79 insertions(+), 6 deletions(-) diff --git a/pallets/subtensor/src/tests/batch_tx.rs b/pallets/subtensor/src/tests/batch_tx.rs index 512fa9b368..8f60a7b2f1 100644 --- a/pallets/subtensor/src/tests/batch_tx.rs +++ b/pallets/subtensor/src/tests/batch_tx.rs @@ -1,8 +1,9 @@ use super::mock::*; -use frame_support::{assert_ok, traits::Currency}; +use frame_support::{assert_ok, traits::{Currency, Contains}}; use frame_system::Config; use sp_core::U256; + // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::batch_tx::test_batch_txs --exact --show-output --nocapture #[test] fn test_batch_txs() { @@ -33,3 +34,30 @@ fn test_batch_txs() { assert_eq!(Balances::total_balance(&charlie), 2_000_000_000); }); } + +#[test] +fn test_cant_nest_batch_txs() { + let _alice = U256::from(0); + let bob = U256::from(1); + let charlie = U256::from(2); + + new_test_ext(1).execute_with(|| { + let call = RuntimeCall::Utility(pallet_utility::Call::batch { + calls: vec![ + RuntimeCall::Balances(BalanceCall::transfer_allow_death { + dest: bob, + value: 1_000_000_000 + }), + RuntimeCall::Utility(pallet_utility::Call::force_batch { + calls: vec![RuntimeCall::Balances(BalanceCall::transfer_allow_death { + dest: charlie, + value: 1_000_000_000 + })] + }) + ] + } + ); + + assert!(!::BaseCallFilter::contains(&call)); + }); +} diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 9729d55d1a..74d324d3a8 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -2,11 +2,12 @@ use crate::utils::rate_limiting::TransactionType; use frame_support::derive_impl; use frame_support::dispatch::DispatchResultWithPostInfo; +use frame_support::traits::{Contains, InsideBoth, Everything}; use frame_support::weights::Weight; use frame_support::weights::constants::RocksDbWeight; use frame_support::{ assert_ok, parameter_types, - traits::{Everything, Hooks, PrivilegeCmp}, + traits::{Hooks, PrivilegeCmp}, }; use frame_system as system; use frame_system::{EnsureNever, EnsureRoot, RawOrigin, limits}; @@ -88,9 +89,31 @@ impl pallet_balances::Config for Test { type MaxFreezes = (); } +pub struct NoNestingCallFilter; + +impl Contains for NoNestingCallFilter { + fn contains(call: &RuntimeCall) -> bool { + match call { + RuntimeCall::Utility(inner) => { + let calls = match inner { + pallet_utility::Call::force_batch { calls } => calls, + pallet_utility::Call::batch { calls } => calls, + pallet_utility::Call::batch_all { calls } => calls, + _ => &Vec::new(), + }; + + !calls.iter().any(|call| { + matches!(call, RuntimeCall::Utility(inner) if matches!(inner, pallet_utility::Call::force_batch { .. } | pallet_utility::Call::batch_all { .. } | pallet_utility::Call::batch { .. })) + }) + } + _ => true, + } + } +} + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl system::Config for Test { - type BaseCallFilter = Everything; + type BaseCallFilter = InsideBoth; type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = RocksDbWeight; diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 41117a6c5d..afdfd15ac4 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -12,7 +12,7 @@ pub mod check_nonce; mod migrations; use codec::{Compact, Decode, Encode}; -use frame_support::traits::Imbalance; +use frame_support::traits::{Imbalance, InsideBoth}; use frame_support::{ dispatch::DispatchResultWithPostInfo, genesis_builder_helper::{build_state, get_preset}, @@ -207,7 +207,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 261, + spec_version: 262, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -242,11 +242,33 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } +pub struct NoNestingCallFilter; + +impl Contains for NoNestingCallFilter { + fn contains(call: &RuntimeCall) -> bool { + match call { + RuntimeCall::Utility(inner) => { + let calls = match inner { + pallet_utility::Call::force_batch { calls } => calls, + pallet_utility::Call::batch { calls } => calls, + pallet_utility::Call::batch_all { calls } => calls, + _ => &Vec::new(), + }; + + !calls.iter().any(|call| { + matches!(call, RuntimeCall::Utility(inner) if matches!(inner, pallet_utility::Call::force_batch { .. } | pallet_utility::Call::batch_all { .. } | pallet_utility::Call::batch { .. })) + }) + } + _ => true, + } + } +} + // Configure FRAME pallets to include in runtime. impl frame_system::Config for Runtime { // The basic call filter to use in dispatchable. - type BaseCallFilter = SafeMode; + type BaseCallFilter = InsideBoth; // Block & extrinsics weights: base values and limits. type BlockWeights = BlockWeights; // The maximum length of a block (in bytes). From 258eb3d73bce5b53708964feae52d40a7d2dc1e9 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 20 May 2025 20:00:58 -0400 Subject: [PATCH 03/22] fmt --- pallets/subtensor/src/tests/batch_tx.rs | 37 +++++++++++++------------ pallets/subtensor/src/tests/mock.rs | 2 +- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/pallets/subtensor/src/tests/batch_tx.rs b/pallets/subtensor/src/tests/batch_tx.rs index 8f60a7b2f1..94480b973d 100644 --- a/pallets/subtensor/src/tests/batch_tx.rs +++ b/pallets/subtensor/src/tests/batch_tx.rs @@ -1,9 +1,11 @@ use super::mock::*; -use frame_support::{assert_ok, traits::{Currency, Contains}}; +use frame_support::{ + assert_ok, + traits::{Contains, Currency}, +}; use frame_system::Config; use sp_core::U256; - // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::batch_tx::test_batch_txs --exact --show-output --nocapture #[test] fn test_batch_txs() { @@ -42,22 +44,21 @@ fn test_cant_nest_batch_txs() { let charlie = U256::from(2); new_test_ext(1).execute_with(|| { - let call = RuntimeCall::Utility(pallet_utility::Call::batch { - calls: vec![ - RuntimeCall::Balances(BalanceCall::transfer_allow_death { - dest: bob, - value: 1_000_000_000 - }), - RuntimeCall::Utility(pallet_utility::Call::force_batch { - calls: vec![RuntimeCall::Balances(BalanceCall::transfer_allow_death { - dest: charlie, - value: 1_000_000_000 - })] - }) - ] - } - ); + let call = RuntimeCall::Utility(pallet_utility::Call::batch { + calls: vec![ + RuntimeCall::Balances(BalanceCall::transfer_allow_death { + dest: bob, + value: 1_000_000_000, + }), + RuntimeCall::Utility(pallet_utility::Call::force_batch { + calls: vec![RuntimeCall::Balances(BalanceCall::transfer_allow_death { + dest: charlie, + value: 1_000_000_000, + })], + }), + ], + }); - assert!(!::BaseCallFilter::contains(&call)); + assert!(!::BaseCallFilter::contains(&call)); }); } diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 74d324d3a8..4cc16ce40a 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -2,7 +2,7 @@ use crate::utils::rate_limiting::TransactionType; use frame_support::derive_impl; use frame_support::dispatch::DispatchResultWithPostInfo; -use frame_support::traits::{Contains, InsideBoth, Everything}; +use frame_support::traits::{Contains, Everything, InsideBoth}; use frame_support::weights::Weight; use frame_support::weights::constants::RocksDbWeight; use frame_support::{ From 5d51d40ce691f017f4e5edd9b2611ca10635b4d9 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 20 May 2025 20:18:26 -0400 Subject: [PATCH 04/22] add more tests --- pallets/subtensor/src/tests/batch_tx.rs | 59 ++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/tests/batch_tx.rs b/pallets/subtensor/src/tests/batch_tx.rs index 94480b973d..127aa513ac 100644 --- a/pallets/subtensor/src/tests/batch_tx.rs +++ b/pallets/subtensor/src/tests/batch_tx.rs @@ -39,7 +39,6 @@ fn test_batch_txs() { #[test] fn test_cant_nest_batch_txs() { - let _alice = U256::from(0); let bob = U256::from(1); let charlie = U256::from(2); @@ -50,7 +49,7 @@ fn test_cant_nest_batch_txs() { dest: bob, value: 1_000_000_000, }), - RuntimeCall::Utility(pallet_utility::Call::force_batch { + RuntimeCall::Utility(pallet_utility::Call::batch { calls: vec![RuntimeCall::Balances(BalanceCall::transfer_allow_death { dest: charlie, value: 1_000_000_000, @@ -62,3 +61,59 @@ fn test_cant_nest_batch_txs() { assert!(!::BaseCallFilter::contains(&call)); }); } + +#[test] +fn test_can_batch_txs() { + let bob = U256::from(1); + + new_test_ext(1).execute_with(|| { + let call = RuntimeCall::Utility(pallet_utility::Call::batch { + calls: vec![RuntimeCall::Balances(BalanceCall::transfer_allow_death { + dest: bob, + value: 1_000_000_000, + })], + }); + + assert!(::BaseCallFilter::contains(&call)); + }); +} + +#[test] +fn test_cant_nest_batch_diff_batch_txs() { + let charlie = U256::from(2); + + new_test_ext(1).execute_with(|| { + let call = RuntimeCall::Utility(pallet_utility::Call::batch { + calls: vec![RuntimeCall::Utility(pallet_utility::Call::force_batch { + calls: vec![RuntimeCall::Balances(BalanceCall::transfer_allow_death { + dest: charlie, + value: 1_000_000_000, + })], + })], + }); + + assert!(!::BaseCallFilter::contains(&call)); + + let call2 = RuntimeCall::Utility(pallet_utility::Call::batch_all { + calls: vec![RuntimeCall::Utility(pallet_utility::Call::batch { + calls: vec![RuntimeCall::Balances(BalanceCall::transfer_allow_death { + dest: charlie, + value: 1_000_000_000, + })], + })], + }); + + assert!(!::BaseCallFilter::contains(&call2)); + + let call3 = RuntimeCall::Utility(pallet_utility::Call::force_batch { + calls: vec![RuntimeCall::Utility(pallet_utility::Call::batch_all { + calls: vec![RuntimeCall::Balances(BalanceCall::transfer_allow_death { + dest: charlie, + value: 1_000_000_000, + })], + })], + }); + + assert!(!::BaseCallFilter::contains(&call3)); + }); +} From 62c8cefa9e28bb175cf2298bdbf39023132dc5df Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Tue, 20 May 2025 21:22:44 -0400 Subject: [PATCH 05/22] Add unstake all call validation in signed ext --- pallets/subtensor/src/lib.rs | 14 ++++++ pallets/subtensor/src/staking/stake_utils.rs | 40 +++++++++++++++ pallets/subtensor/src/tests/staking.rs | 51 ++++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index e360c307e1..16a8994ff6 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -2045,6 +2045,20 @@ where Self::get_priority_staking(who, hotkey, *amount_unstaked), ) } + Some(Call::unstake_all { hotkey }) => { + // Fully validate the user input + Self::result_to_validity( + Pallet::::validate_unstake_all(who, hotkey, false), + Self::get_priority_vanilla(), + ) + } + Some(Call::unstake_all_alpha { hotkey }) => { + // Fully validate the user input + Self::result_to_validity( + Pallet::::validate_unstake_all(who, hotkey, true), + Self::get_priority_vanilla(), + ) + } Some(Call::move_stake { origin_hotkey, destination_hotkey, diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index b67821a7d2..6f0ba96b52 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -987,6 +987,46 @@ impl Pallet { Ok(()) } + /// Validate if unstake_all can be executed + /// + pub fn validate_unstake_all( + coldkey: &T::AccountId, + hotkey: &T::AccountId, + only_alpha: bool, + ) -> Result<(), Error> { + // Get all netuids (filter out root) + let subnets: Vec = Self::get_all_subnet_netuids(); + + // Ensure that the hotkey account exists this is only possible through registration. + ensure!( + Self::hotkey_account_exists(hotkey), + Error::::HotKeyAccountNotExists + ); + + let mut unstaking_any = false; + for netuid in subnets.iter() { + if !SubtokenEnabled::::get(netuid) { + continue; + } + + if only_alpha && (*netuid == Self::get_root_netuid()) { + continue; + } + + // Get user's stake in this subnet + let alpha = Self::get_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, *netuid); + + if Self::validate_remove_stake(coldkey, hotkey, *netuid, alpha, alpha, false).is_ok() { + unstaking_any = true; + } + } + + // If no unstaking happens, return error + ensure!(unstaking_any, Error::::AmountTooLow); + + Ok(()) + } + /// Validate stake transition user input /// That works for move_stake, transfer_stake, and swap_stake /// diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs index a9fa11ba3a..69e0c7ada1 100644 --- a/pallets/subtensor/src/tests/staking.rs +++ b/pallets/subtensor/src/tests/staking.rs @@ -2836,6 +2836,57 @@ fn test_unstake_low_liquidity_validate() { }); } +#[test] +fn test_unstake_all_validate() { + // Testing the signed extension validate function + // correctly filters the `unstake_all` transaction. + + new_test_ext(0).execute_with(|| { + let subnet_owner_coldkey = U256::from(1001); + let subnet_owner_hotkey = U256::from(1002); + let hotkey = U256::from(2); + let coldkey = U256::from(3); + let amount_staked = DefaultMinStake::::get() * 10 + DefaultStakingFee::::get(); + + let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount_staked); + + // Simulate stake for hotkey + SubnetTAO::::insert(netuid, u64::MAX / 1000); + SubnetAlphaIn::::insert(netuid, u64::MAX / 1000); + SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, amount_staked, 0); + + // Set the liquidity at lowest possible value so that all staking requests fail + SubnetTAO::::insert( + netuid, + DefaultMinimumPoolLiquidity::::get().to_num::(), + ); + SubnetAlphaIn::::insert( + netuid, + DefaultMinimumPoolLiquidity::::get().to_num::(), + ); + + // unstake_all call + let call = RuntimeCall::SubtensorModule(SubtensorCall::unstake_all { hotkey }); + + let info: DispatchInfo = + DispatchInfoOf::<::RuntimeCall>::default(); + + let extension = SubtensorSignedExtension::::new(); + // Submit to the signed extension validate function + let result_no_stake = extension.validate(&coldkey, &call.clone(), &info, 10); + + // Should fail due to insufficient stake + assert_err!( + result_no_stake, + TransactionValidityError::Invalid(InvalidTransaction::Custom( + CustomTransactionError::StakeAmountTooLow.into() + )) + ); + }); +} + #[test] fn test_max_amount_add_root() { new_test_ext(0).execute_with(|| { From 54bf122f0daa45933382efe5f73a7b27dc1e8c88 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Tue, 20 May 2025 21:25:52 -0400 Subject: [PATCH 06/22] Fix SubtokenEnabled --- pallets/subtensor/src/staking/stake_utils.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index 6f0ba96b52..ee8326b6c1 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -1005,10 +1005,6 @@ impl Pallet { let mut unstaking_any = false; for netuid in subnets.iter() { - if !SubtokenEnabled::::get(netuid) { - continue; - } - if only_alpha && (*netuid == Self::get_root_netuid()) { continue; } From 3ba9333b4d6f98481d08e9c4a0f03a0efd377c0a Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 20 May 2025 21:30:05 -0400 Subject: [PATCH 07/22] bump spec version --- runtime/src/lib.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index afdfd15ac4..09e16320a6 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -18,16 +18,16 @@ use frame_support::{ genesis_builder_helper::{build_state, get_preset}, pallet_prelude::Get, traits::{ - Contains, LinearStoragePrice, OnUnbalanced, fungible::{ DecreaseIssuance, HoldConsideration, Imbalance as FungibleImbalance, IncreaseIssuance, }, + Contains, LinearStoragePrice, OnUnbalanced, }, }; use frame_system::{EnsureNever, EnsureRoot, EnsureRootWithSuccess, RawOrigin}; use pallet_commitments::CanCommit; use pallet_grandpa::{ - AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, fg_primitives, + fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, }; use pallet_registry::CanRegisterIdentity; use pallet_subtensor::rpc_info::{ @@ -43,18 +43,18 @@ use smallvec::smallvec; use sp_api::impl_runtime_apis; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{ - H160, H256, OpaqueMetadata, U256, crypto::{ByteArray, KeyTypeId}, + OpaqueMetadata, H160, H256, U256, }; use sp_runtime::generic::Era; use sp_runtime::{ - AccountId32, ApplyExtrinsicResult, ConsensusEngineId, create_runtime_str, generic, - impl_opaque_keys, + create_runtime_str, generic, impl_opaque_keys, traits::{ AccountIdLookup, BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, NumberFor, One, PostDispatchInfoOf, UniqueSaturatedInto, Verify, }, transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, + AccountId32, ApplyExtrinsicResult, ConsensusEngineId, }; use sp_std::cmp::Ordering; use sp_std::prelude::*; @@ -66,18 +66,19 @@ use subtensor_runtime_common::{time::*, *}; // A few exports that help ease life for downstream crates. pub use frame_support::{ - StorageValue, construct_runtime, parameter_types, + construct_runtime, parameter_types, traits::{ - ConstBool, ConstU8, ConstU32, ConstU64, ConstU128, FindAuthor, InstanceFilter, + ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, FindAuthor, InstanceFilter, KeyOwnerProofSystem, OnFinalize, OnTimestampSet, PrivilegeCmp, Randomness, StorageInfo, }, weights::{ - IdentityFee, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, - WeightToFeePolynomial, constants::{ BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, }, + IdentityFee, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, + WeightToFeePolynomial, }, + StorageValue, }; pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; @@ -207,7 +208,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 262, + spec_version: 263, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 0c3c6a05140ed6d5c5acb4e72121ac2a2c290c3c Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 20 May 2025 21:35:18 -0400 Subject: [PATCH 08/22] cargo fmt --- runtime/src/lib.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 09e16320a6..193f585e3b 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -18,16 +18,16 @@ use frame_support::{ genesis_builder_helper::{build_state, get_preset}, pallet_prelude::Get, traits::{ + Contains, LinearStoragePrice, OnUnbalanced, fungible::{ DecreaseIssuance, HoldConsideration, Imbalance as FungibleImbalance, IncreaseIssuance, }, - Contains, LinearStoragePrice, OnUnbalanced, }, }; use frame_system::{EnsureNever, EnsureRoot, EnsureRootWithSuccess, RawOrigin}; use pallet_commitments::CanCommit; use pallet_grandpa::{ - fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, + AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, fg_primitives, }; use pallet_registry::CanRegisterIdentity; use pallet_subtensor::rpc_info::{ @@ -43,18 +43,18 @@ use smallvec::smallvec; use sp_api::impl_runtime_apis; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{ + H160, H256, OpaqueMetadata, U256, crypto::{ByteArray, KeyTypeId}, - OpaqueMetadata, H160, H256, U256, }; use sp_runtime::generic::Era; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, + AccountId32, ApplyExtrinsicResult, ConsensusEngineId, create_runtime_str, generic, + impl_opaque_keys, traits::{ AccountIdLookup, BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, NumberFor, One, PostDispatchInfoOf, UniqueSaturatedInto, Verify, }, transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, - AccountId32, ApplyExtrinsicResult, ConsensusEngineId, }; use sp_std::cmp::Ordering; use sp_std::prelude::*; @@ -66,19 +66,18 @@ use subtensor_runtime_common::{time::*, *}; // A few exports that help ease life for downstream crates. pub use frame_support::{ - construct_runtime, parameter_types, + StorageValue, construct_runtime, parameter_types, traits::{ - ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, FindAuthor, InstanceFilter, + ConstBool, ConstU8, ConstU32, ConstU64, ConstU128, FindAuthor, InstanceFilter, KeyOwnerProofSystem, OnFinalize, OnTimestampSet, PrivilegeCmp, Randomness, StorageInfo, }, weights::{ + IdentityFee, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, + WeightToFeePolynomial, constants::{ BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, }, - IdentityFee, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, - WeightToFeePolynomial, }, - StorageValue, }; pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; From cb3a7adf803f5c17ca34c10deb0320b9691ba065 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Wed, 21 May 2025 15:10:32 +0300 Subject: [PATCH 09/22] ignore stale drand --- pallets/drand/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pallets/drand/src/lib.rs b/pallets/drand/src/lib.rs index 40bf7ccb9b..fc44cc557c 100644 --- a/pallets/drand/src/lib.rs +++ b/pallets/drand/src/lib.rs @@ -292,6 +292,10 @@ pub mod pallet { pulses_payload: payload, signature, } => { + // Blacklist stale pulses in the txpool that can stall finalization. + if payload.block_number < BlockNumberFor::::from(5612400u32) { + return InvalidTransaction::Stale.into(); + } let signature = signature.as_ref().ok_or(InvalidTransaction::BadSigner)?; Self::validate_signature_and_parameters( payload, From 5d185cf9f6ce71882b3e67a15fdeccde9204bf8e Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Wed, 21 May 2025 15:30:58 +0300 Subject: [PATCH 10/22] spec version bump --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 193f585e3b..56b1d19268 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -207,7 +207,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 263, + spec_version: 264, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From dd3dcb6c47eaa22ba1a09fad122bfe3eb8ca91b3 Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Wed, 21 May 2025 15:55:10 +0300 Subject: [PATCH 11/22] tests --- pallets/drand/src/tests.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pallets/drand/src/tests.rs b/pallets/drand/src/tests.rs index e12653aebf..3f6470f04c 100644 --- a/pallets/drand/src/tests.rs +++ b/pallets/drand/src/tests.rs @@ -47,7 +47,7 @@ fn it_can_submit_valid_pulse_when_beacon_config_exists() { let p: Pulse = u_p.try_into_pulse().unwrap(); let alice = sp_keyring::Sr25519Keyring::Alice; - let block_number = 1; + let block_number = 100_000_000; System::set_block_number(block_number); // Set the beacon config @@ -91,7 +91,7 @@ fn it_can_submit_valid_pulse_when_beacon_config_exists() { fn it_rejects_invalid_pulse_due_to_bad_signature() { new_test_ext().execute_with(|| { let alice = sp_keyring::Sr25519Keyring::Alice; - let block_number = 1; + let block_number = 100_000_000; System::set_block_number(block_number); // Set the beacon config using Root origin @@ -139,7 +139,7 @@ fn it_rejects_invalid_pulse_due_to_bad_signature() { #[test] fn it_rejects_pulses_with_non_incremental_round_numbers() { new_test_ext().execute_with(|| { - let block_number = 1; + let block_number = 100_000_000; let alice = sp_keyring::Sr25519Keyring::Alice; System::set_block_number(block_number); @@ -189,7 +189,7 @@ fn it_rejects_pulses_with_non_incremental_round_numbers() { #[test] fn it_blocks_non_root_from_submit_beacon_info() { new_test_ext().execute_with(|| { - let block_number = 1; + let block_number = 100_000_000; let alice = sp_keyring::Sr25519Keyring::Alice; System::set_block_number(block_number); @@ -239,7 +239,7 @@ fn it_blocks_non_root_from_submit_beacon_info() { #[test] fn signed_cannot_submit_beacon_info() { new_test_ext().execute_with(|| { - let block_number = 1; + let block_number = 100_000_000; let alice = sp_keyring::Sr25519Keyring::Alice; System::set_block_number(block_number); @@ -268,7 +268,7 @@ fn signed_cannot_submit_beacon_info() { #[test] fn test_validate_unsigned_write_pulse() { new_test_ext().execute_with(|| { - let block_number = 1; + let block_number = 100_000_000; let alice = sp_keyring::Sr25519Keyring::Alice; System::set_block_number(block_number); let pulses_payload = PulsesPayload { @@ -293,7 +293,7 @@ fn test_validate_unsigned_write_pulse() { #[test] fn test_not_validate_unsigned_write_pulse_with_bad_proof() { new_test_ext().execute_with(|| { - let block_number = 1; + let block_number = 100_000_000; let alice = sp_keyring::Sr25519Keyring::Alice; System::set_block_number(block_number); let pulses_payload = PulsesPayload { @@ -319,7 +319,7 @@ fn test_not_validate_unsigned_write_pulse_with_bad_proof() { #[test] fn test_not_validate_unsigned_write_pulse_with_no_payload_signature() { new_test_ext().execute_with(|| { - let block_number = 1; + let block_number = 100_000_000; let alice = sp_keyring::Sr25519Keyring::Alice; System::set_block_number(block_number); let pulses_payload = PulsesPayload { @@ -388,8 +388,8 @@ fn can_execute_and_handle_valid_http_responses() { #[test] fn validate_unsigned_rejects_future_block_number() { new_test_ext().execute_with(|| { - let block_number = 1; - let future_block_number = 100; + let block_number = 100_000_000; + let future_block_number = 100_000_100; let alice = sp_keyring::Sr25519Keyring::Alice; System::set_block_number(block_number); let pulses_payload = PulsesPayload { From 397e997ea2cf6e0ef23ed6b2f419971f186bde8e Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Wed, 21 May 2025 15:57:05 +0300 Subject: [PATCH 12/22] bump for safety --- pallets/drand/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/drand/src/lib.rs b/pallets/drand/src/lib.rs index fc44cc557c..5695f1456d 100644 --- a/pallets/drand/src/lib.rs +++ b/pallets/drand/src/lib.rs @@ -293,7 +293,7 @@ pub mod pallet { signature, } => { // Blacklist stale pulses in the txpool that can stall finalization. - if payload.block_number < BlockNumberFor::::from(5612400u32) { + if payload.block_number < BlockNumberFor::::from(5612500u32) { return InvalidTransaction::Stale.into(); } let signature = signature.as_ref().ok_or(InvalidTransaction::BadSigner)?; From 4a602ff9bee912f1da8f8b460b512acb96622994 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 21 May 2025 17:36:53 -0400 Subject: [PATCH 13/22] fix everything --- runtime/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 56b1d19268..2a8e5ecf01 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1596,6 +1596,12 @@ impl_runtime_apis! { tx: ::Extrinsic, block_hash: ::Hash, ) -> TransactionValidity { + use codec::DecodeLimit; + use frame_support::pallet_prelude::{ValidateUnsigned, InvalidTransaction, TransactionValidityError}; + let encoded = tx.encode(); + if let Err(_) = ::Call::decode_all_with_depth_limit(200, &mut encoded.as_slice()) { + return Err(TransactionValidityError::Invalid(InvalidTransaction::Call)); + } Executive::validate_transaction(source, tx, block_hash) } } From 9e59313aef90bced339829da50a4ba6553f9ee76 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 21 May 2025 17:38:46 -0400 Subject: [PATCH 14/22] add a log --- runtime/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 2a8e5ecf01..a2a8f8304f 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1600,6 +1600,7 @@ impl_runtime_apis! { use frame_support::pallet_prelude::{ValidateUnsigned, InvalidTransaction, TransactionValidityError}; let encoded = tx.encode(); if let Err(_) = ::Call::decode_all_with_depth_limit(200, &mut encoded.as_slice()) { + log::warn!("failed to decde with depth limit of 200"); return Err(TransactionValidityError::Invalid(InvalidTransaction::Call)); } Executive::validate_transaction(source, tx, block_hash) From 268ea4ab19018ba30f153558925a9b95c276b1cf Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 21 May 2025 17:40:20 -0400 Subject: [PATCH 15/22] fixes --- runtime/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index a2a8f8304f..99be060a12 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1598,7 +1598,8 @@ impl_runtime_apis! { ) -> TransactionValidity { use codec::DecodeLimit; use frame_support::pallet_prelude::{ValidateUnsigned, InvalidTransaction, TransactionValidityError}; - let encoded = tx.encode(); + use frame_support::traits::ExtrinsicCall; + let encoded = tx.call().encode(); if let Err(_) = ::Call::decode_all_with_depth_limit(200, &mut encoded.as_slice()) { log::warn!("failed to decde with depth limit of 200"); return Err(TransactionValidityError::Invalid(InvalidTransaction::Call)); From 705e2f84374ccfabd6a5533d2e10fdb2a25e8d0c Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 21 May 2025 17:49:24 -0400 Subject: [PATCH 16/22] cargo clippy --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 99be060a12..340bfb8651 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1600,7 +1600,7 @@ impl_runtime_apis! { use frame_support::pallet_prelude::{ValidateUnsigned, InvalidTransaction, TransactionValidityError}; use frame_support::traits::ExtrinsicCall; let encoded = tx.call().encode(); - if let Err(_) = ::Call::decode_all_with_depth_limit(200, &mut encoded.as_slice()) { + if ::Call::decode_all_with_depth_limit(200, &mut encoded.as_slice()).is_err() { log::warn!("failed to decde with depth limit of 200"); return Err(TransactionValidityError::Invalid(InvalidTransaction::Call)); } From 5a7dde12da8a9d72c59d33d5417aed2bcdb7d870 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Wed, 21 May 2025 18:18:37 -0400 Subject: [PATCH 17/22] use runtime call --- runtime/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 340bfb8651..0d901174d3 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1597,10 +1597,10 @@ impl_runtime_apis! { block_hash: ::Hash, ) -> TransactionValidity { use codec::DecodeLimit; - use frame_support::pallet_prelude::{ValidateUnsigned, InvalidTransaction, TransactionValidityError}; + use frame_support::pallet_prelude::{InvalidTransaction, TransactionValidityError}; use frame_support::traits::ExtrinsicCall; let encoded = tx.call().encode(); - if ::Call::decode_all_with_depth_limit(200, &mut encoded.as_slice()).is_err() { + if RuntimeCall::decode_all_with_depth_limit(200, &mut encoded.as_slice()).is_err() { log::warn!("failed to decde with depth limit of 200"); return Err(TransactionValidityError::Invalid(InvalidTransaction::Call)); } From c34c688dec3da79570c5e8b16db6e4180fd3928a Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 21 May 2025 18:19:45 -0400 Subject: [PATCH 18/22] fix everything --- runtime/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 64937fd3bb..0c1be0e67e 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1709,6 +1709,14 @@ impl_runtime_apis! { tx: ::Extrinsic, block_hash: ::Hash, ) -> TransactionValidity { + use codec::DecodeLimit; + use frame_support::pallet_prelude::{InvalidTransaction, TransactionValidityError}; + use frame_support::traits::ExtrinsicCall; + let encoded = tx.call().encode(); + if RuntimeCall::decode_all_with_depth_limit(200, &mut encoded.as_slice()).is_err() { + log::warn!("failed to decde with depth limit of 200"); + return Err(TransactionValidityError::Invalid(InvalidTransaction::Call)); + } Executive::validate_transaction(source, tx, block_hash) } } From ed91975e5ec29d1613f85df908d60186a45b2d0e Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 21 May 2025 18:21:37 -0400 Subject: [PATCH 19/22] bump spec --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 0c1be0e67e..95b032f9e6 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -209,7 +209,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 271, + spec_version: 272, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 494dfbd30800f34c432a4ee66e1bae9221d0f243 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 21 May 2025 19:01:49 -0400 Subject: [PATCH 20/22] refine --- runtime/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 0d901174d3..7521458ee1 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -207,7 +207,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 264, + spec_version: 265, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -1600,8 +1600,8 @@ impl_runtime_apis! { use frame_support::pallet_prelude::{InvalidTransaction, TransactionValidityError}; use frame_support::traits::ExtrinsicCall; let encoded = tx.call().encode(); - if RuntimeCall::decode_all_with_depth_limit(200, &mut encoded.as_slice()).is_err() { - log::warn!("failed to decde with depth limit of 200"); + if RuntimeCall::decode_all_with_depth_limit(8, &mut encoded.as_slice()).is_err() { + log::warn!("failed to decde with depth limit of 8"); return Err(TransactionValidityError::Invalid(InvalidTransaction::Call)); } Executive::validate_transaction(source, tx, block_hash) From fdd5d938f63fa72b3633ba6be7b9f486ab7c0e4b Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 21 May 2025 19:02:50 -0400 Subject: [PATCH 21/22] typo --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 7521458ee1..cbe8a84a68 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1601,7 +1601,7 @@ impl_runtime_apis! { use frame_support::traits::ExtrinsicCall; let encoded = tx.call().encode(); if RuntimeCall::decode_all_with_depth_limit(8, &mut encoded.as_slice()).is_err() { - log::warn!("failed to decde with depth limit of 8"); + log::warn!("failed to decode with depth limit of 8"); return Err(TransactionValidityError::Invalid(InvalidTransaction::Call)); } Executive::validate_transaction(source, tx, block_hash) From 1db0213c72c30c2981b3385a56860e81109812eb Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 27 May 2025 23:07:33 -0400 Subject: [PATCH 22/22] bump spec version --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 4245dde3ec..0b64ee3cde 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -209,7 +209,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 272, + spec_version: 273, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,