diff --git a/Cargo.lock b/Cargo.lock index f444c9ba9..698607e7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1198,7 +1198,7 @@ dependencies = [ [[package]] name = "common" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof#b273d33f9981e2bb3375ab45faeb537f7ee35224" +source = "git+https://github.com/w3f/ring-proof#665f5f51af5734c7b6d90b985dd6861d4c5b4752" dependencies = [ "ark-ec", "ark-ff", @@ -4150,9 +4150,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" @@ -4976,6 +4976,7 @@ dependencies = [ "frame-system", "log", "pallet-balances", + "pallet-scheduler", "pallet-subtensor", "parity-scale-codec", "scale-info", @@ -4983,6 +4984,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", + "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=v1.10.0-rc3)", "sp-tracing 16.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=v1.10.0-rc3)", "sp-weights", "substrate-fixed", @@ -5264,6 +5266,8 @@ dependencies = [ "pallet-balances", "pallet-collective", "pallet-membership", + "pallet-preimage", + "pallet-scheduler", "pallet-transaction-payment", "pallet-utility", "parity-scale-codec", @@ -6431,13 +6435,14 @@ dependencies = [ [[package]] name = "ring" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof#b273d33f9981e2bb3375ab45faeb537f7ee35224" +source = "git+https://github.com/w3f/ring-proof#665f5f51af5734c7b6d90b985dd6861d4c5b4752" dependencies = [ "ark-ec", "ark-ff", "ark-poly", "ark-serialize", "ark-std", + "arrayvec", "blake2 0.10.6", "common", "fflonk", @@ -7906,9 +7911,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] @@ -7933,9 +7938,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", @@ -8406,7 +8411,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" version = "0.10.0" -source = "git+https://github.com/paritytech/polkadot-sdk#c4b3c1c6c6e492c4196e06fbba824a58e8119a3b" +source = "git+https://github.com/paritytech/polkadot-sdk#6a5b6e03bfc8d0c6f5f05f3180313902c15aee84" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -8468,7 +8473,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#c4b3c1c6c6e492c4196e06fbba824a58e8119a3b" +source = "git+https://github.com/paritytech/polkadot-sdk#6a5b6e03bfc8d0c6f5f05f3180313902c15aee84" dependencies = [ "proc-macro2", "quote", @@ -8488,7 +8493,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.25.0" -source = "git+https://github.com/paritytech/polkadot-sdk#c4b3c1c6c6e492c4196e06fbba824a58e8119a3b" +source = "git+https://github.com/paritytech/polkadot-sdk#6a5b6e03bfc8d0c6f5f05f3180313902c15aee84" dependencies = [ "environmental", "parity-scale-codec", @@ -8671,7 +8676,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "24.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#c4b3c1c6c6e492c4196e06fbba824a58e8119a3b" +source = "git+https://github.com/paritytech/polkadot-sdk#6a5b6e03bfc8d0c6f5f05f3180313902c15aee84" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -8703,7 +8708,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "17.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#c4b3c1c6c6e492c4196e06fbba824a58e8119a3b" +source = "git+https://github.com/paritytech/polkadot-sdk#6a5b6e03bfc8d0c6f5f05f3180313902c15aee84" dependencies = [ "Inflector", "expander", @@ -8792,7 +8797,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=v1.10.0-rc3#8d2 [[package]] name = "sp-std" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#c4b3c1c6c6e492c4196e06fbba824a58e8119a3b" +source = "git+https://github.com/paritytech/polkadot-sdk#6a5b6e03bfc8d0c6f5f05f3180313902c15aee84" [[package]] name = "sp-storage" @@ -8809,7 +8814,7 @@ dependencies = [ [[package]] name = "sp-storage" version = "19.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#c4b3c1c6c6e492c4196e06fbba824a58e8119a3b" +source = "git+https://github.com/paritytech/polkadot-sdk#6a5b6e03bfc8d0c6f5f05f3180313902c15aee84" dependencies = [ "impl-serde", "parity-scale-codec", @@ -8844,7 +8849,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "16.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#c4b3c1c6c6e492c4196e06fbba824a58e8119a3b" +source = "git+https://github.com/paritytech/polkadot-sdk#6a5b6e03bfc8d0c6f5f05f3180313902c15aee84" dependencies = [ "parity-scale-codec", "tracing", @@ -8941,7 +8946,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "20.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#c4b3c1c6c6e492c4196e06fbba824a58e8119a3b" +source = "git+https://github.com/paritytech/polkadot-sdk#6a5b6e03bfc8d0c6f5f05f3180313902c15aee84" dependencies = [ "impl-trait-for-tuples", "log", @@ -9243,6 +9248,16 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "subtensor-tools" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "semver 1.0.23", + "toml_edit 0.22.14", +] + [[package]] name = "subtle" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index 622570dc2..b8fe8c4d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ members = [ "pallets/collective", "pallets/registry", "runtime", + "support/tools", "support/macros", "support/linting", ] diff --git a/pallets/admin-utils/Cargo.toml b/pallets/admin-utils/Cargo.toml index 859972fce..c67c00914 100644 --- a/pallets/admin-utils/Cargo.toml +++ b/pallets/admin-utils/Cargo.toml @@ -37,7 +37,8 @@ sp-io = { workspace = true } sp-tracing = { workspace = true } sp-consensus-aura = { workspace = true } pallet-balances = { workspace = true, features = ["std"] } - +pallet-scheduler = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] @@ -50,12 +51,14 @@ std = [ "pallet-subtensor/std", "sp-consensus-aura/std", "pallet-balances/std", + "pallet-scheduler/std", "sp-runtime/std", "sp-tracing/std", "sp-weights/std", "log/std", "sp-core/std", "sp-io/std", + "sp-std/std", "substrate-fixed/std", ] runtime-benchmarks = [ @@ -64,12 +67,14 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "sp-runtime/runtime-benchmarks", - "pallet-subtensor/runtime-benchmarks" + "pallet-subtensor/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "pallet-balances/try-runtime", + "pallet-scheduler/try-runtime", "sp-runtime/try-runtime", "pallet-subtensor/try-runtime" ] diff --git a/pallets/admin-utils/tests/mock.rs b/pallets/admin-utils/tests/mock.rs index 24475a8c6..342ed01cd 100644 --- a/pallets/admin-utils/tests/mock.rs +++ b/pallets/admin-utils/tests/mock.rs @@ -2,18 +2,20 @@ use frame_support::{ assert_ok, derive_impl, parameter_types, - traits::{Everything, Hooks}, + traits::{Everything, Hooks, PrivilegeCmp}, weights, }; use frame_system as system; -use frame_system::{limits, EnsureNever}; +use frame_system::{limits, EnsureNever, EnsureRoot}; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::U256; use sp_core::{ConstU64, H256}; use sp_runtime::{ traits::{BlakeTwo256, ConstU32, IdentityLookup}, - BuildStorage, + BuildStorage, Perbill, }; +use sp_std::cmp::Ordering; +use sp_weights::Weight; type Block = frame_system::mocking::MockBlock; @@ -25,6 +27,7 @@ frame_support::construct_runtime!( Balances: pallet_balances, AdminUtils: pallet_admin_utils, SubtensorModule: pallet_subtensor::{Pallet, Call, Storage, Event, Error}, + Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event}, } ); @@ -120,17 +123,20 @@ parameter_types! { pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn pub const InitialHotkeyEmissionTempo: u64 = 1; pub const InitialNetworkMaxStake: u64 = u64::MAX; // Maximum possible value for u64, this make the make stake infinity + pub const InitialColdkeySwapScheduleDuration: u64 = 5 * 24 * 60 * 60 / 12; // 5 days + pub const InitialDissolveNetworkScheduleDuration: u64 = 5 * 24 * 60 * 60 / 12; // 5 days } impl pallet_subtensor::Config for Test { type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type Currency = Balances; type InitialIssuance = InitialIssuance; type SudoRuntimeCall = TestRuntimeCall; type CouncilOrigin = EnsureNever; type SenateMembers = (); type TriumvirateInterface = (); - + type Scheduler = Scheduler; type InitialMinAllowedWeights = InitialMinAllowedWeights; type InitialEmissionValue = InitialEmissionValue; type InitialMaxWeightsLimit = InitialMaxWeightsLimit; @@ -181,6 +187,9 @@ impl pallet_subtensor::Config for Test { type LiquidAlphaOn = InitialLiquidAlphaOn; type InitialHotkeyEmissionTempo = InitialHotkeyEmissionTempo; type InitialNetworkMaxStake = InitialNetworkMaxStake; + type Preimages = (); + type InitialColdkeySwapScheduleDuration = InitialColdkeySwapScheduleDuration; + type InitialDissolveNetworkScheduleDuration = InitialDissolveNetworkScheduleDuration; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] @@ -226,6 +235,14 @@ impl pallet_balances::Config for Test { type RuntimeHoldReason = (); } +pub struct OriginPrivilegeCmp; + +impl PrivilegeCmp for OriginPrivilegeCmp { + fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option { + None + } +} + impl pallet_admin_utils::Config for Test { type RuntimeEvent = RuntimeEvent; type AuthorityId = AuraId; @@ -235,6 +252,26 @@ impl pallet_admin_utils::Config for Test { type WeightInfo = (); } +parameter_types! { + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * + BlockWeights::get().max_block; + pub const MaxScheduledPerBlock: u32 = 50; + pub const NoPreimagePostponement: Option = Some(10); +} + +impl pallet_scheduler::Config for Test { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = MaxScheduledPerBlock; + type WeightInfo = pallet_scheduler::weights::SubstrateWeight; + type OriginPrivilegeCmp = OriginPrivilegeCmp; + type Preimages = (); +} + // Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { sp_tracing::try_init_simple(); diff --git a/pallets/subtensor/Cargo.toml b/pallets/subtensor/Cargo.toml index 9f022b5b7..3023d1e0d 100644 --- a/pallets/subtensor/Cargo.toml +++ b/pallets/subtensor/Cargo.toml @@ -49,12 +49,15 @@ num-traits = { version = "0.2.19", default-features = false, features = ["libm"] [dev-dependencies] pallet-balances = { workspace = true, features = ["std"] } +pallet-scheduler = { workspace = true } sp-version = { workspace = true } # Substrate sp-tracing = { workspace = true } parity-util-mem = { workspace = true, features = ["primitive-types"] } rand = { workspace = true } sp-core = { workspace = true } +sp-std = { workspace = true } +pallet-preimage = { workspace = true } [features] default = ["std"] @@ -68,6 +71,8 @@ std = [ "pallet-membership/std", "substrate-fixed/std", "pallet-balances/std", + "pallet-preimage/std", + "pallet-scheduler/std", "pallet-transaction-payment/std", "pallet-utility/std", "sp-core/std", @@ -94,13 +99,17 @@ runtime-benchmarks = [ "pallet-membership/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", - "pallet-collective/runtime-benchmarks" + "pallet-collective/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "pallet-balances/try-runtime", "pallet-membership/try-runtime", + "pallet-preimage/try-runtime", + "pallet-scheduler/try-runtime", "pallet-transaction-payment/try-runtime", "pallet-utility/try-runtime", "sp-runtime/try-runtime", diff --git a/pallets/subtensor/rpc/Cargo.toml b/pallets/subtensor/rpc/Cargo.toml index db2f5f147..861c313d8 100644 --- a/pallets/subtensor/rpc/Cargo.toml +++ b/pallets/subtensor/rpc/Cargo.toml @@ -26,8 +26,8 @@ sp-runtime = { workspace = true } # local packages -subtensor-custom-rpc-runtime-api = { version = "0.0.2", path = "../runtime-api", default-features = false } -pallet-subtensor = { version = "4.0.0-dev", path = "../../subtensor", default-features = false } +subtensor-custom-rpc-runtime-api = { path = "../runtime-api", default-features = false } +pallet-subtensor = { path = "../../subtensor", default-features = false } [features] default = ["std"] diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 0a251894e..e9d5f804c 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -429,6 +429,15 @@ reveal_weights { }: reveal_weights(RawOrigin::Signed(hotkey.clone()), netuid, uids, weight_values, salt, version_key) + schedule_swap_coldkey { + let old_coldkey: T::AccountId = account("old_cold", 0, 1); + let new_coldkey: T::AccountId = account("new_cold", 1, 2); + }: schedule_swap_coldkey(RawOrigin::Signed(old_coldkey.clone()), new_coldkey.clone()) + + schedule_dissolve_network { + let coldkey: T::AccountId = account("coldkey", 0, 1); + let netuid = 1; + }: schedule_dissolve_network(RawOrigin::Signed(coldkey.clone()), netuid) benchmark_sudo_set_tx_childkey_take_rate_limit { // We don't need to set up any initial state for this benchmark // as it's a simple setter function that only requires root origin diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 1966f64ab..02fa4d7d6 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -19,6 +19,7 @@ use codec::{Decode, Encode}; use frame_support::sp_runtime::transaction_validity::InvalidTransaction; use frame_support::sp_runtime::transaction_validity::ValidTransaction; use pallet_balances::Call as BalancesCall; +// use pallet_scheduler as Scheduler; use scale_info::TypeInfo; use sp_runtime::{ traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension}, @@ -63,11 +64,13 @@ pub mod pallet { use frame_support::{ dispatch::GetDispatchInfo, pallet_prelude::{DispatchResult, StorageMap, ValueQuery, *}, - traits::{tokens::fungible, UnfilteredDispatchable}, + traits::{ + tokens::fungible, OriginTrait, QueryPreimage, StorePreimage, UnfilteredDispatchable, + }, }; use frame_system::pallet_prelude::*; use sp_core::H256; - use sp_runtime::traits::TrailingZeroInput; + use sp_runtime::traits::{Dispatchable, TrailingZeroInput}; use sp_std::vec; use sp_std::vec::Vec; @@ -76,6 +79,13 @@ pub mod pallet { #[cfg(feature = "std")] use sp_std::prelude::Box; + /// Origin for the pallet + pub type PalletsOriginOf = + <::RuntimeOrigin as OriginTrait>::PalletsOrigin; + + /// Call type for the pallet + pub type CallOf = ::RuntimeCall; + /// Tracks version for migrations. Should be monotonic with respect to the /// order of migrations. (i.e. always increasing) const STORAGE_VERSION: StorageVersion = StorageVersion::new(7); @@ -94,6 +104,9 @@ pub mod pallet { /// Struct for Axon. pub type AxonInfoOf = AxonInfo; + /// local one + pub type LocalCallOf = ::RuntimeCall; + /// Data structure for Axon information. #[crate::freeze_struct("3545cfb0cac4c1f5")] #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] @@ -601,6 +614,26 @@ pub mod pallet { T::InitialNetworkMaxStake::get() } + #[pallet::type_value] + /// Default value for coldkey swap schedule duration + pub fn DefaultColdkeySwapScheduleDuration() -> BlockNumberFor { + T::InitialColdkeySwapScheduleDuration::get() + } + + #[pallet::storage] + pub type ColdkeySwapScheduleDuration = + StorageValue<_, BlockNumberFor, ValueQuery, DefaultColdkeySwapScheduleDuration>; + + #[pallet::type_value] + /// Default value for dissolve network schedule duration + pub fn DefaultDissolveNetworkScheduleDuration() -> BlockNumberFor { + T::InitialDissolveNetworkScheduleDuration::get() + } + + #[pallet::storage] + pub type DissolveNetworkScheduleDuration = + StorageValue<_, BlockNumberFor, ValueQuery, DefaultDissolveNetworkScheduleDuration>; + #[pallet::storage] pub type SenateRequiredStakePercentage = StorageValue<_, u64, ValueQuery, DefaultSenateRequiredStakePercentage>; @@ -754,6 +787,10 @@ pub mod pallet { pub type OwnedHotkeys = StorageMap<_, Blake2_128Concat, T::AccountId, Vec, ValueQuery>; + #[pallet::storage] // --- DMAP ( cold ) --> () | Maps coldkey to if a coldkey swap is scheduled. + pub type ColdkeySwapScheduled = + StorageMap<_, Blake2_128Concat, T::AccountId, (), ValueQuery>; + /// ============================ /// ==== Global Parameters ===== /// ============================ @@ -1253,13 +1290,27 @@ pub enum CallType { Other, } +#[derive(Debug, PartialEq)] +pub enum CustomTransactionError { + ColdkeyInSwapSchedule, +} + +impl From for u8 { + fn from(variant: CustomTransactionError) -> u8 { + match variant { + CustomTransactionError::ColdkeyInSwapSchedule => 0, + } + } +} + #[freeze_struct("61e2b893d5ce6701")] #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] pub struct SubtensorSignedExtension(pub PhantomData); impl Default for SubtensorSignedExtension where - T::RuntimeCall: Dispatchable, + ::RuntimeCall: + Dispatchable, ::RuntimeCall: IsSubType>, { fn default() -> Self { @@ -1269,7 +1320,8 @@ where impl SubtensorSignedExtension where - T::RuntimeCall: Dispatchable, + ::RuntimeCall: + Dispatchable, ::RuntimeCall: IsSubType>, { pub fn new() -> Self { @@ -1300,14 +1352,15 @@ impl sp_std::fmt::Debug for SubtensorSignedE impl SignedExtension for SubtensorSignedExtension where - T::RuntimeCall: Dispatchable, + ::RuntimeCall: + Dispatchable, ::RuntimeCall: IsSubType>, ::RuntimeCall: IsSubType>, { const IDENTIFIER: &'static str = "SubtensorSignedExtension"; type AccountId = T::AccountId; - type Call = T::RuntimeCall; + type Call = ::RuntimeCall; type AdditionalSigned = (); type Pre = (CallType, u64, Self::AccountId); @@ -1398,14 +1451,36 @@ where priority: Self::get_priority_vanilla(), ..Default::default() }), - Some(Call::dissolve_network { .. }) => Ok(ValidTransaction { - priority: Self::get_priority_vanilla(), - ..Default::default() - }), - _ => Ok(ValidTransaction { - priority: Self::get_priority_vanilla(), - ..Default::default() - }), + Some(Call::dissolve_network { .. }) => { + if ColdkeySwapScheduled::::contains_key(who) { + InvalidTransaction::Custom(CustomTransactionError::ColdkeyInSwapSchedule.into()) + .into() + } else { + Ok(ValidTransaction { + priority: Self::get_priority_vanilla(), + ..Default::default() + }) + } + } + _ => { + if let Some( + BalancesCall::transfer_keep_alive { .. } + | BalancesCall::transfer_all { .. } + | BalancesCall::transfer_allow_death { .. }, + ) = call.is_sub_type() + { + if ColdkeySwapScheduled::::contains_key(who) { + return InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into(), + ) + .into(); + } + } + Ok(ValidTransaction { + priority: Self::get_priority_vanilla(), + ..Default::default() + }) + } } } diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index 5b2d0f25e..414af7e6b 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -1,15 +1,20 @@ #![allow(clippy::crate_in_macro_def)] use frame_support::pallet_macros::pallet_section; - /// A [`pallet_section`] that defines the errors for a pallet. /// This can later be imported into the pallet using [`import_section`]. #[pallet_section] mod config { - /// Configure the pallet by specifying the parameters and types on which it depends. #[pallet::config] pub trait Config: frame_system::Config { + /// call type + type RuntimeCall: Parameter + + Dispatchable + + From> + + IsType<::RuntimeCall> + + From>; + /// Because this pallet emits events, it depends on the runtime's definition of an event. type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -31,6 +36,17 @@ mod config { /// Interface to allow other pallets to control who can register identities type TriumvirateInterface: crate::CollectiveInterface; + /// The scheduler type used for scheduling delayed calls. + type Scheduler: ScheduleAnon< + BlockNumberFor, + LocalCallOf, + PalletsOriginOf, + Hasher = Self::Hashing, + >; + + /// the preimage to store the call data. + type Preimages: QueryPreimage + StorePreimage; + /// ================================= /// ==== Initial Value Constants ==== /// ================================= @@ -188,5 +204,11 @@ mod config { /// Initial hotkey emission tempo. #[pallet::constant] type InitialHotkeyEmissionTempo: Get; + /// Coldkey swap schedule duartion. + #[pallet::constant] + type InitialColdkeySwapScheduleDuration: Get>; + /// Dissolve network schedule duration + #[pallet::constant] + type InitialDissolveNetworkScheduleDuration: Get>; } } diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 2d6c5bde0..ce3f92879 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -4,6 +4,10 @@ use frame_support::pallet_macros::pallet_section; /// This can later be imported into the pallet using [`import_section`]. #[pallet_section] mod dispatches { + use frame_support::traits::schedule::v3::Anon as ScheduleAnon; + use frame_support::traits::schedule::DispatchTime; + use frame_system::pallet_prelude::BlockNumberFor; + use sp_runtime::traits::Saturating; /// Dispatchable functions allow users to interact with the pallet and invoke state changes. /// These functions materialize as "extrinsics", which are often compared to transactions. /// Dispatchable functions must be annotated with a weight and must return a DispatchResult. @@ -673,39 +677,14 @@ mod dispatches { .saturating_add(T::DbWeight::get().writes(527)), DispatchClass::Operational, Pays::No))] pub fn swap_coldkey( origin: OriginFor, + old_coldkey: T::AccountId, new_coldkey: T::AccountId, ) -> DispatchResultWithPostInfo { - Self::do_swap_coldkey(origin, &new_coldkey) - } + // Ensure it's called with root privileges (scheduler has root privileges) + ensure_root(origin.clone())?; + log::info!("swap_coldkey: {:?} -> {:?}", old_coldkey, new_coldkey); - /// Unstakes all tokens associated with a hotkey and transfers them to a new coldkey. - /// - /// # Arguments - /// - /// * `origin` - The origin of the call, must be signed by the current coldkey. - /// * `hotkey` - The hotkey associated with the stakes to be unstaked. - /// * `new_coldkey` - The new coldkey to receive the unstaked tokens. - /// - /// # Returns - /// - /// Returns a `DispatchResult` indicating success or failure of the operation. - /// - /// # Weight - /// - /// Weight is calculated based on the number of database reads and writes. - #[cfg(test)] - #[pallet::call_index(72)] - #[pallet::weight((Weight::from_parts(21_000_000, 0) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Operational, Pays::No))] - pub fn schedule_coldkey_swap( - _origin: OriginFor, - _new_coldkey: T::AccountId, - _work: Vec, - _block_number: u64, - _nonce: u64, - ) -> DispatchResult { - Ok(()) + Self::do_swap_coldkey(&old_coldkey, &new_coldkey) } /// Sets the childkey take for a given hotkey. @@ -955,17 +934,6 @@ mod dispatches { Self::user_remove_network(origin, netuid) } - /// Sets values for liquid alpha - #[pallet::call_index(64)] - #[pallet::weight((0, DispatchClass::Operational, Pays::No))] - pub fn sudo_hotfix_swap_coldkey_delegates( - _origin: OriginFor, - _old_coldkey: T::AccountId, - _new_coldkey: T::AccountId, - ) -> DispatchResult { - Ok(()) - } - /// Set a single child for a given hotkey on a specified network. /// /// This function allows a coldkey to set a single child for a given hotkey on a specified network. @@ -1025,6 +993,137 @@ mod dispatches { Ok(().into()) } + /// Schedules a coldkey swap operation to be executed at a future block. + /// + /// This function allows a user to schedule the swapping of their coldkey to a new one + /// at a specified future block. The swap is not executed immediately but is scheduled + /// to occur at the specified block number. + /// + /// # Arguments + /// + /// * `origin` - The origin of the call, which should be signed by the current coldkey owner. + /// * `new_coldkey` - The account ID of the new coldkey that will replace the current one. + /// * `when` - The block number at which the coldkey swap should be executed. + /// + /// # Returns + /// + /// Returns a `DispatchResultWithPostInfo` indicating whether the scheduling was successful. + /// + /// # Errors + /// + /// This function may return an error if: + /// * The origin is not signed. + /// * The scheduling fails due to conflicts or system constraints. + /// + /// # Notes + /// + /// - The actual swap is not performed by this function. It merely schedules the swap operation. + /// - The weight of this call is set to a fixed value and may need adjustment based on benchmarking. + /// + /// # TODO + /// + /// - Implement proper weight calculation based on the complexity of the operation. + /// - Consider adding checks to prevent scheduling too far into the future. + /// TODO: Benchmark this call + #[pallet::call_index(73)] + #[pallet::weight((Weight::from_parts(119_000_000, 0) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(31)), DispatchClass::Operational, Pays::Yes))] + pub fn schedule_swap_coldkey( + origin: OriginFor, + new_coldkey: T::AccountId, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + ensure!( + !ColdkeySwapScheduled::::contains_key(&who), + Error::::SwapAlreadyScheduled + ); + + let current_block: BlockNumberFor = >::block_number(); + let duration: BlockNumberFor = ColdkeySwapScheduleDuration::::get(); + let when: BlockNumberFor = current_block.saturating_add(duration); + + let call = Call::::swap_coldkey { + old_coldkey: who.clone(), + new_coldkey: new_coldkey.clone(), + }; + + let bound_call = T::Preimages::bound(LocalCallOf::::from(call.clone())) + .map_err(|_| Error::::FailedToSchedule)?; + + T::Scheduler::schedule( + DispatchTime::At(when), + None, + 63, + frame_system::RawOrigin::Root.into(), + bound_call, + ) + .map_err(|_| Error::::FailedToSchedule)?; + + ColdkeySwapScheduled::::insert(&who, ()); + // Emit the SwapScheduled event + Self::deposit_event(Event::ColdkeySwapScheduled { + old_coldkey: who.clone(), + new_coldkey: new_coldkey.clone(), + execution_block: when, + }); + + Ok(().into()) + } + + /// Schedule the dissolution of a network at a specified block number. + /// + /// # Arguments + /// + /// * `origin` - The origin of the call, must be signed by the sender. + /// * `netuid` - The u16 network identifier to be dissolved. + /// + /// # Returns + /// + /// Returns a `DispatchResultWithPostInfo` indicating success or failure of the operation. + /// + /// # Weight + /// + /// Weight is calculated based on the number of database reads and writes. + + #[pallet::call_index(74)] + #[pallet::weight((Weight::from_parts(119_000_000, 0) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(31)), DispatchClass::Operational, Pays::Yes))] + pub fn schedule_dissolve_network( + origin: OriginFor, + netuid: u16, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + + let current_block: BlockNumberFor = >::block_number(); + let duration: BlockNumberFor = DissolveNetworkScheduleDuration::::get(); + let when: BlockNumberFor = current_block.saturating_add(duration); + + let call = Call::::dissolve_network { netuid }; + + let bound_call = T::Preimages::bound(LocalCallOf::::from(call.clone())) + .map_err(|_| Error::::FailedToSchedule)?; + + T::Scheduler::schedule( + DispatchTime::At(when), + None, + 63, + frame_system::RawOrigin::Signed(who.clone()).into(), + bound_call, + ) + .map_err(|_| Error::::FailedToSchedule)?; + + // Emit the SwapScheduled event + Self::deposit_event(Event::DissolveNetworkScheduled { + account: who.clone(), + netuid, + execution_block: when, + }); + + Ok(().into()) + } + /// ---- Set prometheus information for the neuron. /// # Args: /// * 'origin': (Origin): diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index 15e90036f..22a0a6f89 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -168,6 +168,16 @@ mod errors { TooManyChildren, /// Default transaction rate limit exceeded. TxRateLimitExceeded, + /// Swap coldkey only callable by root. + SwapColdkeyOnlyCallableByRoot, + /// Swap already scheduled. + SwapAlreadyScheduled, + /// failed to swap coldkey + FailedToSchedule, + /// New coldkey is hotkey + NewColdKeyIsHotkey, + /// New coldkey is in arbitration + NewColdkeyIsInArbitration, /// Childkey take is invalid. InvalidChildkeyTake, /// Childkey take rate limit exceeded. diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index c66a64b9f..b5e34b842 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -172,7 +172,7 @@ mod events { /// The account ID of the new coldkey new_coldkey: T::AccountId, /// The arbitration block for the coldkey swap - arbitration_block: u64, + execution_block: BlockNumberFor, }, /// The arbitration period has been extended ArbitrationPeriodExtended { @@ -187,5 +187,14 @@ mod events { NetworkMaxStakeSet(u16, u64), /// The identity of a coldkey has been set ChainIdentitySet(T::AccountId), + /// A dissolve network extrinsic scheduled. + DissolveNetworkScheduled { + /// The account ID schedule the dissolve network extrisnic + account: T::AccountId, + /// network ID will be dissolved + netuid: u16, + /// extrinsic execution block number + execution_block: BlockNumberFor, + }, } } diff --git a/pallets/subtensor/src/swap/swap_coldkey.rs b/pallets/subtensor/src/swap/swap_coldkey.rs index bd8a11fa1..498549e5c 100644 --- a/pallets/subtensor/src/swap/swap_coldkey.rs +++ b/pallets/subtensor/src/swap/swap_coldkey.rs @@ -30,51 +30,50 @@ impl Pallet { /// /// Weight is tracked and updated throughout the function execution. pub fn do_swap_coldkey( - origin: T::RuntimeOrigin, + old_coldkey: &T::AccountId, new_coldkey: &T::AccountId, ) -> DispatchResultWithPostInfo { - // 1. Ensure the origin is signed and get the old coldkey - let old_coldkey = ensure_signed(origin)?; - // 2. Initialize the weight for this operation let mut weight: Weight = T::DbWeight::get().reads(2); - // 3. Ensure the new coldkey is not associated with any hotkeys ensure!( StakingHotkeys::::get(new_coldkey).is_empty(), Error::::ColdKeyAlreadyAssociated ); + weight = weight.saturating_add(T::DbWeight::get().reads(1)); // 4. Ensure the new coldkey is not a hotkey ensure!( !Self::hotkey_account_exists(new_coldkey), - Error::::ColdKeyAlreadyAssociated + Error::::NewColdKeyIsHotkey ); + weight = weight.saturating_add(T::DbWeight::get().reads(1)); // 5. Calculate the swap cost and ensure sufficient balance let swap_cost = Self::get_key_swap_cost(); - log::debug!("Coldkey swap cost: {:?}", swap_cost); ensure!( - Self::can_remove_balance_from_coldkey_account(&old_coldkey, swap_cost), + Self::can_remove_balance_from_coldkey_account(old_coldkey, swap_cost), Error::::NotEnoughBalanceToPaySwapColdKey ); // 6. Remove and burn the swap cost from the old coldkey's account - let actual_burn_amount = - Self::remove_balance_from_coldkey_account(&old_coldkey, swap_cost)?; + let actual_burn_amount = Self::remove_balance_from_coldkey_account(old_coldkey, swap_cost)?; Self::burn_tokens(actual_burn_amount); // 7. Update the weight for the balance operations weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); // 8. Perform the actual coldkey swap - let _ = Self::perform_swap_coldkey(&old_coldkey, new_coldkey, &mut weight); + let _ = Self::perform_swap_coldkey(old_coldkey, new_coldkey, &mut weight); // 9. Update the last transaction block for the new coldkey Self::set_last_tx_block(new_coldkey, Self::get_current_block_as_u64()); weight.saturating_accrue(T::DbWeight::get().writes(1)); - // 10. Emit the ColdkeySwapped event + // 10. Remove the coldkey swap scheduled record + ColdkeySwapScheduled::::remove(old_coldkey); + + // 11. Emit the ColdkeySwapped event Self::deposit_event(Event::ColdkeySwapped { old_coldkey: old_coldkey.clone(), new_coldkey: new_coldkey.clone(), diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 366494d11..793e34bff 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -200,11 +200,12 @@ impl Pallet { // 8. Swap delegates. // Delegates( hotkey ) -> take value -- the hotkey delegate take value. - let old_delegate_take = Delegates::::get(old_hotkey); - Delegates::::remove(old_hotkey); // Remove the old delegate take. - Delegates::::insert(new_hotkey, old_delegate_take); // Insert the new delegate take. - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - + if Delegates::::contains_key(old_hotkey) { + let old_delegate_take = Delegates::::get(old_hotkey); + Delegates::::remove(old_hotkey); + Delegates::::insert(new_hotkey, old_delegate_take); + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } // 9. Swap all subnet specific info. let all_netuids: Vec = Self::get_all_subnet_netuids(); for netuid in all_netuids { diff --git a/pallets/subtensor/tests/coinbase.rs b/pallets/subtensor/tests/coinbase.rs index d6e48bbcc..a6c1acde1 100644 --- a/pallets/subtensor/tests/coinbase.rs +++ b/pallets/subtensor/tests/coinbase.rs @@ -6,6 +6,7 @@ use sp_core::U256; // Test the ability to hash all sorts of hotkeys. #[test] + fn test_hotkey_hashing() { new_test_ext(1).execute_with(|| { for i in 0..10000 { @@ -17,6 +18,7 @@ fn test_hotkey_hashing() { // Test drain tempo on hotkeys. // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test coinbase test_hotkey_drain_time -- --nocapture #[test] + fn test_hotkey_drain_time() { new_test_ext(1).execute_with(|| { // Block 0 @@ -44,6 +46,7 @@ fn test_hotkey_drain_time() { // To run this test specifically, use the following command: // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test coinbase test_coinbase_basic -- --nocapture #[test] + fn test_coinbase_basic() { new_test_ext(1).execute_with(|| { // Define network ID @@ -135,6 +138,7 @@ fn test_coinbase_basic() { // Test getting and setting hotkey emission tempo // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test coinbase test_set_and_get_hotkey_emission_tempo -- --nocapture #[test] + fn test_set_and_get_hotkey_emission_tempo() { new_test_ext(1).execute_with(|| { // Get the default hotkey emission tempo diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index 6785bdb02..aa93c3531 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -2,11 +2,10 @@ use frame_support::derive_impl; use frame_support::dispatch::DispatchResultWithPostInfo; use frame_support::weights::constants::RocksDbWeight; -// use frame_support::weights::constants::WEIGHT_PER_SECOND; use frame_support::weights::Weight; use frame_support::{ assert_ok, parameter_types, - traits::{Everything, Hooks}, + traits::{Everything, Hooks, PrivilegeCmp}, }; use frame_system as system; use frame_system::{limits, EnsureNever, EnsureRoot, RawOrigin}; @@ -17,6 +16,7 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, BuildStorage, }; +use sp_std::cmp::Ordering; type Block = frame_system::mocking::MockBlock; @@ -32,6 +32,8 @@ frame_support::construct_runtime!( SenateMembers: pallet_membership::::{Pallet, Call, Storage, Event, Config}, SubtensorModule: pallet_subtensor::{Pallet, Call, Storage, Event}, Utility: pallet_utility::{Pallet, Call, Storage, Event}, + Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event}, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event}, } ); @@ -78,7 +80,6 @@ impl pallet_balances::Config for Test { type WeightInfo = (); type MaxReserves = (); type ReserveIdentifier = (); - type RuntimeHoldReason = (); type FreezeIdentifier = (); type MaxFreezes = (); @@ -174,7 +175,8 @@ parameter_types! { pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn pub const InitialHotkeyEmissionTempo: u64 = 0; // Defaults to draining every block. pub const InitialNetworkMaxStake: u64 = u64::MAX; // Maximum possible value for u64 - + pub const InitialColdkeySwapScheduleDuration: u64 = 5 * 24 * 60 * 60 / 12; // Default as 5 days + pub const InitialDissolveNetworkScheduleDuration: u64 = 5 * 24 * 60 * 60 / 12; // Default as 5 days } // Configure collective pallet for council @@ -338,13 +340,14 @@ impl pallet_membership::Config for Test { impl pallet_subtensor::Config for Test { type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type Currency = Balances; type InitialIssuance = InitialIssuance; type SudoRuntimeCall = TestRuntimeCall; type CouncilOrigin = frame_system::EnsureSigned; type SenateMembers = ManageSenateMembers; type TriumvirateInterface = TriumvirateVotes; - + type Scheduler = Scheduler; type InitialMinAllowedWeights = InitialMinAllowedWeights; type InitialEmissionValue = InitialEmissionValue; type InitialMaxWeightsLimit = InitialMaxWeightsLimit; @@ -395,6 +398,37 @@ impl pallet_subtensor::Config for Test { type LiquidAlphaOn = InitialLiquidAlphaOn; type InitialHotkeyEmissionTempo = InitialHotkeyEmissionTempo; type InitialNetworkMaxStake = InitialNetworkMaxStake; + type Preimages = Preimage; + type InitialColdkeySwapScheduleDuration = InitialColdkeySwapScheduleDuration; + type InitialDissolveNetworkScheduleDuration = InitialDissolveNetworkScheduleDuration; +} + +pub struct OriginPrivilegeCmp; + +impl PrivilegeCmp for OriginPrivilegeCmp { + fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option { + Some(Ordering::Less) + } +} + +parameter_types! { + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * + BlockWeights::get().max_block; + pub const MaxScheduledPerBlock: u32 = 50; + pub const NoPreimagePostponement: Option = Some(10); +} + +impl pallet_scheduler::Config for Test { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = MaxScheduledPerBlock; + type WeightInfo = pallet_scheduler::weights::SubstrateWeight; + type OriginPrivilegeCmp = OriginPrivilegeCmp; + type Preimages = Preimage; } impl pallet_utility::Config for Test { @@ -404,6 +438,20 @@ impl pallet_utility::Config for Test { type WeightInfo = pallet_utility::weights::SubstrateWeight; } +parameter_types! { + pub const PreimageMaxSize: u32 = 4096 * 1024; + pub const PreimageBaseDeposit: Balance = 1; + pub const PreimageByteDeposit: Balance = 1; +} + +impl pallet_preimage::Config for Test { + type WeightInfo = pallet_preimage::weights::SubstrateWeight; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type Consideration = (); +} + #[allow(dead_code)] // Build genesis storage according to the mock runtime. pub fn new_test_ext(block_number: BlockNumber) -> sp_io::TestExternalities { @@ -438,22 +486,30 @@ pub fn test_ext_with_balances(balances: Vec<(U256, u128)>) -> sp_io::TestExterna #[allow(dead_code)] pub(crate) fn step_block(n: u16) { for _ in 0..n { + Scheduler::on_finalize(System::block_number()); SubtensorModule::on_finalize(System::block_number()); System::on_finalize(System::block_number()); System::set_block_number(System::block_number() + 1); System::on_initialize(System::block_number()); SubtensorModule::on_initialize(System::block_number()); + Scheduler::on_initialize(System::block_number()); } } #[allow(dead_code)] pub(crate) fn run_to_block(n: u64) { while System::block_number() < n { + Scheduler::on_finalize(System::block_number()); SubtensorModule::on_finalize(System::block_number()); System::on_finalize(System::block_number()); System::set_block_number(System::block_number() + 1); System::on_initialize(System::block_number()); + System::events().iter().for_each(|event| { + log::info!("Event: {:?}", event.event); + }); + System::reset_events(); SubtensorModule::on_initialize(System::block_number()); + Scheduler::on_initialize(System::block_number()); } } diff --git a/pallets/subtensor/tests/networks.rs b/pallets/subtensor/tests/networks.rs index 93e563683..b41ff985d 100644 --- a/pallets/subtensor/tests/networks.rs +++ b/pallets/subtensor/tests/networks.rs @@ -1,420 +1,96 @@ -// DEPRECATED mod mock; -// use frame_support::{ -// assert_ok, -// dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, -// sp_std::vec, -// }; -// use frame_system::Config; -// use frame_system::{EventRecord, Phase}; -// use mock::*; -// use pallet_subtensor::Error; -// use sp_core::{H256, U256}; - -// #[allow(dead_code)] -// fn record(event: RuntimeEvent) -> EventRecord { -// EventRecord { -// phase: Phase::Initialization, -// event, -// topics: vec![], -// } -// } - -// /*TO DO SAM: write test for LatuUpdate after it is set */ -// // --- add network tests ---- -// #[test] -// fn test_add_network_dispatch_info_ok() { -// new_test_ext().execute_with(|| { -// let netuid: u16 = 1; -// let modality = 0; -// let tempo: u16 = 13; -// let call = RuntimeCall::SubtensorModule(SubtensorCall::sudo_add_network { -// netuid, -// tempo, -// modality, -// }); -// assert_eq!( -// call.get_dispatch_info(), -// DispatchInfo { -// weight: frame_support::weights::Weight::from_parts(50000000, 0), -// class: DispatchClass::Operational, -// pays_fee: Pays::No -// } -// ); -// }); -// } - -// #[test] -// fn test_add_network() { -// new_test_ext().execute_with(|| { -// let modality = 0; -// let tempo: u16 = 13; -// add_network(10, tempo, modality); -// assert_eq!(SubtensorModule::get_number_of_subnets(), 1); -// add_network(20, tempo, modality); -// assert_eq!(SubtensorModule::get_number_of_subnets(), 2); -// }); -// } - -// #[test] -// fn test_add_network_check_tempo() { -// new_test_ext().execute_with(|| { -// let modality = 0; -// let tempo: u16 = 13; -// assert_eq!(SubtensorModule::get_tempo(1), 0); -// add_network(1, tempo, modality); -// assert_eq!(SubtensorModule::get_tempo(1), 13); -// }); -// } - -// #[test] -// fn test_clear_min_allowed_weight_for_network() { -// new_test_ext().execute_with(|| { -// let netuid: u16 = 1; -// let min_allowed_weight = 2; -// let tempo: u16 = 13; -// add_network(netuid, tempo, 0); -// register_ok_neuron(1, U256::from(55), U256::from(66), 0); -// SubtensorModule::set_min_allowed_weights(netuid, min_allowed_weight); -// assert_eq!(SubtensorModule::get_min_allowed_weights(netuid), 2); -// assert_ok!(SubtensorModule::do_remove_network( -// <::RuntimeOrigin>::root(), -// netuid -// )); -// assert_eq!(SubtensorModule::get_min_allowed_weights(netuid), 0); -// }); -// } - -// #[test] -// fn test_remove_uid_for_network() { -// new_test_ext().execute_with(|| { -// let netuid: u16 = 1; -// let tempo: u16 = 13; -// add_network(netuid, tempo, 0); -// register_ok_neuron(1, U256::from(55), U256::from(66), 0); -// let neuron_id; -// match SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(55)) { -// Ok(k) => neuron_id = k, -// Err(e) => panic!("Error: {:?}", e), -// } -// assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(55)).is_ok()); -// assert_eq!(neuron_id, 0); -// register_ok_neuron(1, U256::from(56), U256::from(67), 300000); -// let neuron_uid = -// SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(56)).unwrap(); -// assert_eq!(neuron_uid, 1); -// assert_ok!(SubtensorModule::do_remove_network( -// <::RuntimeOrigin>::root(), -// netuid -// )); -// assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(55)).is_err()); -// }); -// } - -// #[test] -// fn test_remove_difficulty_for_network() { -// new_test_ext().execute_with(|| { -// let netuid: u16 = 1; -// let difficulty: u64 = 10; -// let tempo: u16 = 13; -// add_network(netuid, tempo, 0); -// register_ok_neuron(1, U256::from(55), U256::from(66), 0); -// assert_ok!(SubtensorModule::sudo_set_difficulty( -// <::RuntimeOrigin>::root(), -// netuid, -// difficulty -// )); -// assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), difficulty); -// assert_ok!(SubtensorModule::do_remove_network( -// <::RuntimeOrigin>::root(), -// netuid -// )); -// assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 10000); -// }); -// } - -// #[test] -// fn test_remove_network_for_all_hotkeys() { -// new_test_ext().execute_with(|| { -// let netuid: u16 = 1; -// let tempo: u16 = 13; -// add_network(netuid, tempo, 0); -// register_ok_neuron(1, U256::from(55), U256::from(66), 0); -// register_ok_neuron(1, U256::from(77), U256::from(88), 65536); -// assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 2); -// assert_ok!(SubtensorModule::do_remove_network( -// <::RuntimeOrigin>::root(), -// netuid -// )); -// assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 0); -// }); -// } - -// #[test] -// fn test_network_set_default_value_for_other_parameters() { -// new_test_ext().execute_with(|| { -// let netuid: u16 = 1; -// let tempo: u16 = 13; -// add_network(netuid, tempo, 0); -// assert_eq!(SubtensorModule::get_min_allowed_weights(netuid), 0); -// assert_eq!(SubtensorModule::get_emission_value(netuid), 0); -// assert_eq!(SubtensorModule::get_max_weight_limit(netuid), u16::MAX); -// assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 10000); -// assert_eq!(SubtensorModule::get_immunity_period(netuid), 2); -// }); -// } - -// // --- Set Emission Ratios Tests -// #[test] -// fn test_network_set_emission_ratios_dispatch_info_ok() { -// new_test_ext().execute_with(|| { -// let netuids: Vec = vec![1, 2]; -// let emission: Vec = vec![100000000, 900000000]; -// let call = RuntimeCall::SubtensorModule(SubtensorCall::sudo_set_emission_values { -// netuids, -// emission, -// }); -// assert_eq!( -// call.get_dispatch_info(), -// DispatchInfo { -// weight: frame_support::weights::Weight::from_parts(28000000, 0), -// class: DispatchClass::Operational, -// pays_fee: Pays::No -// } -// ); -// }); -// } - -// #[test] -// fn test_network_set_emission_ratios_ok() { -// new_test_ext().execute_with(|| { -// let netuids: Vec = vec![1, 2]; -// let emission: Vec = vec![100000000, 900000000]; -// add_network(1, 0, 0); -// add_network(2, 0, 0); -// assert_ok!(SubtensorModule::sudo_set_emission_values( -// <::RuntimeOrigin>::root(), -// netuids, -// emission -// )); -// }); -// } - -// #[test] -// fn test_network_set_emission_ratios_fail_summation() { -// new_test_ext().execute_with(|| { -// let netuids: Vec = vec![1, 2]; -// let emission: Vec = vec![100000000, 910000000]; -// add_network(1, 0, 0); -// add_network(2, 0, 0); -// assert_eq!( -// SubtensorModule::sudo_set_emission_values( -// <::RuntimeOrigin>::root(), -// netuids, -// emission -// ), -// Err(Error::::InvalidEmissionValues.into()) -// ); -// }); -// } - -// #[test] -// fn test_network_set_emission_invalid_netuids() { -// new_test_ext().execute_with(|| { -// let netuids: Vec = vec![1, 2]; -// let emission: Vec = vec![100000000, 900000000]; -// add_network(1, 0, 0); -// assert_eq!( -// SubtensorModule::sudo_set_emission_values( -// <::RuntimeOrigin>::root(), -// netuids, -// emission -// ), -// Err(Error::::IncorrectNetuidsLength.into()) -// ); -// }); -// } - -// #[test] -// fn test_network_set_emission_ratios_fail_net() { -// new_test_ext().execute_with(|| { -// let netuids: Vec = vec![1, 2]; -// let emission: Vec = vec![100000000, 900000000]; -// add_network(1, 0, 0); -// add_network(3, 0, 0); -// assert_eq!( -// SubtensorModule::sudo_set_emission_values( -// <::RuntimeOrigin>::root(), -// netuids, -// emission -// ), -// Err(Error::::UidVecContainInvalidOne.into()) -// ); -// }); -// } - -// #[test] -// fn test_add_difficulty_fail() { -// new_test_ext().execute_with(|| { -// let netuid: u16 = 1; -// assert_eq!( -// SubtensorModule::sudo_set_difficulty( -// <::RuntimeOrigin>::root(), -// netuid, -// 120000 -// ), -// Err(Error::::NetworkDoesNotExist.into()) -// ); -// }); -// } - -// #[test] -// fn test_multi_tempo_with_emission() { -// new_test_ext().execute_with(|| { -// let netuid: u16 = 1; -// assert_eq!( -// SubtensorModule::sudo_set_difficulty( -// <::RuntimeOrigin>::root(), -// netuid, -// 120000 -// ), -// Err(Error::::NetworkDoesNotExist.into()) -// ); -// }); -// } - -// #[test] -// // Required by the test otherwise it would panic if compiled in debug mode -// #[allow(arithmetic_overflow)] -// fn test_set_emission_values_errors_on_emission_sum_overflow() { -// new_test_ext().execute_with(|| { -// let netuids: Vec = vec![1, 2]; -// // u64(u64::MAX + 1..000..1) equals to 1_000_000_000 which is the same as -// // the value of Self::get_block_emission() expected by the extrinsic -// let emission: Vec = vec![u64::MAX, 1_000_000_001]; -// add_network(1, 0, 0); -// add_network(2, 0, 0); -// assert_eq!( -// SubtensorModule::sudo_set_emission_values( -// <::RuntimeOrigin>::root(), -// netuids, -// emission -// ), -// Err(Error::::InvalidEmissionValues.into()) -// ); -// }); -// } - -// #[test] -// #[allow(arithmetic_overflow)] -// fn test_set_emission_values_no_errors() { -// new_test_ext().execute_with(|| { -// let netuids: Vec = vec![1, 2]; -// let emission: Vec = vec![600_000_000, 400_000_000]; - -// add_network(1, 0, 0); -// add_network(2, 0, 0); -// assert_eq!( -// SubtensorModule::sudo_set_emission_values( -// <::RuntimeOrigin>::root(), -// netuids, -// emission -// ), -// Ok(()) -// ); -// }); -// } - -// #[test] -// // Required by the test otherwise it would panic if compiled in debug mode -// #[allow(arithmetic_overflow)] -// fn test_set_emission_values_sum_too_large() { -// new_test_ext().execute_with(|| { -// let netuids: Vec = vec![1, 2]; -// // u64(1_000_000_000 + 1) equals to 1_000_000_001 which is more than -// // the value of Self::get_block_emission() expected by the extrinsic -// let emission: Vec = vec![1_000_000_000, 1]; -// add_network(1, 0, 0); -// add_network(2, 0, 0); -// assert_eq!( -// SubtensorModule::sudo_set_emission_values( -// <::RuntimeOrigin>::root(), -// netuids, -// emission -// ), -// Err(Error::::InvalidEmissionValues.into()) -// ); -// }); -// } - -// #[test] -// // Required by the test otherwise it would panic if compiled in debug mode -// #[allow(arithmetic_overflow)] -// fn test_set_emission_values_sum_too_small() { -// new_test_ext().execute_with(|| { -// let netuids: Vec = vec![1, 2]; -// // u64(1 + 2_000) equals to 2_001 which is LESS than -// // the value of Self::get_block_emission() expected by the extrinsic -// let emission: Vec = vec![1, 2_000]; -// add_network(1, 0, 0); -// add_network(2, 0, 0); -// assert_eq!( -// SubtensorModule::sudo_set_emission_values( -// <::RuntimeOrigin>::root(), -// netuids, -// emission -// ), -// Err(Error::::InvalidEmissionValues.into()) -// ); -// }); -// } - -// #[test] -// fn test_set_emission_values_too_many_netuids() { -// new_test_ext().execute_with(|| { -// let netuids: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - -// // Sums to 1_000_000_000 and has 10 elements -// let emission: Vec = vec![1_000_000_000, 0, 0, 0, 0, 0, 0, 0, 0, 0]; -// add_network(1, 0, 0); -// add_network(2, 0, 0); -// // We only add 2 networks, so this should fail -// assert_eq!( -// SubtensorModule::sudo_set_emission_values( -// <::RuntimeOrigin>::root(), -// netuids, -// emission -// ), -// Err(Error::::IncorrectNetuidsLength.into()) -// ); -// }); -// } - -// #[test] -// fn test_set_emission_values_over_u16_max_values() { -// new_test_ext().execute_with(|| { -// // Make vec of u16 with length 2^16 + 2 -// let netuids: Vec = vec![0; 0x10002]; -// // This is greater than u16::MAX -// assert!(netuids.len() > u16::MAX as usize); -// // On cast to u16, this will be 2 -// assert!(netuids.len() as u16 == 2); - -// // Sums to 1_000_000_000 and the length is 65536 -// let mut emission: Vec = vec![0; netuids.len()]; -// emission[0] = 1_000_000_000; - -// add_network(1, 0, 0); -// add_network(2, 0, 0); -// // We only add 2 networks, so this should fail -// // but if we cast to u16 during length comparison, -// // the length will be 2 and the check will pass -// assert_eq!( -// SubtensorModule::sudo_set_emission_values( -// <::RuntimeOrigin>::root(), -// netuids, -// emission -// ), -// Err(Error::::IncorrectNetuidsLength.into()) -// ); -// }); -// } +use crate::mock::*; +use frame_support::assert_ok; +use frame_system::Config; +use pallet_subtensor::{DissolveNetworkScheduleDuration, Event}; +use sp_core::U256; + +mod mock; + +#[test] +fn test_registration_ok() { + new_test_ext(1).execute_with(|| { + let block_number: u64 = 0; + let netuid: u16 = 2; + let tempo: u16 = 13; + let hotkey_account_id: U256 = U256::from(1); + let coldkey_account_id = U256::from(0); // Neighbour of the beast, har har + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 129123813, + &hotkey_account_id, + ); + + //add network + add_network(netuid, tempo, 0); + + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work.clone(), + hotkey_account_id, + coldkey_account_id + )); + + assert_ok!(SubtensorModule::user_remove_network( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid + )); + + assert!(!SubtensorModule::if_subnet_exist(netuid)) + }) +} + +#[test] +fn test_schedule_dissolve_network_execution() { + new_test_ext(1).execute_with(|| { + let block_number: u64 = 0; + let netuid: u16 = 2; + let tempo: u16 = 13; + let hotkey_account_id: U256 = U256::from(1); + let coldkey_account_id = U256::from(0); // Neighbour of the beast, har har + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 129123813, + &hotkey_account_id, + ); + + //add network + add_network(netuid, tempo, 0); + + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work.clone(), + hotkey_account_id, + coldkey_account_id + )); + + assert!(SubtensorModule::if_subnet_exist(netuid)); + + assert_ok!(SubtensorModule::schedule_dissolve_network( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid + )); + + let current_block = System::block_number(); + let execution_block = current_block + DissolveNetworkScheduleDuration::::get(); + + System::assert_last_event( + Event::DissolveNetworkScheduled { + account: coldkey_account_id, + netuid, + execution_block, + } + .into(), + ); + + run_to_block(execution_block); + assert!(!SubtensorModule::if_subnet_exist(netuid)); + }) +} diff --git a/pallets/subtensor/tests/swap_coldkey.rs b/pallets/subtensor/tests/swap_coldkey.rs index 9203e2b3f..ec030ebee 100644 --- a/pallets/subtensor/tests/swap_coldkey.rs +++ b/pallets/subtensor/tests/swap_coldkey.rs @@ -4,10 +4,16 @@ use frame_support::weights::Weight; use frame_support::{assert_err, assert_noop, assert_ok}; use frame_system::{Config, RawOrigin}; mod mock; +use frame_support::error::BadOrigin; +use frame_support::traits::schedule::v3::Named as ScheduleNamed; +use frame_support::traits::schedule::DispatchTime; +use frame_support::traits::OnInitialize; use mock::*; use pallet_subtensor::*; +use pallet_subtensor::{Call, ColdkeySwapScheduleDuration, Error}; use sp_core::H256; use sp_core::U256; +use sp_runtime::DispatchError; // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_total_hotkey_coldkey_stakes_this_interval --exact --nocapture #[test] @@ -542,7 +548,8 @@ fn test_do_swap_coldkey_success() { // Perform the swap assert_ok!(SubtensorModule::do_swap_coldkey( - <::RuntimeOrigin>::signed(old_coldkey), + // <::RuntimeOrigin>::signed(old_coldkey), + &old_coldkey, &new_coldkey )); @@ -882,10 +889,7 @@ fn test_do_swap_coldkey_with_subnet_ownership() { OwnedHotkeys::::insert(old_coldkey, vec![hotkey]); // Perform the swap - assert_ok!(SubtensorModule::do_swap_coldkey( - <::RuntimeOrigin>::signed(old_coldkey), - &new_coldkey - )); + assert_ok!(SubtensorModule::do_swap_coldkey(&old_coldkey, &new_coldkey)); // Verify subnet ownership transfer assert_eq!(SubnetOwner::::get(netuid), new_coldkey); @@ -1286,3 +1290,193 @@ fn test_coldkey_delegations() { assert_eq!(Stake::::get(delegate, coldkey), 0); }); } + +#[test] +fn test_schedule_swap_coldkey_success() { + new_test_ext(1).execute_with(|| { + // Initialize test accounts + let old_coldkey: U256 = U256::from(1); + let new_coldkey: U256 = U256::from(2); + + // Add balance to the old coldkey account + SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, 1000); + + // Schedule the coldkey swap + assert_ok!(SubtensorModule::schedule_swap_coldkey( + <::RuntimeOrigin>::signed(old_coldkey), + new_coldkey + )); + + // Get the current block number + let current_block: u64 = System::block_number(); + + // Calculate the expected execution block (5 days from now) + let expected_execution_block: u64 = current_block + 5 * 24 * 60 * 60 / 12; + + // Check for the SwapScheduled event + System::assert_last_event( + Event::ColdkeySwapScheduled { + old_coldkey, + new_coldkey, + execution_block: expected_execution_block, + } + .into(), + ); + + // TODO: Add additional checks to ensure the swap is correctly scheduled in the system + // For example, verify that the swap is present in the appropriate storage or scheduler + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_schedule_swap_coldkey_duplicate --exact --nocapture +#[test] +fn test_schedule_swap_coldkey_duplicate() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + + SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, 2000); + + assert_ok!(SubtensorModule::schedule_swap_coldkey( + <::RuntimeOrigin>::signed(old_coldkey), + new_coldkey + )); + + // Attempt to schedule again + assert_noop!( + SubtensorModule::schedule_swap_coldkey( + <::RuntimeOrigin>::signed(old_coldkey), + new_coldkey + ), + Error::::SwapAlreadyScheduled + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_schedule_swap_coldkey_execution --exact --nocapture +#[test] +fn test_schedule_swap_coldkey_execution() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let hotkey = U256::from(3); + let netuid = 1u16; + let stake_amount = 100; + + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, old_coldkey, 0); + SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, 1000000000000000); + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(old_coldkey), + hotkey, + stake_amount + )); + + // Check initial ownership + assert_eq!( + Owner::::get(hotkey), + old_coldkey, + "Initial ownership check failed" + ); + + // Schedule the swap + assert_ok!(SubtensorModule::schedule_swap_coldkey( + <::RuntimeOrigin>::signed(old_coldkey), + new_coldkey + )); + + // Get the scheduled execution block + let current_block = System::block_number(); + let execution_block = current_block + ColdkeySwapScheduleDuration::::get(); + + System::assert_last_event( + Event::ColdkeySwapScheduled { + old_coldkey, + new_coldkey, + execution_block, + } + .into(), + ); + + run_to_block(execution_block); + + // Run on_initialize for the execution block + SubtensorModule::on_initialize(execution_block); + + // Also run Scheduler's on_initialize + as OnInitialize>::on_initialize( + execution_block, + ); + + // Check if the swap has occurred + let new_owner = Owner::::get(hotkey); + assert_eq!( + new_owner, new_coldkey, + "Ownership was not updated as expected" + ); + + assert_eq!( + Stake::::get(hotkey, new_coldkey), + stake_amount, + "Stake was not transferred to new coldkey" + ); + assert_eq!( + Stake::::get(hotkey, old_coldkey), + 0, + "Old coldkey still has stake" + ); + + // Check for the SwapExecuted event + System::assert_has_event( + Event::ColdkeySwapped { + old_coldkey, + new_coldkey, + } + .into(), + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_direct_swap_coldkey_call_fails --exact --nocapture +#[test] +fn test_direct_swap_coldkey_call_fails() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + + assert_noop!( + SubtensorModule::swap_coldkey( + <::RuntimeOrigin>::signed(old_coldkey), + old_coldkey, + new_coldkey + ), + BadOrigin + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_schedule_swap_coldkey_with_pending_swap --exact --nocapture +#[test] +fn test_schedule_swap_coldkey_with_pending_swap() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey1 = U256::from(2); + let new_coldkey2 = U256::from(3); + + SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, 2000); + + assert_ok!(SubtensorModule::schedule_swap_coldkey( + <::RuntimeOrigin>::signed(old_coldkey), + new_coldkey1 + )); + + // Attempt to schedule another swap before the first one executes + assert_noop!( + SubtensorModule::schedule_swap_coldkey( + <::RuntimeOrigin>::signed(old_coldkey), + new_coldkey2 + ), + Error::::SwapAlreadyScheduled + ); + }); +} diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 042d0337c..8a2886eb1 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -21,7 +21,7 @@ path = "src/spec_version.rs" [dependencies] subtensor-macros.workspace = true -subtensor-custom-rpc-runtime-api = { version = "0.0.2", path = "../pallets/subtensor/runtime-api", default-features = false } +subtensor-custom-rpc-runtime-api = { path = "../pallets/subtensor/runtime-api", default-features = false } smallvec = { workspace = true } log = { workspace = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ @@ -155,7 +155,7 @@ std = [ "sp-tracing/std", "log/std", "sp-storage/std", - "sp-genesis-builder/std" + "sp-genesis-builder/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", @@ -178,7 +178,7 @@ runtime-benchmarks = [ "pallet-multisig/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", - "pallet-sudo/runtime-benchmarks" + "pallet-sudo/runtime-benchmarks", ] try-runtime = [ "frame-try-runtime/try-runtime", @@ -204,6 +204,6 @@ try-runtime = [ "sp-runtime/try-runtime", "pallet-admin-utils/try-runtime", "pallet-commitments/try-runtime", - "pallet-registry/try-runtime" + "pallet-registry/try-runtime", ] metadata-hash = ["substrate-wasm-builder/metadata-hash"] diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index ab88db026..e6c0e9d32 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -70,6 +70,7 @@ pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; // Subtensor module +pub use pallet_scheduler; pub use pallet_subtensor; // An index to a block. @@ -937,17 +938,20 @@ parameter_types! { pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn pub const SubtensorInitialHotkeyEmissionTempo: u64 = 7200; // Drain every day. pub const SubtensorInitialNetworkMaxStake: u64 = u64::MAX; // Maximum possible value for u64, this make the make stake infinity + pub const InitialColdkeySwapScheduleDuration: BlockNumber = 5 * 24 * 60 * 60 / 12; // 5 days + pub const InitialDissolveNetworkScheduleDuration: BlockNumber = 5 * 24 * 60 * 60 / 12; // 5 days } impl pallet_subtensor::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type SudoRuntimeCall = RuntimeCall; type Currency = Balances; type CouncilOrigin = EnsureMajoritySenate; type SenateMembers = ManageSenateMembers; type TriumvirateInterface = TriumvirateVotes; - + type Scheduler = Scheduler; type InitialRho = SubtensorInitialRho; type InitialKappa = SubtensorInitialKappa; type InitialMaxAllowedUids = SubtensorInitialMaxAllowedUids; @@ -999,6 +1003,9 @@ impl pallet_subtensor::Config for Runtime { type LiquidAlphaOn = InitialLiquidAlphaOn; type InitialHotkeyEmissionTempo = SubtensorInitialHotkeyEmissionTempo; type InitialNetworkMaxStake = SubtensorInitialNetworkMaxStake; + type Preimages = Preimage; + type InitialColdkeySwapScheduleDuration = InitialColdkeySwapScheduleDuration; + type InitialDissolveNetworkScheduleDuration = InitialDissolveNetworkScheduleDuration; } use sp_runtime::BoundedVec; @@ -1038,12 +1045,12 @@ construct_runtime!( Sudo: pallet_sudo, Multisig: pallet_multisig, Preimage: pallet_preimage, - Scheduler: pallet_scheduler, Proxy: pallet_proxy, Registry: pallet_registry, Commitments: pallet_commitments, AdminUtils: pallet_admin_utils, SafeMode: pallet_safe_mode, + Scheduler: pallet_scheduler, } ); diff --git a/scripts/publish.sh b/scripts/publish.sh new file mode 100644 index 000000000..3eb0fc6a5 --- /dev/null +++ b/scripts/publish.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -ex +cd support/macros +cargo publish +cd ../.. +cd pallets/commitments +cargo publish +cd .. +cd collective +cargo publish +cd .. +cd registry +cargo publish +cd .. +cd subtensor +cargo publish +cd runtime-api +cargo publish +cd ../.. +cd admin-utils +cargo publish +cd ../.. +cd runtime +cargo publish +cd .. +cd node +cargo publish +echo "published successfully." diff --git a/support/tools/Cargo.toml b/support/tools/Cargo.toml new file mode 100644 index 000000000..fa3e1fd50 --- /dev/null +++ b/support/tools/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "subtensor-tools" +version = "0.1.0" +edition = "2021" +license = "MIT" + +description = "support tools for Subtensor" +repository = "https://github.com/opentensor/subtensor" +homepage = "https://bittensor.com" + +[[bin]] +name = "bump-version" +path = "src/bump_version.rs" + +[dependencies] +anyhow = "1.0" +clap = { version = "4.5", features = ["derive"] } +semver = "1.0" +toml_edit = "0.22" diff --git a/support/tools/src/bump_version.rs b/support/tools/src/bump_version.rs new file mode 100644 index 000000000..a16293c30 --- /dev/null +++ b/support/tools/src/bump_version.rs @@ -0,0 +1,49 @@ +use clap::Parser; +use semver::Version; +use std::{ + fs, + io::{Read, Seek, Write}, + str::FromStr, +}; +use toml_edit::{DocumentMut, Item, Value}; + +const TOML_PATHS: [&str; 9] = [ + "support/macros", + "pallets/commitments", + "pallets/collective", + "pallets/registry", + "pallets/subtensor", + "pallets/subtensor/runtime-api", + "pallets/admin-utils", + "runtime", + "node", +]; + +#[derive(Parser)] +struct CliArgs { + #[arg(required = true)] + version: Version, +} + +fn main() -> anyhow::Result<()> { + let args = CliArgs::parse(); + let version = args.version; + + for path in TOML_PATHS { + let cargo_toml_path = format!("{path}/Cargo.toml"); + let mut toml_file = fs::File::options() + .read(true) + .write(true) + .open(&cargo_toml_path)?; + let mut toml_str = String::new(); + toml_file.read_to_string(&mut toml_str)?; + let mut modified_toml_doc = DocumentMut::from_str(&toml_str)?; + + modified_toml_doc["package"]["version"] = Item::Value(Value::from(version.to_string())); + toml_file.set_len(0)?; + toml_file.rewind()?; + toml_file.write_all(modified_toml_doc.to_string().as_bytes())?; + } + + Ok(()) +}