diff --git a/Cargo.lock b/Cargo.lock index abf5653..a749487 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2341,9 +2341,9 @@ dependencies = [ [[package]] name = "frame-support" -version = "37.1.0" +version = "37.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7078e2b22461a2987d47b8062c07f28df4e518974a4a28c081c55d237090412a" +checksum = "87cae973c331b7f52ba18435713f9ed02bac20bd4fdedaaad57445d82f05eb9d" dependencies = [ "aquamarine", "array-bytes", @@ -5277,7 +5277,6 @@ dependencies = [ name = "pallet-network" version = "4.0.0-dev" dependencies = [ - "env_logger", "frame-benchmarking", "frame-support", "frame-system", @@ -5286,8 +5285,6 @@ dependencies = [ "pallet-balances", "pallet-collective", "pallet-insecure-randomness-collective-flip", - "pallet-treasury", - "pallet-tx-pause", "parity-scale-codec", "scale-info", "serde", @@ -5472,43 +5469,6 @@ dependencies = [ "sp-weights 31.0.0", ] -[[package]] -name = "pallet-treasury" -version = "36.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59cdefb4591b3c4e7f21284332b4f83b5681663db0976ff2e9cd78ee6f5a5343" -dependencies = [ - "docify", - "frame-benchmarking", - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "pallet-balances", - "parity-scale-codec", - "scale-info", - "serde", - "sp-core 34.0.0", - "sp-runtime 39.0.5", -] - -[[package]] -name = "pallet-tx-pause" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1971e3dafa67fb5149a5077a6a0218d9250854797ae689ec4a3a222bc6587cd" -dependencies = [ - "docify", - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", - "pallet-proxy", - "pallet-utility", - "parity-scale-codec", - "scale-info", - "sp-runtime 39.0.5", -] - [[package]] name = "pallet-utility" version = "37.0.0" @@ -8572,8 +8532,6 @@ dependencies = [ "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", - "pallet-treasury", - "pallet-tx-pause", "pallet-utility", "parity-scale-codec", "scale-info", diff --git a/Cargo.toml b/Cargo.toml index a2aeec3..6c2952c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,8 +77,6 @@ pallet-proxy = { version = "37.0.0", default-features = false } pallet-preimage = { version = "37.0.0", default-features = false } pallet-scheduler = { version = "38.0.0", default-features = false } pallet-node-authorization = { version = "37.0.0", default-features = false } -pallet-treasury = { version = "36.0.0", default-features = false } -pallet-tx-pause = { version = "18.0.0", default-features = false } scale-info = { version = "2.11.1", default-features = false } sp-genesis-builder = { version = "0.15.0", default-features = false } sp-offchain = { version = "34.0.0", default-features = false } diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index 6ebb72f..66c46b0 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -261,9 +261,6 @@ fn local_genesis( "sudo": { // Assign network admin rights. "key": Some(root_key), - }, - "treasury": { - }, // "nodeAuthorization": { // "nodes": vec![ @@ -314,10 +311,6 @@ fn testnet_gavin_genesis( // Assign network admin rights. "key": Some(root_key), }, - "treasury": { - - }, - // "nodeAuthorization": { // "nodes": vec![ // ( @@ -367,10 +360,6 @@ fn testnet_tensor_genesis( // Assign network admin rights. "key": Some(root_key), }, - "treasury": { - - }, - // "nodeAuthorization": { // "nodes": vec![ // ( diff --git a/pallets/collective/src/tests.rs b/pallets/collective/src/tests.rs index 681574b..8abacf4 100644 --- a/pallets/collective/src/tests.rs +++ b/pallets/collective/src/tests.rs @@ -46,27 +46,6 @@ frame_support::construct_runtime!( } ); -pub const MILLISECS_PER_BLOCK: u64 = 6000; - -// NOTE: Currently it is not possible to change the slot duration after the chain has started. -// Attempting to do so will brick block production. -pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; - -// Time is measured by number of blocks. -pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); -pub const HOURS: BlockNumber = MINUTES * 60; -pub const DAYS: BlockNumber = HOURS * 24; -pub const YEAR: BlockNumber = DAYS * 365; -pub const BLOCKS_PER_HALVING: BlockNumber = YEAR * 2; -pub const TARGET_MAX_TOTAL_SUPPLY: u128 = 2_800_000_000_000_000_000_000_000; -pub const INITIAL_REWARD_PER_BLOCK: u128 = (TARGET_MAX_TOTAL_SUPPLY / 2) / BLOCKS_PER_HALVING as u128; - -pub const SECS_PER_BLOCK: u32 = 6000 / 1000; - -pub const EPOCH_LENGTH: u32 = 10; -pub const BLOCKS_PER_EPOCH: u32 = SECS_PER_BLOCK * EPOCH_LENGTH; -pub const EPOCHS_PER_YEAR: u32 = YEAR as u32 / BLOCKS_PER_EPOCH; - mod mock_democracy { pub use pallet::*; #[frame_support::pallet(dev_mode)] @@ -114,14 +93,12 @@ impl pallet_balances::Config for Test { impl pallet_insecure_randomness_collective_flip::Config for Test {} parameter_types! { - pub const EpochLength: u32 = EPOCH_LENGTH; // Testnet 600 blocks per erpoch / 69 mins per epoch, Local 10 - pub const EpochsPerYear: u32 = EPOCHS_PER_YEAR; // Testnet 600 blocks per erpoch / 69 mins per epoch, Local 10 + pub const EpochLength: u64 = 100; pub const NetworkPalletId: PalletId = PalletId(*b"/network"); pub const MinProposalStake: u128 = 1_000_000_000_000_000_000; - pub const DelegateStakeCooldownEpochs: u32 = 100; - pub const NodeDelegateStakeCooldownEpochs: u32 = 100; - pub const StakeCooldownEpochs: u32 = 100; - pub const DelegateStakeEpochsRemovalWindow: u32 = 10; + pub const DelegateStakeCooldownEpochs: u64 = 100; + pub const StakeCooldownEpochs: u64 = 100; + pub const DelegateStakeEpochsRemovalWindow: u64 = 10; pub const MaxDelegateStakeUnlockings: u32 = 32; pub const MaxStakeUnlockings: u32 = 32; } @@ -132,24 +109,26 @@ impl pallet_network::Config for Test { type Currency = Balances; type MajorityCollectiveOrigin = pallet_collective::EnsureProportionAtLeast; type SuperMajorityCollectiveOrigin = pallet_collective::EnsureProportionAtLeast; - type EpochLength = EpochLength; - type EpochsPerYear = EpochsPerYear; + type EpochLength = EpochLength; type StringLimit = ConstU32<100>; - type InitialTxRateLimit = ConstU32<0>; + type InitialTxRateLimit = ConstU64<0>; type Randomness = InsecureRandomnessCollectiveFlip; type PalletId = NetworkPalletId; type DelegateStakeCooldownEpochs = DelegateStakeCooldownEpochs; - type NodeDelegateStakeCooldownEpochs = NodeDelegateStakeCooldownEpochs; type StakeCooldownEpochs = DelegateStakeCooldownEpochs; type DelegateStakeEpochsRemovalWindow = DelegateStakeEpochsRemovalWindow; type MaxDelegateStakeUnlockings = MaxDelegateStakeUnlockings; type MaxStakeUnlockings = MaxStakeUnlockings; type MinProposalStake = MinProposalStake; - type TreasuryAccount = (); } pub type BlockNumber = u32; +pub const MILLISECS_PER_BLOCK: u64 = 6000; +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; + parameter_types! { pub const VotingPeriod: BlockNumber = DAYS * 21; pub const EnactmentPeriod: BlockNumber = DAYS * 7; @@ -1602,6 +1581,7 @@ fn genesis_build_panics_with_duplicate_members() { fn proposal_network_pallet_vote_2_3() { ExtBuilder::default().build_and_execute(|| { let value = pallet_network::MaxSubnetNodes::::get(); + log::error!("value {:?}", value); let proposal = RuntimeCall::Network(pallet_network::Call::set_max_subnet_nodes { value: 999, }); @@ -1628,6 +1608,7 @@ fn proposal_network_pallet_vote_2_3() { proposal_len )); let value_call = pallet_network::MaxSubnetNodes::::get(); + log::error!("value_call {:?}", value_call); assert_ne!(value, value_call); }) } @@ -1636,6 +1617,7 @@ fn proposal_network_pallet_vote_2_3() { fn proposal_network_pallet_vote_1_3() { ExtBuilder::default().build_and_execute(|| { let value = pallet_network::MaxSubnetNodes::::get(); + log::error!("value {:?}", value); let proposal = RuntimeCall::Network(pallet_network::Call::set_max_subnet_nodes { value: 999, }); @@ -1662,6 +1644,7 @@ fn proposal_network_pallet_vote_1_3() { proposal_len )); let value_call = pallet_network::MaxSubnetNodes::::get(); + log::error!("value_call {:?}", value_call); assert_eq!(value, value_call); }) } @@ -1669,9 +1652,10 @@ fn proposal_network_pallet_vote_1_3() { #[test] fn proposal_network_pallet_vote_4_5() { ExtBuilder::default().build_and_execute(|| { - let value = pallet_network::MinSubnetDelegateStakeFactor::::get(); - let proposal = RuntimeCall::Network(pallet_network::Call::set_min_subnet_delegate_stake_factor { - value: 1000000000, + let value = pallet_network::MinStakeBalance::::get(); + log::error!("value {:?}", value); + let proposal = RuntimeCall::Network(pallet_network::Call::set_min_stake_balance { + value: 200_000_000_000_000_000_000, }); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let proposal_weight = proposal.get_dispatch_info().weight; @@ -1695,7 +1679,8 @@ fn proposal_network_pallet_vote_4_5() { proposal_weight, proposal_len )); - let value_call = pallet_network::MinSubnetDelegateStakeFactor::::get(); + let value_call = pallet_network::MinStakeBalance::::get(); + log::error!("value_call {:?}", value_call); assert_ne!(value, value_call); }) } @@ -1703,9 +1688,10 @@ fn proposal_network_pallet_vote_4_5() { #[test] fn proposal_network_pallet_vote_1_5() { ExtBuilder::default().build_and_execute(|| { - let value = pallet_network::MinSubnetDelegateStakeFactor::::get(); - let proposal = RuntimeCall::Network(pallet_network::Call::set_min_subnet_delegate_stake_factor { - value: 1000000000, + let value = pallet_network::MinStakeBalance::::get(); + log::error!("value {:?}", value); + let proposal = RuntimeCall::Network(pallet_network::Call::set_min_stake_balance { + value: 200_000_000_000_000_000_000, }); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let proposal_weight = proposal.get_dispatch_info().weight; @@ -1729,7 +1715,8 @@ fn proposal_network_pallet_vote_1_5() { proposal_weight, proposal_len )); - let value_call = pallet_network::MinSubnetDelegateStakeFactor::::get(); + let value_call = pallet_network::MinStakeBalance::::get(); + log::error!("value_call {:?}", value_call); assert_eq!(value, value_call); }) } diff --git a/pallets/network/Cargo.toml b/pallets/network/Cargo.toml index 90f3ebd..468caca 100644 --- a/pallets/network/Cargo.toml +++ b/pallets/network/Cargo.toml @@ -39,9 +39,6 @@ pallet-collective = { version = "37.0.0", default-features = false, path = "../c [dev-dependencies] sp-io = { default-features = true, workspace = true } -env_logger = "0.10" -pallet-treasury.workspace = true -pallet-tx-pause.workspace = true [features] default = ["std"] diff --git a/pallets/network/src/admin/admin.rs b/pallets/network/src/admin/admin.rs index 338ca60..3c30524 100644 --- a/pallets/network/src/admin/admin.rs +++ b/pallets/network/src/admin/admin.rs @@ -18,64 +18,108 @@ use sp_std::vec::Vec; impl Pallet { // TODO: update this for a smoother line - pub fn do_set_min_nodes_slope_parameters(mut params: CurveParametersSet) -> DispatchResult { - // let x_curve_start = params.x_curve_start; - // let y_end = params.y_end; - // let y_start = params.y_start; - // let x_rise = Self::PERCENTAGE_FACTOR / 100; - - // ensure!( - // y_start > y_end, - // Error::::InvalidCurveParameters - // ); - - // // --- Linear Slope check - // let x_start_plus_1 = x_curve_start + x_rise; - // let x_start_plus_1_adj = (x_start_plus_1 - x_curve_start) * Self::PERCENTAGE_FACTOR / - // (Self::PERCENTAGE_FACTOR - x_curve_start); - // let y_start_minus_1 = (y_start - y_end) * (Self::PERCENTAGE_FACTOR - x_start_plus_1_adj) / - // Self::PERCENTAGE_FACTOR + y_end; - // let y_rise = y_start - y_start_minus_1; - // let slope = y_rise * Self::PERCENTAGE_FACTOR / x_rise; - // let j = slope * Self::TWO_HUNDRED_PERCENT_FACTOR / Self::PERCENTAGE_FACTOR; - // let q = Self::PERCENTAGE_FACTOR * Self::PERCENTAGE_FACTOR / j * y_start / Self::PERCENTAGE_FACTOR; - // let max_x = - // Self::PERCENTAGE_FACTOR * Self::PERCENTAGE_FACTOR / j * y_start / Self::PERCENTAGE_FACTOR + - // (x_curve_start * Self::PERCENTAGE_FACTOR / Self::TWO_HUNDRED_PERCENT_FACTOR); + pub fn set_min_nodes_slope_parameters(mut params: CurveParametersSet) -> DispatchResult { + let x_curve_start = params.x_curve_start; + let y_end = params.y_end; + let y_start = params.y_start; + let x_rise = Self::PERCENTAGE_FACTOR / 100; + + ensure!( + y_start > y_end, + Error::::InvalidCurveParameters + ); + + // --- Linear Slope check + let x_start_plus_1 = x_curve_start + x_rise; + let x_start_plus_1_adj = (x_start_plus_1 - x_curve_start) * Self::PERCENTAGE_FACTOR / + (Self::PERCENTAGE_FACTOR - x_curve_start); + let y_start_minus_1 = (y_start - y_end) * (Self::PERCENTAGE_FACTOR - x_start_plus_1_adj) / + Self::PERCENTAGE_FACTOR + y_end; + let y_rise = y_start - y_start_minus_1; + let slope = y_rise * Self::PERCENTAGE_FACTOR / x_rise; + let j = slope * Self::TWO_HUNDRED_PERCENT_FACTOR / Self::PERCENTAGE_FACTOR; + let q = Self::PERCENTAGE_FACTOR * Self::PERCENTAGE_FACTOR / j * y_start / Self::PERCENTAGE_FACTOR; + let max_x = + Self::PERCENTAGE_FACTOR * Self::PERCENTAGE_FACTOR / j * y_start / Self::PERCENTAGE_FACTOR + + (x_curve_start * Self::PERCENTAGE_FACTOR / Self::TWO_HUNDRED_PERCENT_FACTOR); - // ensure!( - // max_x >= Self::PERCENTAGE_FACTOR, - // Error::::SubnetNotExist - // ); + ensure!( + max_x >= Self::PERCENTAGE_FACTOR, + Error::::SubnetNotExist + ); - // params.max_x = max_x; + params.max_x = max_x; - // MinNodesCurveParameters::::put(params); + MinNodesCurveParameters::::put(params); Ok(()) } - pub fn do_pause() -> DispatchResult { - TxPause::::put(true); + pub fn set_base_subnet_node_memory_mb(value: u128) -> DispatchResult { + BaseSubnetNodeMemoryMB::::put(value); Ok(()) } - pub fn do_unpause() -> DispatchResult { - TxPause::::put(false); + pub fn set_max_subnet_memory_mb(value: u128) -> DispatchResult { + MaxSubnetMemoryMB::::put(value); Ok(()) } - pub fn do_set_proposal_min_subnet_nodes(value: u32) -> DispatchResult { + pub fn set_overall_max_subnet_memory_mb(value: u128) -> DispatchResult { + MaxTotalSubnetMemoryMB::::put(value); + Ok(()) + } + + pub fn set_proposal_min_subnet_nodes(value: u32) -> DispatchResult { ProposalMinSubnetNodes::::put(value); Ok(()) } - pub fn do_set_subnet_owner_percentage(value: u128) -> DispatchResult { - SubnetOwnerPercentage::::put(value); + pub fn set_subnet_node_registration_epochs(value: u64) -> DispatchResult { + SubnetNodeRegistrationEpochs::::put(value); + Ok(()) + } + + // TODO: remove target multipler logic from application + pub fn set_target_subnet_node_multiplier(value: u128) -> DispatchResult { + TargetSubnetNodesMultiplier::::put(value); Ok(()) } - pub fn do_set_max_subnets(value: u32) -> DispatchResult { + pub fn set_subnet_memory(subnet_id: u32, memory_mb: u128) -> DispatchResult { + let subnet = match SubnetsData::::try_get(subnet_id) { + Ok(subnet) => subnet, + Err(()) => return Err(Error::::SubnetNotExist.into()), + }; + + ensure!( + memory_mb <= MaxSubnetMemoryMB::::get(), + Error::::InvalidMaxSubnetMemoryMB + ); + + let base_node_memory: u128 = BaseSubnetNodeMemoryMB::::get(); + + let min_subnet_nodes: u32 = Self::get_min_subnet_nodes(base_node_memory, memory_mb); + let target_subnet_nodes: u32 = Self::get_target_subnet_nodes(min_subnet_nodes); + + let subnet_data = SubnetData { + id: subnet_id, + path: subnet.path, + min_nodes: min_subnet_nodes, + target_nodes: target_subnet_nodes, + memory_mb: memory_mb, + initialized: subnet.initialized, + registration_blocks: subnet.registration_blocks, + activated: subnet.activated, + entry_interval: subnet.entry_interval, + }; + + SubnetsData::::insert(subnet_id, subnet_data); + + Ok(()) + } + + pub fn set_max_subnets(value: u32) -> DispatchResult { MaxSubnets::::set(value); Self::deposit_event(Event::SetMaxSubnets(value)); @@ -83,7 +127,7 @@ impl Pallet { Ok(()) } - pub fn do_set_min_subnet_nodes(value: u32) -> DispatchResult { + pub fn set_min_subnet_nodes(value: u32) -> DispatchResult { ensure!( value > 0 && value < MaxSubnetNodes::::get(), Error::::InvalidMinSubnetNodes @@ -107,51 +151,24 @@ impl Pallet { Ok(()) } - pub fn do_set_tx_rate_limit(value: u32) -> DispatchResult { - TxRateLimit::::set(value); - - Self::deposit_event(Event::SetTxRateLimit(value)); - - Ok(()) - } - - pub fn do_set_subnet_inflation_factor(value: u128) -> DispatchResult { + pub fn do_set_min_stake_balance(value: u128) -> DispatchResult { ensure!( - value <= Self::PERCENTAGE_FACTOR, - Error::::InvalidPercent + value > 0, + Error::::InvalidMinStakeBalance ); - SubnetInflationFactor::::set(value); + MinStakeBalance::::set(value); - Self::deposit_event(Event::SetSubnetInflationFactor(value)); + Self::deposit_event(Event::SetMinStakeBalance(value)); Ok(()) } - - pub fn do_set_inflation_adj_factor(value: u128) -> DispatchResult { - ensure!( - value <= Self::PERCENTAGE_FACTOR, - Error::::InvalidPercent - ); - - InflationAdjFactor::::set(value); + pub fn set_tx_rate_limit(value: u64) -> DispatchResult { + TxRateLimit::::set(value); - Self::deposit_event(Event::SetSubnetInflationFactor(value)); + Self::deposit_event(Event::SetTxRateLimit(value)); Ok(()) } - - pub fn do_set_min_subnet_delegate_stake_factor(value: u128) -> DispatchResult { - ensure!( - value <= Self::PERCENTAGE_FACTOR, - Error::::InvalidPercent - ); - - MinSubnetDelegateStakeFactor::::set(value); - - Self::deposit_event(Event::SetMinSubnetDelegateStakeFactor(value)); - - Ok(()) - } } \ No newline at end of file diff --git a/pallets/network/src/consensus/mod.rs b/pallets/network/src/consensus/mod.rs deleted file mode 100644 index f810490..0000000 --- a/pallets/network/src/consensus/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -use super::*; -pub mod subnet_validator; \ No newline at end of file diff --git a/pallets/network/src/lib.rs b/pallets/network/src/lib.rs index ecf2ea6..1c9d3c1 100644 --- a/pallets/network/src/lib.rs +++ b/pallets/network/src/lib.rs @@ -91,13 +91,9 @@ pub mod rpc_info; pub use rpc_info::*; pub mod admin; pub use admin::*; -pub mod supply; -pub use supply::*; -pub mod consensus; -pub use consensus::*; +mod subnet_validator; mod rewards; -mod rewards_v2; mod proposal; // All pallet logic is defined in its own module and must be annotated by the `pallet` attribute. @@ -137,31 +133,25 @@ pub mod pallet { type SuperMajorityCollectiveOrigin: EnsureOrigin; #[pallet::constant] - type EpochLength: Get; - - #[pallet::constant] - type EpochsPerYear: Get; + type EpochLength: Get; #[pallet::constant] type StringLimit: Get; #[pallet::constant] // Initial transaction rate limit. - type InitialTxRateLimit: Get; + type InitialTxRateLimit: Get; #[pallet::constant] type PalletId: Get; #[pallet::constant] - type DelegateStakeCooldownEpochs: Get; + type DelegateStakeCooldownEpochs: Get; #[pallet::constant] - type NodeDelegateStakeCooldownEpochs: Get; + type StakeCooldownEpochs: Get; #[pallet::constant] - type StakeCooldownEpochs: Get; - - #[pallet::constant] - type DelegateStakeEpochsRemovalWindow: Get; + type DelegateStakeEpochsRemovalWindow: Get; #[pallet::constant] type MaxDelegateStakeUnlockings: Get; @@ -173,11 +163,15 @@ pub mod pallet { #[pallet::constant] type MinProposalStake: Get; - - #[pallet::constant] - type TreasuryAccount: Get; } + /// A storage item for this pallet. + /// + /// In this template, we are declaring a storage item called `Something` that stores a single + /// `u32` value. Learn more about runtime storage here: + #[pallet::storage] + pub type Something = StorageValue<_, u32>; + /// Events that functions in this pallet can emit. /// /// Events are a simple means of indicating to the outside world (such as dApps, chain explorers @@ -213,9 +207,9 @@ pub mod pallet { StakeAdded(u32, T::AccountId, T::AccountId, u128), StakeRemoved(u32, T::AccountId, T::AccountId, u128), - SubnetDelegateStakeAdded(u32, T::AccountId, u128), - SubnetDelegateStakeRemoved(u32, T::AccountId, u128), - SubnetDelegateStakeSwitched(u32, u32, T::AccountId, u128), + DelegateStakeAdded(u32, T::AccountId, u128), + DelegateStakeRemoved(u32, T::AccountId, u128), + DelegateStakeSwitched(u32, u32, T::AccountId, u128), DelegateNodeStakeAdded { account_id: T::AccountId, subnet_id: u32, subnet_node_id: u32, amount: u128 }, DelegateNodeStakeRemoved { account_id: T::AccountId, subnet_id: u32, subnet_node_id: u32, amount: u128 }, @@ -227,29 +221,13 @@ pub mod pallet { to_subnet_node_id: u32, amount: u128 }, - DelegateNodeToSubnetDelegateStakeSwitched { - account_id: T::AccountId, - from_subnet_id: u32, - from_subnet_node_id: u32, - to_subnet_id: u32, - amount: u128 - }, - SubnetDelegateToNodeDelegateStakeSwitched { - account_id: T::AccountId, - from_subnet_id: u32, - to_subnet_id: u32, - to_subnet_node_id: u32, - amount: u128 - }, // Admin SetMaxSubnets(u32), SetMinSubnetNodes(u32), SetMaxSubnetNodes(u32), SetMinStakeBalance(u128), - SetTxRateLimit(u32), - SetSubnetInflationFactor(u128), - SetMinSubnetDelegateStakeFactor(u128), + SetTxRateLimit(u64), // Proposals Proposal { subnet_id: u32, proposal_id: u32, epoch: u32, plaintiff: T::AccountId, defendant: T::AccountId, plaintiff_data: Vec }, @@ -267,9 +245,6 @@ pub mod pallet { // Rewards data RewardResult { subnet_id: u32, attestation_percentage: u128 }, - - // Subnet owners - SubnetEntryIntervalUpdate { subnet_id: u32, owner: T::AccountId, value: u32 } } /// Errors that can be returned by this pallet. @@ -286,30 +261,20 @@ pub mod pallet { /// Subnet must be registering or activated, this error usually occurs during the enactment period SubnetMustBeRegisteringOrActivated, - /// Subnet must be registering to perform this action - SubnetMustBeRegistering, /// Node hasn't been initialized for required epochs to be an accountant NodeAccountantEpochNotReached, /// Maximum subnets reached MaxSubnets, - /// Subnet registration require a coldkey whitelist for whitelisted nodes during the registration period - ColdkeyWhitelistRequired, /// Account has subnet peer under subnet already SubnetNodeExist, - /// Not subnet owner - NotSubnetOwner, - /// Subnet owner not exist, check the subnet ID is correct - SubnetOwnerNotExist, /// Not Uid owner NotUidOwner, /// Subnet node already activated SubnetNodeAlreadyActivated, /// SubnetNodeNotActivated, - /// Peer ID already in use in subnet + /// Node ID already in use PeerIdExist, - /// Bootstrap peer ID already in use in subnet - BootstrapPeerIdExist, /// Node ID already in use PeerIdNotExist, /// Subnet peer doesn't exist @@ -318,6 +283,10 @@ pub mod pallet { SubnetExist, /// Subnet registration cooldown period not met SubnetRegistrationCooldown, + /// Max total subnet memory exceeded + MaxTotalSubnetMemory, + /// Max subnet memory size exceeded + MaxSubnetMemory, /// Invalid registration block InvalidSubnetRegistrationBlocks, /// Subnet node must be unstaked to re-register to use the same balance @@ -332,26 +301,15 @@ pub mod pallet { TxRateLimitExceeded, /// PeerId format invalid InvalidPeerId, - /// PeerId format invalid - InvalidBootstrapPeerId, /// The provided signature is incorrect. WrongSignature, InvalidSubnetId, - /// Coldkey not whitelisted to register - ColdkeyRegistrationWhitelist, - - /// Maximum amount of subnet registrations surpassed, see subnet `node_registration_interval` for more information - MaxSubnetRegistrationReached, - /// Maximum `node_registration_interval` parameter entered during subnet registration - MaxSubnetRegistration, - /// Maximum amount of subnet activations surpassed, see subnet `node_activation_interval` for more information - MaxSubnetActivationReached, - /// Maximum `node_activation_interval` parameter entered during subnet activation - MaxSubnetActivation, + /// Maximum amount of subnet entries surpassed, see subnet `entry_interval` for more information + MaxSubnetEntryIntervalReached, + /// Maximum `entry_interval` parameter entered during subnet registration + MaxSubnetEntryInterval, - /// - DelegateStakeTransferPeriodExceeded, MustUnstakeToRegister, // Admin @@ -367,6 +325,7 @@ pub mod pallet { InvalidMinStakeBalance, /// Invalid percent number, must be in 1e4 format. Used for elements that only require correct format InvalidPercent, + InvalidMaxSubnetMemoryMB, // Staking /// u128 -> BalanceOf conversion error @@ -471,28 +430,23 @@ pub mod pallet { MaxRewardRateUpdates, /// Invalid curve parameters InvalidCurveParameters, - /// Transactions are paused - Paused, } - /// hotkey: Hotkey of subnet node for interacting with subnet on-chain communication - /// peer_id: Peer ID of subnet node within subnet - /// bootstrap_peer_id: Peer ID of subnet nodes bootstrap node + /// hotkey: Hotkey of subnet node for interacting with subnet on-chain communication + /// peer_id: Peer ID of subnet node within subnet + /// initialized: Block initialized /// classification: Subnet node classification for on-chain permissions - /// delegate_reward_rate: Delegate stake rate - /// last_delegate_reward_rate_update: `delegate_reward_rate` latest update block - /// a: (Optional) Unique data for subnet to use and lookup via RPC, can only be added at registration - /// b: (Optional) Data for subnet to use and lookup via RPC - /// c: (Optional) Data for subnet to use and lookup via RPC + /// a: (Optional) Unique data for subnet to use and lookup via RPC, can only be added at registration + /// b: (Optional) Data for subnet to use and lookup via RPC + /// c: (Optional) Data for subnet to use and lookup via RPC #[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, PartialOrd, Ord, scale_info::TypeInfo)] pub struct SubnetNode { - pub id: u32, pub hotkey: AccountId, pub peer_id: PeerId, - pub bootstrap_peer_id: PeerId, + pub initialized: u64, pub classification: SubnetNodeClassification, pub delegate_reward_rate: u128, - pub last_delegate_reward_rate_update: u32, + pub last_delegate_reward_rate_update: u64, pub a: Option>, pub b: Option>, pub c: Option>, @@ -516,47 +470,31 @@ pub mod pallet { /// /// *Deactivated: Subnet node is temporarily activated (done manually). Available to Validator class only. /// *Registered: Subnet node registered, not included in consensus - /// *Queue: Subnet node is activated as queue, unless subnet is registering, and automatically updates on the first successful consensus epoch - /// *Included: Subnet node automatically updates to Included from Queue on the first successful consensus epoch after being Queue + /// *Idle: Subnet node is activated as idle, unless subnet is registering, and automatically updates on the first successful consensus epoch + /// *Included: Subnet node automatically updates to Included from Idle on the first successful consensus epoch after being Idle /// *Validator: Subnet node updates to Submittble from Included on the first successful consensus epoch they are included in consensus data #[derive(Default, EnumIter, FromRepr, Copy, Encode, Decode, Clone, PartialOrd, PartialEq, Eq, RuntimeDebug, Ord, scale_info::TypeInfo)] - pub enum SubnetNodeClass { + pub enum SubnetNodeClass { Deactivated, #[default] Registered, - Queue, + Idle, Included, Validator, } - impl SubnetNodeClass { - /// Increments the node class, but if already at the highest level, stays at Validator. - pub fn next(&self) -> Self { - let new_value = (*self as usize) + 1; // Increment the enum value - Self::from_repr(new_value).unwrap_or(*self) // If out of bounds, return the current value - } - - /// Decrements the node class, but if already at the lowest level, stays at Deactivated. - pub fn previous(&self) -> Self { - if *self == Self::Deactivated { - return Self::Deactivated; // Stay at the lowest level - } - let new_value = (*self as usize) - 1; // Decrement the enum value - Self::from_repr(new_value).unwrap_or(*self) // If out of bounds, return the current value - } - } - #[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, Ord, PartialOrd, scale_info::TypeInfo)] pub struct SubnetNodeClassification { pub class: SubnetNodeClass, - pub start_epoch: u32, + pub start_epoch: u64, } impl SubnetNode { - pub fn has_classification(&self, required: &SubnetNodeClass, epoch: u32) -> bool { + pub fn has_classification(&self, required: &SubnetNodeClass, epoch: u64) -> bool { self.classification.class >= *required && self.classification.start_epoch <= epoch } } + /// Incentives protocol format /// /// Scoring is calculated off-chain between subnet nodes hosting AI subnets together @@ -593,7 +531,6 @@ pub mod pallet { Council, EnactmentPeriod, MaxSubnets, - Owner, } /// Attests format for consensus @@ -604,7 +541,7 @@ pub mod pallet { #[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, scale_info::TypeInfo)] pub struct RewardsData { pub validator_id: u32, // Chosen validator of the epoch - pub attests: BTreeMap, // Count of attestations of the submitted data + pub attests: BTreeMap, // Count of attestations of the submitted data pub data: Vec, // Data submitted by chosen validator pub args: Option>, // Optional arguements to pass for subnet to validate } @@ -635,64 +572,47 @@ pub mod pallet { /// # Arguments /// /// * `path` - Path to download the model, this can be HuggingFace, IPFS, anything. - /// * `max_node_registration_epochs` - Maximum epochs a node can be registered for. After they are removed on the - /// next successfully validated epoch. - /// * `node_registration_interval` - Registration blocks the subnet registerer wants to use - /// - Blocks between each node registration - /// * `node_activation_interval` - Activation blocks the subnet registerer wants to use - /// - Blocks between each node acivation - /// * `node_queue_period` - Epochs a node stays in the Queue class before being Included in consensus. - /// * `max_node_penalties` - Maximum penalties a node can accrue before being removed. - /// * `coldkey_whitelist` - Whitelist of coldkeys for registration while subnets are registering. This is removed on activation. + /// * `memory_mb` - The memory requirement to serve the entirety of the model + /// * `registration_blocks` - Registration blocks the subnet registerer wants to use #[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, scale_info::TypeInfo)] - pub struct RegistrationSubnetData { + pub struct RegistrationSubnetData { pub path: Vec, - pub max_node_registration_epochs: u32, - pub node_registration_interval: u32, - pub node_activation_interval: u32, - pub node_queue_period: u32, - pub max_node_penalties: u32, - pub coldkey_whitelist: BTreeSet, + pub memory_mb: u128, + pub registration_blocks: u64, + pub entry_interval: u64, } - // /// Subnet data used before activation - // #[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, scale_info::TypeInfo)] - // pub struct RegisteredSubnetNodesData { - // pub subnet_id: u32, - // pub subnet_node: SubnetNode, - // } - - /// Subnet node deactivation parameters - /// - /// # Arguments - /// - /// * `subnet_id` - Subnet ID. - /// * `subnet_node_id` - Subnet node ID - #[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, scale_info::TypeInfo, PartialOrd, Ord)] - pub struct SubnetNodeDeactivation { + /// Subnet data used before activation + #[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, scale_info::TypeInfo)] + pub struct RegisteredSubnetNodesData { pub subnet_id: u32, - pub subnet_node_id: u32, + pub subnet_node: SubnetNode, } - #[derive(Default, EnumIter, FromRepr, Copy, Encode, Decode, Clone, PartialOrd, PartialEq, Eq, RuntimeDebug, Ord, scale_info::TypeInfo)] - pub enum SubnetState { - #[default] Registered, - Active, - } - /// Subnet data /// /// # Arguments /// /// * `id` - Unique identifier. /// * `path` - Path to download the model, this can be HuggingFace, IPFS, anything. - /// * `state` - Registered or Active. - /// * `registered` - Epoch subnet registered. + /// * `min_nodes` - Minimum required nodes for subnet. + /// * `target_nodes` - Target nodes of subnet based on minimum nodes. + /// * `memory_mb` - Memory requirements of subnet. + /// * `initialized` - Block subnet registered. + /// * `registration_blocks` - Registration blocks the subnet registerer wants to use. + /// * `activated` - Block subnet activated. + /// * `entry_interval` - Blocks between each node entry into the subnet. #[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, scale_info::TypeInfo)] pub struct SubnetData { pub id: u32, pub path: Vec, - pub state: SubnetState, + pub min_nodes: u32, + pub target_nodes: u32, + pub memory_mb: u128, + pub initialized: u64, + pub registration_blocks: u64, + pub activated: u64, + pub entry_interval: u64, } /// Mapping of votes of a subnet proposal @@ -732,8 +652,8 @@ pub mod pallet { pub defendant_bond: u128, pub eligible_voters: BTreeSet, // Those eligible to vote at time of the proposal pub votes: VoteParams, - pub start_block: u32, - pub challenge_block: u32, + pub start_block: u64, + pub challenge_block: u64, pub plaintiff_data: Vec, pub defendant_data: Vec, pub complete: bool, @@ -756,40 +676,31 @@ pub mod pallet { PeerId(Vec::new()) } #[pallet::type_value] - pub fn DefaultTxRateLimit() -> u32 { + pub fn DefaultTxRateLimit() -> u64 { T::InitialTxRateLimit::get() } #[pallet::type_value] - pub fn DefaultLastTxBlock() -> u32 { + pub fn DefaultLastTxBlock() -> u64 { 0 } #[pallet::type_value] - pub fn DefaultTxPause() -> bool { - false - } - #[pallet::type_value] pub fn DefaultMaxSubnetPenaltyCount() -> u32 { 16 } #[pallet::type_value] - pub fn DefaultMaxSubnetNodeRegistrationEpochs() -> u32 { - T::EpochsPerYear::get() / 365 - } - #[pallet::type_value] - pub fn DefaultSubnetNodeRegistrationEpochs() -> u32 { + pub fn DefaultSubnetNodeRegistrationEpochs() -> u64 { 16 } #[pallet::type_value] - pub fn DefaultSubnetNodeQueuePeriod() -> u32 { - 1 + pub fn DefaultSubnetNodesClasses() -> BTreeMap { + BTreeMap::new() } #[pallet::type_value] pub fn DefaultSubnetNode() -> SubnetNode { return SubnetNode { - id: 0, hotkey: T::AccountId::decode(&mut TrailingZeroInput::zeroes()).unwrap(), peer_id: PeerId(Vec::new()), - bootstrap_peer_id: PeerId(Vec::new()), + initialized: 0, classification: SubnetNodeClassification { class: SubnetNodeClass::Registered, start_epoch: 0, @@ -812,11 +723,7 @@ pub mod pallet { pub fn DefaultAccountTake() -> u128 { 0 } - #[pallet::type_value] - pub fn DefaultRegisteredStakeCooldownEpochs() -> u32 { - 4 - } - #[pallet::type_value] + #[pallet::type_value] pub fn DefaultMaxStakeBalance() -> u128 { 280000000000000000000000 } @@ -830,20 +737,15 @@ pub mod pallet { 1000000000 } #[pallet::type_value] - pub fn DefaultMinSubnetDelegateStakeFactor() -> u128 { - // 0.001% - 1_000_000 - } - #[pallet::type_value] - pub fn DefaultMinDelegateStakeBalance() -> u128 { - 1000 + pub fn DefaultMinSubnetDelegateStake() -> u128 { + 1000e+18 as u128 } #[pallet::type_value] pub fn DefaultMaxDelegateStakeBalance() -> u128 { - 1_000_000_000_000_000_000_000_000 + 280000000000000000000000 } #[pallet::type_value] - pub fn DefaultDelegateStakeTransferPeriod() -> u32 { + pub fn DefaultDelegateStakeTransferPeriod() -> u64 { 1000 } #[pallet::type_value] @@ -852,28 +754,32 @@ pub mod pallet { 110000000 } #[pallet::type_value] - pub fn DefaultDelegateStakeCooldown() -> u32 { + pub fn DefaultDelegateStakeCooldown() -> u64 { 0 } #[pallet::type_value] - pub fn DefaultDelegateStakeUnbondingLedger() -> BTreeMap { + pub fn DefaultDelegateStakeUnbondingLedger() -> BTreeMap { // We use epochs because cooldowns are based on epochs // { - // epoch_start: u32, // cooldown begin epoch (+ cooldown duration for unlock) + // epoch_start: u64, // cooldown begin epoch (+ cooldown duration for unlock) // balance: u128, // } BTreeMap::new() } #[pallet::type_value] - pub fn DefaultStakeUnbondingLedger() -> BTreeMap { + pub fn DefaultStakeUnbondingLedger() -> BTreeMap { // We use epochs because cooldowns are based on epochs // { - // epoch_start: u32, // cooldown begin epoch (+ cooldown duration for unlock) + // epoch_start: u64, // cooldown begin epoch (+ cooldown duration for unlock) // balance: u128, // } BTreeMap::new() } #[pallet::type_value] + pub fn DefaultBaseRewardPerMB() -> u128 { + 1e+18 as u128 + } + #[pallet::type_value] pub fn DefaultBaseValidatorReward() -> u128 { 1e+18 as u128 } @@ -905,6 +811,23 @@ pub mod pallet { 875000000 } #[pallet::type_value] + pub fn DefaultTargetSubnetNodesMultiplier() -> u128 { + // 1/3 + 333333333 + } + #[pallet::type_value] + pub fn DefaultBaseSubnetNodeMemoryMB() -> u128 { + 16_000 + } + #[pallet::type_value] + pub fn DefaultMaxSubnetMemoryMB() -> u128 { + 1_000_000 + } + #[pallet::type_value] + pub fn DefaultMaxTotalSubnetMemoryMB() -> u128 { + 10_000_000 + } + #[pallet::type_value] pub fn DefaultMinSubnetNodes() -> u32 { // development and mainnet // 6 @@ -912,7 +835,7 @@ pub mod pallet { 1 } #[pallet::type_value] - pub fn DefaultMinSubnetRegistrationBlocks() -> u32 { + pub fn DefaultMinSubnetRegistrationBlocks() -> u64 { // 9 days at 6s blocks // 129_600 @@ -920,7 +843,7 @@ pub mod pallet { 150 } #[pallet::type_value] - pub fn DefaultMaxSubnetRegistrationBlocks() -> u32 { + pub fn DefaultMaxSubnetRegistrationBlocks() -> u64 { // 21 days at 6s blocks // 302_400 @@ -928,20 +851,14 @@ pub mod pallet { 43200 } #[pallet::type_value] - pub fn DefaultSubnetActivationEnactmentPeriod() -> u32 { - // 3 days at 6s blocks - 43_200 + pub fn DefaultMaxSubnetNodeRegistrationEpochs() -> u32 { + 16 } #[pallet::type_value] - pub fn DefaultSubnetRegistrationEpochs() -> u32 { - T::EpochsPerYear::get() / 52 + pub fn DefaultSubnetActivationEnactmentPeriod() -> u64 { + // 3 days at 6s blocks + 43_200 } - #[pallet::type_value] - pub fn DefaultSubnetActivationEnactmentEpochs() -> u32 { - T::EpochsPerYear::get() / 52 - } - - #[pallet::type_value] pub fn DefaultMinNodesCurveParameters() -> CurveParametersSet { // math.rs PERCENT_FACTOR format @@ -958,6 +875,10 @@ pub mod pallet { 64 } #[pallet::type_value] + pub fn DefaultTotalSubnetMemoryMB() -> u128 { + 0 + } + #[pallet::type_value] pub fn DefaultSubnetNodeUniqueParamLimit() -> u32 { 2024 } @@ -975,7 +896,6 @@ pub mod pallet { } #[pallet::type_value] pub fn DefaultSubnetRegistrationInterval() -> u32 { - // Based on blocks // 1 week based on 6s blocks using epochs // 1008 // Testnet: @@ -983,137 +903,17 @@ pub mod pallet { 6 } #[pallet::type_value] - pub fn DefaultMaxRegisteredSubnetNodes() -> u32 { - 8 - } - #[pallet::type_value] - pub fn DefaultMaxSubnetRegistrationInterval() -> u32 { - // ~1 month - 438_290 - } - #[pallet::type_value] - pub fn DefaultMaxSubnetActivationInterval() -> u32 { - // ~1 month - 438_290 - } - #[pallet::type_value] - pub fn DefaultSubnetOwnerPercentage() -> u128 { - 100_000_000 - } - #[pallet::type_value] - pub fn DefaultSubnetInflationFactor() -> u128 { - 800_000_000 - } - #[pallet::type_value] - pub fn DefaultInflationAdjFactor() -> u128 { - 150_000_000 - } - #[pallet::type_value] - pub fn DefaultSubnetInflationAdjFactor() -> u128 { - 150_000_000 - } - #[pallet::type_value] - pub fn DefaultSubnetNodeInflationAdjFactor() -> u128 { - 150_000_000 - } - #[pallet::type_value] - pub fn DefaultDeactivationLedger() -> BTreeSet { - BTreeSet::new() - } - #[pallet::type_value] - pub fn DefaultMaxDeactivations() -> u32 { - 512 - } - #[pallet::type_value] - pub fn DefaultChurnDenominator() -> u32 { - 4 - } - #[pallet::type_value] - pub fn DefaultSubnetNodeNonUniqueParamUpdateInterval() -> u32 { - 1 - } - #[pallet::type_value] - pub fn DefaultRewardRateUpdatePeriod() -> u32 { - // 1 day at 6 seconds a block (86,000s per day) - 14400 - } - #[pallet::type_value] - pub fn DefaultMaxRewardRateDecrease() -> u128 { - // 1% - 10_000_000 - } - #[pallet::type_value] - pub fn DefaultNodeAttestationRemovalThreshold() -> u128 { - // 8500 - 850000000 - } - #[pallet::type_value] - pub fn DefaultProposalParams() -> ProposalParams { - return ProposalParams { - subnet_id: 0, - plaintiff_id: 0, - defendant_id: 0, - plaintiff_bond: 0, - defendant_bond: 0, - eligible_voters: BTreeSet::new(), - votes: VoteParams { - yay: BTreeSet::new(), - nay: BTreeSet::new(), - }, - start_block: 0, - challenge_block: 0, - plaintiff_data: Vec::new(), - defendant_data: Vec::new(), - complete: false, - }; - } - #[pallet::type_value] - pub fn DefaultProposalMinSubnetNodes() -> u32 { - 16 - } - #[pallet::type_value] - pub fn DefaultVotingPeriod() -> u32 { - // 7 days - 100800 - } - #[pallet::type_value] - pub fn DefaultChallengePeriod() -> u32 { - // 7 days in blocks - 100800 - } - #[pallet::type_value] - pub fn DefaultProposalQuorum() -> u128 { - // 75.0% - 750000000 - } - #[pallet::type_value] - pub fn DefaultProposalConsensusThreshold() -> u128 { - // 66.0% - 660000000 - } - #[pallet::type_value] - pub fn DefaultProposalsCount() -> u32 { + pub fn DefaultMaxSubnetEntryInterval() -> u64 { + // 1 week based on 6s blocks + // 100800 0 } - #[pallet::type_value] - pub fn DefaultProposalBidAmount() -> u128 { - 1e+18 as u128 - } - - - - // - // Subnet elements - // /// Count of subnets #[pallet::storage] - pub type TotalSubnetUids = StorageValue<_, u32, ValueQuery>; + #[pallet::getter(fn total_subnets)] + pub type TotalSubnets = StorageValue<_, u32, ValueQuery>; - /// Count of active subnets - #[pallet::storage] - pub type TotalActiveSubnets = StorageValue<_, u32, ValueQuery>; - #[pallet::storage] #[pallet::getter(fn max_subnets)] pub type MaxSubnets = StorageValue<_, u32, ValueQuery, DefaultMaxSubnets>; @@ -1121,66 +921,61 @@ pub mod pallet { // Mapping of each subnet stored by ID, uniqued by `SubnetPaths` // Stores subnet data by a unique id #[pallet::storage] // subnet_id => data struct - pub type SubnetsData = StorageMap<_, Identity, u32, SubnetData>; - - // Ensures no duplicate subnet paths within the network at one time - // If a subnet path is voted out, it can be voted up later on and any - // stakes attached to the subnet_id won't impact the re-initialization - // of the subnet path. - #[pallet::storage] - #[pallet::getter(fn subnet_paths)] - pub type SubnetPaths = StorageMap<_, Blake2_128Concat, Vec, u32>; - - #[pallet::storage] // subnet_id => blocks - pub type SubnetRegistrationEpoch = StorageMap<_, Identity, u32, u32>; + pub type SubnetsData = StorageMap<_, Blake2_128Concat, u32, SubnetData>; - // Owner of subnet (registerer) - #[pallet::storage] // subnet_id => AccountId - pub type SubnetOwner = StorageMap<_, Identity, u32, T::AccountId>; - - // Percentage of rewards that allocates to subnet owners - #[pallet::storage] // subnet_id => AccountId - pub type SubnetOwnerPercentage = StorageValue<_, u128, ValueQuery, DefaultSubnetOwnerPercentage>; - - // Whitelist of coldkeys that nodes can register to a subnet during its registration period - #[pallet::storage] // subnet_id => {..., AccountId, ...} - pub type SubnetRegistrationColdkeyWhitelist = StorageMap<_, Identity, u32, BTreeSet>; - // Max per subnet node entry interval to any given subnet #[pallet::storage] // subnet_id => block_interval - pub type MaxSubnetRegistrationInterval = StorageValue<_, u32, ValueQuery, DefaultMaxSubnetRegistrationInterval>; + pub type MaxSubnetEntryInterval = StorageValue<_, u64, ValueQuery, DefaultMaxSubnetEntryInterval>; /// The maximum a single node can enter a subnet per blocks interval #[pallet::storage] // subnet_id => block - pub type LastSubnetRegistration = StorageMap<_, Identity, u32, u32, ValueQuery, DefaultZeroU32>; + pub type LastSubnetEntry = StorageMap<_, Blake2_128Concat, u32, u64, ValueQuery, DefaultZeroU64>; - // Max per subnet node entry interval to any given subnet - #[pallet::storage] // subnet_id => block_interval - pub type MaxSubnetActivationInterval = StorageValue<_, u32, ValueQuery, DefaultMaxSubnetActivationInterval>; + /// Maximum subnet memory per subnet + #[pallet::storage] + pub type MaxSubnetMemoryMB = StorageValue<_, u128, ValueQuery, DefaultMaxSubnetMemoryMB>; - /// The maximum a single node can enter a subnet per blocks interval - #[pallet::storage] // subnet_id => block - pub type LastSubnetActivation = StorageMap<_, Identity, u32, u32, ValueQuery, DefaultZeroU32>; + /// Total sum of subnet memory available in the network + #[pallet::storage] + pub type MaxTotalSubnetMemoryMB = StorageValue<_, u128, ValueQuery, DefaultMaxTotalSubnetMemoryMB>; - /// Subnet registration blocks - /// Total blocks subnet is in registration to reach conditions to activate + /// Total subnet memory across all subnets #[pallet::storage] - pub type SubnetRegistrationEpochs = StorageValue<_, u32, ValueQuery, DefaultSubnetRegistrationEpochs>; + pub type TotalSubnetMemoryMB = StorageValue<_, u128, ValueQuery, DefaultTotalSubnetMemoryMB>; + + // Ensures no duplicate subnet paths within the network at one time + // If a subnet path is voted out, it can be voted up later on and any + // stakes attached to the subnet_id won't impact the re-initialization + // of the subnet path. + #[pallet::storage] + #[pallet::getter(fn subnet_paths)] + pub type SubnetPaths = StorageMap<_, Blake2_128Concat, Vec, u32>; /// Minimum blocks required from subnet registration to activation #[pallet::storage] - pub type MinSubnetRegistrationBlocks = StorageValue<_, u32, ValueQuery, DefaultMinSubnetRegistrationBlocks>; + pub type MinSubnetRegistrationBlocks = StorageValue<_, u64, ValueQuery, DefaultMinSubnetRegistrationBlocks>; /// Maximum blocks required from subnet registration to activation #[pallet::storage] - pub type MaxSubnetRegistrationBlocks = StorageValue<_, u32, ValueQuery, DefaultMaxSubnetRegistrationBlocks>; + pub type MaxSubnetRegistrationBlocks = StorageValue<_, u64, ValueQuery, DefaultMaxSubnetRegistrationBlocks>; /// Time period allowable for subnet activation following registration period #[pallet::storage] - pub type SubnetActivationEnactmentBlocks = StorageValue<_, u32, ValueQuery, DefaultSubnetActivationEnactmentPeriod>; + pub type SubnetActivationEnactmentPeriod = StorageValue<_, u64, ValueQuery, DefaultSubnetActivationEnactmentPeriod>; + // Minimum amount of nodes required per subnet + // required for subnet activity #[pallet::storage] - pub type SubnetActivationEnactmentEpochs = StorageValue<_, u32, ValueQuery, DefaultSubnetActivationEnactmentEpochs>; + #[pallet::getter(fn min_subnet_nodes)] + pub type MinSubnetNodes = StorageValue<_, u32, ValueQuery, DefaultMinSubnetNodes>; + + #[pallet::storage] + pub type MinNodesCurveParameters = StorageValue<_, CurveParametersSet, ValueQuery, DefaultMinNodesCurveParameters>; + + // Maximim nodes in a subnet at any given time + #[pallet::storage] + #[pallet::getter(fn max_subnet_nodes)] + pub type MaxSubnetNodes = StorageValue<_, u32, ValueQuery, DefaultMaxSubnetNodes>; // Max epochs where consensus isn't formed before subnet being removed #[pallet::storage] @@ -1188,74 +983,54 @@ pub mod pallet { // Count of epochs a subnet has consensus errors #[pallet::storage] // subnet_id => count - pub type SubnetPenaltyCount = StorageMap< + pub type SubnetPenaltyCount = StorageMap< _, - Identity, + Blake2_128Concat, u32, u32, ValueQuery, >; - - // Lower bound of registration fee - #[pallet::storage] - pub type MinSubnetRegistrationFee = StorageValue<_, u128, ValueQuery, DefaultMinSubnetRegistrationFee>; - - // Upper bound of registration fee - #[pallet::storage] - pub type MaxSubnetRegistrationFee = StorageValue<_, u128, ValueQuery, DefaultMaxSubnetRegistrationFee>; - - // Last epoch a subnet was registered - #[pallet::storage] - pub type LastSubnetRegistrationEpoch = StorageValue<_, u32, ValueQuery, DefaultZeroU32>; - - // Epochs per subnet registration - // Also used for calculating the fee between the max and min registration fee - // e.g. Amount of epochs required to go by after a subnet registers before another can - #[pallet::storage] - pub type SubnetRegistrationInterval = StorageValue<_, u32, ValueQuery, DefaultSubnetRegistrationInterval>; - - // - // Subnet node elements - // - - // Interval between node registrations into subnets - #[pallet::storage] // subnet_id => blocks - pub type MaxRegisteredSubnetNodes = StorageMap<_, Identity, u32, u32, ValueQuery, DefaultMaxRegisteredSubnetNodes>; - - // Interval between node registrations into subnets - #[pallet::storage] // subnet_id => blocks - pub type SubnetNodeRegistrationInterval = StorageMap<_, Identity, u32, u32, ValueQuery, DefaultZeroU32>; - - // Interval between node activations into subnets - #[pallet::storage] // subnet_id => blocks - pub type SubnetNodeActivationInterval = StorageMap<_, Identity, u32, u32, ValueQuery, DefaultZeroU32>; - // Minimum amount of nodes required per subnet - // required for subnet activity - #[pallet::storage] - #[pallet::getter(fn min_subnet_nodes)] - pub type MinSubnetNodes = StorageValue<_, u32, ValueQuery, DefaultMinSubnetNodes>; - - // Maximim nodes in a subnet at any given time - #[pallet::storage] - #[pallet::getter(fn max_subnet_nodes)] - pub type MaxSubnetNodes = StorageValue<_, u32, ValueQuery, DefaultMaxSubnetNodes>; - #[pallet::storage] // subnet_uid --> u32 #[pallet::getter(fn total_subnet_nodes)] pub type TotalSubnetNodes = - StorageMap<_, Identity, u32, u32, ValueQuery>; + StorageMap<_, Blake2_128Concat, u32, u32, ValueQuery>; + + // #[pallet::storage] + // #[pallet::getter(fn pending_actions)] + // pub type PendingActionsStorage = StorageValue<_, Option>, ValueQuery>; + + #[pallet::type_value] + pub fn DefaultDeactivationLedger() -> BTreeSet { + BTreeSet::new() + } + + #[pallet::type_value] + pub fn DefaultMaxDeactivations() -> u32 { + 512 + } + #[pallet::type_value] + pub fn DefaultSubnetNodeNonUniqueParamUpdateInterval() -> u32 { + 1 + } + #[pallet::type_value] + pub fn DefaultRewardRateUpdatePeriod() -> u64 { + // 1 day at 6 seconds a block (86,000s per day) + 14400 + } + #[pallet::type_value] + pub fn DefaultMaxRewardRateDecrease() -> u128 { + // 1% + 10_000_000 + } - #[pallet::storage] // subnet_uid --> u32 - pub type TotalActiveSubnetNodes = - StorageMap<_, Identity, u32, u32, ValueQuery>; - #[pallet::storage] - pub type TotalActiveNodes = StorageValue<_, u32, ValueQuery, DefaultZeroU32>; - #[pallet::storage] // subnet_uid --> u32 - pub type ChurnDenominator = - StorageMap<_, Identity, u32, u32, ValueQuery, DefaultChurnDenominator>; + #[derive(Default, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, scale_info::TypeInfo, PartialOrd, Ord)] + pub struct SubnetNodeDeactivation { + pub subnet_id: u32, + pub subnet_node_id: u32, + } #[pallet::storage] pub type MaxDeactivations = @@ -1268,30 +1043,8 @@ pub mod pallet { /// Total epochs a subnet node can stay in registration phase. If surpassed, they are removed on the first successful /// consensus epoch #[pallet::storage] - pub type MaxSubnetNodeRegistrationEpochs = StorageValue<_, u32, ValueQuery, DefaultMaxSubnetNodeRegistrationEpochs>; + pub type SubnetNodeRegistrationEpochs = StorageValue<_, u64, ValueQuery, DefaultSubnetNodeRegistrationEpochs>; - /// Max epochs a subnet node can be in the registration phase before being removed - #[pallet::storage] - pub type SubnetNodeRegistrationEpochs = StorageMap< - _, - Identity, - u32, - u32, - ValueQuery, - DefaultSubnetNodeRegistrationEpochs - >; - - /// Epochs a node is in the Queue period before being upgraded to Included - #[pallet::storage] - pub type SubnetNodeQueuePeriod = StorageMap< - _, - Identity, - u32, - u32, - ValueQuery, - DefaultSubnetNodeQueuePeriod - >; - #[pallet::storage] // subnet_id --> u32 pub type TotalSubnetNodeUids = StorageMap<_, Identity, u32, u32, ValueQuery>; @@ -1308,9 +1061,10 @@ pub mod pallet { pub type SubnetNodeIdHotkey = StorageDoubleMap<_, Identity, u32, Identity, u32, T::AccountId, OptionQuery>; #[pallet::storage] // subnet_id --> uid --> data + #[pallet::getter(fn subnet_nodes2)] pub type SubnetNodesData = StorageDoubleMap< _, - Identity, + Blake2_128Concat, u32, Identity, u32, @@ -1319,34 +1073,13 @@ pub mod pallet { DefaultSubnetNode, >; - // subnet_id -> - #[pallet::storage] - pub type QueuedSubnetNodes = StorageMap<_, Identity, u32, BTreeMap>, ValueQuery>; - // pub type QueuedSubnetNodes = StorageMap<_, Identity, u32, BTreeMap>, ValueQuery>; - // pub type QueuedSubnetNodes = StorageMap<_, Identity, u32, BTreeMap, u32>, ValueQuery>; - - #[pallet::storage] - pub type RegisteredSubnetNodes = StorageMap<_, Identity, u32, BTreeMap, u32>, ValueQuery>; - #[pallet::storage] // subnet_id --> peer_id --> subnet_node_id #[pallet::getter(fn subnet_node_account)] - pub type PeerIdSubnetNode = StorageDoubleMap< + pub type SubnetNodeAccount = StorageDoubleMap< _, - Identity, - u32, Blake2_128Concat, - PeerId, u32, - ValueQuery, - DefaultZeroU32, - >; - - #[pallet::storage] // subnet_id --> bootstrap_peer_id --> subnet_node_id - pub type BootstrapPeerIdSubnetNode = StorageDoubleMap< - _, Identity, - u32, - Blake2_128Concat, PeerId, u32, ValueQuery, @@ -1357,9 +1090,9 @@ pub mod pallet { #[pallet::storage] // subnet_id --> param --> peer_id pub type SubnetNodeUniqueParam = StorageDoubleMap< _, - Identity, - u32, Blake2_128Concat, + u32, + Identity, BoundedVec, PeerId, ValueQuery, @@ -1367,11 +1100,24 @@ pub mod pallet { >; #[pallet::storage] - pub type SubnetNodeNonUniqueParamUpdateInterval = + pub type SubnetNodeNonUniqueParamUpdateInterval = StorageValue<_, u32, ValueQuery, DefaultSubnetNodeNonUniqueParamUpdateInterval>; + // // Last update of non unique subnet node params + // #[pallet::storage] + // pub type SubnetNodeNonUniqueParamLastSet = StorageDoubleMap< + // _, + // Blake2_128Concat, + // u32, + // Identity, + // T::AccountId, + // u32, + // ValueQuery, + // DefaultZeroU32, + // >; + #[pallet::storage] - pub type SubnetNodeNonUniqueParamLastSet = StorageDoubleMap< + pub type SubnetNodeNonUniqueParamLastSet = StorageDoubleMap< _, Identity, u32, @@ -1382,21 +1128,22 @@ pub mod pallet { DefaultZeroU32, >; - // - // Network utility elements - // + /// Base subnet node memory used for calculating minimum and target nodes for a subnet + #[pallet::storage] + pub type BaseSubnetNodeMemoryMB = StorageValue<_, u128, ValueQuery, DefaultBaseSubnetNodeMemoryMB>; + + #[pallet::storage] + pub type TargetSubnetNodesMultiplier = StorageValue<_, u128, ValueQuery, DefaultTargetSubnetNodesMultiplier>; + // Rate limit #[pallet::storage] // ( tx_rate_limit ) - pub type TxRateLimit = StorageValue<_, u32, ValueQuery, DefaultTxRateLimit>; + pub type TxRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxRateLimit>; // Last transaction on rate limited functions #[pallet::storage] // key --> last_block pub type LastTxBlock = - StorageMap<_, Identity, T::AccountId, u32, ValueQuery, DefaultLastTxBlock>; + StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; - // Pause the network - #[pallet::storage] - pub type TxPause = StorageValue<_, bool, ValueQuery, DefaultTxPause>; // // Validate / Attestation @@ -1405,7 +1152,7 @@ pub mod pallet { #[pallet::storage] // subnet ID => epoch => subnet node ID pub type SubnetRewardsValidator = StorageDoubleMap< _, - Identity, + Blake2_128Concat, u32, Identity, u32, @@ -1413,9 +1160,9 @@ pub mod pallet { >; #[pallet::storage] // subnet ID => epoch => data - pub type SubnetRewardsSubmission = StorageDoubleMap< + pub type SubnetRewardsSubmission = StorageDoubleMap< _, - Identity, + Blake2_128Concat, u32, Identity, u32, @@ -1429,7 +1176,7 @@ pub mod pallet { pub type MinVastMajorityAttestationPercentage = StorageValue<_, u128, ValueQuery, DefaultMinVastMajorityAttestationPercentage>; // - // Rewards (validator, incentives) + // Rewards (validator, scoring consensus) // // Base reward per epoch for validators @@ -1437,29 +1184,36 @@ pub mod pallet { #[pallet::storage] pub type BaseValidatorReward = StorageValue<_, u128, ValueQuery, DefaultBaseValidatorReward>; + /// Base reward per MB per epoch based on 4,380 MB per year + #[pallet::storage] + pub type BaseRewardPerMB = StorageValue<_, u128, ValueQuery, DefaultBaseRewardPerMB>; + + /// Assumed cost per MB for each epoch + // TODO: (not included in logic yet) + // This will help determine inflation for each epoch on the cost to run a subnet node + #[pallet::storage] + pub type ServerCostPerMB = StorageValue<_, u128, ValueQuery, DefaultBaseRewardPerMB>; + #[pallet::storage] pub type SlashPercentage = StorageValue<_, u128, ValueQuery, DefaultSlashPercentage>; #[pallet::storage] pub type MaxSlashAmount = StorageValue<_, u128, ValueQuery, DefaultMaxSlashAmount>; - + + // The total rewards that go into the rewards pool per epoch per subnet #[pallet::storage] - pub type MaxSubnetNodePenalties = StorageMap< - _, - Identity, - u32, - u32, - ValueQuery, - DefaultMaxSubnetNodePenalties - >; + pub type RewardPerSubnet = StorageValue<_, u128, ValueQuery, DefaultRewardPerSubnet>; + // Maximum epochs in a row a subnet node can be absent from validator submitted consensus data + #[pallet::storage] + pub type MaxSubnetNodePenalties = StorageValue<_, u32, ValueQuery, DefaultMaxSubnetNodePenalties>; + // If subnet node is absent from inclusion in consensus information or attestings, or validator data isn't attested // We don't count penalties per account because a user can bypass this by having multiple accounts - /// subnet_id > subnet_node_id > count #[pallet::storage] pub type SubnetNodePenalties = StorageDoubleMap< _, - Identity, + Blake2_128Concat, u32, Identity, u32, @@ -1468,30 +1222,34 @@ pub mod pallet { DefaultZeroU32, >; + #[pallet::type_value] + pub fn DefaultNodeAttestationRemovalThreshold() -> u128 { + // 8500 + 850000000 + } + // Attestion percentage required to increment a nodes penalty count up #[pallet::storage] - pub type NodeAttestationRemovalThreshold = StorageValue<_, u128, ValueQuery, DefaultNodeAttestationRemovalThreshold>; + pub type NodeAttestationRemovalThreshold = StorageValue<_, u128, ValueQuery, DefaultNodeAttestationRemovalThreshold>; + // // Staking // - #[pallet::storage] - pub type RegisteredStakeCooldownEpochs = StorageValue<_, u32, ValueQuery, DefaultRegisteredStakeCooldownEpochs>; - #[pallet::storage] // stores epoch balance of rewards from block rewards to be distributed to nodes/stakers #[pallet::getter(fn stake_vault_balance)] pub type StakeVaultBalance = StorageValue<_, u128, ValueQuery>; #[pallet::storage] // ( total_stake ) #[pallet::getter(fn total_stake)] - pub type TotalStake = StorageValue<_, u128, ValueQuery>; + pub type TotalStake = StorageValue<_, u128, ValueQuery>; // Total stake sum of all nodes in specified subnet #[pallet::storage] // subnet_uid --> peer_data #[pallet::getter(fn total_subnet_stake)] - pub type TotalSubnetStake = - StorageMap<_, Identity, u32, u128, ValueQuery>; + pub type TotalSubnetStake = + StorageMap<_, Blake2_128Concat, u32, u128, ValueQuery>; // An accounts stake per subnet #[pallet::storage] // account--> subnet_id --> u128 @@ -1509,56 +1267,57 @@ pub mod pallet { #[pallet::storage] pub type StakeUnbondingLedger = - StorageMap<_, Blake2_128Concat, T::AccountId, BTreeMap, ValueQuery, DefaultStakeUnbondingLedger>; + StorageMap<_, Blake2_128Concat, T::AccountId, BTreeMap, ValueQuery, DefaultStakeUnbondingLedger>; // Maximum stake balance per subnet // Only checked on `do_add_stake` and `` // A subnet staker can have greater than the max stake balance although any rewards // they would receive based on their stake balance will only account up to the max stake balance allowed #[pallet::storage] - pub type MaxStakeBalance = StorageValue<_, u128, ValueQuery, DefaultMaxStakeBalance>; + pub type MaxStakeBalance = StorageValue<_, u128, ValueQuery, DefaultMaxStakeBalance>; // Minimum required subnet peer stake balance per subnet #[pallet::storage] - pub type MinStakeBalance = StorageValue<_, u128, ValueQuery, DefaultMinStakeBalance>; + pub type MinStakeBalance = StorageValue<_, u128, ValueQuery, DefaultMinStakeBalance>; // // Delegate Staking // + /// The minimum delegate stake percentage for a subnet to have at any given time + // Based on the minimum subnet stake balance based on minimum nodes for a subnet + // i.e. if a subnet has a minimum node required of 10 and 100 TENSOR per node, and a MinSubnetDelegateStakePercentage of 100% + // then the minimum delegate stake balance towards a subnet must be 1000 TENSOR #[pallet::storage] - pub type MinSubnetDelegateStakeFactor = StorageValue<_, u128, ValueQuery, DefaultMinSubnetDelegateStakeFactor>; - - #[pallet::storage] - pub type MinDelegateStakeBalance = StorageValue<_, u128, ValueQuery, DefaultMinDelegateStakeBalance>; + pub type MinSubnetDelegateStakePercentage = StorageValue<_, u128, ValueQuery, DefaultMinSubnetDelegateStakePercentage>; + /// The absolute minimum delegate stake balance required for a subnet to stay activated + #[pallet::storage] + pub type MinSubnetDelegateStake = StorageValue<_, u128, ValueQuery, DefaultMinSubnetDelegateStake>; + #[pallet::storage] - pub type MaxDelegateStakeBalance = StorageValue<_, u128, ValueQuery, DefaultMaxDelegateStakeBalance>; + pub type MaxDelegateStakeBalance = StorageValue<_, u128, ValueQuery, DefaultMaxDelegateStakeBalance>; /// The required blocks between delegate stake transfers #[pallet::storage] - pub type DelegateStakeTransferPeriod = StorageValue<_, u32, ValueQuery, DefaultDelegateStakeTransferPeriod>; + pub type DelegateStakeTransferPeriod = StorageValue<_, u64, ValueQuery, DefaultDelegateStakeTransferPeriod>; #[pallet::storage] - pub type LastDelegateStakeTransfer = StorageMap<_, Blake2_128Concat, T::AccountId, u32, ValueQuery, DefaultZeroU32>; + pub type LastDelegateStakeTransfer = StorageMap<_, Blake2_128Concat, T::AccountId, u64, ValueQuery, DefaultZeroU64>; // Percentage of epoch rewards that go towards delegate stake pools #[pallet::storage] - pub type DelegateStakeRewardsPercentage = StorageValue<_, u128, ValueQuery, DefaultDelegateStakeRewardsPercentage>; - - #[pallet::storage] // ( total_stake ) - #[pallet::getter(fn total_delegate_stake)] - pub type TotalDelegateStake = StorageValue<_, u128, ValueQuery>; + pub type DelegateStakeRewardsPercentage = StorageValue<_, u128, ValueQuery, DefaultDelegateStakeRewardsPercentage>; // Total stake sum of all nodes in specified subnet #[pallet::storage] // subnet_uid --> peer_data - pub type TotalSubnetDelegateStakeShares = - StorageMap<_, Identity, u32, u128, ValueQuery>; + pub type TotalSubnetDelegateStakeShares = + StorageMap<_, Blake2_128Concat, u32, u128, ValueQuery>; // Total stake sum of all nodes in specified subnet #[pallet::storage] // subnet_uid --> peer_data - pub type TotalSubnetDelegateStakeBalance = - StorageMap<_, Identity, u32, u128, ValueQuery>; + pub type TotalSubnetDelegateStakeBalance = + StorageMap<_, Blake2_128Concat, u32, u128, ValueQuery>; // An accounts delegate stake per subnet #[pallet::storage] // account --> subnet_id --> u128 @@ -1573,14 +1332,14 @@ pub mod pallet { DefaultAccountTake, >; - #[pallet::storage] // account --> subnet_id --> epochs + #[pallet::storage] // account --> subnet_id --> u64 pub type DelegateStakeCooldown = StorageDoubleMap< _, - Identity, + Blake2_128Concat, T::AccountId, Identity, u32, - u32, + u64, ValueQuery, DefaultDelegateStakeCooldown, >; @@ -1592,7 +1351,7 @@ pub mod pallet { T::AccountId, Identity, u32, - BTreeMap, + BTreeMap, ValueQuery, DefaultDelegateStakeUnbondingLedger, >; @@ -1601,23 +1360,17 @@ pub mod pallet { // Node Delegate Stake // - // Time between subnet node updating node delegate staking rate #[pallet::storage] - pub type RewardRateUpdatePeriod = StorageValue<_, u32, ValueQuery, DefaultRewardRateUpdatePeriod>; + pub type RewardRateUpdatePeriod = StorageValue<_, u64, ValueQuery, DefaultRewardRateUpdatePeriod>; - // Max nominal percentage decrease of subnet node delegate reward rate #[pallet::storage] - pub type MaxRewardRateDecrease = StorageValue<_, u128, ValueQuery, DefaultMaxRewardRateDecrease>; - - #[pallet::storage] // ( total_stake ) - #[pallet::getter(fn total_node_delegate_stake)] - pub type TotalNodeDelegateStake = StorageValue<_, u128, ValueQuery>; + pub type MaxRewardRateDecrease = StorageValue<_, u128, ValueQuery, DefaultMaxRewardRateDecrease>; // Total stake sum of shares in specified subnet node #[pallet::storage] - pub type TotalNodeDelegateStakeShares = StorageDoubleMap< + pub type TotalNodeDelegateStakeShares = StorageDoubleMap< _, - Identity, + Blake2_128Concat, u32, Identity, u32, @@ -1628,9 +1381,9 @@ pub mod pallet { // Total stake sum of balance in specified subnet node #[pallet::storage] - pub type TotalNodeDelegateStakeBalance = StorageDoubleMap< + pub type TotalNodeDelegateStakeBalance = StorageDoubleMap< _, - Identity, + Blake2_128Concat, u32, Identity, u32, @@ -1655,11 +1408,31 @@ pub mod pallet { // // Props // + #[pallet::type_value] + pub fn DefaultProposalParams() -> ProposalParams { + return ProposalParams { + subnet_id: 0, + plaintiff_id: 0, + defendant_id: 0, + plaintiff_bond: 0, + defendant_bond: 0, + eligible_voters: BTreeSet::new(), + votes: VoteParams { + yay: BTreeSet::new(), + nay: BTreeSet::new(), + }, + start_block: 0, + challenge_block: 0, + plaintiff_data: Vec::new(), + defendant_data: Vec::new(), + complete: false, + }; + } #[pallet::storage] // subnet => proposal_id => proposal pub type Proposals = StorageDoubleMap< _, - Identity, + Blake2_128Concat, u32, Identity, u32, @@ -1668,6 +1441,10 @@ pub mod pallet { DefaultProposalParams, >; + #[pallet::type_value] + pub fn DefaultProposalMinSubnetNodes() -> u32 { + 16 + } /// The minimum subnet nodes for a subnet to have to be able to use the proposal mechanism // Because of slashing of funds is possible, we ensure the subnet is well decentralized @@ -1676,50 +1453,78 @@ pub mod pallet { #[pallet::storage] pub type ProposalMinSubnetNodes = StorageValue<_, u32, ValueQuery, DefaultProposalMinSubnetNodes>; + #[pallet::type_value] + pub fn DefaultProposalsCount() -> u32 { + 0 + } + #[pallet::storage] pub type ProposalsCount = StorageValue<_, u32, ValueQuery, DefaultProposalsCount>; + #[pallet::type_value] + pub fn DefaultProposalBidAmount() -> u128 { + 1e+18 as u128 + } + // Amount required to put up as a proposer and challenger #[pallet::storage] pub type ProposalBidAmount = StorageValue<_, u128, ValueQuery, DefaultProposalBidAmount>; + #[pallet::type_value] + pub fn DefaultVotingPeriod() -> u64 { + // 7 days + 100800 + } + #[pallet::storage] // Period in blocks for votes after challenge - pub type VotingPeriod = StorageValue<_, u32, ValueQuery, DefaultVotingPeriod>; + pub type VotingPeriod = StorageValue<_, u64, ValueQuery, DefaultVotingPeriod>; + + #[pallet::type_value] + pub fn DefaultChallengePeriod() -> u64 { + // 7 days in blocks + 100800 + } #[pallet::storage] // Period in blocks after proposal to challenge proposal - pub type ChallengePeriod = StorageValue<_, u32, ValueQuery, DefaultChallengePeriod>; + pub type ChallengePeriod = StorageValue<_, u64, ValueQuery, DefaultChallengePeriod>; + + #[pallet::type_value] + pub fn DefaultProposalQuorum() -> u128 { + // 75.0% + 750000000 + } #[pallet::storage] // How many voters are needed in a subnet proposal pub type ProposalQuorum = StorageValue<_, u128, ValueQuery, DefaultProposalQuorum>; + #[pallet::type_value] + pub fn DefaultProposalConsensusThreshold() -> u128 { + // 66.0% + 660000000 + } + // Consensus required to pass proposal #[pallet::storage] pub type ProposalConsensusThreshold = StorageValue<_, u128, ValueQuery, DefaultProposalConsensusThreshold>; - - // - // Inflation helpers elements - // - - // Factor of subnet utilization to help get the overall inflation on an epoch - // *This works alongside subnet node utilization factor - // *Subnet node utilization will be 1.0-SubnetInflationFactor + // Lower bound of registration fee #[pallet::storage] - pub type SubnetInflationFactor = StorageValue<_, u128, ValueQuery, DefaultSubnetInflationFactor>; + pub type MinSubnetRegistrationFee = StorageValue<_, u128, ValueQuery, DefaultMinSubnetRegistrationFee>; - // Factor that is used as the pow against the utilization factors `SubnetInflationFactor` and subet node inflation factor + // Upper bound of registration fee #[pallet::storage] - pub type InflationAdjFactor = StorageValue<_, u128, ValueQuery, DefaultInflationAdjFactor>; + pub type MaxSubnetRegistrationFee = StorageValue<_, u128, ValueQuery, DefaultMaxSubnetRegistrationFee>; - // Exponent used for subnet utilization + // Last epoch a subnet was registered #[pallet::storage] - pub type SubnetInflationAdjFactor = StorageValue<_, u128, ValueQuery, DefaultSubnetInflationAdjFactor>; + pub type LastSubnetRegistrationEpoch = StorageValue<_, u32, ValueQuery, DefaultZeroU32>; - // Exponent used for subnet node utilization + // Epochs per subnet registration + // Also used for calculating the fee between the max and min registration fee + // e.g. Amount of epochs required to go by after a subnet registers before another can #[pallet::storage] - pub type SubnetNodeInflationAdjFactor = StorageValue<_, u128, ValueQuery, DefaultSubnetNodeInflationAdjFactor>; + pub type SubnetRegistrationInterval = StorageValue<_, u32, ValueQuery, DefaultSubnetRegistrationInterval>; - /// The pallet's dispatchable functions ([`Call`]s). /// /// Dispatchable functions allows users to interact with the pallet and invoke state changes. @@ -1744,12 +1549,10 @@ pub mod pallet { #[pallet::weight({0})] pub fn register_subnet( origin: OriginFor, - subnet_data: RegistrationSubnetData, + subnet_data: RegistrationSubnetData, ) -> DispatchResult { let account_id: T::AccountId = ensure_signed(origin)?; - Self::is_paused()?; - Self::do_register_subnet( account_id, subnet_data, @@ -1770,15 +1573,11 @@ pub mod pallet { ) -> DispatchResult { let account_id: T::AccountId = ensure_signed(origin)?; - Self::is_paused()?; - Self::do_activate_subnet(subnet_id) } /// Try removing a subnet. /// - /// This can be useful if there is no network activity on a span of epochs - /// /// # Arguments /// /// * `subnet_id` - Subnet ID. @@ -1796,8 +1595,6 @@ pub mod pallet { ) -> DispatchResult { ensure_signed(origin)?; - Self::is_paused()?; - let subnet = match SubnetsData::::try_get(subnet_id) { Ok(subnet) => subnet, Err(()) => return Err(Error::::SubnetNotExist.into()), @@ -1805,24 +1602,24 @@ pub mod pallet { // --- Ensure the subnet has passed it's required period to begin consensus submissions ensure!( - subnet.state == SubnetState::Active, + subnet.activated != 0, Error::::SubnetInitializing ); let penalties = SubnetPenaltyCount::::get(subnet_id); let subnet_delegate_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); - let min_subnet_delegate_stake_balance = Self::get_min_subnet_delegate_stake_balance(); + let min_subnet_delegate_stake_balance = Self::get_min_subnet_delegate_stake_balance(subnet.min_nodes); if penalties > MaxSubnetPenaltyCount::::get() { // --- If the subnet has reached max penalty, remove it - Self::do_remove_subnet( + Self::deactivate_subnet( subnet.path, SubnetRemovalReason::MaxPenalties, ).map_err(|e| e)?; } else if subnet_delegate_stake_balance < min_subnet_delegate_stake_balance { // --- If the delegate stake balance is below minimum threshold, remove it - Self::do_remove_subnet( + Self::deactivate_subnet( subnet.path, SubnetRemovalReason::MinSubnetDelegateStake, ).map_err(|e| e)?; @@ -1832,50 +1629,6 @@ pub mod pallet { Err(Error::::InvalidSubnetRemoval.into()) } - #[pallet::call_index(3)] - #[pallet::weight({0})] - pub fn owner_deactivate_subnet( - origin: OriginFor, - subnet_id: u32, - path: Vec - ) -> DispatchResult { - Self::is_paused()?; - Self::do_owner_deactivate_subnet(origin, subnet_id, path) - } - - #[pallet::call_index(4)] - #[pallet::weight({0})] - pub fn owner_update_registration_interval( - origin: OriginFor, - subnet_id: u32, - value: u32 - ) -> DispatchResult { - Self::is_paused()?; - Self::do_owner_update_registration_interval(origin, subnet_id, value) - } - - #[pallet::call_index(5)] - #[pallet::weight({0})] - pub fn owner_update_activation_interval( - origin: OriginFor, - subnet_id: u32, - value: u32 - ) -> DispatchResult { - Self::is_paused()?; - Self::do_owner_update_activation_interval(origin, subnet_id, value) - } - - #[pallet::call_index(6)] - #[pallet::weight({0})] - pub fn owner_remove_subnet_node( - origin: OriginFor, - subnet_id: u32, - subnet_node_id: u32 - ) -> DispatchResult { - Self::is_paused()?; - Self::do_owner_remove_subnet_node(origin, subnet_id, subnet_node_id) - } - /// Add a subnet node to the subnet by registering and activating in one call /// /// The subnet node will be assigned a class (`SubnetNodeClass`) @@ -1897,7 +1650,7 @@ pub mod pallet { /// /// * `stake_to_be_added` must be the minimum required stake balance /// - #[pallet::call_index(7)] + #[pallet::call_index(3)] // #[pallet::weight(T::WeightInfo::add_subnet_node())] #[pallet::weight({0})] pub fn add_subnet_node( @@ -1905,21 +1658,17 @@ pub mod pallet { subnet_id: u32, hotkey: T::AccountId, peer_id: PeerId, - bootstrap_peer_id: PeerId, delegate_reward_rate: u128, stake_to_be_added: u128, a: Option>, b: Option>, c: Option>, ) -> DispatchResult { - Self::is_paused()?; - Self::do_register_subnet_node( origin.clone(), subnet_id, hotkey.clone(), peer_id, - bootstrap_peer_id, delegate_reward_rate, stake_to_be_added, a, @@ -1962,28 +1711,24 @@ pub mod pallet { /// /// * `stake_to_be_added` must be the minimum required stake balance /// - #[pallet::call_index(8)] + #[pallet::call_index(4)] #[pallet::weight({0})] pub fn register_subnet_node( origin: OriginFor, subnet_id: u32, hotkey: T::AccountId, peer_id: PeerId, - bootstrap_peer_id: PeerId, delegate_reward_rate: u128, stake_to_be_added: u128, a: Option>, b: Option>, c: Option>, ) -> DispatchResult { - Self::is_paused()?; - Self::do_register_subnet_node( origin, subnet_id, hotkey, peer_id, - bootstrap_peer_id, delegate_reward_rate, stake_to_be_added, a, @@ -2002,15 +1747,13 @@ pub mod pallet { /// * `subnet_id` - Subnet ID. /// * `subnet_node_id` - Subnet node ID assigned during registration /// - #[pallet::call_index(9)] + #[pallet::call_index(5)] #[pallet::weight({0})] pub fn activate_subnet_node( origin: OriginFor, subnet_id: u32, subnet_node_id: u32, ) -> DispatchResult { - Self::is_paused()?; - Self::do_activate_subnet_node( origin, subnet_id, @@ -2039,15 +1782,13 @@ pub mod pallet { /// /// * Must be a Validator class to deactivate, otherwise the subnet node must /// - #[pallet::call_index(10)] + #[pallet::call_index(6)] #[pallet::weight({0})] pub fn deactivate_subnet_node( origin: OriginFor, subnet_id: u32, subnet_node_id: u32, ) -> DispatchResult { - Self::is_paused()?; - Self::do_deactivate_subnet_node( origin, subnet_id, @@ -2066,7 +1807,7 @@ pub mod pallet { /// /// * Caller must be owner of subnet node, hotkey or coldkey /// - #[pallet::call_index(11)] + #[pallet::call_index(7)] // #[pallet::weight(T::WeightInfo::remove_subnet_node())] #[pallet::weight({0})] pub fn remove_subnet_node( @@ -2074,8 +1815,6 @@ pub mod pallet { subnet_id: u32, subnet_node_id: u32, ) -> DispatchResult { - Self::is_paused()?; - let key: T::AccountId = ensure_signed(origin)?; ensure!( @@ -2103,7 +1842,7 @@ pub mod pallet { /// * Caller must be coldkey owner of subnet node ID. /// * If decreasing rate, new rate must not be more than a 1% decrease nominally (10_000_000 using 1e9) /// - #[pallet::call_index(12)] + #[pallet::call_index(8)] #[pallet::weight({0})] pub fn update_delegate_reward_rate( origin: OriginFor, @@ -2111,8 +1850,6 @@ pub mod pallet { subnet_node_id: u32, new_delegate_reward_rate: u128 ) -> DispatchResult { - Self::is_paused()?; - let coldkey: T::AccountId = ensure_signed(origin)?; ensure!( @@ -2130,7 +1867,7 @@ pub mod pallet { Error::::InvalidDelegateRewardRate ); - let block: u32 = Self::get_current_block_as_u32(); + let block: u64 = Self::get_current_block_as_u64(); let max_reward_rate_decrease = MaxRewardRateDecrease::::get(); let reward_rate_update_period = RewardRateUpdatePeriod::::get(); @@ -2192,7 +1929,7 @@ pub mod pallet { /// * Subnet must exist /// * Must have amount free in wallet /// - #[pallet::call_index(13)] + #[pallet::call_index(9)] // #[pallet::weight(T::WeightInfo::add_to_stake())] #[pallet::weight({0})] pub fn add_to_stake( @@ -2202,8 +1939,6 @@ pub mod pallet { hotkey: T::AccountId, stake_to_be_added: u128, ) -> DispatchResult { - Self::is_paused()?; - let coldkey: T::AccountId = ensure_signed(origin.clone())?; // Each account can only have one peer // Staking is accounted for per account_id per subnet_id @@ -2217,7 +1952,7 @@ pub mod pallet { // --- Ensure coldkey owns the hotkey ensure!( - HotkeyOwner::::get(&hotkey) == coldkey, + HotkeyOwner::::get(hotkey.clone()) == coldkey, Error::::NotKeyOwner ); @@ -2248,7 +1983,7 @@ pub mod pallet { /// * Coldkey caller only /// * If subnet node, must have available staked balance greater than minimum required stake balance /// - #[pallet::call_index(14)] + #[pallet::call_index(10)] #[pallet::weight({0})] pub fn remove_stake( origin: OriginFor, @@ -2256,30 +1991,20 @@ pub mod pallet { hotkey: T::AccountId, stake_to_be_removed: u128 ) -> DispatchResult { - Self::is_paused()?; - let coldkey: T::AccountId = ensure_signed(origin.clone())?; // --- Ensure the hotkey stake owner is owned by the caller ensure!( - HotkeyOwner::::get(&hotkey) == coldkey, + HotkeyOwner::::get(hotkey.clone()) == coldkey, Error::::NotKeyOwner ); // If account is a subnet node they can remove stake up to minimum required stake balance // Else they can remove entire balance because they are not hosting subnets according to consensus // They are removed in `do_remove_subnet_node()` when self or consensus removed - let (is_subnet_node, is_active): (bool, bool) = match HotkeySubnetNodeId::::try_get(subnet_id, &hotkey) { - Ok(subnet_node_id) => { - let is_active = match SubnetNodesData::::try_get(subnet_id, subnet_node_id) { - Ok(subnet_node) => { - subnet_node.classification.class >= SubnetNodeClass::Registered - }, - Err(()) => false, - }; - (true, is_active) - }, - Err(()) => (false, false), + let is_subnet_node: bool = match HotkeySubnetNodeId::::try_get(subnet_id, hotkey.clone()) { + Ok(_) => true, + Err(()) => false, }; // Remove stake @@ -2290,7 +2015,6 @@ pub mod pallet { subnet_id, hotkey, is_subnet_node, - is_active, stake_to_be_removed, ) } @@ -2302,13 +2026,11 @@ pub mod pallet { /// * Coldkey caller only /// * Must be owner of stake balance /// - #[pallet::call_index(15)] + #[pallet::call_index(11)] #[pallet::weight({0})] pub fn claim_unbondings( origin: OriginFor, ) -> DispatchResult { - Self::is_paused()?; - let coldkey: T::AccountId = ensure_signed(origin)?; let successful_unbondings: u32 = Self::do_claim_unbondings(&coldkey); // Give error if there is no unbondings @@ -2331,7 +2053,7 @@ pub mod pallet { /// /// * Subnet must exist /// - #[pallet::call_index(16)] + #[pallet::call_index(12)] // #[pallet::weight(T::WeightInfo::add_to_delegate_stake())] #[pallet::weight({0})] pub fn add_to_delegate_stake( @@ -2339,8 +2061,6 @@ pub mod pallet { subnet_id: u32, stake_to_be_added: u128, ) -> DispatchResult { - Self::is_paused()?; - let account_id: T::AccountId = ensure_signed(origin.clone())?; // --- Ensure subnet exists @@ -2370,7 +2090,7 @@ pub mod pallet { /// /// * `to_subnet_id` subnet must exist /// - #[pallet::call_index(17)] + #[pallet::call_index(13)] #[pallet::weight({0})] pub fn transfer_delegate_stake( origin: OriginFor, @@ -2378,8 +2098,6 @@ pub mod pallet { to_subnet_id: u32, delegate_stake_shares_to_be_switched: u128 ) -> DispatchResult { - Self::is_paused()?; - // --- Ensure ``to`` subnet exists ensure!( SubnetsData::::contains_key(to_subnet_id), @@ -2410,7 +2128,7 @@ pub mod pallet { /// /// * Must have balance /// - #[pallet::call_index(18)] + #[pallet::call_index(14)] // #[pallet::weight(T::WeightInfo::remove_delegate_stake())] #[pallet::weight({0})] pub fn remove_delegate_stake( @@ -2418,8 +2136,6 @@ pub mod pallet { subnet_id: u32, shares_to_be_removed: u128 ) -> DispatchResult { - Self::is_paused()?; - Self::do_remove_delegate_stake( origin, subnet_id, @@ -2440,17 +2156,13 @@ pub mod pallet { /// * `subnet_id` - Subnet ID to increase delegate pool balance of. /// * `amount` - Amount TENSOR to add to pool /// - /// - /// TODO: Change name of function to avoid delegate staking confusions - #[pallet::call_index(19)] + #[pallet::call_index(15)] #[pallet::weight({0})] pub fn increase_delegate_stake( origin: OriginFor, subnet_id: u32, amount: u128, ) -> DispatchResult { - Self::is_paused()?; - let account_id: T::AccountId = ensure_signed(origin)?; // --- Ensure subnet exists, otherwise at risk of burning tokens @@ -2494,7 +2206,7 @@ pub mod pallet { /// * `node_account_id` - Subnet node ID /// * `node_delegate_stake_to_be_added` - Amount TENSOR to delegate stake /// - #[pallet::call_index(20)] + #[pallet::call_index(16)] #[pallet::weight({0})] pub fn add_to_node_delegate_stake( origin: OriginFor, @@ -2502,8 +2214,6 @@ pub mod pallet { subnet_node_id: u32, node_delegate_stake_to_be_added: u128 ) -> DispatchResult { - Self::is_paused()?; - Self::do_add_node_delegate_stake( origin, subnet_id, @@ -2526,7 +2236,7 @@ pub mod pallet { /// /// * `to_subnet_id` subnet must exist /// - #[pallet::call_index(21)] + #[pallet::call_index(17)] #[pallet::weight({0})] pub fn transfer_node_delegate_stake( origin: OriginFor, @@ -2536,8 +2246,6 @@ pub mod pallet { to_subnet_node_id: u32, node_delegate_stake_shares_to_be_switched: u128 ) -> DispatchResult { - Self::is_paused()?; - // --- Ensure ``to`` subnet node exists ensure!( SubnetNodesData::::contains_key(to_subnet_id, to_subnet_node_id), @@ -2562,7 +2270,7 @@ pub mod pallet { /// * `node_account_id` - Subnet node ID /// * `node_delegate_stake_shares_to_be_removed` - Pool shares to remove /// - #[pallet::call_index(22)] + #[pallet::call_index(18)] #[pallet::weight({0})] pub fn remove_node_delegate_stake( origin: OriginFor, @@ -2570,8 +2278,6 @@ pub mod pallet { subnet_node_id: u32, node_delegate_stake_shares_to_be_removed: u128 ) -> DispatchResult { - Self::is_paused()?; - Self::do_remove_node_delegate_stake( origin, subnet_id, @@ -2594,7 +2300,7 @@ pub mod pallet { /// * `subnet_node_id` - Subnet node ID. /// * `amount` - Amount TENSOR to add to pool /// - #[pallet::call_index(23)] + #[pallet::call_index(19)] #[pallet::weight({0})] pub fn increase_node_delegate_stake( origin: OriginFor, @@ -2602,8 +2308,6 @@ pub mod pallet { subnet_node_id: u32, amount: u128, ) -> DispatchResult { - Self::is_paused()?; - let account_id: T::AccountId = ensure_signed(origin)?; // --- Ensure subnet node exists, otherwise at risk of burning tokens @@ -2640,64 +2344,6 @@ pub mod pallet { Ok(()) } - /// Transfer stake from a subnet node to a subnet - /// - /// # Arguments - /// - /// * `from_subnet_id` - From subnet ID to remove delegate stake from. - /// * `from_subnet_node_id` - From subnet node ID to remove delegate stake from. - /// * `to_subnet_id` - To subnet ID to add delegate stake to - /// * `node_delegate_stake_shares_to_be_switched` - Shares to remove from delegate pool and add balance to subnet - /// - #[pallet::call_index(24)] - #[pallet::weight({0})] - pub fn transfer_from_node_to_subnet( - origin: OriginFor, - from_subnet_id: u32, - from_subnet_node_id: u32, - to_subnet_id: u32, - node_delegate_stake_shares_to_be_switched: u128, - ) -> DispatchResult { - Self::is_paused()?; - - Self::do_transfer_from_node_to_subnet( - origin, - from_subnet_id, - from_subnet_node_id, - to_subnet_id, - node_delegate_stake_shares_to_be_switched, - ) - } - - /// Transfer stake from a subnet to a subnet node - /// - /// # Arguments - /// - /// * `from_subnet_id` - From subnet ID to remove delegate stake from. - /// * `to_subnet_id` - To subnet ID to add delegate stake to. - /// * `to_subnet_node_id` - To subnet node ID to add delegate stake to - /// * `delegate_stake_shares_to_be_switched` - Shares to remove from delegate pool and add balance to node - /// - #[pallet::call_index(25)] - #[pallet::weight({0})] - pub fn transfer_from_subnet_to_node( - origin: OriginFor, - from_subnet_id: u32, - to_subnet_id: u32, - to_subnet_node_id: u32, - delegate_stake_shares_to_be_switched: u128, - ) -> DispatchResult { - Self::is_paused()?; - - Self::do_transfer_from_subnet_to_node( - origin, - from_subnet_id, - to_subnet_id, - to_subnet_node_id, - delegate_stake_shares_to_be_switched, - ) - } - /// Validator extrinsic for submitting incentives protocol data of the validators view of of the subnet /// This is used t oscore each subnet node for allocation of emissions /// @@ -2707,7 +2353,7 @@ pub mod pallet { /// * `data` - Vector of SubnetNodeData on each subnet node for scoring each /// * `args` (Optional) - Data that can be used by the subnet /// - #[pallet::call_index(26)] + #[pallet::call_index(20)] #[pallet::weight({0})] pub fn validate( origin: OriginFor, @@ -2715,13 +2361,11 @@ pub mod pallet { data: Vec, args: Option>, ) -> DispatchResultWithPostInfo { - Self::is_paused()?; - let hotkey: T::AccountId = ensure_signed(origin)?; - let block: u32 = Self::get_current_block_as_u32(); - let epoch_length: u32 = T::EpochLength::get(); - let epoch: u32 = block / epoch_length; + let block: u64 = Self::get_current_block_as_u64(); + let epoch_length: u64 = T::EpochLength::get(); + let epoch: u64 = block / epoch_length; Self::do_validate( subnet_id, @@ -2740,19 +2384,17 @@ pub mod pallet { /// /// * `subnet_id` - Subnet ID to increase delegate pool balance of. /// - #[pallet::call_index(27)] + #[pallet::call_index(21)] #[pallet::weight({0})] pub fn attest( origin: OriginFor, subnet_id: u32, ) -> DispatchResultWithPostInfo { - Self::is_paused()?; - let hotkey: T::AccountId = ensure_signed(origin)?; - let block: u32 = Self::get_current_block_as_u32(); - let epoch_length: u32 = T::EpochLength::get(); - let epoch: u32 = block / epoch_length; + let block: u64 = Self::get_current_block_as_u64(); + let epoch_length: u64 = T::EpochLength::get(); + let epoch: u64 = block / epoch_length; Self::do_attest( subnet_id, @@ -2776,7 +2418,7 @@ pub mod pallet { /// * `peer_id` - The defendants subnet node peer ID /// * `data` - Data used to justify dispute for subnet use /// - #[pallet::call_index(28)] + #[pallet::call_index(22)] #[pallet::weight({0})] pub fn propose( origin: OriginFor, @@ -2785,8 +2427,6 @@ pub mod pallet { peer_id: PeerId, data: Vec, ) -> DispatchResult { - Self::is_paused()?; - let account_id: T::AccountId = ensure_signed(origin)?; Self::do_propose( @@ -2812,7 +2452,7 @@ pub mod pallet { /// * `peer_id` - The defendants subnet node peer ID /// * `data` - Data used to justify dispute for subnet use /// - #[pallet::call_index(29)] + #[pallet::call_index(23)] #[pallet::weight({0})] pub fn attest_proposal( origin: OriginFor, @@ -2821,8 +2461,6 @@ pub mod pallet { peer_id: PeerId, data: Vec, ) -> DispatchResult { - Self::is_paused()?; - let account_id: T::AccountId = ensure_signed(origin)?; Self::do_propose( @@ -2842,7 +2480,7 @@ pub mod pallet { /// * `subnet_node_id` - The proposers subnet node ID /// * `proposal_id` - The proposal ID /// - #[pallet::call_index(30)] + #[pallet::call_index(24)] #[pallet::weight({0})] pub fn cancel_proposal( origin: OriginFor, @@ -2850,8 +2488,6 @@ pub mod pallet { subnet_node_id: u32, proposal_id: u32, ) -> DispatchResult { - Self::is_paused()?; - let account_id: T::AccountId = ensure_signed(origin)?; Self::do_cancel_proposal( @@ -2870,7 +2506,7 @@ pub mod pallet { /// * `proposal_id` - The proposers subnet node ID /// * `data` - Data used to justify challenge for subnet use /// - #[pallet::call_index(31)] + #[pallet::call_index(25)] #[pallet::weight({0})] pub fn challenge_proposal( origin: OriginFor, @@ -2878,8 +2514,6 @@ pub mod pallet { proposal_id: u32, data: Vec, ) -> DispatchResult { - Self::is_paused()?; - let account_id: T::AccountId = ensure_signed(origin)?; Self::do_challenge_proposal( @@ -2899,7 +2533,7 @@ pub mod pallet { /// * `proposal_id` - The proposal ID /// * `vote` - YAY or NAY /// - #[pallet::call_index(32)] + #[pallet::call_index(26)] #[pallet::weight({0})] pub fn vote( origin: OriginFor, @@ -2908,8 +2542,6 @@ pub mod pallet { proposal_id: u32, vote: VoteType ) -> DispatchResult { - Self::is_paused()?; - let account_id: T::AccountId = ensure_signed(origin)?; Self::do_vote( @@ -2930,15 +2562,13 @@ pub mod pallet { /// * `subnet_id` - Subnet ID. /// * `proposal_id` - The proposal ID /// - #[pallet::call_index(33)] + #[pallet::call_index(27)] #[pallet::weight({0})] pub fn finalize_proposal( origin: OriginFor, subnet_id: u32, proposal_id: u32, ) -> DispatchResult { - Self::is_paused()?; - let account_id: T::AccountId = ensure_signed(origin)?; Self::do_finalize_proposal( @@ -2956,7 +2586,7 @@ pub mod pallet { /// * `subnet_node_id` - Callers subnet node ID /// * `a` - The unique parameter /// - #[pallet::call_index(34)] + #[pallet::call_index(28)] #[pallet::weight({0})] pub fn register_subnet_node_a_parameter( origin: OriginFor, @@ -2964,8 +2594,6 @@ pub mod pallet { subnet_node_id: u32, a: BoundedVec, ) -> DispatchResult { - Self::is_paused()?; - let key: T::AccountId = ensure_signed(origin)?; ensure!( @@ -2978,7 +2606,7 @@ pub mod pallet { ); ensure!( - !SubnetNodeUniqueParam::::contains_key(subnet_id, &a), + !SubnetNodeUniqueParam::::contains_key(subnet_id, a.clone()), Error::::SubnetNodeUniqueParamTaken ); @@ -2991,8 +2619,8 @@ pub mod pallet { params.a.is_none(), Error::::SubnetNodeUniqueParamIsSet ); - SubnetNodeUniqueParam::::insert(subnet_id, &a, ¶ms.peer_id); - params.a = Some(a); + SubnetNodeUniqueParam::::insert(subnet_id, a.clone(), params.peer_id.clone()); + params.a = Some(a.clone()); Ok(()) } ) @@ -3007,7 +2635,7 @@ pub mod pallet { /// * `b` (Optional) - The non-unique parameter /// * `c` (Optional) - The non-unique parameter /// - #[pallet::call_index(35)] + #[pallet::call_index(29)] #[pallet::weight({0})] pub fn set_subnet_node_non_unique_parameter( origin: OriginFor, @@ -3016,8 +2644,6 @@ pub mod pallet { b: Option>, c: Option>, ) -> DispatchResult { - Self::is_paused()?; - let key: T::AccountId = ensure_signed(origin)?; ensure!( @@ -3029,13 +2655,15 @@ pub mod pallet { Error::::NotKeyOwner ); - let epoch: u32 = Self::get_current_epoch_as_u32(); + let block: u64 = Self::get_current_block_as_u64(); + let epoch_length: u64 = T::EpochLength::get(); + let epoch: u64 = block / epoch_length; let last_update_epoch = SubnetNodeNonUniqueParamLastSet::::get(subnet_id, subnet_node_id); let interval = SubnetNodeNonUniqueParamUpdateInterval::::get(); ensure!( - last_update_epoch.saturating_add(interval) <= epoch as u32, + last_update_epoch + interval <= epoch as u32, Error::::SubnetNodeNonUniqueParamUpdateIntervalNotReached ); @@ -3072,20 +2700,18 @@ pub mod pallet { /// * `hotkey` - Current hotkey. /// * `new_coldkey` - New coldkey /// - #[pallet::call_index(36)] + #[pallet::call_index(30)] #[pallet::weight({0})] pub fn update_coldkey( origin: OriginFor, hotkey: T::AccountId, new_coldkey: T::AccountId, ) -> DispatchResult { - Self::is_paused()?; - let curr_coldkey: T::AccountId = ensure_signed(origin)?; HotkeyOwner::::try_mutate_exists(hotkey, |maybe_coldkey| -> DispatchResult { match maybe_coldkey { - Some(coldkey) if *coldkey == curr_coldkey => { + Some(status) if *status == curr_coldkey => { // Condition met, update or remove *maybe_coldkey = Some(new_coldkey.clone()); // Update StakeUnbondingLedger @@ -3110,42 +2736,40 @@ pub mod pallet { /// * `old_hotkey` - Old hotkey to be replaced. /// * `new_hotkey` - New hotkey to replace the old hotkey. /// - #[pallet::call_index(37)] + #[pallet::call_index(31)] #[pallet::weight({0})] pub fn update_hotkey( origin: OriginFor, old_hotkey: T::AccountId, new_hotkey: T::AccountId, ) -> DispatchResult { - Self::is_paused()?; - let coldkey: T::AccountId = ensure_signed(origin.clone())?; // --- Ensure hotkey not taken ensure!( - !HotkeyOwner::::contains_key(&new_hotkey), + !HotkeyOwner::::contains_key(new_hotkey.clone()), Error::::KeyOwnerTaken ); // Each subnet node hotkey is unique across the entire network ensure!( - HotkeyOwner::::get(&old_hotkey) == coldkey, + HotkeyOwner::::get(old_hotkey.clone()) == coldkey, Error::::NotKeyOwner ); - HotkeyOwner::::remove(&old_hotkey); - HotkeyOwner::::insert(&new_hotkey, &coldkey); + HotkeyOwner::::remove(old_hotkey.clone()); + HotkeyOwner::::insert(new_hotkey.clone(), coldkey.clone()); for (subnet_id, _) in SubnetsData::::iter() { - let subnet_node_owner: (bool, u32) = match HotkeySubnetNodeId::::try_get(subnet_id, &old_hotkey) { + let subnet_node_owner: (bool, u32) = match HotkeySubnetNodeId::::try_get(subnet_id, old_hotkey.clone()) { Ok(subnet_node_id) => (true, subnet_node_id), Err(()) => (false, 0), }; if subnet_node_owner.0 { // --- might not be needed here `SubnetNodeIdHotkey` - SubnetNodeIdHotkey::::insert(subnet_id, subnet_node_owner.1, &new_hotkey); - HotkeySubnetNodeId::::swap(subnet_id, &old_hotkey, subnet_id, &new_hotkey); + SubnetNodeIdHotkey::::insert(subnet_id, subnet_node_owner.1, new_hotkey.clone()); + HotkeySubnetNodeId::::swap(subnet_id, old_hotkey.clone(), subnet_id, new_hotkey.clone()); SubnetNodesData::::try_mutate_exists( subnet_id, subnet_node_owner.1, @@ -3164,8 +2788,8 @@ pub mod pallet { Self::do_swap_hotkey_balance( origin.clone(), subnet_id, - &old_hotkey, - &new_hotkey, + &old_hotkey.clone(), + &new_hotkey.clone(), ); } } @@ -3173,7 +2797,7 @@ pub mod pallet { Ok(()) } - #[pallet::call_index(38)] + #[pallet::call_index(32)] #[pallet::weight({0})] pub fn update_peer_id( origin: OriginFor, @@ -3181,60 +2805,6 @@ pub mod pallet { subnet_node_id: u32, new_peer_id: PeerId, ) -> DispatchResult { - Self::is_paused()?; - - let coldkey: T::AccountId = ensure_signed(origin.clone())?; - - ensure!( - Self::is_subnet_node_coldkey( - subnet_id, - subnet_node_id, - coldkey, - ), - Error::::NotKeyOwner - ); - - ensure!( - Self::validate_peer_id(&new_peer_id), - Error::::InvalidBootstrapPeerId - ); - - // Subnet node PeerIds and bootstrap PeerIds can match only if they are under the same subnet node ID - ensure!( - Self::is_owner_of_peer_or_ownerless(subnet_id, subnet_node_id, &new_peer_id), - Error::::PeerIdExist - ); - - SubnetNodesData::::try_mutate_exists( - subnet_id, - subnet_node_id, - |maybe_params| -> DispatchResult { - let params = maybe_params.as_mut().ok_or(Error::::SubnetNodeExist)?; - - PeerIdSubnetNode::::remove(subnet_id, ¶ms.peer_id); - PeerIdSubnetNode::::insert(subnet_id, &new_peer_id, subnet_node_id); - - params.peer_id = new_peer_id; - Ok(()) - } - )?; - - // TODO: Must update Rewards Submissions to use SN-UID instead of PeerId to allow updating PeerId - - - Ok(()) - } - - #[pallet::call_index(39)] - #[pallet::weight({0})] - pub fn update_bootstrap_peer_id( - origin: OriginFor, - subnet_id: u32, - subnet_node_id: u32, - new_bootstrap_peer_id: PeerId, - ) -> DispatchResult { - Self::is_paused()?; - let coldkey: T::AccountId = ensure_signed(origin.clone())?; ensure!( @@ -3246,88 +2816,49 @@ pub mod pallet { Error::::NotKeyOwner ); - ensure!( - Self::validate_peer_id(&new_bootstrap_peer_id), - Error::::InvalidBootstrapPeerId - ); - - ensure!( - Self::is_owner_of_peer_or_ownerless(subnet_id, subnet_node_id, &new_bootstrap_peer_id), - Error::::BootstrapPeerIdExist - ); + // Must be deactivated to update peer_id - // Subnet node PeerIds and bootstrap PeerIds can match only if they are under the same subnet node ID - SubnetNodesData::::try_mutate_exists( - subnet_id, - subnet_node_id, - |maybe_params| -> DispatchResult { - let params = maybe_params.as_mut().ok_or(Error::::SubnetNodeExist)?; - BootstrapPeerIdSubnetNode::::remove(subnet_id, ¶ms.bootstrap_peer_id); - BootstrapPeerIdSubnetNode::::insert(subnet_id, &new_bootstrap_peer_id, subnet_node_id); - - params.bootstrap_peer_id = new_bootstrap_peer_id; - Ok(()) - } - )?; + // let subnet_node = match SubnetNodesData::::try_get(subnet_id) { + // Ok(subnet_node) => subnet_node, + // Err(()) => return Err(Error::::SubnetNodeNotExist.into()), + // }; Ok(()) } - #[pallet::call_index(41)] - #[pallet::weight({0})] - pub fn pause(origin: OriginFor) -> DispatchResult { - T::MajorityCollectiveOrigin::ensure_origin(origin)?; - Self::do_pause() - } - - #[pallet::call_index(42)] - #[pallet::weight({0})] - pub fn unpause(origin: OriginFor) -> DispatchResult { - T::MajorityCollectiveOrigin::ensure_origin(origin)?; - Self::do_unpause() - } - - #[pallet::call_index(43)] + #[pallet::call_index(33)] #[pallet::weight({0})] pub fn set_max_subnet_nodes( origin: OriginFor, value: u32 ) -> DispatchResult { T::MajorityCollectiveOrigin::ensure_origin(origin)?; + Self::do_set_max_subnet_nodes(value) } - #[pallet::call_index(44)] + #[pallet::call_index(34)] #[pallet::weight({0})] - pub fn set_min_subnet_delegate_stake_factor( + pub fn set_min_stake_balance( origin: OriginFor, value: u128 ) -> DispatchResult { T::SuperMajorityCollectiveOrigin::ensure_origin(origin)?; - Self::do_set_min_subnet_delegate_stake_factor(value) - } - #[pallet::call_index(45)] - #[pallet::weight({0})] - pub fn set_subnet_owner_percentage( - origin: OriginFor, - value: u128 - ) -> DispatchResult { - T::SuperMajorityCollectiveOrigin::ensure_origin(origin)?; - Self::do_set_subnet_owner_percentage(value) + Self::do_set_min_stake_balance(value) } } impl Pallet { /// Register subnet pub fn do_register_subnet( - owner: T::AccountId, - subnet_registration_data: RegistrationSubnetData, + activator: T::AccountId, + subnet_data: RegistrationSubnetData, ) -> DispatchResult { // Ensure path is unique ensure!( - !SubnetPaths::::contains_key(&subnet_registration_data.path), + !SubnetPaths::::contains_key(subnet_data.clone().path), Error::::SubnetExist ); @@ -3337,82 +2868,98 @@ pub mod pallet { Self::can_subnet_register(epoch), Error::::SubnetRegistrationCooldown ); - - // --- Ensure owner didn't submit over max subnet entry intervals - // This is the blocks that must go by between each node registration - // Use `0` to not have a rate limit + + // --- Ensure total network memory isn't exceeded + ensure!( + TotalSubnetMemoryMB::::get() + subnet_data.memory_mb <= MaxTotalSubnetMemoryMB::::get(), + Error::::MaxTotalSubnetMemory + ); + + // Ensure max subnets not reached + // Get total live subnets + let total_subnets: u32 = (SubnetsData::::iter().count()).try_into().unwrap(); + let max_subnets: u32 = MaxSubnets::::get(); + ensure!( + total_subnets < max_subnets, + Error::::MaxSubnets + ); + + // --- Ensure registration time period is allowed ensure!( - subnet_registration_data.node_registration_interval <= MaxSubnetRegistrationInterval::::get(), - Error::::MaxSubnetRegistration + subnet_data.registration_blocks >= MinSubnetRegistrationBlocks::::get() && + subnet_data.registration_blocks <= MaxSubnetRegistrationBlocks::::get(), + Error::::InvalidSubnetRegistrationBlocks ); + // --- Ensure memory under max ensure!( - subnet_registration_data.node_activation_interval <= MaxSubnetActivationInterval::::get(), - Error::::MaxSubnetActivation + subnet_data.memory_mb <= MaxSubnetMemoryMB::::get(), + Error::::MaxSubnetMemory ); ensure!( - subnet_registration_data.max_node_registration_epochs <= MaxSubnetNodeRegistrationEpochs::::get(), - Error::::MaxSubnetActivation + subnet_data.entry_interval <= MaxSubnetEntryInterval::::get(), + Error::::MaxSubnetEntryInterval ); + let block: u64 = Self::get_current_block_as_u64(); let subnet_fee: u128 = Self::registration_cost(epoch); if subnet_fee > 0 { + // unreserve from activator let subnet_fee_as_balance = Self::u128_to_balance(subnet_fee); - // Ensure user has the funds, give accurate information on errors ensure!( - Self::can_remove_balance_from_coldkey_account(&owner, subnet_fee_as_balance.unwrap()), + Self::can_remove_balance_from_coldkey_account(&activator, subnet_fee_as_balance.unwrap()), Error::::NotEnoughBalanceToStake ); - // Send funds to Treasury and revert if failed - Self::send_to_treasury(&owner, subnet_fee_as_balance.unwrap())?; + // --- Burn fee + ensure!( + Self::remove_balance_from_coldkey_account(&activator, subnet_fee_as_balance.unwrap()) == true, + Error::::BalanceWithdrawalError + ); + + // TODO + // Send portion to treasury } // Get total subnets ever - let subnet_uids: u32 = TotalSubnetUids::::get(); + let subnet_len: u32 = TotalSubnets::::get(); // Start the subnet_ids at 1 - let subnet_id = subnet_uids.saturating_add(1); + let subnet_id = subnet_len + 1; + let base_node_memory: u128 = BaseSubnetNodeMemoryMB::::get(); + + let min_subnet_nodes: u32 = Self::get_min_subnet_nodes(base_node_memory, subnet_data.memory_mb); + let target_subnet_nodes: u32 = Self::get_target_subnet_nodes(min_subnet_nodes); + let subnet_data = SubnetData { id: subnet_id, - path: subnet_registration_data.path, - state: SubnetState::Registered, + path: subnet_data.clone().path, + min_nodes: min_subnet_nodes, + target_nodes: target_subnet_nodes, + memory_mb: subnet_data.memory_mb, + registration_blocks: subnet_data.clone().registration_blocks, + initialized: block, + activated: 0, + entry_interval: 0, }; - // Store registration epoch temporarily - SubnetRegistrationEpoch::::insert(subnet_id, epoch); - // Store owner - SubnetOwner::::insert(subnet_id, &owner); - // Store node registration interval - SubnetNodeRegistrationInterval::::insert(subnet_id, subnet_registration_data.node_registration_interval); - // Store max node registration epochs - SubnetNodeRegistrationEpochs::::insert(subnet_id, subnet_registration_data.max_node_registration_epochs); - // Store node activation interval - SubnetNodeActivationInterval::::insert(subnet_id, subnet_registration_data.node_activation_interval); - // Store max node penalties - MaxSubnetNodePenalties::::insert(subnet_id, subnet_registration_data.max_node_penalties); - - // Store whitelisted coldkeys for registration period - SubnetRegistrationColdkeyWhitelist::::insert( - subnet_id, - subnet_registration_data.coldkey_whitelist - ); - + // Increase total subnet memory + TotalSubnetMemoryMB::::mutate(|n: &mut u128| *n += subnet_data.memory_mb); // Store unique path - SubnetPaths::::insert(&subnet_data.path, subnet_id); + SubnetPaths::::insert(subnet_data.clone().path, subnet_id); // Store subnet data - SubnetsData::::insert(subnet_id, &subnet_data); + SubnetsData::::insert(subnet_id, subnet_data.clone()); // Increase total subnets. This is used for unique Subnet IDs - TotalSubnetUids::::mutate(|n: &mut u32| *n += 1); - // Update latest registration epoch for all subnets + TotalSubnets::::mutate(|n: &mut u32| *n += 1); + // Update latest registration epoch LastSubnetRegistrationEpoch::::set(epoch); Self::deposit_event(Event::SubnetRegistered { - account_id: owner, + account_id: activator, path: subnet_data.path, subnet_id: subnet_id }); @@ -3428,53 +2975,47 @@ pub mod pallet { }; ensure!( - subnet.state == SubnetState::Registered, + subnet.activated == 0, Error::::SubnetActivatedAlready ); - let epoch: u32 = Self::get_current_epoch_as_u32(); + let block: u64 = Self::get_current_block_as_u64(); - let subnet_registration_epochs = SubnetRegistrationEpochs::::get(); - // --- Ensure the subnet has passed it's required period to begin consensus submissions // --- Ensure the subnet is within the enactment period ensure!( - Self::is_subnet_registering(subnet_id, subnet.state, epoch) == false, + block > subnet.initialized + subnet.registration_blocks, Error::::SubnetInitializing ); // --- If subnet not activated yet and is outside the enactment period, remove subnet - if Self::is_subnet_in_enactment(subnet_id, subnet.state, epoch) == false { - return Self::do_remove_subnet( + if block > subnet.initialized + subnet.registration_blocks + SubnetActivationEnactmentPeriod::::get() { + return Self::deactivate_subnet( subnet.path, SubnetRemovalReason::EnactmentPeriod, ) } - // if epoch > subnet.registered.saturating_add(subnet_registration_epochs).saturating_add(SubnetActivationEnactmentBlocks::::get()) { - // return Self::do_remove_subnet( - // subnet.path, - // SubnetRemovalReason::EnactmentPeriod, - // ) - // } - // --- 1. Ensure minimum nodes are activated + // --- Ensure minimum nodes are activated + let epoch_length: u64 = T::EpochLength::get(); + let epoch: u64 = block / epoch_length; let subnet_node_ids: Vec = Self::get_classified_subnet_node_ids(subnet_id, &SubnetNodeClass::Validator, epoch); let subnet_nodes_count: u32 = subnet_node_ids.len() as u32; - if subnet_nodes_count < MinSubnetNodes::::get() { - return Self::do_remove_subnet( + if subnet_nodes_count < subnet.min_nodes { + return Self::deactivate_subnet( subnet.path, SubnetRemovalReason::MinSubnetNodes, ) } - // --- 2. Ensure minimum delegate stake achieved + // --- Ensure minimum delegate stake achieved let subnet_delegate_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); - let min_subnet_delegate_stake_balance = Self::get_min_subnet_delegate_stake_balance(); + let min_subnet_delegate_stake_balance = Self::get_min_subnet_delegate_stake_balance(subnet.min_nodes); // --- Ensure delegate stake balance is below minimum threshold required if subnet_delegate_stake_balance < min_subnet_delegate_stake_balance { - return Self::do_remove_subnet( + return Self::deactivate_subnet( subnet.path, SubnetRemovalReason::MinSubnetDelegateStake, ) @@ -3487,33 +3028,26 @@ pub mod pallet { subnet_id, |maybe_params| -> DispatchResult { let params = maybe_params.as_mut().ok_or(Error::::InvalidSubnetId)?; - params.state = SubnetState::Active; + params.activated = block; Ok(()) } )?; - TotalActiveSubnets::::mutate(|n: &mut u32| *n += 1); - - // --- Remove registration epoch - SubnetRegistrationEpoch::::remove(subnet_id); - // --- Remove registration whitelist - SubnetRegistrationColdkeyWhitelist::::remove(subnet_id); - Self::deposit_event(Event::SubnetActivated { subnet_id: subnet_id }); Ok(()) } - pub fn do_remove_subnet( + pub fn deactivate_subnet( path: Vec, reason: SubnetRemovalReason, ) -> DispatchResult { ensure!( - SubnetPaths::::contains_key(&path), + SubnetPaths::::contains_key(path.clone()), Error::::SubnetNotExist ); - let subnet_id = SubnetPaths::::get(&path).unwrap(); + let subnet_id = SubnetPaths::::get(path.clone()).unwrap(); let subnet = match SubnetsData::::try_get(subnet_id) { Ok(subnet) => subnet, @@ -3521,45 +3055,28 @@ pub mod pallet { }; // Remove unique path - SubnetPaths::::remove(&path); + SubnetPaths::::remove(path.clone()); // Remove subnet data SubnetsData::::remove(subnet_id); + // Decrease total subnet memory + TotalSubnetMemoryMB::::mutate(|n: &mut u128| n.saturating_reduce(subnet.memory_mb)); // Remove subnet entry ledger - LastSubnetRegistration::::remove(subnet_id); - - SubnetRegistrationEpoch::::remove(subnet_id); - SubnetRegistrationColdkeyWhitelist::::remove(subnet_id); - - QueuedSubnetNodes::::remove(subnet_id); + LastSubnetEntry::::remove(subnet_id); - if subnet.state == SubnetState::Active { - // Dec total active subnets - TotalActiveSubnets::::mutate(|n: &mut u32| n.saturating_dec()); - } + // We don't subtract TotalSubnets since it's used for ids // Remove all subnet nodes data let _ = SubnetNodesData::::clear_prefix(subnet_id, u32::MAX, None); - - let subnet_node_ids: Vec = Self::get_classified_subnet_node_ids(subnet_id, &SubnetNodeClass::Validator, 0); - let subnet_nodes_count = subnet_node_ids.len(); - TotalActiveNodes::::mutate(|n: &mut u32| n.saturating_reduce(subnet_nodes_count as u32)); - let _ = TotalSubnetNodes::::remove(subnet_id); - let _ = TotalSubnetNodeUids::::remove(subnet_id); - let _ = PeerIdSubnetNode::::clear_prefix(subnet_id, u32::MAX, None); - let _ = BootstrapPeerIdSubnetNode::::clear_prefix(subnet_id, u32::MAX, None); + let _ = SubnetNodeAccount::::clear_prefix(subnet_id, u32::MAX, None); let _ = SubnetNodeUniqueParam::::clear_prefix(subnet_id, u32::MAX, None); let _ = HotkeySubnetNodeId::::clear_prefix(subnet_id, u32::MAX, None); let _ = SubnetNodeIdHotkey::::clear_prefix(subnet_id, u32::MAX, None); - let _ = SubnetNodeNonUniqueParamLastSet::::clear_prefix(subnet_id, u32::MAX, None); - let _ = SubnetNodePenalties::::clear_prefix(subnet_id, u32::MAX, None); - let _ = SubnetNodeRegistrationInterval::::remove(subnet_id); // Remove all subnet consensus data let _ = SubnetPenaltyCount::::remove(subnet_id); // Remove consensus data - let _ = SubnetRewardsValidator::::clear_prefix(subnet_id, u32::MAX, None); let _ = SubnetRewardsSubmission::::clear_prefix(subnet_id, u32::MAX, None); // Remove proposals @@ -3574,7 +3091,7 @@ pub mod pallet { subnet_id: u32, subnet_node_id: u32, ) -> DispatchResult { - let block: u32 = Self::get_current_block_as_u32(); + let block: u64 = Self::get_current_block_as_u64(); // We don't check consensus steps here because a subnet nodes stake isn't included in calculating rewards // that hasn't reached their consensus submission epoch yet @@ -3587,7 +3104,6 @@ pub mod pallet { subnet_id: u32, hotkey: T::AccountId, peer_id: PeerId, - bootstrap_peer_id: PeerId, delegate_reward_rate: u128, stake_to_be_added: u128, a: Option>, @@ -3601,51 +3117,31 @@ pub mod pallet { Err(()) => return Err(Error::::SubnetNotExist.into()), }; - let epoch: u32 = Self::get_current_epoch_as_u32(); - let block: u32 = Self::get_current_block_as_u32(); - let is_registering: bool = subnet.state == SubnetState::Registered; - - // Add subnet entry interval logic if active + let block: u64 = Self::get_current_block_as_u64(); ensure!( - is_registering || - !is_registering && block >= LastSubnetRegistration::::get(subnet_id) - .saturating_add(SubnetNodeRegistrationInterval::::get(subnet_id)), - Error::::MaxSubnetRegistrationReached + block >= LastSubnetEntry::::get(subnet_id) + subnet.entry_interval, + Error::::MaxSubnetEntryIntervalReached ); // Ensure hotkey either has no owner or is the origins hotkey - match HotkeyOwner::::try_get(&hotkey) { + match HotkeyOwner::::try_get(hotkey.clone()) { Ok(coldkey_owner) => { ensure!( coldkey_owner == coldkey, Error::::KeyOwnerTaken ) }, - // Has no owner, pass + // Has no owner Err(()) => (), }; - // If in enactment period, no registering until activated - // Nodes must enter in the registration period or activation period - // Once we are in the enactment period, only delegate staking is enabled to reach the qualifications + // --- Subnet nodes can only register if within registration period or if it's activated + // --- Ensure the subnet outside of the enactment period or still registering ensure!( - !Self::is_subnet_in_enactment(subnet_id, subnet.state, epoch), + subnet.activated != 0 || subnet.activated == 0 && block <= subnet.initialized + subnet.registration_blocks, Error::::SubnetMustBeRegisteringOrActivated ); - // --- If in registration period, check if there is a whitelist and coldkey is in the whitelist - // `SubnetRegistrationColdkeyWhitelist` is removed on activation - match SubnetRegistrationColdkeyWhitelist::::try_get(subnet_id) { - Ok(key_tree) => { - ensure!( - key_tree.contains(&coldkey), - Error::::ColdkeyRegistrationWhitelist - ) - }, - // Has no whitelist, pass - Err(()) => (), - }; - // Ensure max nodes isn't surpassed let total_subnet_nodes: u32 = TotalSubnetNodes::::get(subnet_id); let max_subnet_nodes: u32 = MaxSubnetNodes::::get(); @@ -3657,7 +3153,7 @@ pub mod pallet { // Unique subnet_id -> AccountId // Ensure account doesn't already have a peer within subnet ensure!( - !HotkeySubnetNodeId::::contains_key(subnet_id, &hotkey), + !HotkeySubnetNodeId::::contains_key(subnet_id, hotkey.clone()), Error::::SubnetNodeExist ); @@ -3668,38 +3164,26 @@ pub mod pallet { !SubnetNodeUniqueParam::::contains_key(subnet_id, a.clone().unwrap()), Error::::SubnetNodeUniqueParamTaken ); - SubnetNodeUniqueParam::::insert(subnet_id, a.clone().unwrap(), &peer_id); + SubnetNodeUniqueParam::::insert(subnet_id, a.clone().unwrap(), peer_id.clone()); } - // Validate peer_id - ensure!( - Self::validate_peer_id(&peer_id), - Error::::InvalidPeerId - ); - - ensure!( - Self::validate_peer_id(&bootstrap_peer_id), - Error::::InvalidBootstrapPeerId - ); - - // Ensure peer and boostrap peer ID doesn't already exist within subnet regardless of coldkey - // Unique subnet_id -> PeerId - ensure!( - Self::is_owner_of_peer_or_ownerless(subnet_id, 0, &peer_id), - Error::::PeerIdExist - ); + // Ensure peer ID doesn't already exist within subnet regardless of coldkey + match SubnetNodeAccount::::try_get(subnet_id, peer_id.clone()) { + Ok(_) => return Err(Error::::PeerIdExist.into()), + Err(()) => (), + }; - // Unique subnet_id -> Bootstrap PeerId + // Validate peer_id ensure!( - Self::is_owner_of_peer_or_ownerless(subnet_id, 0, &bootstrap_peer_id), - Error::::BootstrapPeerIdExist + Self::validate_peer_id(peer_id.clone()), + Error::::InvalidPeerId ); // --- Ensure they have no stake on registration // If a subnet node deregisters, then they must fully unstake its stake balance to register again using that same balance ensure!( - AccountSubnetStake::::get(&hotkey, subnet_id) == 0, + AccountSubnetStake::::get(hotkey.clone(), subnet_id) == 0, Error::::MustUnstakeToRegister ); @@ -3715,7 +3199,9 @@ pub mod pallet { // To ensure the AccountId that owns the PeerId, they must sign the PeerId for others to verify // This ensures others cannot claim to own a PeerId they are not the owner of - let epoch: u32 = Self::get_current_epoch_as_u32(); + // Self::validate_signature(&Encode::encode(&peer_id), &signature, &signer)?; + let epoch_length: u64 = T::EpochLength::get(); + let epoch: u64 = block / epoch_length; // ======================== // Insert peer into storage @@ -3725,59 +3211,54 @@ pub mod pallet { start_epoch: epoch, }; - // --- Only use block for last_delegate_reward_rate_update is rate is greater than zero - let mut last_delegate_reward_rate_update = 0; - if delegate_reward_rate > 0 { - last_delegate_reward_rate_update = block; - } - - // --- Start the UIDs at 1 - TotalSubnetNodeUids::::mutate(subnet_id, |n: &mut u32| *n += 1); - let current_uid = TotalSubnetNodeUids::::get(subnet_id); + // + // TODO: Only use block for `last_delegate_reward_rate_update` if reward rate is > 0 + // let subnet_node: SubnetNode = SubnetNode { - id: current_uid, hotkey: hotkey.clone(), peer_id: peer_id.clone(), - bootstrap_peer_id: bootstrap_peer_id.clone(), + initialized: 0, classification: classification, delegate_reward_rate: delegate_reward_rate, - last_delegate_reward_rate_update: last_delegate_reward_rate_update, + last_delegate_reward_rate_update: block, a: a, b: b, c: c, }; - HotkeySubnetNodeId::::insert(subnet_id, &hotkey, current_uid); + // --- Start the UIDs at zero + let uid = TotalSubnetNodeUids::::get(subnet_id); + + HotkeySubnetNodeId::::insert(subnet_id, hotkey.clone(), uid); // Insert subnet node ID -> hotkey - SubnetNodeIdHotkey::::insert(subnet_id, current_uid, &hotkey); + SubnetNodeIdHotkey::::insert(subnet_id, uid, hotkey.clone()); // Insert hotkey -> coldkey - HotkeyOwner::::insert(&hotkey, &coldkey); + HotkeyOwner::::insert(hotkey.clone(), coldkey.clone()); // Insert SubnetNodesData with hotkey as key - SubnetNodesData::::insert(subnet_id, current_uid, subnet_node); + SubnetNodesData::::insert(subnet_id, uid, subnet_node); + + // Insert subnet peer account to keep peer_ids unique within subnets + SubnetNodeAccount::::insert(subnet_id, peer_id.clone(), uid); - // Insert subnet peer and bootstrap peer to keep peer_ids unique within subnets - PeerIdSubnetNode::::insert(subnet_id, &peer_id, current_uid); - BootstrapPeerIdSubnetNode::::insert(subnet_id, &bootstrap_peer_id, current_uid); + let next_uid = uid + 1; + TotalSubnetNodeUids::::insert(subnet_id, next_uid); // Increase total subnet nodes TotalSubnetNodes::::mutate(subnet_id, |n: &mut u32| *n += 1); - // --- Update last subnet entry only if it's not register / is active - if !is_registering { - LastSubnetRegistration::::insert(subnet_id, block); - } + LastSubnetEntry::::insert(subnet_id, block); Self::deposit_event( Event::SubnetNodeRegistered { subnet_id: subnet_id, - subnet_node_id: current_uid, - coldkey: coldkey, - hotkey: hotkey, - peer_id: peer_id, + subnet_node_id: uid, + coldkey: coldkey.clone(), + hotkey: hotkey.clone(), + peer_id: peer_id.clone(), } ); @@ -3792,32 +3273,30 @@ pub mod pallet { let hotkey: T::AccountId = ensure_signed(origin)?; ensure!( - HotkeySubnetNodeId::::get(subnet_id, &hotkey) == Some(subnet_node_id), + HotkeySubnetNodeId::::get(subnet_id, hotkey.clone()) == Some(subnet_node_id), Error::::NotUidOwner ); - let epoch: u32 = Self::get_current_epoch_as_u32(); + let epoch_length: u64 = T::EpochLength::get(); + let block: u64 = Self::get_current_block_as_u64(); + let epoch: u64 = block / epoch_length; let subnet = match SubnetsData::::try_get(subnet_id) { Ok(subnet) => subnet, Err(()) => return Err(Error::::SubnetNotExist.into()), }; - let is_registering: bool = subnet.state == SubnetState::Registered; - let block: u32 = Self::get_current_block_as_u32(); - - // Add subnet entry interval logic if active - ensure!( - is_registering || - !is_registering && block >= LastSubnetActivation::::get(subnet_id) - .saturating_add(SubnetNodeActivationInterval::::get(subnet_id)), - Error::::MaxSubnetRegistrationReached - ); - // // TODO: Allow node to activate if already registered // + // --- Subnet nodes can only register if within registration period or if it's activated + // --- Ensure the subnet outside of the enactment period or still registering + // ensure!( + // subnet.activated != 0 || subnet.activated == 0 && block <= subnet.initialized + subnet.registration_blocks, + // Error::::SubnetMustBeRegisteringOrActivated + // ); + SubnetNodesData::::try_mutate_exists( subnet_id, subnet_node_id, @@ -3828,15 +3307,19 @@ pub mod pallet { Error::::SubnetNodeAlreadyActivated ); - // --- If subnet activated, activate starting at `Queue` - let mut class = SubnetNodeClass::Queue; + // ensure!( + // params.initialized == 0, + // Error::::SubnetNodeAlreadyActivated + // ); + // --- If subnet activated, activate starting at `Idle` + let mut class = SubnetNodeClass::Idle; // --- Increase epoch by one to ensure node starts on a fresh epoch unless subnet is still registering let mut epoch_increase = 1; // --- If subnet in registration, activate starting at `Validator` to start off subnet consensus // --- Initial nodes before activation are entered as ``submittable`` nodes // They initiate the first consensus epoch and are responsible for increasing classifications // of other nodes that come in post activation - if subnet.state == SubnetState::Registered { + if subnet.activated == 0 { class = SubnetNodeClass::Validator; // --- Start node on current epoch for the next era epoch_increase -= 1; @@ -3845,6 +3328,7 @@ pub mod pallet { class = SubnetNodeClass::Validator; } + params.initialized = block; params.classification = SubnetNodeClassification { class: class, start_epoch: epoch + epoch_increase, @@ -3852,14 +3336,7 @@ pub mod pallet { Ok(()) } )?; - - TotalActiveNodes::::mutate(|n: &mut u32| *n += 1); - // --- Update last subnet entry only if it's not register / is active - if !is_registering { - LastSubnetActivation::::insert(subnet_id, block); - } - Self::deposit_event( Event::SubnetNodeActivated { subnet_id: subnet_id, @@ -3891,7 +3368,9 @@ pub mod pallet { Error::::NotKeyOwner ); - let epoch: u32 = Self::get_current_epoch_as_u32(); + let epoch_length: u64 = T::EpochLength::get(); + let block: u64 = Self::get_current_block_as_u64(); + let epoch: u64 = block / epoch_length; let subnet_node = match SubnetNodesData::::try_get(subnet_id, subnet_node_id) { Ok(subnet_node) => { @@ -4000,10 +3479,12 @@ pub mod pallet { .map(|id| id) .collect(); - // let max_subnet_node_registration_epochs = SubnetNodeRegistrationEpochs::::get(); + let subnet_node_registration_epochs = SubnetNodeRegistrationEpochs::::get(); let max = MaxDeactivations::::get(); - let epoch: u32 = Self::get_current_epoch_as_u32(); + let epoch_length: u64 = T::EpochLength::get(); + let block: u64 = Self::get_current_block_as_u64(); + let epoch: u64 = block / epoch_length; let mut i: u32 = 0; for data in deactivation_ledger.clone().iter() { @@ -4012,7 +3493,6 @@ pub mod pallet { } let subnet_id = data.subnet_id; - let max_subnet_node_registration_epochs = SubnetNodeRegistrationEpochs::::get(subnet_id); // --- If subnet and subnet node exists, otherwise pass and remove set if subnet_ids.get(&subnet_id) != None { @@ -4022,6 +3502,7 @@ pub mod pallet { subnet_node_id, |maybe_params| -> DispatchResult { let params = maybe_params.as_mut().ok_or(Error::::SubnetNodeExist)?; + params.initialized = block; params.classification = SubnetNodeClassification { class: SubnetNodeClass::Deactivated, start_epoch: epoch + 1, @@ -4037,53 +3518,10 @@ pub mod pallet { i+=1; } - DeactivationLedger::::set(deactivation_ledger); + DeactivationLedger::::set(deactivation_ledger.clone()); T::WeightInfo::do_deactivation_ledger(subnet_ids.len() as u32, i) } - - pub fn do_queue(block: u32) { - let current_epoch: u32 = Self::get_current_epoch_as_u32(); - let epoch_length: u32 = T::EpochLength::get(); - let queue_epochs: u32 = 16; - - for (subnet_id, _) in SubnetsData::::iter() { - let mut max_nodes_per_epoch = Self::get_subnet_churn_limit(subnet_id); - if max_nodes_per_epoch > epoch_length { - max_nodes_per_epoch = epoch_length; - } - let registration_interval = epoch_length / max_nodes_per_epoch; - - if block >= registration_interval && block % registration_interval == 0 { - // --- We're on a block that is open to activating a node from the queue - QueuedSubnetNodes::::mutate(subnet_id, |subnet_nodes| { - if let Some((uid, subnet_node)) = subnet_nodes.first_key_value() { - // --- Check if the first node in the tree can be activated (FIFO) - if current_epoch >= &subnet_node.classification.start_epoch + queue_epochs { - log::error!("do_queue start_epoch: {:?}", &subnet_node.classification.start_epoch); - log::error!("do_queue start_epoch 2: {:?}", &subnet_node.classification.start_epoch + queue_epochs); - log::error!("do_queue current_epoch: {:?}", &subnet_node.classification.start_epoch); - - // --- Update classification - let mut new_subnet_node = subnet_node.clone(); - let new_classification: SubnetNodeClassification = SubnetNodeClassification { - class: SubnetNodeClass::Registered, - start_epoch: current_epoch + 1, - }; - new_subnet_node.classification = new_classification; - - // --- Activate - SubnetNodesData::::insert(subnet_id, subnet_node.id, new_subnet_node); - TotalActiveSubnetNodes::::mutate(subnet_id, |n: &mut u32| *n += 1); - - // --- Remove from queue - subnet_nodes.remove(&uid.clone()); - } - } - }); - } - } - } } #[pallet::hooks] @@ -4105,20 +3543,16 @@ pub mod pallet { /// * `block_number` - Current block number. /// fn on_initialize(block_number: BlockNumberFor) -> Weight { - if Self::is_paused().is_err() { - return Weight::from_parts(0, 0) - } - - let block: u32 = Self::convert_block_as_u32(block_number); - let epoch_length: u32 = T::EpochLength::get(); + let block: u64 = Self::convert_block_as_u64(block_number); + let epoch_length: u64 = T::EpochLength::get(); // Reward subnet nodes if block >= epoch_length && block % epoch_length == 0 { - let epoch: u32 = block / epoch_length; + let epoch: u64 = block / epoch_length; // Reward subnets for the previous epoch // Reward before shifting - Self::reward_subnets_v2(block, epoch - 1); + Self::reward_subnets(block, (epoch - 1) as u32); // return T::WeightInfo::on_initialize_reward_subnets(); return Weight::from_parts(207_283_478_000, 22166406) @@ -4131,10 +3565,10 @@ pub mod pallet { } else if (block - 2) >= epoch_length && (block - 2) % epoch_length == 0 { // We save some weight by waiting one more block to choose validators // Run the block succeeding form consensus - let epoch: u32 = block / epoch_length; + let epoch: u64 = block / epoch_length; // Choose validators for the current epoch - Self::do_epoch_preliminaries(block, epoch, epoch_length); + Self::do_epoch_preliminaries(block, epoch as u32, epoch_length); return Weight::from_parts(207_283_478_000, 22166406) .saturating_add(T::DbWeight::get().reads(18250_u64)) @@ -4147,13 +3581,8 @@ pub mod pallet { .saturating_add(T::DbWeight::get().writes(12002_u64)) } - fn on_finalize(block_number: BlockNumberFor) { - let block: u32 = Self::convert_block_as_u32(block_number); - Self::do_queue(block); - } - fn on_idle(block_number: BlockNumberFor, remaining_weight: Weight) -> Weight { - let block: u32 = Self::convert_block_as_u32(block_number); + let block: u64 = Self::convert_block_as_u64(block_number); if remaining_weight.any_lt(T::DbWeight::get().reads(2)) { return Weight::from_parts(0, 0) @@ -4192,60 +3621,74 @@ pub mod pallet { } let subnet_id = 1; + + let base_node_memory: u128 = BaseSubnetNodeMemoryMB::::get(); + + // --- Get min nodes based on default memory settings + let real_min_subnet_nodes: u128 = self.memory_mb.clone() / base_node_memory; + let mut min_subnet_nodes: u32 = MinSubnetNodes::::get(); + if real_min_subnet_nodes as u32 > min_subnet_nodes { + min_subnet_nodes = real_min_subnet_nodes as u32; + } + let target_subnet_nodes: u32 = (min_subnet_nodes as u128).saturating_mul(TargetSubnetNodesMultiplier::::get()).saturating_div(1000000000) as u32 + min_subnet_nodes; + let subnet_data = SubnetData { id: subnet_id, path: self.subnet_path.clone(), - state: SubnetState::Active, + min_nodes: min_subnet_nodes, + target_nodes: target_subnet_nodes, + memory_mb: self.memory_mb.clone(), + registration_blocks: MinSubnetRegistrationBlocks::::get(), + initialized: 1, + activated: 0, + entry_interval: 0, }; - - SubnetRegistrationEpoch::::insert(subnet_id, 1); + + // Increase total subnet memory + TotalSubnetMemoryMB::::mutate(|n: &mut u128| *n += subnet_data.memory_mb); // Store unique path SubnetPaths::::insert(self.subnet_path.clone(), subnet_id); // Store subnet data SubnetsData::::insert(subnet_id, subnet_data.clone()); // Increase total subnets count - TotalSubnetUids::::mutate(|n: &mut u32| *n += 1); + TotalSubnets::::mutate(|n: &mut u32| *n += 1); LastSubnetRegistrationEpoch::::set(1); // Increase delegate stake to allow activation of subnet model let min_stake_balance = MinStakeBalance::::get(); // --- Get minimum subnet stake balance - let min_subnet_stake_balance = min_stake_balance; - - let total_issuance_as_balance = T::Currency::total_issuance(); - let total_issuance: u128 = total_issuance_as_balance.try_into().unwrap_or(0); - let total_staked: u128 = TotalStake::::get(); - let total_delegate_staked: u128 = TotalDelegateStake::::get(); - let total_node_delegate_staked: u128 = TotalNodeDelegateStake::::get(); - let total_network_issuance = total_issuance - .saturating_add(total_staked) - .saturating_add(total_delegate_staked) - .saturating_add(total_node_delegate_staked); - - let factor: u128 = MinSubnetDelegateStakeFactor::::get(); - let min_subnet_delegate_stake_balance = total_network_issuance.saturating_mul(factor).saturating_div(1000000000); - + let min_subnet_stake_balance = min_stake_balance * min_subnet_nodes as u128; + // --- Get required delegate stake balance for a subnet to have to stay live + let mut min_subnet_delegate_stake_balance = (min_subnet_stake_balance as u128).saturating_mul(MinSubnetDelegateStakePercentage::::get()).saturating_div(1000000000); + + // --- Get absolute minimum required subnet delegate stake balance + let min_subnet_delegate_stake = MinSubnetDelegateStake::::get(); + // --- Return here if the absolute minimum required subnet delegate stake balance is greater + // than the calculated minimum requirement + if min_subnet_delegate_stake > min_subnet_delegate_stake_balance { + min_subnet_delegate_stake_balance = min_subnet_delegate_stake + } TotalSubnetDelegateStakeBalance::::insert(subnet_id, min_subnet_delegate_stake_balance); - // --- Initialize subnet nodes - // Only initialize to test using subnet nodes - // If testing using subnet nodes in a subnet, comment out the ``for`` loop + // // --- Initialize subnet nodes + // // Only initialize to test using subnet nodes + // // If testing using subnet nodes in a subnet, comment out the ``for`` loop - let mut stake_amount: u128 = MinStakeBalance::::get(); + // let mut stake_amount: u128 = MinStakeBalance::::get(); - - - + // + // + // // let mut count = 0; // for (account_id, peer_id) in &self.subnet_nodes { // // Redundant // // Unique subnet_id -> PeerId // // Ensure peer ID doesn't already exist within subnet regardless of account_id - // let peer_exists: bool = match PeerIdSubnetNode::::try_get(subnet_id, peer_id.clone()) { + // let peer_exists: bool = match SubnetNodeAccount::::try_get(subnet_id, peer_id.clone()) { // Ok(_) => true, // Err(()) => false, // }; @@ -4295,6 +3738,7 @@ pub mod pallet { // let subnet_node: SubnetNode = SubnetNode { // hotkey: account_id.clone(), // peer_id: peer_id.clone(), + // initialized: 0, // classification: classification, // delegate_reward_rate: 0, // last_delegate_reward_rate_update: 0, @@ -4303,27 +3747,29 @@ pub mod pallet { // c: Some(BoundedVec::new()), // }; - // TotalSubnetNodeUids::::mutate(subnet_id, |n: &mut u32| *n += 1); - // let current_uid = TotalSubnetNodeUids::::get(subnet_id); - - // HotkeySubnetNodeId::::insert(subnet_id, account_id.clone(), current_uid); + // let uid = TotalSubnetNodeUids::::get(subnet_id); + + // HotkeySubnetNodeId::::insert(subnet_id, account_id.clone(), uid); // // Insert subnet node ID -> hotkey - // SubnetNodeIdHotkey::::insert(subnet_id, current_uid, account_id.clone()); + // SubnetNodeIdHotkey::::insert(subnet_id, uid, account_id.clone()); // // Insert hotkey -> coldkey // HotkeyOwner::::insert(account_id.clone(), account_id.clone()); // // Insert SubnetNodesData with hotkey as key - // SubnetNodesData::::insert(subnet_id, current_uid, subnet_node); + // SubnetNodesData::::insert(subnet_id, uid, subnet_node); // // Insert subnet peer account to keep peer_ids unique within subnets - // PeerIdSubnetNode::::insert(subnet_id, peer_id.clone(), current_uid); - + // SubnetNodeAccount::::insert(subnet_id, peer_id.clone(), uid); + + // let next_uid = uid + 1; + // TotalSubnetNodeUids::::insert(subnet_id, next_uid); + // // Increase total subnet nodes // TotalSubnetNodes::::mutate(subnet_id, |n: &mut u32| *n += 1); - // LastSubnetRegistration::::insert(subnet_id, 0); + // LastSubnetEntry::::insert(subnet_id, 0); // count += 1; // } diff --git a/pallets/network/src/proposal.rs b/pallets/network/src/proposal.rs index 72b4ec9..cc68d45 100644 --- a/pallets/network/src/proposal.rs +++ b/pallets/network/src/proposal.rs @@ -25,7 +25,7 @@ impl Pallet { peer_id: PeerId, data: Vec, ) -> DispatchResult { - let proposer_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, &hotkey); + let proposer_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, hotkey.clone()); ensure!( proposer_subnet_node_id == Some(subnet_node_id), Error::::NotUidOwner @@ -37,21 +37,21 @@ impl Pallet { Err(()) => return Err(Error::::SubnetNotExist.into()), }; - let block: u32 = Self::get_current_block_as_u32(); - let epoch: u32 = block / T::EpochLength::get(); + let block: u64 = Self::get_current_block_as_u64(); + let epoch: u64 = block / T::EpochLength::get(); // --- Ensure proposer account has peer and is validator class match SubnetNodesData::::try_get( subnet_id, subnet_node_id ) { - Ok(subnet_node) => subnet_node.has_classification(&SubnetNodeClass::Validator, epoch), + Ok(subnet_node) => subnet_node.has_classification(&SubnetNodeClass::Validator, epoch as u64), Err(()) => return Err(Error::::SubnetNotExist.into()), }; // Unique subnet_id -> PeerId // Ensure peer ID exists within subnet - let defendant_subnet_node_id = match PeerIdSubnetNode::::try_get(subnet_id, &peer_id) { + let defendant_subnet_node_id = match SubnetNodeAccount::::try_get(subnet_id, peer_id.clone()) { Ok(defendant_subnet_node_id) => defendant_subnet_node_id, Err(()) => return Err(Error::::PeerIdNotExist.into()), }; @@ -73,7 +73,7 @@ impl Pallet { // safe unwrap after `contains_key` ensure!( - subnet_nodes_count as u32 >= MinSubnetNodes::::get(), + subnet_nodes_count as u32 >= subnet.min_nodes, Error::::SubnetNodesMin ); @@ -105,7 +105,7 @@ impl Pallet { let proposal_bid_amount_as_balance = Self::u128_to_balance(proposal_bid_amount); let can_withdraw: bool = Self::can_remove_balance_from_coldkey_account( - &hotkey, + &hotkey.clone(), proposal_bid_amount_as_balance.unwrap(), ); @@ -116,7 +116,7 @@ impl Pallet { // --- Withdraw bid amount from proposer accounts let _ = T::Currency::withdraw( - &hotkey, + &hotkey.clone(), proposal_bid_amount_as_balance.unwrap(), WithdrawReasons::except(WithdrawReasons::TRANSFER), ExistenceRequirement::KeepAlive, @@ -201,7 +201,7 @@ impl Pallet { return Err(Error::::ProposalInvalid.into()), }; - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, &hotkey); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, hotkey.clone()); // --- Ensure defendant ensure!( @@ -216,7 +216,7 @@ impl Pallet { ); let challenge_period = ChallengePeriod::::get(); - let block: u32 = Self::get_current_block_as_u32(); + let block: u64 = Self::get_current_block_as_u64(); // --- Ensure challenge period is active ensure!( @@ -253,7 +253,7 @@ impl Pallet { ExistenceRequirement::KeepAlive, ); - let epoch: u32 = block / T::EpochLength::get(); + let epoch: u64 = block / T::EpochLength::get(); Proposals::::mutate( subnet_id, @@ -284,7 +284,7 @@ impl Pallet { proposal_id: u32, vote: VoteType ) -> DispatchResult { - let voter_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, &hotkey); + let voter_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, hotkey.clone()); ensure!( voter_subnet_node_id == Some(subnet_node_id), Error::::NotUidOwner @@ -326,7 +326,7 @@ impl Pallet { ); let voting_period = VotingPeriod::::get(); - let block: u32 = Self::get_current_block_as_u32(); + let block: u64 = Self::get_current_block_as_u64(); // --- Ensure voting period is active // Voting period starts after the challenge block @@ -386,7 +386,7 @@ impl Pallet { return Err(Error::::ProposalInvalid.into()), }; - let canceler_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, &hotkey); + let canceler_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, hotkey.clone()); ensure!( subnet_node_id == canceler_subnet_node_id.unwrap(), Error::::NotUidOwner @@ -454,7 +454,7 @@ impl Pallet { ); let voting_period = VotingPeriod::::get(); - let block: u32 = Self::get_current_block_as_u32(); + let block: u64 = Self::get_current_block_as_u64(); // --- Ensure voting period is completed ensure!( @@ -588,7 +588,7 @@ impl Pallet { fn account_has_active_proposal_as_plaintiff( subnet_id: u32, subnet_node_id: u32, - block: u32, + block: u64, ) -> bool { let challenge_period = ChallengePeriod::::get(); let voting_period = VotingPeriod::::get(); @@ -602,8 +602,8 @@ impl Pallet { } // At this point we have a proposal that matches the plaintiff - let proposal_block: u32 = proposal.start_block; - let challenge_block: u32 = proposal.challenge_block; + let proposal_block: u64 = proposal.start_block; + let challenge_block: u64 = proposal.challenge_block; if challenge_block == 0 { // If time remaining for challenge if block < proposal.start_block + challenge_period { @@ -627,7 +627,7 @@ impl Pallet { fn account_has_active_proposal_as_defendant( subnet_id: u32, subnet_node_id: u32, - block: u32, + block: u64, ) -> bool { let challenge_period = ChallengePeriod::::get(); let voting_period = VotingPeriod::::get(); @@ -646,8 +646,8 @@ impl Pallet { } // At this point we have a proposal that matches the defendant - let proposal_block: u32 = proposal.start_block; - let challenge_block: u32 = proposal.challenge_block; + let proposal_block: u64 = proposal.start_block; + let challenge_block: u64 = proposal.challenge_block; if challenge_block == 0 { // If time remaining for challenge if block < proposal.start_block + challenge_period { diff --git a/pallets/network/src/rewards.rs b/pallets/network/src/rewards.rs index d69394a..6985434 100644 --- a/pallets/network/src/rewards.rs +++ b/pallets/network/src/rewards.rs @@ -1,358 +1,353 @@ -// // Copyright (C) Hypertensor. -// // SPDX-License-Identifier: Apache-2.0 - -// // Licensed under the Apache License, Version 2.0 (the "License"); -// // you may not use this file except in compliance with the License. -// // You may obtain a copy of the License at -// // -// // http://www.apache.org/licenses/LICENSE-2.0 -// // -// // Unless required by applicable law or agreed to in writing, software -// // distributed under the License is distributed on an "AS IS" BASIS, -// // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// // See the License for the specific language governing permissions and -// // limitations under the License. - -// use super::*; -// use sp_runtime::Saturating; -// use frame_support::pallet_prelude::DispatchResultWithPostInfo; -// use frame_support::pallet_prelude::Pays; - -// impl Pallet { -// pub fn reward_subnets(block: u64, epoch: u32) -> DispatchResultWithPostInfo { -// // --- Get base rewards based on subnet memory requirements -// let base_reward_per_mb: u128 = BaseRewardPerMB::::get(); -// // --- Get required attestation percentage -// let min_attestation_percentage = MinAttestationPercentage::::get(); -// let min_vast_majority_attestation_percentage = MinVastMajorityAttestationPercentage::::get(); -// // --- Get max epochs in a row a subnet node can be absent from consensus data -// let max_subnet_node_penalties = MaxSubnetNodePenalties::::get(); -// // --- Get the max penalties a subnet node can have before being removed from the network -// let max_subnet_penalty_count = MaxSubnetPenaltyCount::::get(); -// // --- Get the attestation percentage for a subnet node to be removed from the network -// // if they are not included in the validators consensus data -// // --- If this attestation threshold is exceeded, the subnet node that is absent will have its -// // SubnetNodePenalties incrememented -// let node_attestation_removal_threshold = NodeAttestationRemovalThreshold::::get(); -// // --- Get the percentage of the subnet rewards that go to subnet delegate stakers -// let delegate_stake_rewards_percentage: u128 = DelegateStakeRewardsPercentage::::get(); - -// let max_subnet_node_registration_epochs = MaxSubnetNodeRegistrationEpochs::::get(); -// let subnet_owner_percentage = SubnetOwnerPercentage::::get(); - -// for (subnet_id, data) in SubnetsData::::iter() { -// let mut attestation_percentage: u128 = 0; - -// // --- We don't check for minimum nodes because nodes cannot validate or attest if they are not met -// // as they the validator will not be chosen in ``do_epoch_preliminaries`` if the -// // min nodes are not met on that epoch. -// if let Ok(mut submission) = SubnetRewardsSubmission::::try_get(subnet_id, epoch) { -// // --- Get memory of the subnet -// let memory_mb = data.memory_mb; - -// // --- Get overall subnet rewards -// let overall_subnet_reward: u128 = Self::percent_mul(base_reward_per_mb, memory_mb); - -// // --- Get delegators rewards -// let delegate_stake_reward: u128 = Self::percent_mul(overall_subnet_reward, delegate_stake_rewards_percentage); - -// // --- Get subnet nodes rewards -// let subnet_node_reward: u128 = overall_subnet_reward.saturating_sub(delegate_stake_reward); - -// // --- Redundant -// if subnet_node_reward == 0 { -// continue -// } - -// let min_nodes = data.min_nodes; - -// // --- Get subnet nodes count to check against attestation count -// // ``reward_subnuts`` is called before ``shift_node_classes`` so we can know how many nodes are validators -// // while in this function that should have in the epoch the rewards are destined for -// let subnet_nodes: Vec = Self::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Validator, epoch as u64); -// let subnet_node_count = subnet_nodes.len() as u128; - -// // --- Ensure nodes are at min requirement to continue rewards operations -// if subnet_node_count < min_nodes as u128 { -// continue -// } - -// let attestations: u128 = submission.attests.len() as u128; -// attestation_percentage = Self::percent_div(attestations, subnet_node_count); - -// // Redundant -// // When subnet nodes exit, the consensus data is updated to remove them from it -// if attestation_percentage > Self::PERCENTAGE_FACTOR { -// attestation_percentage = Self::PERCENTAGE_FACTOR; -// } +// Copyright (C) Hypertensor. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use sp_runtime::Saturating; +use frame_support::pallet_prelude::DispatchResultWithPostInfo; +use frame_support::pallet_prelude::Pays; + +impl Pallet { + pub fn reward_subnets(block: u64, epoch: u32) -> DispatchResultWithPostInfo { + // --- Get base rewards based on subnet memory requirements + let base_reward_per_mb: u128 = BaseRewardPerMB::::get(); + // --- Get required attestation percentage + let min_attestation_percentage = MinAttestationPercentage::::get(); + let min_vast_majority_attestation_percentage = MinVastMajorityAttestationPercentage::::get(); + // --- Get max epochs in a row a subnet node can be absent from consensus data + let max_subnet_node_penalties = MaxSubnetNodePenalties::::get(); + // --- Get the max penalties a subnet node can have before being removed from the network + let max_subnet_penalty_count = MaxSubnetPenaltyCount::::get(); + // --- Get the attestation percentage for a subnet node to be removed from the network + // if they are not included in the validators consensus data + // --- If this attestation threshold is exceeded, the subnet node that is absent will have its + // SubnetNodePenalties incrememented + let node_attestation_removal_threshold = NodeAttestationRemovalThreshold::::get(); + // --- Get the percentage of the subnet rewards that go to subnet delegate stakers + let delegate_stake_rewards_percentage: u128 = DelegateStakeRewardsPercentage::::get(); + + let subnet_node_registration_epochs = SubnetNodeRegistrationEpochs::::get(); + + for (subnet_id, data) in SubnetsData::::iter() { + let mut attestation_percentage: u128 = 0; + + // --- We don't check for minimum nodes because nodes cannot validate or attest if they are not met + // as they the validator will not be chosen in ``do_epoch_preliminaries`` if the + // min nodes are not met on that epoch. + if let Ok(mut submission) = SubnetRewardsSubmission::::try_get(subnet_id, epoch) { + // --- Get memory of the subnet + let memory_mb = data.memory_mb; + + // --- Get subnet rewards + let overall_subnet_reward: u128 = Self::percent_mul(base_reward_per_mb, memory_mb); + + // --- Get delegators rewards + // We get the delegators rewards in case of rounding issues in favor of subnet nodes over delegators + let delegate_stake_reward: u128 = Self::percent_mul(overall_subnet_reward, delegate_stake_rewards_percentage); + + // --- Get subnet nodes rewards + let subnet_reward: u128 = overall_subnet_reward.saturating_sub(delegate_stake_reward); + + let min_nodes = data.min_nodes; + + // --- Get subnet nodes count to check against attestation count + // ``reward_subnuts`` is called before ``shift_node_classes`` so we can know how many nodes are validators + // while in this function that should have in the epoch the rewards are destined for + let subnet_nodes: Vec = Self::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Validator, epoch as u64); + let subnet_node_count = subnet_nodes.len() as u128; + + // --- Ensure nodes are at min requirement to continue rewards operations + if subnet_node_count < min_nodes as u128 { + continue + } + + let attestations: u128 = submission.attests.len() as u128; + attestation_percentage = Self::percent_div(attestations, subnet_node_count); + + // Redundant + // When subnet nodes exit, the consensus data is updated to remove them from it + if attestation_percentage > Self::PERCENTAGE_FACTOR { + attestation_percentage = Self::PERCENTAGE_FACTOR; + } -// let validator_subnet_node_id: u32 = submission.validator_id; - -// let data_len = submission.data.len(); - -// // --- If validator submitted no data, or less than the minimum required subnet nodes -// // we assume the subnet is broken -// // There is no slashing if subnet is broken, only risk of subnet being removed -// // The subnet is deemed broken is there is no consensus or not enough nodes -// // -// // The subnet has up to the MaxSubnetPenaltyCount to solve the issue before the subnet and all subnet nodes are removed -// if (data_len as u32) < min_nodes { -// // --- Increase the penalty count for the subnet because its deemed in a broken state -// SubnetPenaltyCount::::mutate(subnet_id, |n: &mut u32| *n += 1); - -// // If the subnet is broken, the validator can avoid slashing by submitting consensus with null data - -// // --- If subnet nodes aren't in consensus this is true -// // Since we can assume the subnet is in a broken state, we don't slash the validator -// // even if others do not attest to this state??? - -// // --- If the subnet nodes are not in agreement with the validator that the model is broken, we -// // increase the penalty score for the validator -// // and slash -// // --- We only do this if the vast majority of nodes are not in agreement with the validator -// // Otherwise we assume the issue just started or is being resolved. -// // i.e. if a validator sends in no data but by the time some other nodes check, it's resolved, -// // the validator only gets slashed if the vast majority of nodes disagree at ~87.5% -// // Or vice versa if validator submits data in a healthy state and the subnet breaks -// // -// // This is an unlikely scenario because all nodes should be checking the subnets state within a few seconds -// // of each other. -// if attestation_percentage < min_vast_majority_attestation_percentage { -// // --- Slash validator and increase penalty score -// Self::slash_validator(subnet_id, validator_subnet_node_id, attestation_percentage, block); -// } - -// // --- If the subnet was deemed in a broken stake by the validator, rewards are bypassed -// continue; -// } - -// // --- If the minimum required attestation not reached, assume validator is dishonest, slash, and continue -// // We don't increase subnet penalty count here because this is likely the validators fault -// if attestation_percentage < min_attestation_percentage { -// // --- Slash validator and increase penalty score -// Self::slash_validator(subnet_id, validator_subnet_node_id, attestation_percentage, block); + let validator_subnet_node_id: u32 = submission.validator_id; + + let data_len = submission.data.len(); + + // --- If validator submitted no data, or less than the minimum required subnet nodes + // we assume the subnet is broken + // There is no slashing if subnet is broken, only risk of subnet being removed + // The subnet is deemed broken is there is no consensus or not enough nodes + // + // The subnet has up to the MaxSubnetPenaltyCount to solve the issue before the subnet and all subnet nodes are removed + if (data_len as u32) < min_nodes { + // --- Increase the penalty count for the subnet because its deemed in a broken state + SubnetPenaltyCount::::mutate(subnet_id, |n: &mut u32| *n += 1); + + // If the subnet is broken, the validator can avoid slashing by submitting consensus with null data + + // --- If subnet nodes aren't in consensus this is true + // Since we can assume the subnet is in a broken state, we don't slash the validator + // even if others do not attest to this state??? + + // --- If the subnet nodes are not in agreement with the validator that the model is broken, we + // increase the penalty score for the validator + // and slash + // --- We only do this if the vast majority of nodes are not in agreement with the validator + // Otherwise we assume the issue just started or is being resolved. + // i.e. if a validator sends in no data but by the time some other nodes check, it's resolved, + // the validator only gets slashed if the vast majority of nodes disagree at ~87.5% + // Or vice versa if validator submits data in a healthy state and the subnet breaks + // + // This is an unlikely scenario because all nodes should be checking the subnets state within a few seconds + // of each other. + if attestation_percentage < min_vast_majority_attestation_percentage { + // --- Slash validator and increase penalty score + Self::slash_validator(subnet_id, validator_subnet_node_id, attestation_percentage, block); + } + + // --- If the subnet was deemed in a broken stake by the validator, rewards are bypassed + continue; + } + + // --- If the minimum required attestation not reached, assume validator is dishonest, slash, and continue + // We don't increase subnet penalty count here because this is likely the validators fault + if attestation_percentage < min_attestation_percentage { + // --- Slash validator and increase penalty score + Self::slash_validator(subnet_id, validator_subnet_node_id, attestation_percentage, block); -// // --- Attestation not successful, move on to next subnet -// continue -// } + // --- Attestation not successful, move on to next subnet + continue + } -// // --- Get sum of subnet total scores for use of divvying rewards -// let sum = submission.data.iter().fold(0, |acc, x| acc + x.score); + // --- Get sum of subnet total scores for use of divvying rewards + let sum = submission.data.iter().fold(0, |acc, x| acc + x.score); -// // --- Reward validators -// for (subnet_node_id, subnet_node) in SubnetNodesData::::iter_prefix(subnet_id) { -// let hotkey: T::AccountId = match SubnetNodeIdHotkey::::try_get(subnet_id, subnet_node_id) { -// Ok(hotkey) => hotkey, -// Err(()) => continue, -// }; + // --- Reward validators + for (subnet_node_id, subnet_node) in SubnetNodesData::::iter_prefix(subnet_id) { + let hotkey: T::AccountId = match SubnetNodeIdHotkey::::try_get(subnet_id, subnet_node_id) { + Ok(hotkey) => hotkey, + Err(()) => continue, + }; -// // --- (if) Check if subnet node is past the max registration epochs to activate (if registered or deactivated) -// // --- (else if) Check if past Queue and can be included in validation data -// // Always continue if any of these are true -// // Note: Only ``included`` or above nodes can get emissions -// if subnet_node.classification.class <= SubnetNodeClass::Registered { -// if epoch as u64 > subnet_node.classification.start_epoch.saturating_add(max_subnet_node_registration_epochs) { -// Self::perform_remove_subnet_node(block, subnet_id, subnet_node_id); -// } -// continue -// } else if subnet_node.classification.class == SubnetNodeClass::Queue { -// // If not, upgrade classification and continue -// // --- Upgrade to included -// SubnetNodesData::::mutate( -// subnet_id, -// subnet_node_id, -// |params: &mut SubnetNode| { -// params.classification = SubnetNodeClassification { -// class: SubnetNodeClass::Included, -// start_epoch: (epoch) as u64, -// }; -// }, -// ); -// continue -// } - -// // --- At this point, all nodes should be included in consensus data - -// let peer_id: PeerId = subnet_node.peer_id; - -// let mut subnet_node_data: SubnetNodeData = SubnetNodeData::default(); - -// // --- Confirm if ``peer_id`` is present in validator data -// let subnet_node_data_find: Option<(usize, &SubnetNodeData)> = submission.data.iter().enumerate().find( -// |&x| x.1.peer_id == peer_id -// ); + // --- (if) Check if subnet node is past the max registration epochs to activate (if registered or deactivated) + // --- (else if) Check if past Idle and can be included in validation data + // Always continue if any of these are true + // Note: Only ``included`` or above nodes can get emissions + if subnet_node.classification.class <= SubnetNodeClass::Registered { + if epoch as u64 > subnet_node.classification.start_epoch.saturating_add(subnet_node_registration_epochs) { + Self::perform_remove_subnet_node(block, subnet_id, subnet_node_id); + } + continue + } else if subnet_node.classification.class == SubnetNodeClass::Idle { + // If not, upgrade classification and continue + // --- Upgrade to included + SubnetNodesData::::mutate( + subnet_id, + subnet_node_id, + |params: &mut SubnetNode| { + params.classification = SubnetNodeClassification { + class: SubnetNodeClass::Included, + start_epoch: (epoch) as u64, + }; + }, + ); + continue + } + + // --- At this point, all nodes should be included in consensus data + + let peer_id: PeerId = subnet_node.peer_id; + + let mut subnet_node_data: SubnetNodeData = SubnetNodeData::default(); + + // --- Confirm if ``peer_id`` is present in validator data + let subnet_node_data_find: Option<(usize, &SubnetNodeData)> = submission.data.iter().enumerate().find( + |&x| x.1.peer_id == peer_id + ); -// // --- If subnet_node_id is present in validator data -// let validated: bool = subnet_node_data_find.is_some(); - -// if validated { -// subnet_node_data = subnet_node_data_find.unwrap().1.clone(); -// submission.data.remove(subnet_node_data_find.unwrap().0); -// } - -// let penalties = SubnetNodePenalties::::get(subnet_id, subnet_node_id); - -// // --- If node not validated and consensus reached: -// // otherwise, increment penalty score only -// // remove them if max penalties threshold is reached -// if !validated { -// // --- Mutate nodes penalties count if not in consensus -// SubnetNodePenalties::::insert(subnet_id, subnet_node_id, penalties + 1); - -// // --- To be removed or increase absent count, the consensus threshold must be reached -// if attestation_percentage > node_attestation_removal_threshold { -// // We don't slash nodes for not being in consensus -// // A node can be removed for any reason and may not be due to dishonesty -// // If subnet validators want to remove and slash a node, they can use the proposals mechanism - -// // --- Ensure maximum sequential removal consensus threshold is reached -// // We make sure the super majority are in agreeance to remove someone -// // TODO: Check the size of subnet and scale it from there -// if penalties + 1 > max_subnet_node_penalties { -// // --- Increase account penalty count -// Self::perform_remove_subnet_node(block, subnet_id, subnet_node_id); -// } -// } -// // Even if there is a n-1 100% consensus on the node being out of consensus, we don't remove them. -// // In the case where a subnet wants to remove a node, they should initiate a proposal to have them removed -// // using ``propose``method -// continue -// } - -// // --- At this point, a subnet node is in the consensus data - -// // --- Check if can be included in validation data -// // By this point, node is validated, update to submittable if they have no penalties -// let is_included = subnet_node.classification.class == SubnetNodeClass::Included; -// if is_included && penalties == 0 { -// // --- Upgrade to Validator -// SubnetNodesData::::mutate( -// subnet_id, -// subnet_node_id, -// |params: &mut SubnetNode| { -// params.classification = SubnetNodeClassification { -// class: SubnetNodeClass::Validator, -// start_epoch: (epoch) as u64, // in case rewards are called late, we add them to the next epoch, 2 from the consensus data -// }; -// }, -// ); -// continue -// } else if is_included && penalties != 0 { -// // --- Decrease subnet node penalty count by one if in consensus and attested consensus -// SubnetNodePenalties::::mutate(subnet_id, subnet_node_id, |n: &mut u32| n.saturating_dec()); -// continue -// } - -// // --- At this point, the subnet node is submittable and included in consensus data - -// // -// // TODO: Test removing this ``!submission.attests.contains(&hotkey)`` to allow those that do not attest to gain rewards -// // - -// // --- If not attested, do not receive rewards -// // We only penalize accounts on vast majority attestations for not attesting data in case data is corrupted -// // It is up to subnet nodes to remove them via consensus -// // But since consensus was formed at the least, we assume they're against the consensus, therefor likely dishonest -// if !submission.attests.contains_key(&subnet_node_id) { -// if attestation_percentage > min_vast_majority_attestation_percentage { -// // --- Penalize on vast majority only -// SubnetNodePenalties::::insert(subnet_id, subnet_node_id, penalties + 1); -// } -// continue -// } - -// let score = subnet_node_data.score; - -// // The subnet node has passed the gauntlet and is about to receive rewards + // --- If subnet_node_id is present in validator data + let validated: bool = subnet_node_data_find.is_some(); + + if validated { + subnet_node_data = subnet_node_data_find.unwrap().1.clone(); + submission.data.remove(subnet_node_data_find.unwrap().0); + } + + let penalties = SubnetNodePenalties::::get(subnet_id, subnet_node_id); + + // --- If node not validated and consensus reached: + // otherwise, increment penalty score only + // remove them if max penalties threshold is reached + if !validated { + // --- Mutate nodes penalties count if not in consensus + SubnetNodePenalties::::insert(subnet_id, subnet_node_id, penalties + 1); + + // --- To be removed or increase absent count, the consensus threshold must be reached + if attestation_percentage > node_attestation_removal_threshold { + // We don't slash nodes for not being in consensus + // A node can be removed for any reason and may not be due to dishonesty + // If subnet validators want to remove and slash a node, they can use the proposals mechanism + + // --- Ensure maximum sequential removal consensus threshold is reached + // We make sure the super majority are in agreeance to remove someone + // TODO: Check the size of subnet and scale it from there + if penalties + 1 > max_subnet_node_penalties { + // --- Increase account penalty count + Self::perform_remove_subnet_node(block, subnet_id, subnet_node_id); + } + } + // Even if there is a n-1 100% consensus on the node being out of consensus, we don't remove them. + // In the case where a subnet wants to remove a node, they should initiate a proposal to have them removed + // using ``propose``method + continue + } + + // --- At this point, a subnet node is in the consensus data + + // --- Check if can be included in validation data + // By this point, node is validated, update to submittable if they have no penalties + let is_included = subnet_node.classification.class == SubnetNodeClass::Included; + if is_included && penalties == 0 { + // --- Upgrade to Validator + SubnetNodesData::::mutate( + subnet_id, + subnet_node_id, + |params: &mut SubnetNode| { + params.classification = SubnetNodeClassification { + class: SubnetNodeClass::Validator, + start_epoch: (epoch) as u64, // in case rewards are called late, we add them to the next epoch, 2 from the consensus data + }; + }, + ); + continue + } else if is_included && penalties != 0 { + // --- Decrease subnet node penalty count by one if in consensus and attested consensus + SubnetNodePenalties::::mutate(subnet_id, subnet_node_id, |n: &mut u32| n.saturating_dec()); + continue + } + + // --- At this point, the subnet node is submittable and included in consensus data + + // + // TODO: Test removing this ``!submission.attests.contains(&hotkey)`` to allow those that do not attest to gain rewards + // + + // --- If not attested, do not receive rewards + // We only penalize accounts on vast majority attestations for not attesting data in case data is corrupted + // It is up to subnet nodes to remove them via consensus + // But since consensus was formed at the least, we assume they're against the consensus, therefor likely dishonest + if !submission.attests.contains_key(&subnet_node_id) { + if attestation_percentage > min_vast_majority_attestation_percentage { + // --- Penalize on vast majority only + SubnetNodePenalties::::insert(subnet_id, subnet_node_id, penalties + 1); + } + continue + } + + let score = subnet_node_data.score; + + // The subnet node has passed the gauntlet and is about to receive rewards -// // --- Decrease subnet node penalty count by one if in consensus and attested consensus -// // Don't hit the storage unless we have to -// if penalties != 0 { -// SubnetNodePenalties::::mutate(subnet_id, subnet_node_id, |n: &mut u32| n.saturating_dec()); -// } - -// // --- Calculate score percentage of peer versus sum -// let score_percentage: u128 = Self::percent_div(subnet_node_data.score, sum as u128); -// // --- Calculate score percentage of total subnet generated epoch rewards -// let mut account_reward: u128 = Self::percent_mul(score_percentage, subnet_node_reward); - -// // --- Increase reward if validator -// if subnet_node_id == validator_subnet_node_id { -// account_reward += Self::get_validator_reward(attestation_percentage); -// } - -// // --- Skip if no rewards to give -// // Unlikely to happen -// if account_reward == 0 { -// continue -// } - -// let mut node_delegate_reward = 0; -// if subnet_node.delegate_reward_rate != 0 { -// let total_node_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(subnet_id, subnet_node_id); -// if total_node_delegated_stake_shares != 0 { -// node_delegate_reward = Self::percent_mul(account_reward, subnet_node.delegate_reward_rate); -// account_reward = account_reward - node_delegate_reward; -// Self::do_increase_node_delegate_stake( -// subnet_id, -// subnet_node_id, -// node_delegate_reward, -// ); -// } -// } - -// // --- Increase account stake and emit event -// Self::increase_account_stake( -// &hotkey, -// subnet_id, -// account_reward, -// ); -// } - -// // --- Portion of rewards to delegate stakers -// Self::do_increase_delegate_stake( -// subnet_id, -// delegate_stake_reward, -// ); - -// // --- Increment down subnet penalty score on successful epochs -// SubnetPenaltyCount::::mutate(subnet_id, |n: &mut u32| n.saturating_dec()); -// } else if let Ok(validator_id) = SubnetRewardsValidator::::try_get(subnet_id, epoch) { -// // --- If a validator has been chosen that means they are supposed to be submitting consensus data -// // --- If there is no submission but validator chosen, increase penalty on subnet and validator -// // --- Increase the penalty count for the subnet -// // The next validator on the next epoch can increment the penalty score down -// SubnetPenaltyCount::::mutate(subnet_id, |n: &mut u32| *n += 1); - -// // NOTE: -// // Each subnet increases the penalty score if they don't have the minimum subnet nodes required by the time -// // the subnet is enabled for emissions. This happens by the blockchain validator before choosing the subnet validator - -// // If validator didn't submit anything, then slash -// // Even if a subnet is in a broken state, the chosen validator must submit blank data -// Self::slash_validator(subnet_id, validator_id, 0, block); -// } - -// // TODO: Automatically remove subnet if greater than max penalties count -// // TODO: Get benchmark for removing max subnets in one epoch to ensure does not surpass max weights - -// Self::deposit_event( -// Event::RewardResult { -// subnet_id: subnet_id, -// attestation_percentage: attestation_percentage, -// } -// ); + // --- Decrease subnet node penalty count by one if in consensus and attested consensus + // Don't hit the storage unless we have to + if penalties != 0 { + SubnetNodePenalties::::mutate(subnet_id, subnet_node_id, |n: &mut u32| n.saturating_dec()); + } + + // --- Calculate score percentage of peer versus sum + let score_percentage: u128 = Self::percent_div(subnet_node_data.score, sum as u128); + // --- Calculate score percentage of total subnet generated epoch rewards + let mut account_reward: u128 = Self::percent_mul(score_percentage, subnet_reward); + + // --- Increase reward if validator + if subnet_node_id == validator_subnet_node_id { + account_reward += Self::get_validator_reward(attestation_percentage); + } + + // --- Skip if no rewards to give + // Unlikely to happen + if account_reward == 0 { + continue + } + + let mut node_delegate_reward = 0; + if subnet_node.delegate_reward_rate != 0 { + let total_node_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(subnet_id, subnet_node_id); + if total_node_delegated_stake_shares != 0 { + node_delegate_reward = Self::percent_mul(account_reward, subnet_node.delegate_reward_rate); + account_reward = account_reward - node_delegate_reward; + Self::do_increase_node_delegate_stake( + subnet_id, + subnet_node_id, + node_delegate_reward, + ); + } + } + + // --- Increase account stake and emit event + Self::increase_account_stake( + &hotkey, + subnet_id, + account_reward, + ); + } + + // --- Portion of rewards to delegate stakers + Self::do_increase_delegate_stake( + subnet_id, + delegate_stake_reward, + ); + + // --- Increment down subnet penalty score on successful epochs + SubnetPenaltyCount::::mutate(subnet_id, |n: &mut u32| n.saturating_dec()); + } else if let Ok(validator_id) = SubnetRewardsValidator::::try_get(subnet_id, epoch) { + // --- If a validator has been chosen that means they are supposed to be submitting consensus data + // --- If there is no submission but validator chosen, increase penalty on subnet and validator + // --- Increase the penalty count for the subnet + // The next validator on the next epoch can increment the penalty score down + SubnetPenaltyCount::::mutate(subnet_id, |n: &mut u32| *n += 1); + + // NOTE: + // Each subnet increases the penalty score if they don't have the minimum subnet nodes required by the time + // the subnet is enabled for emissions. This happens by the blockchain validator before choosing the subnet validator + + // If validator didn't submit anything, then slash + // Even if a subnet is in a broken state, the chosen validator must submit blank data + Self::slash_validator(subnet_id, validator_id, 0, block); + } + + // TODO: Automatically remove subnet if greater than max penalties count + // TODO: Get benchmark for removing max subnets in one epoch to ensure does not surpass max weights + + Self::deposit_event( + Event::RewardResult { + subnet_id: subnet_id, + attestation_percentage: attestation_percentage, + } + ); -// // --- If subnet is past its max penalty count, remove -// let subnet_penalty_count = SubnetPenaltyCount::::get(subnet_id); -// if subnet_penalty_count > max_subnet_penalty_count { -// Self::do_remove_subnet( -// data.path, -// SubnetRemovalReason::MaxPenalties, -// ); -// } -// } - -// Ok(None.into()) -// } -// } \ No newline at end of file + // --- If subnet is past its max penalty count, remove + let subnet_penalty_count = SubnetPenaltyCount::::get(subnet_id); + if subnet_penalty_count > max_subnet_penalty_count { + Self::deactivate_subnet( + data.path, + SubnetRemovalReason::MaxPenalties, + ); + } + } + + Ok(None.into()) + } +} \ No newline at end of file diff --git a/pallets/network/src/rewards_v2.rs b/pallets/network/src/rewards_v2.rs deleted file mode 100644 index e09c1f9..0000000 --- a/pallets/network/src/rewards_v2.rs +++ /dev/null @@ -1,736 +0,0 @@ -// Copyright (C) Hypertensor. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::*; -use sp_runtime::Saturating; -use frame_support::pallet_prelude::DispatchResultWithPostInfo; -use frame_support::pallet_prelude::Pays; -use libm::sqrt; - -impl Pallet { - pub fn reward_subnets(block: u32, epoch: u32) -> DispatchResultWithPostInfo { - // --- Get required attestation percentage - let min_attestation_percentage = MinAttestationPercentage::::get(); - let min_vast_majority_attestation_percentage = MinVastMajorityAttestationPercentage::::get(); - // --- Get max epochs in a row a subnet node can be absent from consensus data - // --- Get the max penalties a subnet node can have before being removed from the network - let max_subnet_penalty_count = MaxSubnetPenaltyCount::::get(); - // --- Get the attestation percentage for a subnet node to be removed from the network - // if they are not included in the validators consensus data - // --- If this attestation threshold is exceeded, the subnet node that is absent will have its - // SubnetNodePenalties incrememented - let node_attestation_removal_threshold = NodeAttestationRemovalThreshold::::get(); - // --- Get the percentage of the subnet rewards that go to subnet delegate stakers - let delegate_stake_rewards_percentage: u128 = DelegateStakeRewardsPercentage::::get(); - - // let max_subnet_node_registration_epochs = SubnetNodeRegistrationEpochs::::get(); - let subnet_owner_percentage = SubnetOwnerPercentage::::get(); - - let total_delegate_stake = TotalDelegateStake::::get(); - let min_subnet_nodes = MinSubnetNodes::::get(); - - // --- Get total rewards for this epoch - let rewards: u128 = Self::get_epoch_emissions(epoch); - - for (subnet_id, data) in SubnetsData::::iter() { - let mut attestation_percentage: u128 = 0; - - // --- We don't check for minimum nodes because nodes cannot validate or attest if they are not met - // as they the validator will not be chosen in ``do_epoch_preliminaries`` if the - // min nodes are not met on that epoch. - if let Ok(mut submission) = SubnetRewardsSubmission::::try_get(subnet_id, epoch) { - // --- Get total subnet delegate stake balance - let total_subnet_delegate_stake = TotalSubnetDelegateStakeBalance::::get(subnet_id); - - // --- Get subnet delegate stake weight - let subnet_delegate_stake_weight = Self::percent_div(total_subnet_delegate_stake, total_delegate_stake); - - // --- Get overall subnet rewards - let overall_subnet_reward: u128 = Self::percent_mul(rewards, subnet_delegate_stake_weight); - - // --- Get owner rewards - let subnet_owner_reward: u128 = Self::percent_mul(overall_subnet_reward, subnet_owner_percentage); - - // --- Get subnet rewards minus owner cut - let subnet_reward: u128 = overall_subnet_reward.saturating_sub(subnet_owner_reward); - - // --- Get delegators rewards - let delegate_stake_reward: u128 = Self::percent_mul(subnet_reward, delegate_stake_rewards_percentage); - - // --- Get subnet nodes rewards - let subnet_node_reward: u128 = subnet_reward.saturating_sub(delegate_stake_reward); - - // --- Redundant - if subnet_node_reward == 0 { - continue - } - - // --- Get subnet nodes count to check against attestation count - // while in this function that should have in the epoch the rewards are destined for - let subnet_nodes: Vec = Self::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Validator, epoch); - let subnet_node_count = subnet_nodes.len() as u128; - - // --- Ensure nodes are at min requirement to continue rewards operations - if subnet_node_count < min_subnet_nodes as u128 { - // We don't give penalties here because they will be given in the next step operation when selecting a new - // validator - continue - } - - let attestations: u128 = submission.attests.len() as u128; - attestation_percentage = Self::percent_div(attestations, subnet_node_count); - - // Redundant - // When subnet nodes exit, the consensus data is updated to remove them from it - if attestation_percentage > Self::PERCENTAGE_FACTOR { - attestation_percentage = Self::PERCENTAGE_FACTOR; - } - - let validator_subnet_node_id: u32 = submission.validator_id; - - let data_len = submission.data.len(); - - // --- If validator submitted no data, or less than the minimum required subnet nodes - // we assume the subnet is broken - // There is no slashing if subnet is broken, only risk of subnet being removed - // The subnet is deemed broken is there is no consensus or not enough nodes - // - // The subnet has up to the MaxSubnetPenaltyCount to solve the issue before the subnet and all subnet nodes are removed - if (data_len as u32) < min_subnet_nodes { - // --- Increase the penalty count for the subnet because its deemed in a broken state - SubnetPenaltyCount::::mutate(subnet_id, |n: &mut u32| *n += 1); - - // If the subnet is broken, the validator can avoid slashing by submitting consensus with null data - - // --- If subnet nodes aren't in consensus this is true - // Since we can assume the subnet is in a broken state, we don't slash the validator - // even if others do not attest to this state??? - - // --- If the subnet nodes are not in agreement with the validator that the model is broken, we - // increase the penalty score for the validator - // and slash - // --- We only do this if the vast majority of nodes are not in agreement with the validator - // Otherwise we assume the issue just started or is being resolved. - // i.e. if a validator sends in no data but by the time some other nodes check, it's resolved, - // the validator only gets slashed if the vast majority of nodes disagree at ~87.5% - // Or vice versa if validator submits data in a healthy state and the subnet breaks - // - // This is an unlikely scenario because all nodes should be checking the subnets state within a few seconds - // of each other. - if attestation_percentage < min_vast_majority_attestation_percentage { - // --- Slash validator and increase penalty score - Self::slash_validator(subnet_id, validator_subnet_node_id, attestation_percentage, block); - } - - // --- If the subnet was deemed in a broken stake by the validator, rewards are bypassed - continue; - } - - // --- If the minimum required attestation not reached, assume validator is dishonest, slash, and continue - // We don't increase subnet penalty count here because this is likely the validators fault - if attestation_percentage < min_attestation_percentage { - // --- Slash validator and increase penalty score - Self::slash_validator(subnet_id, validator_subnet_node_id, attestation_percentage, block); - - // --- Attestation not successful, move on to next subnet - continue - } - - // --- Deposit owners rewards - match SubnetOwner::::try_get(subnet_id) { - Ok(coldkey) => { - let subnet_owner_reward_as_currency = Self::u128_to_balance(subnet_owner_reward); - if subnet_owner_reward_as_currency.is_some() { - Self::add_balance_to_coldkey_account( - &coldkey, - subnet_owner_reward_as_currency.unwrap() - ); - } - }, - Err(()) => (), - }; - - // --- Get sum of subnet total scores for use of divvying rewards - let sum = submission.data.iter().fold(0, |acc, x| acc + x.score); - - let max_subnet_node_registration_epochs = SubnetNodeRegistrationEpochs::::get(subnet_id); - let max_subnet_node_penalties = MaxSubnetNodePenalties::::get(subnet_id); - - // --- Reward validators - for (subnet_node_id, subnet_node) in SubnetNodesData::::iter_prefix(subnet_id) { - let hotkey: T::AccountId = match SubnetNodeIdHotkey::::try_get(subnet_id, subnet_node_id) { - Ok(hotkey) => hotkey, - Err(()) => continue, - }; - - // --- (if) Check if subnet node is past the max registration epochs to activate (if registered or deactivated) - // --- (else if) Check if past Queue and can be included in validation data - // Always continue if any of these are true - // Note: Only ``included`` or above nodes can get emissions - if subnet_node.classification.class <= SubnetNodeClass::Registered { - if epoch > subnet_node.classification.start_epoch.saturating_add(max_subnet_node_registration_epochs) { - Self::perform_remove_subnet_node(block, subnet_id, subnet_node_id); - } - continue - } else if subnet_node.classification.class == SubnetNodeClass::Queue { - // If not, upgrade classification and continue - // --- Upgrade to included - Self::increase_class( - subnet_id, - subnet_node_id, - epoch, - ); - continue - } - - // --- At this point, all nodes should be included in consensus data - - let peer_id: PeerId = subnet_node.peer_id; - - let mut subnet_node_data: SubnetNodeData = SubnetNodeData::default(); - - // --- Confirm if ``peer_id`` is present in validator data - let subnet_node_data_find: Option<(usize, &SubnetNodeData)> = submission.data.iter().enumerate().find( - |&x| x.1.peer_id == peer_id - ); - - // --- If subnet_node_id is present in validator data - let validated: bool = subnet_node_data_find.is_some(); - - if validated { - subnet_node_data = subnet_node_data_find.unwrap().1.clone(); - submission.data.remove(subnet_node_data_find.unwrap().0); - } - - let penalties = SubnetNodePenalties::::get(subnet_id, subnet_node_id); - - // --- If node not validated and consensus reached: - // otherwise, increment penalty score only - // remove them if max penalties threshold is reached - if !validated { - // --- Mutate nodes penalties count if not in consensus - SubnetNodePenalties::::insert(subnet_id, subnet_node_id, penalties + 1); - - // --- To be removed or increase absent count, the consensus threshold must be reached - if attestation_percentage > node_attestation_removal_threshold { - // We don't slash nodes for not being in consensus - // A node can be removed for any reason and may not be due to dishonesty - // If subnet validators want to remove and slash a node, they can use the proposals mechanism - - // --- Ensure maximum sequential removal consensus threshold is reached - // We make sure the super majority are in agreeance to remove someone - // TODO: Check the size of subnet and scale it from there - if penalties + 1 > max_subnet_node_penalties { - // --- Increase account penalty count - Self::perform_remove_subnet_node(block, subnet_id, subnet_node_id); - } - } - // Even if there is a n-1 100% consensus on the node being out of consensus, we don't remove them. - // In the case where a subnet wants to remove a node, they should initiate a proposal to have them removed - // using ``propose``method - continue - } - - // --- At this point, a subnet node is in the consensus data - - // --- Check if can be included in validation data - // By this point, node is validated, update to submittable if they have no penalties - let is_included = subnet_node.classification.class == SubnetNodeClass::Included; - if is_included && penalties == 0 { - // --- Upgrade to Validator - Self::increase_class( - subnet_id, - subnet_node_id, - epoch, - ); - continue - } else if is_included && penalties != 0 { - // --- Decrease subnet node penalty count by one if in consensus and attested consensus - SubnetNodePenalties::::mutate(subnet_id, subnet_node_id, |n: &mut u32| n.saturating_dec()); - continue - } - - // --- At this point, the subnet node is submittable and included in consensus data - - // - // TODO: Test removing this ``!submission.attests.contains(&hotkey)`` to allow those that do not attest to gain rewards - // - - // --- If not attested, do not receive rewards - // We only penalize accounts on vast majority attestations for not attesting data in case data is corrupted - // It is up to subnet nodes to remove them via consensus - // But since consensus was formed at the least, we assume they're against the consensus, therefor likely dishonest - if !submission.attests.contains_key(&subnet_node_id) { - if attestation_percentage > min_vast_majority_attestation_percentage { - // --- Penalize on vast majority only - SubnetNodePenalties::::insert(subnet_id, subnet_node_id, penalties + 1); - } - continue - } - - let score = subnet_node_data.score; - - // The subnet node has passed the gauntlet and is about to receive rewards - - // --- Decrease subnet node penalty count by one if in consensus and attested consensus - // Don't hit the storage unless we have to - if penalties != 0 { - SubnetNodePenalties::::mutate(subnet_id, subnet_node_id, |n: &mut u32| n.saturating_dec()); - } - - // --- Calculate score percentage of peer versus sum - let score_percentage: u128 = Self::percent_div(subnet_node_data.score, sum as u128); - // --- Calculate score percentage of total subnet generated epoch rewards - let mut account_reward: u128 = Self::percent_mul(score_percentage, subnet_node_reward); - - // --- Increase reward if validator - if subnet_node_id == validator_subnet_node_id { - account_reward += Self::get_validator_reward(attestation_percentage); - } - - // --- Skip if no rewards to give - // Unlikely to happen - if account_reward == 0 { - continue - } - - let mut node_delegate_reward = 0; - if subnet_node.delegate_reward_rate != 0 { - let total_node_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(subnet_id, subnet_node_id); - if total_node_delegated_stake_shares != 0 { - node_delegate_reward = Self::percent_mul(account_reward, subnet_node.delegate_reward_rate); - account_reward = account_reward - node_delegate_reward; - Self::do_increase_node_delegate_stake( - subnet_id, - subnet_node_id, - node_delegate_reward, - ); - } - } - - // --- Increase account stake and emit event - Self::increase_account_stake( - &hotkey, - subnet_id, - account_reward, - ); - } - - // --- Portion of rewards to delegate stakers - Self::do_increase_delegate_stake( - subnet_id, - delegate_stake_reward, - ); - - // --- Increment down subnet penalty score on successful epochs - SubnetPenaltyCount::::mutate(subnet_id, |n: &mut u32| n.saturating_dec()); - } else if let Ok(validator_id) = SubnetRewardsValidator::::try_get(subnet_id, epoch) { - // --- If a validator has been chosen that means they are supposed to be submitting consensus data - // --- If there is no submission but validator chosen, increase penalty on subnet and validator - // --- Increase the penalty count for the subnet - // The next validator on the next epoch can increment the penalty score down - SubnetPenaltyCount::::mutate(subnet_id, |n: &mut u32| *n += 1); - - // NOTE: - // Each subnet increases the penalty score if they don't have the minimum subnet nodes required by the time - // the subnet is enabled for emissions. This happens by the blockchain validator before choosing the subnet validator - - // If validator didn't submit anything, then slash - // Even if a subnet is in a broken state, the chosen validator must submit blank data - Self::slash_validator(subnet_id, validator_id, 0, block); - } - - // TODO: Get benchmark for removing max subnets in one epoch to ensure does not surpass max weights - - Self::deposit_event( - Event::RewardResult { - subnet_id: subnet_id, - attestation_percentage: attestation_percentage, - } - ); - - // --- If subnet is past its max penalty count, remove - let subnet_penalty_count = SubnetPenaltyCount::::get(subnet_id); - if subnet_penalty_count > max_subnet_penalty_count { - Self::do_remove_subnet( - data.path, - SubnetRemovalReason::MaxPenalties, - ); - } - } - - Ok(None.into()) - } - - pub fn reward_subnets_v2(block: u32, epoch: u32) -> DispatchResultWithPostInfo { - // --- Get total rewards for this epoch - let rewards: u128 = Self::get_epoch_emissions(epoch); - log::error!("v2 rewards {:?}", rewards); - - let subnets: Vec<_> = SubnetsData::::iter() - .filter(|(_, subnet)| subnet.state == SubnetState::Active) - .collect(); - - let total_subnets: u32 = subnets.len() as u32; - let total_delegate_stake = TotalDelegateStake::::get(); - - let mut stake_weights: BTreeMap<&u32, f64> = BTreeMap::new(); - let mut stake_weight_sum: f64 = 0.0; - - for (subnet_id, _) in &subnets { - let total_subnet_delegate_stake = TotalSubnetDelegateStakeBalance::::get(subnet_id); - // 1. Get all weights in f64 - // *We later use sqrt that uses floats - - let weight: f64 = total_subnet_delegate_stake as f64 / total_delegate_stake as f64; - let weight_sqrt: f64 = sqrt(weight); - - stake_weights.insert(subnet_id, weight_sqrt); - stake_weight_sum += weight_sqrt; - } - - let mut stake_weights_normalized: BTreeMap<&u32, u128> = BTreeMap::new(); - - // --- Normalize delegate stake weights from `sqrt` - for (subnet_id, weight) in stake_weights { - let weight_normalized: u128 = (weight / stake_weight_sum * Self::PERCENTAGE_FACTOR as f64) as u128; - stake_weights_normalized.insert(subnet_id, weight_normalized); - } - - let subnet_owner_percentage = SubnetOwnerPercentage::::get(); - let delegate_stake_rewards_percentage: u128 = DelegateStakeRewardsPercentage::::get(); - let min_attestation_percentage = MinAttestationPercentage::::get(); - let min_vast_majority_attestation_percentage = MinVastMajorityAttestationPercentage::::get(); - let min_subnet_nodes = MinSubnetNodes::::get(); - let node_attestation_removal_threshold = NodeAttestationRemovalThreshold::::get(); - let max_subnet_penalty_count = MaxSubnetPenaltyCount::::get(); - - for (subnet_id, data) in &subnets { - let mut attestation_percentage: u128 = 0; - - // --- Get subnet validator submission - // --- - Run rewards logic - // --- Otherwise, check if validator exists since they didn't submit incentives consensus - // --- - Penalize and slash validator if existed - if let Ok(mut submission) = SubnetRewardsSubmission::::try_get(subnet_id, epoch) { - // --- Get overall subnet rewards - let weight: u128 = match stake_weights_normalized.get(&subnet_id) { - Some(weight) => { - if weight == &0 { - continue - } - *weight - }, - None => continue, - }; - log::error!("v2 weight {:?}", weight); - - let overall_subnet_reward: u128 = Self::percent_mul(rewards, weight); - log::error!("v2 overall_subnet_reward {:?}", overall_subnet_reward); - - // --- Get owner rewards - let subnet_owner_reward: u128 = Self::percent_mul(overall_subnet_reward, subnet_owner_percentage); - log::error!("v2 subnet_owner_reward {:?}", subnet_owner_reward); - - // --- Get subnet rewards minus owner cut - let subnet_reward: u128 = overall_subnet_reward.saturating_sub(subnet_owner_reward); - log::error!("v2 subnet_reward {:?}", subnet_reward); - - // --- Get delegators rewards - let delegate_stake_reward: u128 = Self::percent_mul(subnet_reward, delegate_stake_rewards_percentage); - log::error!("v2 delegate_stake_reward {:?}", delegate_stake_reward); - - // --- Get subnet nodes rewards total - let subnet_node_reward: u128 = subnet_reward.saturating_sub(delegate_stake_reward); - log::error!("v2 subnet_node_reward {:?}", subnet_node_reward); - - // --- Get subnet nodes count to check against attestation count and make sure min nodes are present during time of rewards - let subnet_nodes: Vec = Self::get_classified_hotkeys(*subnet_id, &SubnetNodeClass::Validator, epoch); - let subnet_node_count = subnet_nodes.len() as u128; - - // --- Ensure nodes are at min requirement to continue rewards operations - if subnet_node_count < min_subnet_nodes as u128 { - // We don't give penalties here because they will be given in the next step operation when selecting a new - // validator - continue - } - - let attestations: u128 = submission.attests.len() as u128; - attestation_percentage = Self::percent_div(attestations, subnet_node_count); - - // Redundant - // When subnet nodes exit, the consensus data is updated to remove them from it - if attestation_percentage > Self::PERCENTAGE_FACTOR { - attestation_percentage = Self::PERCENTAGE_FACTOR; - } - - let validator_subnet_node_id: u32 = submission.validator_id; - - let data_len = submission.data.len(); - log::error!("data_len {:?}", data_len); - - /* - - Ensures the subnet has enough nodes. - * If validator submits under the minimum nodes we assume the subnet is in an unusable state - - If the subnet agrees in the validators logic we don't skip rewards - * This is to not incentivize subnets from falsely attesting any epochs that have under the required nodes. - - Slashes the validator if attestation is below the required minimum. - */ - // If the number of data points (data_len) is less than the required minimum subnet nodes - if (data_len as u32) < min_subnet_nodes { - // --- Subnet no longer submitting consensus - // Increase the penalty count - SubnetPenaltyCount::::mutate(subnet_id, |n: &mut u32| *n += 1); - - // Check if the attestation percentage is below the "vast majority" threshold - if attestation_percentage < min_vast_majority_attestation_percentage { - // If the attestation percentage is also below the minimum required threshold, slash the validator - if attestation_percentage < min_attestation_percentage { - Self::slash_validator(*subnet_id, validator_subnet_node_id, attestation_percentage, block); - } - // Skip further execution and continue to the next iteration - continue; - } - // Subnet agrees with validators submission, continue unless results are None - if data_len == 0 { - continue - } - } - - // --- If the minimum required attestation not reached, assume validator is dishonest, slash, and continue - // We don't increase subnet penalty count here because this is likely the validators fault - if attestation_percentage < min_attestation_percentage { - // --- Slash validator and increase penalty score - Self::slash_validator(*subnet_id, validator_subnet_node_id, attestation_percentage, block); - - // --- Attestation not successful, move on to next subnet - continue - } - - // --- Deposit owners rewards - match SubnetOwner::::try_get(subnet_id) { - Ok(coldkey) => { - let subnet_owner_reward_as_currency = Self::u128_to_balance(subnet_owner_reward); - if subnet_owner_reward_as_currency.is_some() { - Self::add_balance_to_coldkey_account( - &coldkey, - subnet_owner_reward_as_currency.unwrap() - ); - } - }, - Err(()) => (), - }; - - // --- Get sum of subnet total scores for use of divvying rewards - let sum = submission.data.iter().fold(0, |acc, x| acc.saturating_add(x.score)); - - let max_subnet_node_registration_epochs = SubnetNodeRegistrationEpochs::::get(subnet_id); - let max_subnet_node_penalties = MaxSubnetNodePenalties::::get(subnet_id); - - for (subnet_node_id, subnet_node) in SubnetNodesData::::iter_prefix(subnet_id) { - let hotkey: T::AccountId = match SubnetNodeIdHotkey::::try_get(subnet_id, subnet_node_id) { - Ok(hotkey) => hotkey, - Err(()) => continue, - }; - - // --- (if) Check if subnet node is past the max registration epochs to activate (if registered or deactivated) - // --- (else if) Check if past Queue and can be included in validation data - // - // Note: Only ``included`` or above nodes can get emissions - if subnet_node.classification.class <= SubnetNodeClass::Registered { - if epoch > subnet_node.classification.start_epoch.saturating_add(max_subnet_node_registration_epochs) { - Self::perform_remove_subnet_node(block, *subnet_id, subnet_node_id); - } - continue - } else if subnet_node.classification.class == SubnetNodeClass::Queue { - // --- Automatically upgrade to Inclusion if activated into Queue class - Self::increase_class(*subnet_id, subnet_node_id, epoch); - continue - } - - // --- At this point, all nodes can be included in consensus data and receive rewards - - let peer_id: PeerId = subnet_node.peer_id; - - let subnet_node_data_find = submission.data - .iter() - .find(|data| data.peer_id == peer_id); - - let penalties = SubnetNodePenalties::::get(subnet_id, subnet_node_id); - - if subnet_node_data_find.is_none() { - // --- Mutate nodes penalties count if not in consensus - SubnetNodePenalties::::insert(subnet_id, subnet_node_id, penalties + 1); - - // --- To be removed or increase penalty count, the consensus threshold must be reached - if attestation_percentage > node_attestation_removal_threshold { - // We don't slash nodes for not being in consensus - // A node can be removed for any reason such as shutting their node down and may not be due to dishonesty - // If subnet validators want to remove and slash a node, they can use the proposals mechanism - - // --- Ensure maximum sequential removal consensus threshold is reached - // We make sure the super majority are in agreeance to remove someone - // TODO: Check the size of subnet and scale it from there - if penalties + 1 > max_subnet_node_penalties { - // --- Increase account penalty count - Self::perform_remove_subnet_node(block, *subnet_id, subnet_node_id); - } - } - - continue - } - - // --- At this point, the subnet node is in the consensus data - - // --- Check if can be included in validation data - // By this point, node is validated, update to submittable if they have no penalties - let is_included = subnet_node.classification.class == SubnetNodeClass::Included; - if is_included && penalties == 0 { - // --- Upgrade to Validator - Self::increase_class(*subnet_id, subnet_node_id, epoch); - continue - } else if is_included && penalties != 0 { - // --- Decrease subnet node penalty count by one if in consensus and attested consensus - SubnetNodePenalties::::mutate(subnet_id, subnet_node_id, |n: &mut u32| n.saturating_dec()); - continue - } - - // --- At this point, the subnet node is submittable and included in consensus data - - // --- If subnet node does not attest a super majority attested era, we penalize and skip them - if !submission.attests.contains_key(&subnet_node_id) { - if attestation_percentage > min_vast_majority_attestation_percentage { - // --- Penalize on vast majority only - SubnetNodePenalties::::insert(subnet_id, subnet_node_id, penalties + 1); - continue - } - } - - let subnet_node_data: SubnetNodeData = subnet_node_data_find.unwrap().clone(); - - let score = subnet_node_data.score; - - // --- Validators are allowed to submit scores of 0 - // This is useful if a subnet wants to keep a node around but not give them rewards - // This can be used in scenarios when the max subnet nodes are reached and they don't - // want to kick them out as a way to have a waitlist. - if score == 0 { - continue - } - - // --- Decrease subnet node penalty count by one if in consensus and attested consensus - // Don't hit the db unless we have to - if penalties != 0 { - SubnetNodePenalties::::mutate(subnet_id, subnet_node_id, |n: &mut u32| n.saturating_dec()); - } - - // --- Calculate score percentage of peer versus sum - let score_percentage: u128 = Self::percent_div(subnet_node_data.score, sum as u128); - log::error!("v2 score_percentage: {:?}", score_percentage); - - // --- Calculate score percentage of total subnet generated epoch rewards - let mut account_reward: u128 = Self::percent_mul(score_percentage, subnet_node_reward); - log::error!("v2 account_reward: {:?}", account_reward); - log::error!("v2 subnet_node_reward: {:?}", subnet_node_reward); - - // --- Skip if no rewards to give - // Unlikely to happen - if account_reward == 0 { - continue - } - - if subnet_node.delegate_reward_rate != 0 { - // --- Ensure users are staked to subnet node - let total_node_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(subnet_id, subnet_node_id); - if total_node_delegated_stake_shares != 0 { - log::error!("v2 subnet_node.delegate_reward_rate: {:?}", subnet_node.delegate_reward_rate); - - let node_delegate_reward = Self::percent_mul(account_reward, subnet_node.delegate_reward_rate); - log::error!("v2 node_delegate_reward: {:?}", node_delegate_reward); - log::error!("v2 b4 account_reward: {:?}", account_reward); - - account_reward = account_reward - node_delegate_reward; - log::error!("v2 a4 account_reward: {:?}", account_reward); - - Self::do_increase_node_delegate_stake( - *subnet_id, - subnet_node_id, - node_delegate_reward, - ); - } - } - - // --- Increase reward if validator - if subnet_node_id == validator_subnet_node_id { - log::error!("attestation_percentage: {:?}", attestation_percentage); - - account_reward += Self::get_validator_reward(attestation_percentage); - log::error!("validator reward here: {:?}", account_reward); - } - - // --- Increase account stake and emit event - Self::increase_account_stake( - &hotkey, - *subnet_id, - account_reward, - ); - } - // --- Portion of rewards to delegate stakers - Self::do_increase_delegate_stake( - *subnet_id, - delegate_stake_reward, - ); - - // --- Increment down subnet penalty score on successful epochs if result were greater than or equal to the min required nodes - if data_len as u32 >= min_subnet_nodes { - SubnetPenaltyCount::::mutate(subnet_id, |n: &mut u32| n.saturating_dec()); - } - } else if let Ok(validator_id) = SubnetRewardsValidator::::try_get(subnet_id, epoch) { - // --- If a validator has been chosen that means they are supposed to be submitting consensus data - // --- If there is no submission but validator chosen, increase penalty on subnet and validator - // --- Increase the penalty count for the subnet - // The next validator on the next epoch can increment the penalty score down - SubnetPenaltyCount::::mutate(subnet_id, |n: &mut u32| *n += 1); - - // NOTE: - // Each subnet increases the penalty score if they don't have the minimum subnet nodes required by the time - // the subnet is enabled for emissions. This happens by the blockchain validator before choosing the subnet validator - - // If validator didn't submit anything, then slash - // Even if a subnet is in a broken state, the chosen validator must submit blank data - Self::slash_validator(*subnet_id, validator_id, 0, block); - } - // TODO: Get benchmark for removing max subnets in one epoch to ensure does not surpass max weights - - Self::deposit_event( - Event::RewardResult { - subnet_id: *subnet_id, - attestation_percentage: attestation_percentage, - } - ); - - // --- If subnet is past its max penalty count, remove - let subnet_penalty_count = SubnetPenaltyCount::::get(subnet_id); - if subnet_penalty_count > max_subnet_penalty_count { - Self::do_remove_subnet( - data.path.clone(), - SubnetRemovalReason::MaxPenalties, - ); - } - } - - Ok(None.into()) - } -} \ No newline at end of file diff --git a/pallets/network/src/rpc_info/info.rs b/pallets/network/src/rpc_info/info.rs index cbb1cc8..b3b3a06 100644 --- a/pallets/network/src/rpc_info/info.rs +++ b/pallets/network/src/rpc_info/info.rs @@ -22,8 +22,10 @@ impl Pallet { if !SubnetsData::::contains_key(subnet_id) { return Vec::new(); } - let epoch: u32 = Self::get_current_epoch_as_u32(); - Self::get_classified_subnet_nodes(subnet_id, &SubnetNodeClass::Queue, epoch) + let block: u64 = Self::get_current_block_as_u64(); + let epoch_length: u64 = T::EpochLength::get(); + let epoch: u64 = block / epoch_length; + Self::get_classified_subnet_nodes(subnet_id, &SubnetNodeClass::Idle, epoch) } pub fn get_subnet_nodes_included( @@ -32,7 +34,9 @@ impl Pallet { if !SubnetsData::::contains_key(subnet_id) { return Vec::new(); } - let epoch: u32 = Self::get_current_epoch_as_u32(); + let block: u64 = Self::get_current_block_as_u64(); + let epoch_length: u64 = T::EpochLength::get(); + let epoch: u64 = block / epoch_length; Self::get_classified_subnet_nodes(subnet_id, &SubnetNodeClass::Included, epoch) } @@ -42,7 +46,9 @@ impl Pallet { if !SubnetsData::::contains_key(subnet_id) { return Vec::new(); } - let epoch: u32 = Self::get_current_epoch_as_u32(); + let block: u64 = Self::get_current_block_as_u64(); + let epoch_length: u64 = T::EpochLength::get(); + let epoch: u64 = block / epoch_length; Self::get_classified_subnet_nodes(subnet_id, &SubnetNodeClass::Validator, epoch) } @@ -52,7 +58,9 @@ impl Pallet { if !SubnetsData::::contains_key(subnet_id) { return Vec::new(); } - let epoch: u32 = Self::get_current_epoch_as_u32(); + let block: u64 = Self::get_current_block_as_u64(); + let epoch_length: u64 = T::EpochLength::get(); + let epoch: u64 = block / epoch_length; Self::get_classified_subnet_node_info(subnet_id, &SubnetNodeClass::Validator, epoch) } @@ -99,15 +107,16 @@ impl Pallet { // } pub fn get_minimum_subnet_nodes(memory_mb: u128) -> u32 { - MinSubnetNodes::::get() + Self::get_min_subnet_nodes(BaseSubnetNodeMemoryMB::::get(), memory_mb) } pub fn get_minimum_delegate_stake(memory_mb: u128) -> u128 { - Self::get_min_subnet_delegate_stake_balance() + let min_nodes = Self::get_min_subnet_nodes(BaseSubnetNodeMemoryMB::::get(), memory_mb); + Self::get_min_subnet_delegate_stake_balance(min_nodes) } pub fn get_subnet_node_stake_by_peer_id(subnet_id: u32, peer_id: PeerId) -> u128 { - match PeerIdSubnetNode::::try_get(subnet_id, &peer_id) { + match SubnetNodeAccount::::try_get(subnet_id, peer_id.clone()) { Ok(subnet_node_id) => { let hotkey = SubnetNodeIdHotkey::::get(subnet_id, subnet_node_id).unwrap(); // TODO: error fallback AccountSubnetStake::::get(hotkey, subnet_id) @@ -118,15 +127,8 @@ impl Pallet { // TODO: Make this only return true is Validator subnet node pub fn is_subnet_node_by_peer_id(subnet_id: u32, peer_id: Vec) -> bool { - match PeerIdSubnetNode::::try_get(subnet_id, PeerId(peer_id)) { - Ok(_) => true, - Err(()) => false, - } - } - - pub fn is_subnet_node_by_bootstrap_peer_id(subnet_id: u32, peer_id: Vec) -> bool { - match BootstrapPeerIdSubnetNode::::try_get(subnet_id, PeerId(peer_id)) { - Ok(_) => true, + match SubnetNodeAccount::::try_get(subnet_id, PeerId(peer_id)) { + Ok(account_id) => true, Err(()) => false, } } @@ -135,7 +137,7 @@ impl Pallet { let mut subnet_nodes: BTreeMap, bool> = BTreeMap::new(); for peer_id in peer_ids.iter() { - let is = match PeerIdSubnetNode::::try_get(subnet_id, PeerId(peer_id.clone())) { + let is = match SubnetNodeAccount::::try_get(subnet_id, PeerId(peer_id.clone())) { Ok(_) => true, Err(()) => false, }; diff --git a/pallets/network/src/stake/delegate_staking.rs b/pallets/network/src/stake/delegate_staking.rs index 26fda7a..360077b 100644 --- a/pallets/network/src/stake/delegate_staking.rs +++ b/pallets/network/src/stake/delegate_staking.rs @@ -26,94 +26,54 @@ impl Pallet { ) -> DispatchResult { let account_id: T::AccountId = ensure_signed(origin)?; - let (result, balance, shares) = Self::perform_do_add_delegate_stake( - &account_id, - subnet_id, - delegate_stake_to_be_added, - false - ); - - result?; - - let block: u32 = Self::get_current_block_as_u32(); - - // Set last block for rate limiting - Self::set_last_tx_block(&account_id, block); - - Self::deposit_event(Event::SubnetDelegateStakeAdded(subnet_id, account_id, delegate_stake_to_be_added)); - - Ok(()) - } - - /// Add to the subnet delegate stake balance of a user - /// - /// # Arguments - /// - /// * `account_id` - Account adding to balance of subnet. - /// * `subnet_id` - Subnet ID adding stake to. - /// * `delegate_stake_to_be_added` - Balance to add or switch. - /// * `switch` - If we are switching between subnets or nodes. - /// - True: Don't remove balance from users account - /// - False: Check user balance is withdrawable and withdraw balance - /// - pub fn perform_do_add_delegate_stake( - account_id: &T::AccountId, - subnet_id: u32, - delegate_stake_to_be_added: u128, - switch: bool - ) -> (DispatchResult, u128, u128) { let delegate_stake_as_balance = Self::u128_to_balance(delegate_stake_to_be_added); - - if !delegate_stake_as_balance.is_some() { - return (Err(Error::::CouldNotConvertToBalance.into()), 0, 0); - } - if delegate_stake_to_be_added < MinDelegateStakeBalance::::get() { - return (Err(Error::::CouldNotConvertToBalance.into()), 0, 0); - } + ensure!( + delegate_stake_as_balance.is_some(), + Error::::CouldNotConvertToBalance + ); + + let account_delegate_stake_shares: u128 = AccountSubnetDelegateStakeShares::::get(&account_id, subnet_id); + let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); + let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); // --- Get accounts current balance - // let account_delegate_stake_balance = Self::convert_to_balance( - // account_delegate_stake_shares, - // total_subnet_delegated_stake_shares, - // total_subnet_delegated_stake_balance + let account_delegate_stake_balance = Self::convert_to_balance( + account_delegate_stake_shares, + total_subnet_delegated_stake_shares, + total_subnet_delegated_stake_balance + ); + + // ensure!( + // account_delegate_stake_balance != 0, + // Error::::InsufficientBalanceToSharesConversion // ); - // if account_delegate_stake_balance.saturating_add(delegate_stake_to_be_added) > MaxDelegateStakeBalance::::get() { - // return (Err(Error::::MaxDelegatedStakeReached.into()), 0, 0); - // } + ensure!( + account_delegate_stake_balance.saturating_add(delegate_stake_to_be_added) <= MaxDelegateStakeBalance::::get(), + Error::::MaxDelegatedStakeReached + ); // --- Ensure the callers account_id has enough delegate_stake to perform the transaction. - if !switch { - if !Self::can_remove_balance_from_coldkey_account(&account_id, delegate_stake_as_balance.unwrap()) { - return (Err(Error::::NotEnoughBalanceToStake.into()), 0, 0); - } - } + ensure!( + Self::can_remove_balance_from_coldkey_account(&account_id, delegate_stake_as_balance.unwrap()), + Error::::NotEnoughBalanceToStake + ); // to-do: add AddStakeRateLimit instead of universal rate limiter // this allows peers to come in freely - let block: u32 = Self::get_current_block_as_u32(); - if Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&account_id), block) { - return (Err(Error::::TxRateLimitExceeded.into()), 0, 0); - } + let block: u64 = Self::get_current_block_as_u64(); + ensure!( + !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&account_id), block), + Error::::TxRateLimitExceeded + ); // --- Ensure the remove operation from the account_id is a success. - if !switch { - if Self::remove_balance_from_coldkey_account(&account_id, delegate_stake_as_balance.unwrap()) == false { - return (Err(Error::::BalanceWithdrawalError.into()), 0, 0); - } - } - - let total_subnet_delegated_stake_shares = match TotalSubnetDelegateStakeShares::::get(subnet_id) { - 0 => { - // --- Mitigate inflation attack - TotalSubnetDelegateStakeShares::::mutate(subnet_id, |mut n| n.saturating_accrue(1000)); - 0 - }, - shares => shares, - }; - let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); - + ensure!( + Self::remove_balance_from_coldkey_account(&account_id, delegate_stake_as_balance.unwrap()) == true, + Error::::BalanceWithdrawalError + ); + // --- Get amount to be added as shares based on stake to balance added to account let mut delegate_stake_to_be_added_as_shares = Self::convert_to_shares( delegate_stake_to_be_added, @@ -121,10 +81,18 @@ impl Pallet { total_subnet_delegated_stake_balance ); - // --- Check rounding errors - if delegate_stake_to_be_added_as_shares == 0 { - return (Err(Error::::CouldNotConvertToShares.into()), 0, 0); + // --- Mitigate inflation attack + if total_subnet_delegated_stake_shares == 0 { + // no need for saturation here + TotalSubnetDelegateStakeShares::::mutate(subnet_id, |mut n| *n += 1000); + delegate_stake_to_be_added_as_shares = delegate_stake_to_be_added_as_shares.saturating_sub(1000); } + + // --- Check rounding errors + ensure!( + delegate_stake_to_be_added_as_shares != 0, + Error::::CouldNotConvertToShares + ); Self::increase_account_delegate_stake_shares( &account_id, @@ -133,64 +101,35 @@ impl Pallet { delegate_stake_to_be_added_as_shares, ); - (Ok(()), delegate_stake_to_be_added, delegate_stake_to_be_added_as_shares) - } - - pub fn do_remove_delegate_stake( - origin: T::RuntimeOrigin, - subnet_id: u32, - delegate_stake_shares_to_be_removed: u128, - ) -> DispatchResult { - let account_id: T::AccountId = ensure_signed(origin)?; - - let (result, delegate_stake_to_be_removed, _) = Self::perform_do_remove_delegate_stake( - &account_id, - subnet_id, - delegate_stake_shares_to_be_removed, - true - ); - - result?; - - let block: u32 = Self::get_current_block_as_u32(); - // Set last block for rate limiting Self::set_last_tx_block(&account_id, block); - Self::deposit_event(Event::SubnetDelegateStakeRemoved(subnet_id, account_id, delegate_stake_to_be_removed)); + Self::deposit_event(Event::DelegateStakeAdded(subnet_id, account_id, delegate_stake_to_be_added)); Ok(()) } - /// Remove the subnet delegate stake balance of a user - /// - /// # Arguments - /// - /// * `account_id` - Account removing balance from subnet. - /// * `subnet_id` - Subnet ID removing stake from. - /// * `delegate_stake_shares_to_be_removed` - Shares of pool to remove. - /// * `add_to_ledger` - If we are unstaking from network and not switching between staking options. - /// - True: Unstake user to unstaking ledger. - /// - False: Don't add balance to unstaking ledger. - /// - pub fn perform_do_remove_delegate_stake( - account_id: &T::AccountId, + pub fn do_remove_delegate_stake( + origin: T::RuntimeOrigin, subnet_id: u32, delegate_stake_shares_to_be_removed: u128, - add_to_ledger: bool - ) -> (DispatchResult, u128, u128) { + ) -> DispatchResult { + let account_id: T::AccountId = ensure_signed(origin)?; + // --- Ensure that the delegate_stake amount to be removed is above zero. - if delegate_stake_shares_to_be_removed == 0 { - return (Err(Error::::NotEnoughStakeToWithdraw.into()), 0, 0); - } + ensure!( + delegate_stake_shares_to_be_removed > 0, + Error::::NotEnoughStakeToWithdraw + ); let account_delegate_stake_shares: u128 = AccountSubnetDelegateStakeShares::::get(&account_id, subnet_id); - // --- Ensure that the account has enough delegate_stake to withdraw. - if account_delegate_stake_shares < delegate_stake_shares_to_be_removed { - return (Err(Error::::NotEnoughStakeToWithdraw.into()), 0, 0); - } - + // --- Ensure that the account has enough delegate_stake to withdraw. + ensure!( + account_delegate_stake_shares >= delegate_stake_shares_to_be_removed, + Error::::NotEnoughStakeToWithdraw + ); + let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); @@ -204,33 +143,34 @@ impl Pallet { // --- Ensure that we can convert this u128 to a balance. // Redunant let delegate_stake_to_be_added_as_currency = Self::u128_to_balance(delegate_stake_to_be_removed); - if !delegate_stake_to_be_added_as_currency.is_some() { - return (Err(Error::::CouldNotConvertToBalance.into()), 0, 0); - } + ensure!( + delegate_stake_to_be_added_as_currency.is_some(), + Error::::CouldNotConvertToBalance + ); - let block: u32 = Self::get_current_block_as_u32(); - if Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&account_id), block) { - return (Err(Error::::TxRateLimitExceeded.into()), 0, 0); - } + let block: u64 = Self::get_current_block_as_u64(); + ensure!( + !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&account_id), block), + Error::::TxRateLimitExceeded + ); // --- We remove the shares from the account and balance from the pool Self::decrease_account_delegate_stake_shares(&account_id, subnet_id, delegate_stake_to_be_removed, delegate_stake_shares_to_be_removed); // --- We add the balancer to the account_id. If the above fails we will not credit this account_id. - if add_to_ledger { - let result = Self::add_balance_to_unbonding_ledger( - &account_id, - delegate_stake_to_be_removed, - T::DelegateStakeCooldownEpochs::get(), - block - ); - - if let Err(e) = result { - return (Err(e), 0, 0); - } - } + Self::add_balance_to_unbonding_ledger( + &account_id, + delegate_stake_to_be_removed, + T::DelegateStakeCooldownEpochs::get(), + block + ).map_err(|e| e)?; + + // Set last block for rate limiting + Self::set_last_tx_block(&account_id, block); + + Self::deposit_event(Event::DelegateStakeRemoved(subnet_id, account_id.clone(), delegate_stake_to_be_removed)); - (Ok(()), delegate_stake_to_be_removed, delegate_stake_shares_to_be_removed) + Ok(()) } pub fn do_switch_delegate_stake( @@ -241,36 +181,109 @@ impl Pallet { ) -> DispatchResult { let account_id: T::AccountId = ensure_signed(origin)?; - let (result, delegate_stake_to_be_removed, _) = Self::perform_do_remove_delegate_stake( - &account_id, - from_subnet_id, - delegate_stake_shares_to_be_switched, - false, + // --- Ensure that the delegate_stake amount to be removed is above zero. + ensure!( + delegate_stake_shares_to_be_switched > 0, + Error::::NotEnoughStakeToWithdraw ); + let from_account_delegate_stake_shares: u128 = AccountSubnetDelegateStakeShares::::get(&account_id.clone(), from_subnet_id); + + // --- Ensure that the account has enough delegate_stake to withdraw. + ensure!( + from_account_delegate_stake_shares >= delegate_stake_shares_to_be_switched, + Error::::NotEnoughStakeToWithdraw + ); + + let block: u64 = Self::get_current_block_as_u64(); + + // --- Logic + ensure!( + block - LastDelegateStakeTransfer::::get(account_id.clone()) > DelegateStakeTransferPeriod::::get(), + Error::::DelegateStakeTransferPeriodExceeded + ); + + LastDelegateStakeTransfer::::insert(account_id.clone(), block); + + let total_from_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(from_subnet_id); + let total_from_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(from_subnet_id); + + // --- Get accounts current balance + let delegate_stake_to_be_transferred = Self::convert_to_balance( + from_account_delegate_stake_shares, + total_from_subnet_delegated_stake_shares, + total_from_subnet_delegated_stake_balance + ); + + // --- Ensure that we can convert this u128 to a balance. + // Redunant + let delegate_stake_to_be_transferred_as_currency = Self::u128_to_balance(delegate_stake_to_be_transferred); + ensure!( + delegate_stake_to_be_transferred_as_currency.is_some(), + Error::::CouldNotConvertToBalance + ); + + // --- We remove the shares from the account and balance from the pool + Self::decrease_account_delegate_stake_shares(&account_id, from_subnet_id, delegate_stake_to_be_transferred, delegate_stake_shares_to_be_switched); + + + - result?; // --- Add - let (result, balance, shares) = Self::perform_do_add_delegate_stake( - &account_id, - to_subnet_id, - delegate_stake_to_be_removed, - true + let to_account_delegate_stake_shares: u128 = AccountSubnetDelegateStakeShares::::get(&account_id.clone(), to_subnet_id); + let total_to_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(to_subnet_id); + let total_to_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(to_subnet_id); + + // --- Get accounts current balance + let to_account_delegate_stake_balance = Self::convert_to_balance( + to_account_delegate_stake_shares, + total_to_subnet_delegated_stake_shares, + total_to_subnet_delegated_stake_balance ); - result?; + ensure!( + to_account_delegate_stake_balance.saturating_add(delegate_stake_to_be_transferred) <= MaxDelegateStakeBalance::::get(), + Error::::MaxDelegatedStakeReached + ); + + // to-do: add AddStakeRateLimit instead of universal rate limiter + // this allows peers to come in freely + ensure!( + !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&account_id), block), + Error::::TxRateLimitExceeded + ); + + // --- Get amount to be added as shares based on stake to balance added to account + let mut delegate_stake_to_be_added_as_shares = Self::convert_to_shares( + delegate_stake_to_be_transferred, + total_to_subnet_delegated_stake_shares, + total_to_subnet_delegated_stake_balance + ); + + // --- Mitigate inflation attack + if total_to_subnet_delegated_stake_shares == 0 { + // no need for saturation here + TotalSubnetDelegateStakeShares::::mutate(to_subnet_id, |mut n| *n += 1000); + delegate_stake_to_be_added_as_shares = delegate_stake_to_be_added_as_shares.saturating_sub(1000); + } + + // --- Check rounding errors + ensure!( + delegate_stake_to_be_added_as_shares != 0, + Error::::CouldNotConvertToShares + ); - let block: u32 = Self::get_current_block_as_u32(); + Self::increase_account_delegate_stake_shares( + &account_id, + to_subnet_id, + delegate_stake_to_be_transferred, + delegate_stake_to_be_added_as_shares, + ); // Set last block for rate limiting Self::set_last_tx_block(&account_id, block); - Self::deposit_event(Event::SubnetDelegateStakeSwitched( - from_subnet_id, - to_subnet_id, - account_id, - delegate_stake_to_be_removed - )); + Self::deposit_event(Event::DelegateStakeSwitched(from_subnet_id, to_subnet_id, account_id.clone(), delegate_stake_to_be_transferred)); Ok(()) } @@ -289,8 +302,6 @@ impl Pallet { // -- increase total subnet delegate stake shares TotalSubnetDelegateStakeShares::::mutate(subnet_id, |mut n| n.saturating_accrue(shares)); - - TotalDelegateStake::::mutate(|mut n| n.saturating_accrue(amount)); } pub fn decrease_account_delegate_stake_shares( @@ -307,8 +318,6 @@ impl Pallet { // -- decrease total subnet delegate stake shares TotalSubnetDelegateStakeShares::::mutate(subnet_id, |mut n| n.saturating_reduce(shares)); - - TotalDelegateStake::::mutate(|mut n| n.saturating_reduce(amount)); } /// Rewards are deposited here from the ``rewards.rs`` or by donations @@ -316,16 +325,8 @@ impl Pallet { subnet_id: u32, amount: u128, ) { - if TotalSubnetDelegateStakeBalance::::get(subnet_id) == 0 || - TotalSubnetDelegateStakeShares::::get(subnet_id) == 0 - { - TotalSubnetDelegateStakeShares::::mutate(subnet_id, |mut n| n.saturating_accrue(1000)); - }; - // -- increase total subnet delegate stake TotalSubnetDelegateStakeBalance::::mutate(subnet_id, |mut n| n.saturating_accrue(amount)); - - TotalDelegateStake::::mutate(|mut n| n.saturating_accrue(amount)); } pub fn convert_account_shares_to_balance( @@ -346,4 +347,32 @@ impl Pallet { total_subnet_delegated_stake_balance ) } + + pub fn convert_to_balance( + shares: u128, + total_shares: u128, + total_balance: u128 + ) -> u128 { + if total_shares == 0 { + return shares; + } + // shares * (total_balance * Self::PERCENTAGE_FACTOR / (total_shares + 1)) / Self::PERCENTAGE_FACTOR + shares.saturating_mul( + total_balance.saturating_mul(Self::PERCENTAGE_FACTOR).saturating_div(total_shares + 1) + ).saturating_div(Self::PERCENTAGE_FACTOR) + } + + pub fn convert_to_shares( + balance: u128, + total_shares: u128, + total_balance: u128 + ) -> u128 { + if total_shares == 0 { + return balance; + } + // balance * (total_shares * Self::PERCENTAGE_FACTOR / (total_balance + 1)) / Self::PERCENTAGE_FACTOR + balance.saturating_mul( + total_shares.saturating_mul(Self::PERCENTAGE_FACTOR).saturating_div(total_balance + 1) + ).saturating_div(Self::PERCENTAGE_FACTOR) + } } \ No newline at end of file diff --git a/pallets/network/src/stake/mod.rs b/pallets/network/src/stake/mod.rs index 39517a2..87fe8e6 100644 --- a/pallets/network/src/stake/mod.rs +++ b/pallets/network/src/stake/mod.rs @@ -2,5 +2,4 @@ use super::*; pub mod staking; pub mod delegate_staking; pub mod node_delegate_staking; -pub mod staking_utils; -pub mod transfer_utils; \ No newline at end of file +pub mod staking_utils; \ No newline at end of file diff --git a/pallets/network/src/stake/node_delegate_staking.rs b/pallets/network/src/stake/node_delegate_staking.rs index 3f6bab1..7b8efcc 100644 --- a/pallets/network/src/stake/node_delegate_staking.rs +++ b/pallets/network/src/stake/node_delegate_staking.rs @@ -27,111 +27,67 @@ impl Pallet { ) -> DispatchResult { let account_id: T::AccountId = ensure_signed(origin)?; - let (result, balance, shares) = Self::perform_do_add_node_delegate_stake( - &account_id, - subnet_id, - subnet_node_id, - node_delegate_stake_to_be_added, - false - ); - - result?; - - let block: u32 = Self::get_current_block_as_u32(); - - // Set last block for rate limiting - Self::set_last_tx_block(&account_id, block); - - Self::deposit_event(Event::DelegateNodeStakeAdded { - account_id: account_id, - subnet_id: subnet_id, - subnet_node_id: subnet_node_id, - amount: node_delegate_stake_to_be_added - }); - - Ok(()) - } - - /// Add to the subnet delegate stake balance of a user - /// - /// # Arguments - /// - /// * `account_id` - Account adding to balance of subnet. - /// * `subnet_id` - Subnet ID. - /// * `subnet_node_id` - Subnet node ID adding stake to. - /// * `node_delegate_stake_to_be_added` - Balance to add or switch. - /// * `switch` - If we are switching between subnets or nodes. - /// - True: Don't remove balance from users account - /// - False: Check user balance is withdrawable and withdraw balance - /// - pub fn perform_do_add_node_delegate_stake( - account_id: &T::AccountId, - subnet_id: u32, - subnet_node_id: u32, - node_delegate_stake_to_be_added: u128, - switch: bool - ) -> (DispatchResult, u128, u128) { let delegate_stake_as_balance = Self::u128_to_balance(node_delegate_stake_to_be_added); - if !delegate_stake_as_balance.is_some() { - return (Err(Error::::CouldNotConvertToBalance.into()), 0, 0); - } - - // let account_node_delegate_stake_shares = AccountNodeDelegateStakeShares::::get((&account_id, subnet_id, subnet_node_id)); - let total_node_delegated_stake_shares = match TotalNodeDelegateStakeShares::::get(subnet_id, subnet_node_id) { - 0 => { - // --- Mitigate inflation attack - TotalNodeDelegateStakeShares::::mutate(subnet_id, subnet_node_id, |mut n| n.saturating_accrue(1000)); - 0 - }, - shares => shares, - }; - + ensure!( + delegate_stake_as_balance.is_some(), + Error::::CouldNotConvertToBalance + ); + let account_node_delegate_stake_shares = AccountNodeDelegateStakeShares::::get((&account_id, subnet_id, subnet_node_id)); + let total_node_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(subnet_id, subnet_node_id); let total_node_delegated_stake_balance = TotalNodeDelegateStakeBalance::::get(subnet_id, subnet_node_id); // --- Get accounts current balance - // let account_delegate_stake_balance = Self::convert_to_balance( - // account_node_delegate_stake_shares, - // total_node_delegated_stake_shares, - // total_node_delegated_stake_balance - // ); + let account_delegate_stake_balance = Self::convert_to_balance( + account_node_delegate_stake_shares, + total_node_delegated_stake_shares, + total_node_delegated_stake_balance + ); - // if account_delegate_stake_balance.saturating_add(node_delegate_stake_to_be_added) > MaxDelegateStakeBalance::::get() { - // return (Err(Error::::MaxDelegatedStakeReached.into()), 0, 0); - // } + ensure!( + account_delegate_stake_balance.saturating_add(node_delegate_stake_to_be_added) <= MaxDelegateStakeBalance::::get(), + Error::::MaxDelegatedStakeReached + ); // --- Ensure the callers account_id has enough delegate_stake to perform the transaction. - if !switch { - if !Self::can_remove_balance_from_coldkey_account(&account_id, delegate_stake_as_balance.unwrap()) { - return (Err(Error::::NotEnoughBalanceToStake.into()), 0, 0); - } - } - + ensure!( + Self::can_remove_balance_from_coldkey_account(&account_id, delegate_stake_as_balance.unwrap()), + Error::::NotEnoughBalanceToStake + ); + // to-do: add AddStakeRateLimit instead of universal rate limiter // this allows peers to come in freely - let block: u32 = Self::get_current_block_as_u32(); - if Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&account_id), block) { - return (Err(Error::::TxRateLimitExceeded.into()), 0, 0); - } + let block: u64 = Self::get_current_block_as_u64(); + ensure!( + !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&account_id), block), + Error::::TxRateLimitExceeded + ); // --- Ensure the remove operation from the account_id is a success. - if !switch { - if Self::remove_balance_from_coldkey_account(&account_id, delegate_stake_as_balance.unwrap()) == false { - return (Err(Error::::BalanceWithdrawalError.into()), 0, 0); - } - } - + ensure!( + Self::remove_balance_from_coldkey_account(&account_id, delegate_stake_as_balance.unwrap()) == true, + Error::::BalanceWithdrawalError + ); + // --- Get amount to be added as shares based on stake to balance added to account let mut delegate_stake_to_be_added_as_shares = Self::convert_to_shares( node_delegate_stake_to_be_added, total_node_delegated_stake_shares, total_node_delegated_stake_balance ); + + // --- Mitigate inflation attack + if total_node_delegated_stake_shares == 0 { + // no need for saturation here + TotalNodeDelegateStakeShares::::mutate(subnet_id, subnet_node_id, |mut n| *n += 1000); + delegate_stake_to_be_added_as_shares = delegate_stake_to_be_added_as_shares.saturating_sub(1000); + } // --- Check rounding errors - if delegate_stake_to_be_added_as_shares == 0 { - return (Err(Error::::CouldNotConvertToShares.into()), 0, 0); - } + ensure!( + delegate_stake_to_be_added_as_shares != 0, + Error::::CouldNotConvertToShares + ); Self::increase_account_node_delegate_stake_shares( &account_id, @@ -141,79 +97,46 @@ impl Pallet { delegate_stake_to_be_added_as_shares, ); - (Ok(()), node_delegate_stake_to_be_added, delegate_stake_to_be_added_as_shares) - } - - - pub fn do_remove_node_delegate_stake( - origin: T::RuntimeOrigin, - subnet_id: u32, - subnet_node_id: u32, - node_delegate_stake_shares_to_be_removed: u128, - ) -> DispatchResult { - let account_id: T::AccountId = ensure_signed(origin)?; - - let (result, node_delegate_stake_to_be_removed, _) = Self::perform_do_remove_node_delegate_stake( - &account_id, - subnet_id, - subnet_node_id, - node_delegate_stake_shares_to_be_removed, - true, - ); - - result?; - - let block: u32 = Self::get_current_block_as_u32(); - // Set last block for rate limiting Self::set_last_tx_block(&account_id, block); - Self::deposit_event(Event::DelegateNodeStakeRemoved { + Self::deposit_event(Event::DelegateNodeStakeAdded { account_id: account_id, subnet_id: subnet_id, subnet_node_id: subnet_node_id, - amount: node_delegate_stake_to_be_removed + amount: node_delegate_stake_to_be_added }); Ok(()) } - /// Remove the node delegate stake balance of a user - /// - /// # Arguments - /// - /// * `account_id` - Account adding to balance of subnet. - /// * `subnet_id` - Subnet ID. - /// * `subnet_node_id` - Subnet Node ID removing stake from. - /// * `node_delegate_stake_shares_to_be_removed` - Shares of pool to remove. - /// * `add_to_ledger` - If we are unstaking from network and not switching between staking options. - /// - True: Unstake user to unstaking ledger. - /// - False: Don't add balance to unstaking ledger. - /// - pub fn perform_do_remove_node_delegate_stake( - account_id: &T::AccountId, + pub fn do_remove_node_delegate_stake( + origin: T::RuntimeOrigin, subnet_id: u32, subnet_node_id: u32, node_delegate_stake_shares_to_be_removed: u128, - add_to_ledger: bool - ) -> (DispatchResult, u128, u128) { + ) -> DispatchResult { + let account_id: T::AccountId = ensure_signed(origin)?; + // --- Ensure that the delegate_stake amount to be removed is above zero. - if node_delegate_stake_shares_to_be_removed == 0 { - return (Err(Error::::NotEnoughStakeToWithdraw.into()), 0, 0); - } + ensure!( + node_delegate_stake_shares_to_be_removed > 0, + Error::::NotEnoughStakeToWithdraw + ); let account_node_delegate_stake_shares = AccountNodeDelegateStakeShares::::get((&account_id, subnet_id, subnet_node_id)); // --- Ensure that the account has enough delegate_stake to withdraw. - if account_node_delegate_stake_shares < node_delegate_stake_shares_to_be_removed { - return (Err(Error::::NotEnoughStakeToWithdraw.into()), 0, 0); - } - + ensure!( + account_node_delegate_stake_shares >= node_delegate_stake_shares_to_be_removed, + Error::::NotEnoughStakeToWithdraw + ); + let total_node_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(subnet_id, subnet_node_id); let total_node_delegated_stake_balance = TotalNodeDelegateStakeBalance::::get(subnet_id, subnet_node_id); // --- Get accounts current balance - let node_delegate_stake_to_be_removed = Self::convert_to_balance( + let delegate_stake_to_be_removed = Self::convert_to_balance( node_delegate_stake_shares_to_be_removed, total_node_delegated_stake_shares, total_node_delegated_stake_balance @@ -221,52 +144,48 @@ impl Pallet { // --- Ensure that we can convert this u128 to a balance. // Redunant - let delegate_stake_to_be_added_as_currency = Self::u128_to_balance(node_delegate_stake_to_be_removed); - if !delegate_stake_to_be_added_as_currency.is_some() { - return (Err(Error::::CouldNotConvertToBalance.into()), 0, 0); - } + let delegate_stake_to_be_added_as_currency = Self::u128_to_balance(delegate_stake_to_be_removed); + ensure!( + delegate_stake_to_be_added_as_currency.is_some(), + Error::::CouldNotConvertToBalance + ); - let block: u32 = Self::get_current_block_as_u32(); - if Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&account_id), block) { - return (Err(Error::::TxRateLimitExceeded.into()), 0, 0); - } + let block: u64 = Self::get_current_block_as_u64(); + ensure!( + !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&account_id), block), + Error::::TxRateLimitExceeded + ); // --- We remove the shares from the account and balance from the pool Self::decrease_account_node_delegate_stake_shares( &account_id, subnet_id, subnet_node_id, - node_delegate_stake_to_be_removed, + delegate_stake_to_be_removed, node_delegate_stake_shares_to_be_removed ); // --- We add the balancer to the account_id. If the above fails we will not credit this account_id. - if add_to_ledger { - let result = Self::add_balance_to_unbonding_ledger( - &account_id, - node_delegate_stake_to_be_removed, - T::NodeDelegateStakeCooldownEpochs::get(), - block - ); - - if let Err(e) = result { - return (Err(e), 0, 0); - } - } + Self::add_balance_to_unbonding_ledger( + &account_id, + delegate_stake_to_be_removed, + T::DelegateStakeCooldownEpochs::get(), + block + ).map_err(|e| e)?; - (Ok(()), node_delegate_stake_to_be_removed, node_delegate_stake_shares_to_be_removed) + // Set last block for rate limiting + Self::set_last_tx_block(&account_id, block); + + Self::deposit_event(Event::DelegateNodeStakeRemoved { + account_id: account_id, + subnet_id: subnet_id, + subnet_node_id: subnet_node_id, + amount: delegate_stake_to_be_removed + }); + + Ok(()) } - /// Switch delegate staking between subnet nodes - /// - /// # Arguments - /// - /// * `from_subnet_id` - Subnet ID unstaking from in relation to subnet node ID. - /// * `from_subnet_node_id` - Subnet node ID unstaking from . - /// * `to_subnet_id` - Subnet ID adding staking to from in relation to subnet node ID. - /// * `to_subnet_node_id` - Subnet node ID adding stake to. - /// * `node_delegate_stake_shares_to_be_switched` - Shares to remove to then be added as converted balance - /// pub fn do_switch_node_delegate_stake( origin: T::RuntimeOrigin, from_subnet_id: u32, @@ -277,40 +196,122 @@ impl Pallet { ) -> DispatchResult { let account_id: T::AccountId = ensure_signed(origin)?; - // --- Remove - let (result, node_delegate_stake_to_be_transferred, _) = Self::perform_do_remove_node_delegate_stake( - &account_id, - from_subnet_id, - from_subnet_node_id, - node_delegate_stake_shares_to_be_switched, - false, + // --- Ensure that the delegate_stake amount to be removed is above zero. + ensure!( + node_delegate_stake_shares_to_be_switched > 0, + Error::::NotEnoughStakeToWithdraw + ); + let from_account_delegate_stake_shares: u128 = AccountNodeDelegateStakeShares::::get((&account_id.clone(), from_subnet_id, from_subnet_node_id.clone())); + + // --- Ensure that the account has enough delegate_stake to withdraw. + ensure!( + from_account_delegate_stake_shares >= node_delegate_stake_shares_to_be_switched, + Error::::NotEnoughStakeToWithdraw + ); + + let block: u64 = Self::get_current_block_as_u64(); + + // --- Logic + ensure!( + block - LastDelegateStakeTransfer::::get(account_id.clone()) > DelegateStakeTransferPeriod::::get(), + Error::::DelegateStakeTransferPeriodExceeded ); - result?; + LastDelegateStakeTransfer::::insert(account_id.clone(), block); + + let total_from_subnet_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(from_subnet_id, from_subnet_node_id); + let total_from_subnet_delegated_stake_balance = TotalNodeDelegateStakeBalance::::get(from_subnet_id, from_subnet_node_id); + + // --- Get accounts current balance + let delegate_stake_to_be_transferred = Self::convert_to_balance( + from_account_delegate_stake_shares, + total_from_subnet_delegated_stake_shares, + total_from_subnet_delegated_stake_balance + ); + + // --- Ensure that we can convert this u128 to a balance. + // Redunant + let delegate_stake_to_be_transferred_as_currency = Self::u128_to_balance(delegate_stake_to_be_transferred); + ensure!( + delegate_stake_to_be_transferred_as_currency.is_some(), + Error::::CouldNotConvertToBalance + ); + + // --- We remove the shares from the account and balance from the pool + Self::decrease_account_node_delegate_stake_shares( + &account_id, + from_subnet_id, + from_subnet_node_id.clone(), + delegate_stake_to_be_transferred, + node_delegate_stake_shares_to_be_switched + ); + + + + // --- Add - let (result, balance, shares) = Self::perform_do_add_node_delegate_stake( - &account_id, - to_subnet_id, - to_subnet_node_id, - node_delegate_stake_to_be_transferred, - true + let to_account_delegate_stake_shares: u128 = AccountNodeDelegateStakeShares::::get((&account_id.clone(), to_subnet_id, to_subnet_node_id.clone())); + let total_to_subnet_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(to_subnet_id, to_subnet_node_id); + let total_to_subnet_delegated_stake_balance = TotalNodeDelegateStakeBalance::::get(to_subnet_id, to_subnet_node_id); + + // --- Get accounts current balance + let to_account_delegate_stake_balance = Self::convert_to_balance( + to_account_delegate_stake_shares, + total_to_subnet_delegated_stake_shares, + total_to_subnet_delegated_stake_balance + ); + + ensure!( + to_account_delegate_stake_balance.saturating_add(delegate_stake_to_be_transferred) <= MaxDelegateStakeBalance::::get(), + Error::::MaxDelegatedStakeReached + ); + + // to-do: add AddStakeRateLimit instead of universal rate limiter + // this allows peers to come in freely + ensure!( + !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&account_id), block), + Error::::TxRateLimitExceeded + ); + + // --- Get amount to be added as shares based on stake to balance added to account + let mut delegate_stake_to_be_added_as_shares = Self::convert_to_shares( + delegate_stake_to_be_transferred, + total_to_subnet_delegated_stake_shares, + total_to_subnet_delegated_stake_balance ); - result?; + // --- Mitigate inflation attack + if total_to_subnet_delegated_stake_shares == 0 { + // no need for saturation here + TotalNodeDelegateStakeShares::::mutate(to_subnet_id, to_subnet_node_id.clone(), |mut n| *n += 1000); + delegate_stake_to_be_added_as_shares = delegate_stake_to_be_added_as_shares.saturating_sub(1000); + } + + // --- Check rounding errors + ensure!( + delegate_stake_to_be_added_as_shares != 0, + Error::::CouldNotConvertToShares + ); - let block: u32 = Self::get_current_block_as_u32(); + Self::increase_account_node_delegate_stake_shares( + &account_id, + to_subnet_id, + to_subnet_node_id.clone(), + delegate_stake_to_be_transferred, + delegate_stake_to_be_added_as_shares, + ); // Set last block for rate limiting Self::set_last_tx_block(&account_id, block); Self::deposit_event(Event::DelegateNodeStakeSwitched { - account_id: account_id, + account_id: account_id.clone(), from_subnet_id: from_subnet_id, from_subnet_node_id: from_subnet_node_id, to_subnet_id: to_subnet_id, to_subnet_node_id: to_subnet_node_id, - amount: node_delegate_stake_to_be_transferred + amount: delegate_stake_to_be_transferred }); Ok(()) @@ -331,8 +332,6 @@ impl Pallet { // -- increase total subnet delegate stake shares TotalNodeDelegateStakeShares::::mutate(subnet_id, subnet_node_id, |mut n| n.saturating_accrue(shares)); - - TotalNodeDelegateStake::::mutate(|mut n| n.saturating_accrue(amount)); } pub fn decrease_account_node_delegate_stake_shares( @@ -350,8 +349,6 @@ impl Pallet { // -- decrease total subnet delegate stake shares TotalNodeDelegateStakeShares::::mutate(subnet_id, subnet_node_id, |mut n| n.saturating_reduce(shares)); - - TotalNodeDelegateStake::::mutate(|mut n| n.saturating_reduce(amount)); } /// Rewards are deposited here from the ``rewards.rs`` or by donations @@ -360,15 +357,7 @@ impl Pallet { subnet_node_id: u32, amount: u128, ) { - if TotalNodeDelegateStakeBalance::::get(subnet_id, subnet_node_id) == 0 || - TotalNodeDelegateStakeShares::::get(subnet_id, subnet_node_id) == 0 - { - TotalNodeDelegateStakeShares::::mutate(subnet_id, subnet_node_id, |mut n| n.saturating_accrue(1000)); - }; - // -- increase total subnet delegate stake TotalNodeDelegateStakeBalance::::mutate(subnet_id, subnet_node_id, |mut n| n.saturating_accrue(amount)); - - TotalNodeDelegateStake::::mutate(|mut n| n.saturating_accrue(amount)); } } \ No newline at end of file diff --git a/pallets/network/src/stake/staking.rs b/pallets/network/src/stake/staking.rs index 1b05466..aa3a9a2 100644 --- a/pallets/network/src/stake/staking.rs +++ b/pallets/network/src/stake/staking.rs @@ -52,7 +52,7 @@ impl Pallet { // to-do: add AddStakeRateLimit instead of universal rate limiter // this allows peers to come in freely - let block: u32 = Self::get_current_block_as_u32(); + let block: u64 = Self::get_current_block_as_u64(); ensure!( !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), Error::::TxRateLimitExceeded @@ -84,7 +84,6 @@ impl Pallet { subnet_id: u32, hotkey: T::AccountId, is_subnet_node: bool, - is_active: bool, stake_to_be_removed: u128, ) -> DispatchResult { let coldkey: T::AccountId = ensure_signed(origin)?; @@ -118,7 +117,7 @@ impl Pallet { Error::::CouldNotConvertToBalance ); - let block: u32 = Self::get_current_block_as_u32(); + let block: u64 = Self::get_current_block_as_u64(); ensure!( !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), Error::::TxRateLimitExceeded @@ -128,22 +127,12 @@ impl Pallet { Self::decrease_account_stake(&hotkey, subnet_id, stake_to_be_removed); // --- 9. We add the balancer to the coldkey. If the above fails we will not credit this coldkey. - if is_active { - Self::add_balance_to_unbonding_ledger( - &coldkey, - stake_to_be_removed, - T::StakeCooldownEpochs::get(), - block - ).map_err(|e| e)?; - } else { - // Unstaking cooldown for nodes that never activated - Self::add_balance_to_unbonding_ledger( - &coldkey, - stake_to_be_removed, - RegisteredStakeCooldownEpochs::::get(), - block - ).map_err(|e| e)?; - } + Self::add_balance_to_unbonding_ledger( + &coldkey, + stake_to_be_removed, + T::StakeCooldownEpochs::get(), + block + ).map_err(|e| e)?; // Set last block for rate limiting Self::set_last_tx_block(&coldkey, block); diff --git a/pallets/network/src/stake/staking_utils.rs b/pallets/network/src/stake/staking_utils.rs index 7fe729e..02ef8f8 100644 --- a/pallets/network/src/stake/staking_utils.rs +++ b/pallets/network/src/stake/staking_utils.rs @@ -14,19 +14,18 @@ // limitations under the License. use super::*; -use sp_core::U256; impl Pallet { pub fn add_balance_to_unbonding_ledger( coldkey: &T::AccountId, amount: u128, - cooldown_epoch_length: u32, - block: u32, + cooldown_epoch_length: u64, + block: u64, ) -> DispatchResult { - let epoch = Self::get_current_epoch_as_u32(); - let claim_epoch = cooldown_epoch_length.saturating_add(epoch); + let epoch_length: u64 = T::EpochLength::get(); + let epoch: u64 = block / epoch_length; - let unbondings = StakeUnbondingLedger::::get(&coldkey); + let unbondings = StakeUnbondingLedger::::get(coldkey.clone()); // --- Ensure we don't surpass max unlockings by attempting to unlock unbondings if unbondings.len() as u32 == T::MaxStakeUnlockings::get() { @@ -34,7 +33,7 @@ impl Pallet { } // --- Get updated unbondings after claiming unbondings - let mut unbondings = StakeUnbondingLedger::::get(&coldkey); + let mut unbondings = StakeUnbondingLedger::::get(coldkey.clone()); // We're about to add another unbonding to the ledger - it must be n-1 ensure!( @@ -43,7 +42,7 @@ impl Pallet { ); StakeUnbondingLedger::::mutate(&coldkey, |ledger| { - ledger.entry(claim_epoch).and_modify(|v| v.saturating_accrue(amount)).or_insert(amount); + ledger.entry(epoch).and_modify(|v| *v += amount).or_insert(amount); }); Ok(()) @@ -51,15 +50,17 @@ impl Pallet { // Infallible pub fn do_claim_unbondings(coldkey: &T::AccountId) -> u32 { - let epoch = Self::get_current_epoch_as_u32(); - let unbondings = StakeUnbondingLedger::::get(&coldkey); + let block: u64 = Self::get_current_block_as_u64(); + let epoch_length: u64 = T::EpochLength::get(); + let epoch: u64 = block / epoch_length; + let unbondings = StakeUnbondingLedger::::get(coldkey.clone()); let mut unbondings_copy = unbondings.clone(); let mut successful_unbondings = 0; for (unbonding_epoch, amount) in unbondings.iter() { - if epoch <= *unbonding_epoch { + if epoch <= unbonding_epoch + T::StakeCooldownEpochs::get() { continue } @@ -76,7 +77,7 @@ impl Pallet { } if unbondings.len() != unbondings_copy.len() { - StakeUnbondingLedger::::insert(&coldkey, unbondings_copy); + StakeUnbondingLedger::::insert(coldkey.clone(), unbondings_copy); } successful_unbondings } @@ -137,38 +138,4 @@ impl Pallet { > { input.try_into().ok() } - - pub fn convert_to_shares( - balance: u128, - total_shares: u128, - total_balance: u128, - ) -> u128 { - if total_shares == 0 { - return balance; - } - - let balance = U256::from(balance); - let total_shares = U256::from(total_shares) + U256::from(10_u128.pow(1)); - let total_balance = U256::from(total_balance) + U256::from(1); - - let shares = balance * total_shares / total_balance; - shares.try_into().unwrap_or(u128::MAX) - } - - pub fn convert_to_balance( - shares: u128, - total_shares: u128, - total_balance: u128, - ) -> u128 { - if total_shares == 0 { - return shares; - } - - let shares = U256::from(shares); - let total_balance = U256::from(total_balance) + U256::from(1); - let total_shares = U256::from(total_shares) + U256::from(10_u128.pow(1)); - - let balance = shares * total_balance / total_shares; - balance.try_into().unwrap_or(u128::MAX) - } } \ No newline at end of file diff --git a/pallets/network/src/stake/transfer_utils.rs b/pallets/network/src/stake/transfer_utils.rs deleted file mode 100644 index 249ea0e..0000000 --- a/pallets/network/src/stake/transfer_utils.rs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (C) Hypertensor. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Enables users to swap bidirectionally subnets <-> nodes - -use super::*; -use sp_runtime::Saturating; - -impl Pallet { - /// Transfer stake from a subnet node to a subnet - /// - /// # Arguments - /// - /// * `from_subnet_id` - Subnet ID unstaking from in relation to subnet node ID. - /// * `from_subnet_node_id` - Subnet node ID unstaking from . - /// * `to_subnet_id` - Subnet ID adding stake to. - /// * `node_delegate_stake_shares_to_be_switched` - Shares to remove to then be added as converted balance. - /// - pub fn do_transfer_from_node_to_subnet( - origin: T::RuntimeOrigin, - from_subnet_id: u32, - from_subnet_node_id: u32, - to_subnet_id: u32, - node_delegate_stake_shares_to_be_switched: u128, - ) -> DispatchResult { - let account_id: T::AccountId = ensure_signed(origin)?; - - // Perform removal of stake AND ensure success - // Return the balance we removed - let (result, balance_removed, _) = Self::perform_do_remove_node_delegate_stake( - &account_id, - from_subnet_id, - from_subnet_node_id, - node_delegate_stake_shares_to_be_switched, - false, - ); - - result?; - - let (result, _, _) = Self::perform_do_add_delegate_stake( - &account_id, - to_subnet_id, - balance_removed, - true - ); - - result?; - - Self::deposit_event(Event::DelegateNodeToSubnetDelegateStakeSwitched { - account_id: account_id, - from_subnet_id: from_subnet_id, - from_subnet_node_id: from_subnet_node_id, - to_subnet_id: to_subnet_id, - amount: balance_removed - }); - - Ok(()) - } - - /// Transfer stake from a subnet to a subnet node - /// - /// # Arguments - /// - /// * `from_subnet_id` - Subnet ID unstaking from. - /// * `to_subnet_id` - Subnet ID staking to in relation to subnet node ID . - /// * `to_subnet_node_id` - Subnet node ID adding stake to. - /// * `delegate_stake_shares_to_be_switched` - Shares to remove to then be added as converted balance. - /// - pub fn do_transfer_from_subnet_to_node( - origin: T::RuntimeOrigin, - from_subnet_id: u32, - to_subnet_id: u32, - to_subnet_node_id: u32, - delegate_stake_shares_to_be_switched: u128, - ) -> DispatchResult { - let account_id: T::AccountId = ensure_signed(origin)?; - - let (result, balance_removed, _) = Self::perform_do_remove_delegate_stake( - &account_id, - from_subnet_id, - delegate_stake_shares_to_be_switched, - false, - ); - - result?; - - let (result, _, _) = Self::perform_do_add_node_delegate_stake( - &account_id, - to_subnet_id, - to_subnet_node_id, - balance_removed, - true - ); - - result?; - - Self::deposit_event(Event::SubnetDelegateToNodeDelegateStakeSwitched { - account_id: account_id, - from_subnet_id: from_subnet_id, - to_subnet_id: to_subnet_id, - to_subnet_node_id: to_subnet_node_id, - amount: balance_removed - }); - - Ok(()) - } -} \ No newline at end of file diff --git a/pallets/network/src/consensus/subnet_validator.rs b/pallets/network/src/subnet_validator.rs similarity index 92% rename from pallets/network/src/consensus/subnet_validator.rs rename to pallets/network/src/subnet_validator.rs index d0ac51c..608fec4 100644 --- a/pallets/network/src/consensus/subnet_validator.rs +++ b/pallets/network/src/subnet_validator.rs @@ -23,8 +23,8 @@ impl Pallet { pub fn do_validate( subnet_id: u32, hotkey: T::AccountId, - block: u32, - epoch_length: u32, + block: u64, + epoch_length: u64, epoch: u32, mut data: Vec, args: Option>, @@ -49,14 +49,14 @@ impl Pallet { // Remove duplicates based on peer_id data.dedup_by(|a, b| a.peer_id == b.peer_id); - // Remove queue classified entries + // Remove idle classified entries // Each peer must have an inclusion classification at minimum data.retain(|x| { match SubnetNodesData::::try_get( subnet_id, - PeerIdSubnetNode::::get(subnet_id, &x.peer_id) + SubnetNodeAccount::::get(subnet_id, &x.peer_id) ) { - Ok(subnet_node) => subnet_node.has_classification(&SubnetNodeClass::Included, epoch), + Ok(subnet_node) => subnet_node.has_classification(&SubnetNodeClass::Included, epoch as u64), Err(()) => false, } }); @@ -67,7 +67,7 @@ impl Pallet { // --- Get count of eligible nodes that can be submitted for consensus rewards // This is the maximum amount of nodes that can be entered - let included_nodes: Vec = Self::get_classified_subnet_node_ids(subnet_id, &SubnetNodeClass::Included, epoch); + let included_nodes: Vec = Self::get_classified_subnet_node_ids(subnet_id, &SubnetNodeClass::Included, epoch as u64); let included_nodes_count = included_nodes.len(); // --- Ensure data isn't greater than current registered subnet peers @@ -78,7 +78,7 @@ impl Pallet { ); // --- Validator auto-attests the epoch - let mut attests: BTreeMap = BTreeMap::new(); + let mut attests: BTreeMap = BTreeMap::new(); attests.insert(validator_id, block); let rewards_data: RewardsData = RewardsData { @@ -106,14 +106,14 @@ impl Pallet { pub fn do_attest( subnet_id: u32, hotkey: T::AccountId, - block: u32, - epoch_length: u32, + block: u64, + epoch_length: u64, epoch: u32, ) -> DispatchResultWithPostInfo { // --- Ensure subnet node exists under hotkey let subnet_node_id = match HotkeySubnetNodeId::::try_get( subnet_id, - &hotkey + hotkey.clone() ) { Ok(subnet_node_id) => subnet_node_id, Err(()) => return Err(Error::::SubnetNodeNotExist.into()), @@ -124,13 +124,13 @@ impl Pallet { subnet_id, subnet_node_id ) { - Ok(subnet_node) => subnet_node.has_classification(&SubnetNodeClass::Validator, epoch), + Ok(subnet_node) => subnet_node.has_classification(&SubnetNodeClass::Validator, epoch as u64), Err(()) => return Err(Error::::SubnetNodeNotExist.into()), }; SubnetRewardsSubmission::::try_mutate_exists( subnet_id, - epoch, + epoch.clone(), |maybe_params| -> DispatchResult { let params = maybe_params.as_mut().ok_or(Error::::InvalidSubnetRewardsSubmission)?; let mut attests = &mut params.attests; @@ -154,7 +154,7 @@ impl Pallet { } pub fn choose_validator( - block: u32, + block: u64, subnet_id: u32, subnet_node_ids: Vec, min_subnet_nodes: u32, @@ -202,7 +202,7 @@ impl Pallet { subnet_id: u32, subnet_node_id: u32, attestation_percentage: u128, - block: u32 + block: u64 ) { // We never ensure balance is above 0 because any hotkey chosen must have the target stake // balance at a minimum @@ -210,13 +210,13 @@ impl Pallet { // --- Get stake balance // This could be greater than the target stake balance - let account_subnet_stake: u128 = AccountSubnetStake::::get(&hotkey, subnet_id); + let account_subnet_stake: u128 = AccountSubnetStake::::get(hotkey.clone(), subnet_id); // --- Get slash amount up to max slash // let mut slash_amount: u128 = Self::percent_mul(account_subnet_stake, SlashPercentage::::get()); // --- Update slash amount up to attestation percent - slash_amount = Self::percent_mul(slash_amount, Self::PERCENTAGE_FACTOR.saturating_sub(attestation_percentage)); + slash_amount = Self::percent_mul(slash_amount, Self::PERCENTAGE_FACTOR - attestation_percentage); // --- Update slash amount up to max slash let max_slash: u128 = MaxSlashAmount::::get(); if slash_amount > max_slash { @@ -225,7 +225,7 @@ impl Pallet { // --- Decrease account stake Self::decrease_account_stake( - &hotkey, + &hotkey.clone(), subnet_id, slash_amount, ); @@ -235,7 +235,7 @@ impl Pallet { SubnetNodePenalties::::insert(subnet_id, subnet_node_id, penalties + 1); // --- Ensure maximum sequential removal consensus threshold is reached - if penalties + 1 > MaxSubnetNodePenalties::::get(subnet_id) { + if penalties + 1 > MaxSubnetNodePenalties::::get() { // --- Increase account penalty count Self::perform_remove_subnet_node(block, subnet_id, subnet_node_id); } else { diff --git a/pallets/network/src/supply/emissions.rs b/pallets/network/src/supply/emissions.rs new file mode 100644 index 0000000..e69de29 diff --git a/pallets/network/src/supply/inflation.rs b/pallets/network/src/supply/inflation.rs deleted file mode 100644 index b9794a5..0000000 --- a/pallets/network/src/supply/inflation.rs +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright (C) Hypertensor. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Enables accounts to delegate stake to subnets for a portion of emissions - -use super::*; -use libm::{exp, pow}; - -pub struct Inflation { - /// Initial inflation percentage, from time=0 - pub initial: f64, - - /// Terminal inflation percentage, to time=INF - pub terminal: f64, - - /// Rate per year, at which inflation is lowered until reaching terminal - /// i.e. inflation(year) == MAX(terminal, initial*((1-taper)^year)) - pub taper: f64, - - /// Percentage of total inflation allocated to the foundation - pub foundation: f64, - /// Duration of foundation pool inflation, in years - pub foundation_term: f64, -} - -const DEFAULT_INITIAL: f64 = 0.1; -const DEFAULT_TERMINAL: f64 = 0.015; -const DEFAULT_TAPER: f64 = 0.15; -const DEFAULT_FOUNDATION: f64 = 0.05; -const DEFAULT_FOUNDATION_TERM: f64 = 7.0; - -impl Default for Inflation { - fn default() -> Self { - Self { - initial: DEFAULT_INITIAL, - terminal: DEFAULT_TERMINAL, - taper: DEFAULT_TAPER, - foundation: DEFAULT_FOUNDATION, - foundation_term: DEFAULT_FOUNDATION_TERM, - } - } -} - -impl Inflation { - pub fn epoch(&self, epoch: u32, epochs_per_year: u32, denominator: u128) -> f64 { - let years_elapsed = epoch as f64 / epochs_per_year as f64; - // let rate = self.initial * pow(1.0 - self.terminal, years_elapsed); - - self.total(years_elapsed) - - // Ensure inflation does not go below the minimum taper rate - // let final_rate = rate.max(self.taper); - - // final_rate - // final_rate as u128 * denominator - } - - /// portion of total that goes to validators - pub fn validator(&self, year: f64) -> f64 { - self.total(year) - self.foundation(year) - } - - /// portion of total that goes to foundation - pub fn foundation(&self, year: f64) -> f64 { - if year < self.foundation_term { - self.total(year) * self.foundation - } else { - 0.0 - } - } - - /// inflation rate at year - pub fn total(&self, year: f64) -> f64 { - let tapered = self.initial * pow(1.0 - self.taper, year); - - if tapered > self.terminal { - tapered - } else { - self.terminal - } - } - - pub fn year_from_epoch(&self, epoch: u32, epochs_per_year: u32) -> f64 { - epoch as f64 / epochs_per_year as f64 - } -} - -impl Pallet { - /// Get the current epochs total emissions to subnets - /// - /// Inflation is based on the current network activity - /// - Subnet activity - /// - Subnet node activity - /// - /// # Steps - /// - /// 1. Gets utilization factors - /// - Subnet utilization - /// - Subnet node utilization - /// - /// 2. Combine the utilization factors based on the `SubnetInflationFactor` - /// e.g. SubnetInflationFactor == 80%, then subnet node factor will be 20% (1.0-sif) - /// - SIF is 80% - /// - SNIF is 20% - /// - /// If subnet utilization is 20% and subnet node utilization is 15% - /// e.g. 19% = 20% * 80% + 15% * 20% = `inflation_factor` - /// - /// 3. Get exponential adjustment of `inflation_factor` - /// - /// 4. Get network inflation on epoch - /// - /// 5. Adjust network inflation based on network activity - /// - pub fn get_epoch_emissions( - epoch: u32, - ) -> u128 { - let max_subnets: u32 = MaxSubnets::::get(); - let mut total_activate_subnets: u32 = TotalActiveSubnets::::get(); - // There can be n+1 subnets at this time before 1 is removed in the epoch steps - if total_activate_subnets > max_subnets { - total_activate_subnets = max_subnets; - } - - // ========================== - // --- Get subnet utilization - // ========================== - let subnet_utilization_rate: f64 = total_activate_subnets as f64 / max_subnets as f64; - let adj_subnet_utilization_rate: f64 = Self::pow( - subnet_utilization_rate, - Self::get_percent_as_f64(SubnetInflationAdjFactor::::get()) - ).min(1.0); - - // Max subnet nodes per subnet - let max_nodes: u32 = max_subnets.saturating_mul(MaxSubnetNodes::::get()); - let total_active_nodes: u32 = TotalActiveNodes::::get(); - - // ========================== - // --- Get subnet node utilization - // ========================== - let node_utilization_rate: f64 = total_active_nodes as f64 / max_nodes as f64; - let adj_node_utilization_rate: f64 = Self::pow( - node_utilization_rate, - Self::get_percent_as_f64(SubnetNodeInflationAdjFactor::::get()) - ).min(1.0); - - // ========================== - // --- Get final utilization factors - // ========================== - // Subnet inflation factor - let sif: f64 = Self::get_percent_as_f64(SubnetInflationFactor::::get()); - // Subnet node inflation factor - let snif: f64 = 1.0 - sif; - - let adj_subnet_utilization_rate: f64 = subnet_utilization_rate * sif; - let adj_node_utilization_rate: f64 = node_utilization_rate * snif; - - // --- Get percentage of inflation to use in current epoch - // This is the network activity factor - let inflation_factor: f64 = Self::get_inflation_factor(snif + adj_node_utilization_rate); - - // ========================== - // --- Get current epochs total inflation - // - // * Adjusts the inflation based on network activity using `let inflation_factor` - // ========================== - // let total_issuance: f64 = Self::get_total_network_issuance() as f64; - let total_issuance: f64 = 19536777003861893185536.0; - let epochs_per_year: f64 = T::EpochsPerYear::get() as f64; - - log::error!("inflation total_issuance: {:?}", total_issuance as u128); - - let inflation = Inflation::default(); - - let year: f64 = epoch as f64 / epochs_per_year; - log::error!("inflation year: {:?}", year); - - // --- Get current yearly inflation - let apr: f64 = inflation.total(year); - log::error!("inflation apr: {:?}", apr); - - (total_issuance * apr * inflation_factor) as u128 - } - - pub fn get_epoch_emissions_adj( - epoch: u32, - increase_issuance: u128, - decrease_issuance: u128, - ) -> u128 { - let max_subnets: u32 = MaxSubnets::::get(); - let mut total_activate_subnets: u32 = TotalActiveSubnets::::get(); - // There can be n+1 subnets at this time before 1 is removed in the epoch steps - if total_activate_subnets > max_subnets { - total_activate_subnets = max_subnets; - } - - // ========================== - // --- Get subnet utilization - // ========================== - let subnet_utilization_rate: f64 = total_activate_subnets as f64 / max_subnets as f64; - let adj_subnet_utilization_rate: f64 = Self::pow( - subnet_utilization_rate, - Self::get_percent_as_f64(SubnetInflationAdjFactor::::get()) - ).min(1.0); - - // Max subnet nodes per subnet - let max_nodes: u32 = max_subnets.saturating_mul(MaxSubnetNodes::::get()); - let total_active_nodes: u32 = TotalActiveNodes::::get(); - - // ========================== - // --- Get subnet node utilization - // ========================== - let node_utilization_rate: f64 = total_active_nodes as f64 / max_nodes as f64; - let adj_node_utilization_rate: f64 = Self::pow( - node_utilization_rate, - Self::get_percent_as_f64(SubnetNodeInflationAdjFactor::::get()) - ).min(1.0); - - // ========================== - // --- Get final utilization factors - // ========================== - // Subnet inflation factor - let sif: f64 = Self::get_percent_as_f64(SubnetInflationFactor::::get()); - // Subnet node inflation factor - let snif: f64 = 1.0 - sif; - - let adj_subnet_utilization_rate: f64 = subnet_utilization_rate * sif; - let adj_node_utilization_rate: f64 = node_utilization_rate * snif; - - // --- Get percentage of inflation to use in current epoch - // This is the network activity factor - let inflation_factor: f64 = Self::get_inflation_factor(snif + adj_node_utilization_rate); - - // ========================== - // --- Get current epochs total inflation - // - // * Adjusts the inflation based on network activity using `let inflation_factor` - // ========================== - let total_issuance: f64 = Self::get_total_network_issuance() as f64 + increase_issuance as f64 - decrease_issuance as f64; - let epochs_per_year: f64 = T::EpochsPerYear::get() as f64; - - log::error!("inflation total_issuance: {:?}", total_issuance); - - let inflation = Inflation::default(); - - let year: f64 = epoch as f64 / epochs_per_year; - log::error!("inflation year: {:?}", year); - - // --- Get current yearly inflation - let apr: f64 = inflation.total(year); - log::error!("inflation apr: {:?}", apr); - - (total_issuance * apr * inflation_factor) as u128 - } - - pub fn get_inflation_factor(x: f64) -> f64 { - if x >= 1.0 { - return 1.0 - } - - let k: f64 = Self::get_percent_as_f64(InflationAdjFactor::::get()); - if k == 0.0 { - return 1.0 - } - - pow(x, k).min(1.0) - } -} \ No newline at end of file diff --git a/pallets/network/src/supply/mod.rs b/pallets/network/src/supply/mod.rs index 32c2503..e69de29 100644 --- a/pallets/network/src/supply/mod.rs +++ b/pallets/network/src/supply/mod.rs @@ -1,2 +0,0 @@ -use super::*; -pub mod inflation; \ No newline at end of file diff --git a/pallets/network/src/tests/delegate_staking.rs b/pallets/network/src/tests/delegate_staking.rs index ce74940..d060378 100644 --- a/pallets/network/src/tests/delegate_staking.rs +++ b/pallets/network/src/tests/delegate_staking.rs @@ -18,14 +18,7 @@ use crate::{ TotalSubnetDelegateStakeBalance, SubnetRemovalReason, StakeUnbondingLedger, - AccountNodeDelegateStakeShares, - TotalNodeDelegateStakeBalance, - TotalNodeDelegateStakeShares, - MinStakeBalance, }; -use codec::Decode; -use sp_runtime::traits::TrailingZeroInput; -use sp_core::U256; // // @@ -46,87 +39,31 @@ use sp_core::U256; #[test] fn test_delegate_math() { new_test_ext().execute_with(|| { - let _ = env_logger::builder().is_test(true).try_init(); - - let subnet_id = 0; - let account_id = account(0); - let delegate_stake_to_be_added = 1000e+18 as u128; - - let account_delegate_stake_shares: u128 = AccountSubnetDelegateStakeShares::::get(&account_id, subnet_id); - // let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); - let total_subnet_delegated_stake_shares = match TotalSubnetDelegateStakeShares::::get(subnet_id) { - 0 => { - // --- Mitigate inflation attack - // Network::increase_account_delegate_stake_shares( - // &::AccountId::decode(&mut TrailingZeroInput::zeroes()).unwrap(), - // subnet_id, - // 0, - // 1000, - // ); - TotalSubnetDelegateStakeShares::::mutate(subnet_id, |mut n| *n += 10000); - 0 - }, - shares => shares, - }; - let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); - log::error!("total_subnet_delegated_stake_shares {:?}", total_subnet_delegated_stake_shares); - log::error!("total_subnet_delegated_stake_balance {:?}", total_subnet_delegated_stake_balance); - - let mut delegate_stake_to_be_added_as_shares = Network::convert_to_shares( - delegate_stake_to_be_added, - total_subnet_delegated_stake_shares, - total_subnet_delegated_stake_balance - ); - log::error!("delegate_stake_to_be_added_as_shares {:?}", delegate_stake_to_be_added_as_shares); - - Network::increase_account_delegate_stake_shares( - &account_id, - subnet_id, - delegate_stake_to_be_added, - delegate_stake_to_be_added_as_shares, - ); - - let account_delegate_shares = AccountSubnetDelegateStakeShares::::get(&account_id, subnet_id); - let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); - let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); - - log::error!(" "); - log::error!("account_delegate_shares {:?}", account_delegate_shares); - log::error!("total_subnet_delegated_stake_shares {:?}", total_subnet_delegated_stake_shares); - log::error!("total_subnet_delegated_stake_balance {:?}", total_subnet_delegated_stake_balance); - - let delegate_balance = Network::convert_to_balance( - account_delegate_shares, - total_subnet_delegated_stake_shares, - total_subnet_delegated_stake_balance + let test1 = Network::convert_to_balance( + 1000000000000000000000, + 6000000000000000000000, + 6000000000000000000000 ); - log::error!("delegate_balance {:?}", delegate_balance); - - // Ensure balance is within <= 0.01% of deposited balance, and less than deposited balance - assert!( - (delegate_balance >= Network::percent_mul(delegate_stake_to_be_added, 990000000)) && - (delegate_balance < delegate_stake_to_be_added) + let test2 = Network::convert_to_balance( + 1000000000000000000000, + 6000000000000000000000, + 7000000000000000000000 ); - let delegate_balance2 = Network::convert_to_balance( - account_delegate_shares, - total_subnet_delegated_stake_shares + 9000, - total_subnet_delegated_stake_balance - ); - log::error!("delegate_balance2 {:?}", delegate_balance2); + assert_eq!(test1, 999999999000000000000); + assert_eq!(test2, 1166666666000000000000); }); } #[test] -fn test_delegate_math_with_storage_deposit() { +fn test_delegate_math_with_storage() { new_test_ext().execute_with(|| { let subnet_path: Vec = "petals-team/StableBeluga2".into(); let deposit_amount: u128 = 1000000000000000000000000; - let amount: u128 = 1000000000000000000000; // 1000 - let stake_amount: u128 = MinStakeBalance::::get(); + let amount: u128 = 1000000000000000000000; - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -142,7 +79,6 @@ fn test_delegate_math_with_storage_deposit() { ) ); - // ensure removes wallet balance let post_delegator_balance = Balances::free_balance(&account(total_subnet_nodes+1)); assert_eq!(post_delegator_balance, starting_delegator_balance - amount); @@ -155,35 +91,22 @@ fn test_delegate_math_with_storage_deposit() { total_subnet_delegated_stake_balance ); - // Ensure balance is within <= 0.01% of deposited balance, and less than deposited balance + // assert_eq!(amount, delegate_balance); assert!( - (delegate_balance >= Network::percent_mul(amount, 990000000)) && - (delegate_balance < amount) + (delegate_balance >= Network::percent_mul(amount, 9999)) && + (delegate_balance <= amount) ); - let pre_balance = Balances::free_balance(&account(total_subnet_nodes+1)); - let delegate_shares = AccountSubnetDelegateStakeShares::::get(account(total_subnet_nodes+1), subnet_id); - let shares_to_remove = delegate_shares / 2; - let expected_ledger_balance = Network::convert_to_balance( - shares_to_remove, - total_subnet_delegated_stake_shares, - total_subnet_delegated_stake_balance - ); - - let epoch = System::block_number() / EpochLength::get(); assert_ok!( Network::remove_delegate_stake( RuntimeOrigin::signed(account(total_subnet_nodes+1)), subnet_id, - shares_to_remove, + delegate_shares / 2, ) ); - let post_balance = Balances::free_balance(&account(total_subnet_nodes+1)); - assert_eq!(pre_balance, post_balance); - let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); let delegate_shares = AccountSubnetDelegateStakeShares::::get(account(total_subnet_nodes+1), subnet_id); @@ -193,11 +116,6 @@ fn test_delegate_math_with_storage_deposit() { total_subnet_delegated_stake_balance ); - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); - assert_eq!(unbondings.len(), 1); - let (ledger_epoch, ledger_balance) = unbondings.iter().next().unwrap(); - assert_eq!(*ledger_epoch, &epoch + DelegateStakeCooldownEpochs::get()); - assert_eq!(*ledger_balance, expected_ledger_balance); }); } @@ -207,9 +125,8 @@ fn test_remove_claim_delegate_stake_after_remove_subnet() { let subnet_path: Vec = "petals-team/StableBeluga2".into(); let deposit_amount: u128 = 1000000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -236,26 +153,20 @@ fn test_remove_claim_delegate_stake_after_remove_subnet() { total_subnet_delegated_stake_shares, total_subnet_delegated_stake_balance ); - let expected_ledger_balance = Network::convert_to_balance( - delegate_shares, - total_subnet_delegated_stake_shares, - total_subnet_delegated_stake_balance - ); + // assert_eq!(amount, delegate_balance); assert!( - (delegate_balance >= Network::percent_mul(amount, 990000000)) && - (delegate_balance < amount) + (delegate_balance >= Network::percent_mul(amount, 9999)) && + (delegate_balance <= amount) ); assert_ok!( - Network::do_remove_subnet( + Network::deactivate_subnet( subnet_path.clone().into(), SubnetRemovalReason::MinSubnetDelegateStake, ) ); - let epoch = System::block_number() / EpochLength::get(); - assert_ok!( Network::remove_delegate_stake( RuntimeOrigin::signed(account(total_subnet_nodes+1)), @@ -264,12 +175,6 @@ fn test_remove_claim_delegate_stake_after_remove_subnet() { ) ); - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); - assert_eq!(unbondings.len(), 1); - let (ledger_epoch, ledger_balance) = unbondings.iter().next().unwrap(); - assert_eq!(*ledger_epoch, &epoch + DelegateStakeCooldownEpochs::get()); - assert_eq!(*ledger_balance, expected_ledger_balance); - System::set_block_number(System::block_number() + ((EpochLength::get() + 1) * DelegateStakeCooldownEpochs::get())); assert_ok!( @@ -281,11 +186,11 @@ fn test_remove_claim_delegate_stake_after_remove_subnet() { let post_balance = Balances::free_balance(&account(total_subnet_nodes+1)); assert!( - (post_balance >= Network::percent_mul(starting_delegator_balance, 990000000)) && - (post_balance < starting_delegator_balance) + (post_balance >= Network::percent_mul(starting_delegator_balance, 9999)) && + (post_balance <= starting_delegator_balance) ); - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); + let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); assert_eq!(unbondings.len(), 0); }); } @@ -296,16 +201,15 @@ fn test_add_to_delegate_stake() { let subnet_path: Vec = "petals-team/StableBeluga2".into(); let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); let n_account = total_subnet_nodes + 1; - let _ = Balances::deposit_creating(&account(n_account), amount+500); + let _ = Balances::deposit_creating(&account(n_account), deposit_amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); @@ -358,8 +262,8 @@ fn test_add_to_delegate_stake() { // assert_eq!(delegate_balance, delegate_stake_to_be_added_as_shares); assert!( - (delegate_balance >= Network::percent_mul(amount, 990000000)) && - (delegate_balance < amount) + (delegate_balance >= Network::percent_mul(amount, 9999)) && + (delegate_balance <= amount) ); }); } @@ -371,16 +275,14 @@ fn test_add_to_delegate_stake_increase_pool_check_balance() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); let n_account = total_subnet_nodes + 1; - let _ = Balances::deposit_creating(&account(n_account), amount+500); + let _ = Balances::deposit_creating(&account(n_account), deposit_amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); @@ -413,34 +315,21 @@ fn test_add_to_delegate_stake_increase_pool_check_balance() { let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); - log::error!("total_subnet_delegated_stake_shares {:?}", total_subnet_delegated_stake_shares); - log::error!("total_subnet_delegated_stake_balance {:?}", total_subnet_delegated_stake_balance); let delegate_balance = Network::convert_to_balance( delegate_shares, total_subnet_delegated_stake_shares, total_subnet_delegated_stake_balance ); - log::error!("delegate_balance {:?}", delegate_balance); - // The first depositor will lose a percentage of their deposit depending on the size // https://docs.openzeppelin.com/contracts/4.x/erc4626#inflation-attack // assert_eq!(delegate_balance, delegate_stake_to_be_added_as_shares); assert!( - (delegate_balance >= Network::percent_mul(amount, 990000000)) && - (delegate_balance < amount) + (delegate_balance >= Network::percent_mul(amount, 9999)) && + (delegate_balance <= amount) ); let increase_delegate_stake_amount: u128 = 1000000000000000000000; - - let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); - let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); - let expected_post_delegate_balance = Network::convert_to_balance( - delegate_shares, - total_subnet_delegated_stake_shares, - total_subnet_delegated_stake_balance + increase_delegate_stake_amount - ); - Network::do_increase_delegate_stake( subnet_id, increase_delegate_stake_amount, @@ -449,36 +338,36 @@ fn test_add_to_delegate_stake_increase_pool_check_balance() { // ensure balance has increase let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); - + let post_delegate_balance = Network::convert_to_balance( delegate_shares, total_subnet_delegated_stake_shares, total_subnet_delegated_stake_balance ); - log::error!("post_delegate_balance {:?}", post_delegate_balance); - assert_eq!(post_delegate_balance, expected_post_delegate_balance); + assert!(delegate_balance < post_delegate_balance); + assert_ne!(delegate_balance, post_delegate_balance); + assert!( + (post_delegate_balance >= Network::percent_mul(amount + increase_delegate_stake_amount, 9999)) && + (post_delegate_balance <= amount + increase_delegate_stake_amount) + ); }); } #[test] fn test_claim_removal_of_delegate_stake() { new_test_ext().execute_with(|| { - let _ = env_logger::builder().is_test(true).try_init(); - let subnet_path: Vec = "petals-team/StableBeluga2".into(); let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); let n_account = total_subnet_nodes + 1; - let _ = Balances::deposit_creating(&account(n_account), amount+500); + let _ = Balances::deposit_creating(&account(n_account), deposit_amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); @@ -521,8 +410,8 @@ fn test_claim_removal_of_delegate_stake() { // https://docs.openzeppelin.com/contracts/4.x/erc4626#inflation-attack // assert_eq!(delegate_balance, delegate_stake_to_be_added_as_shares); assert!( - (delegate_balance >= Network::percent_mul(amount, 990000000)) && - (delegate_balance < amount) + (delegate_balance >= Network::percent_mul(amount, 9999)) && + (delegate_balance <= amount) ); let epoch_length = EpochLength::get(); @@ -543,10 +432,10 @@ fn test_claim_removal_of_delegate_stake() { let post_balance = Balances::free_balance(&account(n_account)); assert_eq!(post_balance, balance); - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); + let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); assert_eq!(unbondings.len(), 1); let (ledger_epoch, ledger_balance) = unbondings.iter().next().unwrap(); - assert_eq!(*ledger_epoch, &epoch + DelegateStakeCooldownEpochs::get()); + assert_eq!(ledger_epoch, &epoch); assert!(*ledger_balance <= delegate_balance); assert_err!( @@ -570,83 +459,81 @@ fn test_claim_removal_of_delegate_stake() { assert_eq!(after_claim_balance, pre_claim_balance + *ledger_balance); - log::error!("starting_delegator_balance {:?}", starting_delegator_balance); - log::error!("after_claim_balance {:?}", after_claim_balance); - log::error!("post_balance {:?}", post_balance); - log::error!("ledger_balance {:?}", ledger_balance); + assert!( + (post_balance >= Network::percent_mul(starting_delegator_balance, 9999)) && + (post_balance <= starting_delegator_balance) + ); - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); + let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); assert_eq!(unbondings.len(), 0); }); } -// // #[test] -// // fn test_remove_to_delegate_stake_max_unlockings_per_epoch_err() { -// // new_test_ext().execute_with(|| { -// // let subnet_path: Vec = "petals-team/StableBeluga2".into(); -// // let deposit_amount: u128 = 10000000000000000000000; -// // let amount: u128 = 1000000000000000000000; +// #[test] +// fn test_remove_to_delegate_stake_max_unlockings_per_epoch_err() { +// new_test_ext().execute_with(|| { +// let subnet_path: Vec = "petals-team/StableBeluga2".into(); +// let deposit_amount: u128 = 10000000000000000000000; +// let amount: u128 = 1000000000000000000000; -// // let stake_amount: u128 = MinStakeBalance::::get(); +// build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); -// // build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); +// let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); +// let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); -// // let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); -// // let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); +// let n_account = total_subnet_nodes + 1; -// // let n_account = total_subnet_nodes + 1; +// let _ = Balances::deposit_creating(&account(n_account), deposit_amount); -// // let _ = Balances::deposit_creating(&account(n_account), amount+500); +// let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); -// // let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); +// let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); +// let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); -// // let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); -// // let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); +// let mut delegate_stake_to_be_added_as_shares = Network::convert_to_shares( +// amount, +// total_subnet_delegated_stake_shares, +// total_subnet_delegated_stake_balance +// ); -// // let mut delegate_stake_to_be_added_as_shares = Network::convert_to_shares( -// // amount, -// // total_subnet_delegated_stake_shares, -// // total_subnet_delegated_stake_balance -// // ); +// if total_subnet_delegated_stake_shares == 0 { +// delegate_stake_to_be_added_as_shares = delegate_stake_to_be_added_as_shares.saturating_sub(1000); +// } -// // if total_subnet_delegated_stake_shares == 0 { -// // delegate_stake_to_be_added_as_shares = delegate_stake_to_be_added_as_shares.saturating_sub(1000); -// // } +// System::set_block_number(System::block_number() + DelegateStakeCooldownEpochs::get() * EpochLength::get()); -// // System::set_block_number(System::block_number() + DelegateStakeCooldownEpochs::get() * EpochLength::get()); +// let starting_delegator_balance = Balances::free_balance(&account(n_account)); -// // let starting_delegator_balance = Balances::free_balance(&account(n_account)); +// assert_ok!( +// Network::add_to_delegate_stake( +// RuntimeOrigin::signed(account(n_account)), +// subnet_id, +// amount, +// ) +// ); -// // assert_ok!( -// // Network::add_to_delegate_stake( -// // RuntimeOrigin::signed(account(n_account)), -// // subnet_id, -// // amount, -// // ) -// // ); +// let delegate_shares = AccountSubnetDelegateStakeShares::::get(account(n_account), subnet_id); -// // let delegate_shares = AccountSubnetDelegateStakeShares::::get(account(n_account), subnet_id); +// assert_ok!( +// Network::remove_delegate_stake( +// RuntimeOrigin::signed(account(n_account)), +// subnet_id, +// delegate_shares/2, +// ) +// ); +// let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); +// assert_eq!(unbondings.len(), 1); -// // assert_ok!( -// // Network::remove_delegate_stake( -// // RuntimeOrigin::signed(account(n_account)), -// // subnet_id, -// // delegate_shares/2, -// // ) -// // ); -// // let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); -// // assert_eq!(unbondings.len(), 1); - -// // assert_err!( -// // Network::remove_delegate_stake( -// // RuntimeOrigin::signed(account(n_account)), -// // subnet_id, -// // delegate_shares/2, -// // ), -// // Error::::MaxUnlockingsPerEpochReached -// // ); -// // }); -// // } +// assert_err!( +// Network::remove_delegate_stake( +// RuntimeOrigin::signed(account(n_account)), +// subnet_id, +// delegate_shares/2, +// ), +// Error::::MaxUnlockingsPerEpochReached +// ); +// }); +// } #[test] fn test_remove_to_delegate_stake_max_unlockings_reached_err() { @@ -655,16 +542,14 @@ fn test_remove_to_delegate_stake_max_unlockings_reached_err() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); let n_account = total_subnet_nodes + 1; - let _ = Balances::deposit_creating(&account(n_account), amount+500); + let _ = Balances::deposit_creating(&account(n_account), deposit_amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); @@ -694,9 +579,9 @@ fn test_remove_to_delegate_stake_max_unlockings_reached_err() { ); let max_unlockings = MaxDelegateStakeUnlockings::get(); - for n in 1..max_unlockings+2 { + for n in 0..max_unlockings+1 { System::set_block_number(System::block_number() + EpochLength::get() + 1); - if n > max_unlockings { + if n+1 > max_unlockings { assert_err!( Network::remove_delegate_stake( RuntimeOrigin::signed(account(n_account)), @@ -713,8 +598,8 @@ fn test_remove_to_delegate_stake_max_unlockings_reached_err() { 1000, ) ); - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); - assert_eq!(unbondings.len() as u32, n); + let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); + assert_eq!(unbondings.len() as u32, n+1); } } }); @@ -725,19 +610,18 @@ fn test_switch_delegate_stake() { new_test_ext().execute_with(|| { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); let from_subnet_path: Vec = "petals-team/StableBeluga2".into(); - build_activated_subnet(from_subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(from_subnet_path.clone(), 0, 0, deposit_amount, amount); let from_subnet_id = SubnetPaths::::get(from_subnet_path.clone()).unwrap(); let to_subnet_path: Vec = "petals-team/StableBeluga3".into(); - build_activated_subnet(to_subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(to_subnet_path.clone(), 0, 0, deposit_amount, amount); let to_subnet_id = SubnetPaths::::get(to_subnet_path.clone()).unwrap(); let n_account = 255; - let _ = Balances::deposit_creating(&account(n_account), amount+500); + let _ = Balances::deposit_creating(&account(n_account), deposit_amount); let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(from_subnet_id); let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(from_subnet_id); @@ -792,6 +676,7 @@ fn test_switch_delegate_stake() { assert_eq!(from_delegate_shares, 0); let to_delegate_shares = AccountSubnetDelegateStakeShares::::get(account(n_account), to_subnet_id); + // assert_eq!(to_delegate_shares, delegate_stake_to_be_added_as_shares); assert_ne!(to_delegate_shares, 0); let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(to_subnet_id); @@ -807,8 +692,8 @@ fn test_switch_delegate_stake() { // Will lose about .01% of the transfer value on first transfer into a pool // The balance should be about ~99% of the ``from`` subnet to the ``to`` subnet assert!( - (to_delegate_balance >= Network::percent_mul(from_delegate_balance, 990000000)) && - (to_delegate_balance < from_delegate_balance) + (to_delegate_balance >= Network::percent_mul(from_delegate_balance, 9999)) && + (to_delegate_balance <= from_delegate_balance) ); }); } @@ -816,111 +701,108 @@ fn test_switch_delegate_stake() { #[test] fn test_switch_delegate_stake_not_enough_stake_err() { new_test_ext().execute_with(|| { - let _ = env_logger::builder().is_test(true).try_init(); - let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); let from_subnet_path: Vec = "petals-team/StableBeluga2".into(); - build_activated_subnet(from_subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(from_subnet_path.clone(), 0, 0, deposit_amount, amount); let from_subnet_id = SubnetPaths::::get(from_subnet_path.clone()).unwrap(); let to_subnet_path: Vec = "petals-team/StableBeluga3".into(); - build_activated_subnet(to_subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(to_subnet_path.clone(), 0, 0, deposit_amount, amount); let to_subnet_id = SubnetPaths::::get(to_subnet_path.clone()).unwrap(); - // let n_account = 255; - - // let _ = Balances::deposit_creating(&account(n_account), amount+500); - - // assert_err!( - // Network::transfer_delegate_stake( - // RuntimeOrigin::signed(account(n_account)), - // from_subnet_id, - // to_subnet_id, - // 0, - // ), - // Error::::NotEnoughStakeToWithdraw - // ); - - // assert_err!( - // Network::transfer_delegate_stake( - // RuntimeOrigin::signed(account(n_account)), - // from_subnet_id, - // to_subnet_id, - // 1000, - // ), - // Error::::NotEnoughStakeToWithdraw - // ); + let n_account = 255; + + let _ = Balances::deposit_creating(&account(n_account), deposit_amount); + + assert_err!( + Network::transfer_delegate_stake( + RuntimeOrigin::signed(account(n_account)), + from_subnet_id, + to_subnet_id, + 0, + ), + Error::::NotEnoughStakeToWithdraw + ); + + assert_err!( + Network::transfer_delegate_stake( + RuntimeOrigin::signed(account(n_account)), + from_subnet_id, + to_subnet_id, + 1000, + ), + Error::::NotEnoughStakeToWithdraw + ); }); } -// // #[test] -// // fn test_remove_to_delegate_stake_epochs_not_met_err() { -// // new_test_ext().execute_with(|| { -// // let subnet_path: Vec = "petals-team/StableBeluga2".into(); - -// // build_subnet(subnet_path.clone()); -// // let deposit_amount: u128 = 10000000000000000000000; -// // let amount: u128 = 1000000000000000000000; -// // let _ = Balances::deposit_creating(&account(0), amount+500); - -// // let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); - -// // let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); -// // let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); - -// // let mut delegate_stake_to_be_added_as_shares = Network::convert_to_shares( -// // amount, -// // total_subnet_delegated_stake_shares, -// // total_subnet_delegated_stake_balance -// // ); - -// // if total_subnet_delegated_stake_shares == 0 { -// // delegate_stake_to_be_added_as_shares = delegate_stake_to_be_added_as_shares.saturating_sub(1000); -// // } - -// // System::set_block_number(System::block_number() + DelegateStakeCooldownEpochs::get() * EpochLength::get()); - -// // assert_ok!( -// // Network::add_to_delegate_stake( -// // RuntimeOrigin::signed(account(0)), -// // subnet_id, -// // amount, -// // ) -// // ); - -// // let delegate_shares = AccountSubnetDelegateStakeShares::::get(account(0), subnet_id); -// // assert_eq!(delegate_shares, delegate_stake_to_be_added_as_shares); -// // assert_ne!(delegate_shares, 0); - -// // let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); -// // let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); - -// // let mut delegate_balance = Network::convert_to_balance( -// // delegate_shares, -// // total_subnet_delegated_stake_shares, -// // total_subnet_delegated_stake_balance -// // ); -// // // The first depositor will lose a percentage of their deposit depending on the size -// // // https://docs.openzeppelin.com/contracts/4.x/erc4626#inflation-attack -// // assert_eq!(delegate_balance, delegate_stake_to_be_added_as_shares); -// // assert!( -// // (delegate_balance >= Network::percent_mul(amount, 990000000)) && -// // (delegate_balance < amount) -// // ); - -// // // assert_err!( -// // // Network::remove_delegate_stake( -// // // RuntimeOrigin::signed(account(0)), -// // // subnet_id, -// // // delegate_shares, -// // // ), -// // // Error::::InsufficientCooldown -// // // ); -// // }); -// // } +// #[test] +// fn test_remove_to_delegate_stake_epochs_not_met_err() { +// new_test_ext().execute_with(|| { +// let subnet_path: Vec = "petals-team/StableBeluga2".into(); + +// build_subnet(subnet_path.clone()); +// let deposit_amount: u128 = 10000000000000000000000; +// let amount: u128 = 1000000000000000000000; +// let _ = Balances::deposit_creating(&account(0), deposit_amount); + +// let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); + +// let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); +// let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); + +// let mut delegate_stake_to_be_added_as_shares = Network::convert_to_shares( +// amount, +// total_subnet_delegated_stake_shares, +// total_subnet_delegated_stake_balance +// ); + +// if total_subnet_delegated_stake_shares == 0 { +// delegate_stake_to_be_added_as_shares = delegate_stake_to_be_added_as_shares.saturating_sub(1000); +// } + +// System::set_block_number(System::block_number() + DelegateStakeCooldownEpochs::get() * EpochLength::get()); + +// assert_ok!( +// Network::add_to_delegate_stake( +// RuntimeOrigin::signed(account(0)), +// subnet_id, +// amount, +// ) +// ); + +// let delegate_shares = AccountSubnetDelegateStakeShares::::get(account(0), subnet_id); +// assert_eq!(delegate_shares, delegate_stake_to_be_added_as_shares); +// assert_ne!(delegate_shares, 0); + +// let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(subnet_id); +// let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); + +// let mut delegate_balance = Network::convert_to_balance( +// delegate_shares, +// total_subnet_delegated_stake_shares, +// total_subnet_delegated_stake_balance +// ); +// // The first depositor will lose a percentage of their deposit depending on the size +// // https://docs.openzeppelin.com/contracts/4.x/erc4626#inflation-attack +// assert_eq!(delegate_balance, delegate_stake_to_be_added_as_shares); +// assert!( +// (delegate_balance >= Network::percent_mul(amount, 9999)) && +// (delegate_balance <= amount) +// ); + +// // assert_err!( +// // Network::remove_delegate_stake( +// // RuntimeOrigin::signed(account(0)), +// // subnet_id, +// // delegate_shares, +// // ), +// // Error::::InsufficientCooldown +// // ); +// }); +// } #[test] fn test_remove_delegate_stake_after_subnet_remove() { @@ -929,16 +811,14 @@ fn test_remove_delegate_stake_after_subnet_remove() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); let n_account = total_subnet_nodes + 1; - let _ = Balances::deposit_creating(&account(n_account), amount+500); + let _ = Balances::deposit_creating(&account(n_account), deposit_amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); @@ -983,15 +863,15 @@ fn test_remove_delegate_stake_after_subnet_remove() { // https://docs.openzeppelin.com/contracts/4.x/erc4626#inflation-attack // assert_eq!(delegate_balance, delegate_stake_to_be_added_as_shares); assert!( - (delegate_balance >= Network::percent_mul(amount, 990000000)) && - (delegate_balance < amount) + (delegate_balance >= Network::percent_mul(amount, 9999)) && + (delegate_balance <= amount) ); let epoch_length = EpochLength::get(); let cooldown_epochs = DelegateStakeCooldownEpochs::get(); assert_ok!( - Network::do_remove_subnet( + Network::deactivate_subnet( subnet_path.clone().into(), SubnetRemovalReason::MinSubnetDelegateStake, ) @@ -1012,10 +892,10 @@ fn test_remove_delegate_stake_after_subnet_remove() { let post_balance = Balances::free_balance(&account(n_account)); assert_eq!(post_balance, balance); - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); + let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); assert_eq!(unbondings.len(), 1); let (ledger_epoch, ledger_balance) = unbondings.iter().next().unwrap(); - assert_eq!(*ledger_epoch, &epoch + DelegateStakeCooldownEpochs::get()); + assert_eq!(ledger_epoch, &epoch); assert!(*ledger_balance <= delegate_balance); @@ -1037,222 +917,11 @@ fn test_remove_delegate_stake_after_subnet_remove() { let post_balance = Balances::free_balance(&account(n_account)); assert!( - (post_balance >= Network::percent_mul(starting_delegator_balance, 990000000)) && - (post_balance < starting_delegator_balance) + (post_balance >= Network::percent_mul(starting_delegator_balance, 9999)) && + (post_balance <= starting_delegator_balance) ); - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); + let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); assert_eq!(unbondings.len(), 0); }); -} - -#[test] -fn test_switch_delegate_stake_node_to_subnet() { - new_test_ext().execute_with(|| { - let subnet_path: Vec = "petals-team/StableBeluga2".into(); - let deposit_amount: u128 = 10000000000000000000000; - let amount: u128 = 1000000000000000000000; - - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet_with_delegator_rewards( - subnet_path.clone(), - 0, - 16, - deposit_amount, - stake_amount, - DEFAULT_DELEGATE_REWARD_RATE, - ); - - let from_subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); - let total_from_subnet_nodes = TotalSubnetNodes::::get(from_subnet_id); - - let to_subnet_path: Vec = "petals-team/StableBeluga3".into(); - - build_activated_subnet_with_delegator_rewards( - to_subnet_path.clone(), - 0, - 16, - deposit_amount, - stake_amount, - DEFAULT_DELEGATE_REWARD_RATE, - ); - - let to_subnet_id = SubnetPaths::::get(to_subnet_path.clone()).unwrap(); - - let _ = Balances::deposit_creating(&account(total_from_subnet_nodes+1), amount+500); - - assert_ok!( - Network::add_to_node_delegate_stake( - RuntimeOrigin::signed(account(total_from_subnet_nodes+1)), - from_subnet_id, - 1, - amount, - ) - ); - - let account_node_delegate_stake_shares = AccountNodeDelegateStakeShares::::get((account(total_from_subnet_nodes+1), from_subnet_id, 1)); - let total_node_delegate_stake_balance = TotalNodeDelegateStakeBalance::::get(from_subnet_id, 1); - let total_node_delegate_stake_shares = TotalNodeDelegateStakeShares::::get(from_subnet_id, 1); - - let account_node_delegate_stake_balance = Network::convert_to_balance( - account_node_delegate_stake_shares, - total_node_delegate_stake_shares, - total_node_delegate_stake_balance - ); - - assert!( - (account_node_delegate_stake_balance >= Network::percent_mul(amount, 990000000)) && - (account_node_delegate_stake_balance < amount) - ); - - let account_node_delegate_stake_shares_to_be_removed = account_node_delegate_stake_shares / 2; - - let expected_balance_to_be_removed = Network::convert_to_balance( - account_node_delegate_stake_shares_to_be_removed, - total_node_delegate_stake_shares, - total_node_delegate_stake_balance - ); - - let before_transfer_tensor = Balances::free_balance(&account(total_from_subnet_nodes+1)); - - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_from_subnet_nodes+1)); - assert_eq!(unbondings.len(), 0); - - assert_ok!( - Network::transfer_from_node_to_subnet( - RuntimeOrigin::signed(account(total_from_subnet_nodes+1)), - from_subnet_id, - 1, - to_subnet_id, - account_node_delegate_stake_shares_to_be_removed, - ) - ); - - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_from_subnet_nodes+1)); - assert_eq!(unbondings.len(), 0); - - let after_transfer_tensor = Balances::free_balance(&account(total_from_subnet_nodes+1)); - assert_eq!(after_transfer_tensor, before_transfer_tensor); - - let from_delegate_shares = AccountSubnetDelegateStakeShares::::get(account(total_from_subnet_nodes+1), from_subnet_id); - assert_eq!(from_delegate_shares, 0); - - let to_delegate_shares = AccountSubnetDelegateStakeShares::::get(account(total_from_subnet_nodes+1), to_subnet_id); - assert_ne!(to_delegate_shares, 0); - - let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(to_subnet_id); - let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(to_subnet_id); - - let mut to_delegate_balance = Network::convert_to_balance( - to_delegate_shares, - total_subnet_delegated_stake_shares, - total_subnet_delegated_stake_balance - ); - // The first depositor will lose a percentage of their deposit depending on the size - // https://docs.openzeppelin.com/contracts/4.x/erc4626#inflation-attack - // Will lose about .01% of the transfer value on first transfer into a pool - // The balance should be about ~99% of the ``from`` subnet to the ``to`` subnet - assert!( - (to_delegate_balance >= Network::percent_mul(expected_balance_to_be_removed, 990000000)) && - (to_delegate_balance < expected_balance_to_be_removed) - ); - }); -} - -#[test] -fn test_switch_delegate_stake_subnet_to_node() { - new_test_ext().execute_with(|| { - let deposit_amount: u128 = 10000000000000000000000; - let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - let from_subnet_path: Vec = "petals-team/StableBeluga2".into(); - build_activated_subnet(from_subnet_path.clone(), 0, 16, deposit_amount, stake_amount); - let from_subnet_id = SubnetPaths::::get(from_subnet_path.clone()).unwrap(); - - let to_subnet_path: Vec = "petals-team/StableBeluga3".into(); - build_activated_subnet(to_subnet_path.clone(), 0, 16, deposit_amount, stake_amount); - let to_subnet_id = SubnetPaths::::get(to_subnet_path.clone()).unwrap(); - - let n_account = 255; - - let _ = Balances::deposit_creating(&account(n_account), amount+500); - - let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(from_subnet_id); - let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(from_subnet_id); - - let mut delegate_stake_to_be_added_as_shares = Network::convert_to_shares( - amount, - total_subnet_delegated_stake_shares, - total_subnet_delegated_stake_balance - ); - - if total_subnet_delegated_stake_shares == 0 { - delegate_stake_to_be_added_as_shares = delegate_stake_to_be_added_as_shares.saturating_sub(1000); - } - - System::set_block_number(System::block_number() + DelegateStakeCooldownEpochs::get() * EpochLength::get()); - - let starting_delegator_balance = Balances::free_balance(&account(n_account)); - - assert_ok!( - Network::add_to_delegate_stake( - RuntimeOrigin::signed(account(n_account)), - from_subnet_id, - amount, - ) - ); - - let delegate_shares = AccountSubnetDelegateStakeShares::::get(account(n_account), from_subnet_id); - assert_eq!(delegate_shares, delegate_stake_to_be_added_as_shares); - assert_ne!(delegate_shares, 0); - - let total_subnet_delegated_stake_shares = TotalSubnetDelegateStakeShares::::get(from_subnet_id); - let total_subnet_delegated_stake_balance = TotalSubnetDelegateStakeBalance::::get(from_subnet_id); - - let mut from_delegate_balance = Network::convert_to_balance( - delegate_shares, - total_subnet_delegated_stake_shares, - total_subnet_delegated_stake_balance - ); - // The first depositor will lose a percentage of their deposit depending on the size - // https://docs.openzeppelin.com/contracts/4.x/erc4626#inflation-attack - - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); - assert_eq!(unbondings.len(), 0); - let before_transfer_tensor = Balances::free_balance(&account(n_account)); - - assert_ok!( - Network::transfer_from_subnet_to_node( - RuntimeOrigin::signed(account(n_account)), - from_subnet_id, - to_subnet_id, - 1, - delegate_shares, - ) - ); - - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(n_account)); - assert_eq!(unbondings.len(), 0); - let after_transfer_tensor = Balances::free_balance(&account(n_account)); - assert_eq!(after_transfer_tensor, before_transfer_tensor); - - let account_node_delegate_stake_shares = AccountNodeDelegateStakeShares::::get((account(n_account), to_subnet_id, 1)); - let total_node_delegate_stake_balance = TotalNodeDelegateStakeBalance::::get(to_subnet_id, 1); - let total_node_delegate_stake_shares = TotalNodeDelegateStakeShares::::get(to_subnet_id, 1); - - let account_node_delegate_stake_balance = Network::convert_to_balance( - account_node_delegate_stake_shares, - total_node_delegate_stake_shares, - total_node_delegate_stake_balance - ); - - assert_ne!(account_node_delegate_stake_balance, 0); - - assert!( - (account_node_delegate_stake_balance >= Network::percent_mul(from_delegate_balance, 990000000)) && - (account_node_delegate_stake_balance < from_delegate_balance) - ); - }); -} +} \ No newline at end of file diff --git a/pallets/network/src/tests/incentives_protocol.rs b/pallets/network/src/tests/incentives_protocol.rs index 8178831..74470bb 100644 --- a/pallets/network/src/tests/incentives_protocol.rs +++ b/pallets/network/src/tests/incentives_protocol.rs @@ -24,17 +24,14 @@ use crate::{ MaxSubnetNodePenalties, SubnetNodePenalties, RegistrationSubnetData, + BaseRewardPerMB, SubnetRemovalReason, MaxSubnetPenaltyCount, MinSubnetRegistrationBlocks, - SubnetActivationEnactmentBlocks, + SubnetActivationEnactmentPeriod, HotkeySubnetNodeId, SubnetNodeIdHotkey, - PeerIdSubnetNode, - MinStakeBalance, - SubnetOwnerPercentage, - SubnetNodesData, - TotalNodeDelegateStakeShares, + SubnetNodeAccount, }; use frame_support::BoundedVec; use strum::IntoEnumIterator; @@ -72,9 +69,7 @@ fn test_validate() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 12, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 12, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -84,11 +79,11 @@ fn test_validate() { let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - Network::do_epoch_preliminaries(System::block_number(), epoch, epoch_length); + Network::do_epoch_preliminaries(System::block_number(), epoch as u32, epoch_length); let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); - let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch); + let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch as u32); assert!(validator_id != None, "Validator is None"); let hotkey = SubnetNodeIdHotkey::::get(subnet_id, validator_id.unwrap()).unwrap(); @@ -103,7 +98,7 @@ fn test_validate() { ) ); - let submission = SubnetRewardsSubmission::::get(subnet_id, epoch).unwrap(); + let submission = SubnetRewardsSubmission::::get(subnet_id, epoch as u32).unwrap(); assert_eq!(submission.validator_id, validator_id.unwrap(), "Err: validator"); assert_eq!(submission.data.len(), subnet_node_data_vec.len(), "Err: data len"); @@ -113,7 +108,7 @@ fn test_validate() { assert_err!( Network::validate( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_data_vec.clone(), None, @@ -130,9 +125,7 @@ fn test_validate_peer_with_0_score() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -140,7 +133,7 @@ fn test_validate_peer_with_0_score() { let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - Network::do_epoch_preliminaries(System::block_number(), epoch, epoch_length); + Network::do_epoch_preliminaries(System::block_number(), epoch as u32, epoch_length); let mut subnet_node_data_vec: Vec = Vec::new(); for n in 0..total_subnet_nodes { @@ -156,21 +149,21 @@ fn test_validate_peer_with_0_score() { subnet_node_data_vec.push(peer_subnet_node_data); } - let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch); + let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch as u32); assert!(validator_id != None, "Validator is None"); let hotkey = SubnetNodeIdHotkey::::get(subnet_id, validator_id.unwrap()).unwrap(); assert_ok!( Network::validate( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_data_vec.clone(), None, ) ); - let submission = SubnetRewardsSubmission::::get(subnet_id, epoch).unwrap(); + let submission = SubnetRewardsSubmission::::get(subnet_id, epoch as u32).unwrap(); let data = submission.data; // peer should be removed due to 0 score @@ -189,9 +182,7 @@ fn test_validate_invalid_validator() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -200,17 +191,17 @@ fn test_validate_invalid_validator() { let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - Network::do_epoch_preliminaries(System::block_number(), epoch, epoch_length); + Network::do_epoch_preliminaries(System::block_number(), epoch as u32, epoch_length); let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); - let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch); + let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch as u32); assert!(validator_id != None, "Validator is None"); let mut validator = SubnetNodeIdHotkey::::get(subnet_id, validator_id.unwrap()).unwrap(); - if validator.clone() == account(1) { - validator = account(2); + if validator.clone() == account(0) { + validator = account(1); } assert_err!( @@ -234,9 +225,7 @@ fn test_attest() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -246,13 +235,12 @@ fn test_attest() { let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - Network::do_epoch_preliminaries(System::block_number(), epoch, epoch_length); + Network::do_epoch_preliminaries(System::block_number(), epoch as u32, epoch_length); let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); - let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch); + let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch as u32); assert!(validator_id != None, "Validator is None"); - assert!(validator_id != Some(0), "Validator is 0"); let mut validator = SubnetNodeIdHotkey::::get(subnet_id, validator_id.unwrap()).unwrap(); @@ -266,9 +254,8 @@ fn test_attest() { ); // Attest - for n in 1..total_subnet_nodes+1 { - let attestor = SubnetNodeIdHotkey::::get(subnet_id, n).unwrap(); - if attestor == validator.clone() { + for n in 0..total_subnet_nodes { + if account(n) == validator.clone() { continue } assert_ok!( @@ -279,30 +266,18 @@ fn test_attest() { ); } - let submission = SubnetRewardsSubmission::::get(subnet_id, epoch).unwrap(); + let submission = SubnetRewardsSubmission::::get(subnet_id, epoch as u32).unwrap(); assert_eq!(submission.validator_id, validator_id.unwrap()); assert_eq!(submission.data.len(), subnet_node_data_vec.len()); assert_eq!(submission.attests.len(), total_subnet_nodes as usize); - - // for n in 1..total_subnet_nodes+1 { - // let attestor = SubnetNodeIdHotkey::::get(subnet_id, n).unwrap(); - // if attestor == validator.clone() { - // assert_ne!(submission.attests.get(&n), None); - // assert_eq!(submission.attests.get(&n), Some(&System::block_number())); - // } else { - // assert_ne!(submission.attests.get(&n), None); - // assert_eq!(submission.attests.get(&n), Some(&System::block_number())); - // } - // } - - // if account(1) == validator.clone() { - // assert_ne!(submission.attests.get(&validator_id.unwrap()), None); - // assert_eq!(submission.attests.get(&validator_id.unwrap()), Some(&System::block_number())); - // } else { - // assert_ne!(submission.attests.get(&2), None); - // assert_eq!(submission.attests.get(&2), Some(&System::block_number())); - // } + if account(0) == validator.clone() { + assert_ne!(submission.attests.get(&0), None); + assert_eq!(submission.attests.get(&0), Some(&System::block_number())); + } else { + assert_ne!(submission.attests.get(&1), None); + assert_eq!(submission.attests.get(&1), Some(&System::block_number())); + } }); } @@ -314,9 +289,7 @@ fn test_attest_remove_exiting_attester() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -326,17 +299,17 @@ fn test_attest_remove_exiting_attester() { let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - Network::do_epoch_preliminaries(System::block_number(), epoch, epoch_length); + Network::do_epoch_preliminaries(System::block_number(), epoch as u32, epoch_length); let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); // --- Get validator - let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch).unwrap(); + let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch as u32).unwrap(); let mut validator = SubnetNodeIdHotkey::::get(subnet_id, validator_id).unwrap(); assert_ok!( Network::validate( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_data_vec.clone(), None, @@ -344,9 +317,8 @@ fn test_attest_remove_exiting_attester() { ); // Attest - for n in 1..total_subnet_nodes+1 { - let attestor = SubnetNodeIdHotkey::::get(subnet_id, n).unwrap(); - if attestor == validator.clone() { + for n in 0..total_subnet_nodes { + if account(n) == validator.clone() { continue } assert_ok!( @@ -356,44 +328,20 @@ fn test_attest_remove_exiting_attester() { ) ); } - - // for n in 1..total_subnet_nodes+1 { - // if account(n) == validator.clone() { - // continue - // } - // assert_ok!( - // Network::attest( - // RuntimeOrigin::signed(account(n)), - // subnet_id, - // ) - // ); - // } - let submission = SubnetRewardsSubmission::::get(subnet_id, epoch).unwrap(); + let submission = SubnetRewardsSubmission::::get(subnet_id, epoch as u32).unwrap(); assert_eq!(submission.validator_id, validator_id); assert_eq!(submission.data.len(), subnet_node_data_vec.len()); assert_eq!(submission.attests.len(), total_subnet_nodes as usize); - - for n in 1..total_subnet_nodes+1 { - let attestor = SubnetNodeIdHotkey::::get(subnet_id, n).unwrap(); - if attestor == validator.clone() { - assert_ne!(submission.attests.get(&n), None); - assert_eq!(submission.attests.get(&n), Some(&System::block_number())); - } else { - assert_ne!(submission.attests.get(&n), None); - assert_eq!(submission.attests.get(&n), Some(&System::block_number())); - } + if account(0) == validator.clone() { + assert_ne!(submission.attests.get(&0), None); + assert_eq!(submission.attests.get(&0), Some(&System::block_number())); + } else { + assert_ne!(submission.attests.get(&1), None); + assert_eq!(submission.attests.get(&1), Some(&System::block_number())); } - // if account(1) == validator.clone() { - // assert_ne!(submission.attests.get(&0), None); - // assert_eq!(submission.attests.get(&0), Some(&System::block_number())); - // } else { - // assert_ne!(submission.attests.get(&1), None); - // assert_eq!(submission.attests.get(&1), Some(&System::block_number())); - // } - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); assert_ok!( Network::remove_subnet_node( @@ -405,7 +353,7 @@ fn test_attest_remove_exiting_attester() { post_remove_subnet_node_ensures(1, subnet_id); - let submission = SubnetRewardsSubmission::::get(subnet_id, epoch).unwrap(); + let submission = SubnetRewardsSubmission::::get(subnet_id, epoch as u32).unwrap(); assert_eq!(submission.attests.len(), (total_subnet_nodes - 1) as usize); assert_eq!(submission.attests.get(&subnet_node_id), None); }); @@ -418,9 +366,7 @@ fn test_attest_no_submission_err() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -430,12 +376,12 @@ fn test_attest_no_submission_err() { let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - Network::do_epoch_preliminaries(System::block_number(), epoch, epoch_length); + Network::do_epoch_preliminaries(System::block_number(), epoch as u32, epoch_length); let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); // --- Get validator - let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch).unwrap(); + let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch as u32).unwrap(); let mut validator = SubnetNodeIdHotkey::::get(subnet_id, validator_id).unwrap(); assert_err!( @@ -455,9 +401,7 @@ fn test_attest_already_attested_err() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -467,11 +411,11 @@ fn test_attest_already_attested_err() { let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - Network::do_epoch_preliminaries(System::block_number(), epoch, epoch_length); + Network::do_epoch_preliminaries(System::block_number(), epoch as u32, epoch_length); let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); - let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch).unwrap(); + let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch as u32).unwrap(); let mut validator = SubnetNodeIdHotkey::::get(subnet_id, validator_id).unwrap(); assert_ok!( @@ -484,7 +428,7 @@ fn test_attest_already_attested_err() { ); // Attest - for n in 1..total_subnet_nodes+1 { + for n in 0..total_subnet_nodes { if account(n) == validator.clone() { continue } @@ -496,7 +440,7 @@ fn test_attest_already_attested_err() { ); } - let submission = SubnetRewardsSubmission::::get(subnet_id, epoch).unwrap(); + let submission = SubnetRewardsSubmission::::get(subnet_id, epoch as u32).unwrap(); assert_eq!(submission.validator_id, validator_id); assert_eq!(submission.data.len(), subnet_node_data_vec.len()); @@ -504,7 +448,7 @@ fn test_attest_already_attested_err() { assert_eq!(sum, DEFAULT_SCORE * total_subnet_nodes as u128); assert_eq!(submission.attests.len(), total_subnet_nodes as usize); - for n in 1..total_subnet_nodes+1 { + for n in 0..total_subnet_nodes { if account(n) == validator.clone() { continue } @@ -512,7 +456,7 @@ fn test_attest_already_attested_err() { assert_eq!(submission.attests.get(&n), Some(&System::block_number())); } - for n in 1..total_subnet_nodes+1 { + for n in 0..total_subnet_nodes { if account(n) == validator.clone() { continue } @@ -550,9 +494,7 @@ fn test_reward_subnets() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -562,13 +504,13 @@ fn test_reward_subnets() { let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - Network::do_epoch_preliminaries(System::block_number(), epoch, epoch_length); + Network::do_epoch_preliminaries(System::block_number(), epoch as u32, epoch_length); let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); // --- Get validator - let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch).unwrap(); + let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch as u32).unwrap(); let mut validator = SubnetNodeIdHotkey::::get(subnet_id, validator_id).unwrap(); assert_ok!( @@ -581,7 +523,7 @@ fn test_reward_subnets() { ); // Attest - for n in 1..total_subnet_nodes+1 { + for n in 0..total_subnet_nodes { if account(n) == validator.clone() { continue } @@ -593,191 +535,129 @@ fn test_reward_subnets() { ); } - Network::reward_subnets(System::block_number(), epoch); + Network::reward_subnets(System::block_number(), epoch as u32); }); } #[test] -fn test_reward_subnets_v2() { +fn test_reward_subnets_remove_subnet_node() { new_test_ext().execute_with(|| { + let max_absent = MaxSubnetNodePenalties::::get(); let subnet_path: Vec = "petals-team/StableBeluga2".into(); let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 15, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - // increase_epochs(1); + increase_epochs(1); let epoch_length = EpochLength::get(); - let epoch = System::block_number() / epoch_length; - - Network::do_epoch_preliminaries(System::block_number(), epoch, epoch_length); - - - let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); - // --- Get validator - let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch).unwrap(); - let mut validator = SubnetNodeIdHotkey::::get(subnet_id, validator_id).unwrap(); - - assert_ok!( - Network::validate( - RuntimeOrigin::signed(validator.clone()), - subnet_id, - subnet_node_data_vec.clone(), - None, - ) - ); - - // Attest - for n in 1..total_subnet_nodes+1 { - if account(n) == validator.clone() { - continue - } + // shift node classes + // validate n-1 + // attest n-1 + // Simulate epochs + for num in 0..max_absent+1 { + let epoch = System::block_number() / epoch_length; + + let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes-1); + + // --- Insert validator + SubnetRewardsValidator::::insert(subnet_id, epoch as u32, 0); + + // validate without n-1 assert_ok!( - Network::attest( - RuntimeOrigin::signed(account(n)), + Network::validate( + RuntimeOrigin::signed(account(0)), subnet_id, + subnet_node_data_vec.clone(), + None, ) ); - } - - Network::reward_subnets_v2(System::block_number(), epoch); - }); -} - - -// #[test] -// fn test_reward_subnets_remove_subnet_node() { -// new_test_ext().execute_with(|| { -// let max_absent = MaxSubnetNodePenalties::::get(); -// let subnet_path: Vec = "petals-team/StableBeluga2".into(); -// let deposit_amount: u128 = 10000000000000000000000; -// let amount: u128 = 1000000000000000000000; - -// let stake_amount: u128 = MinStakeBalance::::get(); - -// build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + + // Attest without n-1 + for n in 1..total_subnet_nodes-1 { + assert_ok!( + Network::attest( + RuntimeOrigin::signed(account(n)), + subnet_id, + ) + ); + } + + // --- Get submission data and count before node is removed + // Check rewards + // Ensure only attestors, validators, and validated get rewards + let submission = SubnetRewardsSubmission::::get(subnet_id, epoch as u32).unwrap(); + + // --- Any removals impact the following epochs attestation data unless removed ahead of rewards + let submission_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys( + subnet_id, + &SubnetNodeClass::Validator, + epoch as u64 + ); -// let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); -// let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); + let submission_nodes_count = submission_nodes.len() as u128; -// increase_epochs(1); + Network::reward_subnets(System::block_number(), epoch as u32); + let node_absent_count = SubnetNodePenalties::::get(subnet_id, total_subnet_nodes-1); -// let epoch_length = EpochLength::get(); + if num + 1 > max_absent { + post_remove_subnet_node_ensures(total_subnet_nodes-1, subnet_id); + // when node is removed they're SubnetNodePenalties is reset to zero + assert_eq!(node_absent_count, 0); + } else { + assert_eq!(node_absent_count, num+1); + } -// // shift node classes -// // validate n-1 -// // attest n-1 -// // Simulate epochs -// for num in 0..max_absent+1 { -// let epoch = System::block_number() / epoch_length; - -// let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes-1); - -// // --- Insert validator -// SubnetRewardsValidator::::insert(subnet_id, epoch, 1); -// let validator = SubnetNodeIdHotkey::::get(subnet_id, 1).unwrap(); - -// // validate without n-1 -// assert_ok!( -// Network::validate( -// RuntimeOrigin::signed(account(1)), -// subnet_id, -// subnet_node_data_vec.clone(), -// None, -// ) -// ); - -// // Attest without n-1 -// for n in 1..total_subnet_nodes { -// let attestor = SubnetNodeIdHotkey::::get(subnet_id, n).unwrap(); -// if attestor == validator.clone() { -// continue -// } -// assert_ok!( -// Network::attest( -// RuntimeOrigin::signed(account(n)), -// subnet_id, -// ) -// ); -// } + let base_reward_per_mb: u128 = BaseRewardPerMB::::get(); + let delegate_stake_rewards_percentage: u128 = DelegateStakeRewardsPercentage::::get(); + let overall_subnet_reward: u128 = Network::percent_mul(base_reward_per_mb, DEFAULT_MEM_MB); + let delegate_stake_reward: u128 = Network::percent_mul(overall_subnet_reward, delegate_stake_rewards_percentage); + let subnet_reward: u128 = overall_subnet_reward.saturating_sub(delegate_stake_reward); -// // --- Get submission data and count before node is removed -// // Check rewards -// // Ensure only attestors, validators, and validated get rewards -// let submission = SubnetRewardsSubmission::::get(subnet_id, epoch).unwrap(); - -// // --- Any removals impact the following epochs attestation data unless removed ahead of rewards -// let submission_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys( -// subnet_id, -// &SubnetNodeClass::Validator, -// epoch -// ); - -// let submission_nodes_count = submission_nodes.len() as u128; - -// Network::reward_subnets(System::block_number(), epoch); -// let node_absent_count = SubnetNodePenalties::::get(subnet_id, total_subnet_nodes); - -// if num + 1 > max_absent { -// post_remove_subnet_node_ensures(total_subnet_nodes, subnet_id); -// // when node is removed they're SubnetNodePenalties is reset to zero -// assert_eq!(node_absent_count, 0); -// } else { -// assert_eq!(node_absent_count, num+1); -// } - -// let base_reward_per_mb: u128 = BaseRewardPerMB::::get(); -// let delegate_stake_rewards_percentage: u128 = DelegateStakeRewardsPercentage::::get(); -// let overall_subnet_reward: u128 = Network::percent_mul(base_reward_per_mb, DEFAULT_MEM_MB); -// let delegate_stake_reward: u128 = Network::percent_mul(overall_subnet_reward, delegate_stake_rewards_percentage); -// let subnet_reward: u128 = overall_subnet_reward.saturating_sub(delegate_stake_reward); - -// let sum = submission.data.iter().fold(0, |acc, x| acc + x.score); + let sum = submission.data.iter().fold(0, |acc, x| acc + x.score); -// let reward_ratio: u128 = Network::percent_div(DEFAULT_SCORE, sum); -// let account_reward: u128 = Network::percent_mul(reward_ratio, subnet_reward); + let reward_ratio: u128 = Network::percent_div(DEFAULT_SCORE, sum); + let account_reward: u128 = Network::percent_mul(reward_ratio, subnet_reward); -// let base_reward = BaseValidatorReward::::get(); + let base_reward = BaseValidatorReward::::get(); -// let submission_attestations: u128 = submission.attests.len() as u128; -// let attestation_percentage: u128 = Network::percent_div(submission_attestations, submission_nodes_count); - -// // check each subnet nodes balance increased -// for n in 1..total_subnet_nodes+1 { -// if n == 1 { -// // validator -// let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); -// let validator_reward: u128 = Network::percent_mul(base_reward, attestation_percentage); -// assert_eq!(stake_balance, amount + (account_reward * (num+1) as u128) + (validator_reward * (num+1) as u128)); -// } else if n == total_subnet_nodes { -// // node removed | should have no rewards -// let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); -// assert!(stake_balance == amount, "Invalid subnet node staking rewards"); -// } else { -// // attestors -// let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); -// assert!(stake_balance == amount + (account_reward * (num+1) as u128), "Invalid subnet node staking rewards"); -// } -// } - -// increase_epochs(1); -// } - -// // node should be removed -// let subnet_node_id = HotkeySubnetNodeId::::try_get(subnet_id, account(total_subnet_nodes)); -// assert_eq!(subnet_node_id, Err(())); - -// let subnet_node_account = PeerIdSubnetNode::::try_get(subnet_id, peer(total_subnet_nodes)); -// assert_eq!(subnet_node_account, Err(())); -// }); -// } + let submission_attestations: u128 = submission.attests.len() as u128; + let attestation_percentage: u128 = Network::percent_div(submission_attestations, submission_nodes_count); + + // check each subnet nodes balance increased + for n in 0..total_subnet_nodes { + if n == 0 { + // validator + let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); + let validator_reward: u128 = Network::percent_mul(base_reward, attestation_percentage); + assert_eq!(stake_balance, amount + (account_reward * (num+1) as u128) + (validator_reward * (num+1) as u128)); + } else if n == total_subnet_nodes - 1 { + // node removed | should have no rewards + let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); + assert!(stake_balance == amount, "Invalid subnet node staking rewards"); + } else { + // attestors + let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); + assert!(stake_balance == amount + (account_reward * (num+1) as u128), "Invalid subnet node staking rewards"); + } + } + + increase_epochs(1); + } + + // node should be removed + let subnet_node_id = HotkeySubnetNodeId::::try_get(subnet_id, account(total_subnet_nodes - 1)); + assert_eq!(subnet_node_id, Err(())); + + let subnet_node_account = SubnetNodeAccount::::try_get(subnet_id, peer(total_subnet_nodes - 1)); + assert_eq!(subnet_node_account, Err(())); + }); +} // // #[test] // // fn test_reward_subnets_absent_node_increment_decrement() { @@ -802,7 +682,7 @@ fn test_reward_subnets_v2() { // // let epoch = System::block_number() / epoch_length; // // // --- Insert validator -// // SubnetRewardsValidator::::insert(subnet_id, epoch, account(1)); +// // SubnetRewardsValidator::::insert(subnet_id, epoch as u32, account(0)); // // if num % 2 == 0 { // // // increment on even epochs @@ -811,7 +691,7 @@ fn test_reward_subnets_v2() { // // assert_ok!( // // Network::validate( -// // RuntimeOrigin::signed(account(1)), +// // RuntimeOrigin::signed(account(0)), // // subnet_id, // // subnet_node_data_vec.clone() // // ) @@ -827,7 +707,7 @@ fn test_reward_subnets_v2() { // // ); // // } -// // Network::reward_subnets(System::block_number(), epoch); +// // Network::reward_subnets(System::block_number(), epoch as u32); // // let node_absent_count = SubnetNodePenalties::::get(subnet_id, (total_subnet_nodes-1)); // // assert_eq!(node_absent_count, 1); @@ -837,7 +717,7 @@ fn test_reward_subnets_v2() { // // assert_ok!( // // Network::validate( -// // RuntimeOrigin::signed(account(1)), +// // RuntimeOrigin::signed(account(0)), // // subnet_id, // // subnet_node_data_vec.clone() // // ) @@ -853,7 +733,7 @@ fn test_reward_subnets_v2() { // // ); // // } -// // Network::reward_subnets(System::block_number(), epoch); +// // Network::reward_subnets(System::block_number(), epoch as u32); // // let node_absent_count = SubnetNodePenalties::::get(subnet_id, (total_subnet_nodes-1)); // // assert_eq!(node_absent_count, 0); @@ -864,158 +744,102 @@ fn test_reward_subnets_v2() { // // }); // // } -// #[test] -// fn test_reward_subnets_check_balances() { -// new_test_ext().execute_with(|| { -// let max_absent = MaxSubnetNodePenalties::::get(); - -// let subnet_path: Vec = "petals-team/StableBeluga2".into(); -// let deposit_amount: u128 = 10000000000000000000000; -// let amount: u128 = 1000000000000000000000; - -// build_activated_subnet(subnet_path.clone(), 0, 15, deposit_amount, amount); - -// let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); -// let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - -// increase_epochs(1); - -// let epoch_length = EpochLength::get(); -// let epoch = System::block_number() / epoch_length; - -// let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); - -// // --- Insert validator -// SubnetRewardsValidator::::insert(subnet_id, epoch, 1); -// let validator = SubnetNodeIdHotkey::::get(subnet_id, 1).unwrap(); - -// // validate without n-1 -// assert_ok!( -// Network::validate( -// RuntimeOrigin::signed(account(1)), -// subnet_id, -// subnet_node_data_vec.clone(), -// None, -// ) -// ); - -// // Attest without n-1 -// for n in 1..total_subnet_nodes { -// let attestor = SubnetNodeIdHotkey::::get(subnet_id, n).unwrap(); -// if attestor == validator.clone() { -// continue -// } -// assert_ok!( -// Network::attest( -// RuntimeOrigin::signed(account(n)), -// subnet_id, -// ) -// ); -// } - -// // --- Get submission data and count before node is removed -// // Check rewards -// // Ensure only attestors, validators, and validated get rewards -// let submission = SubnetRewardsSubmission::::get(subnet_id, epoch).unwrap(); - -// // --- Any removals impact the following epochs attestation data unless removed ahead of rewards -// let submission_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Validator, epoch); -// let submission_nodes_count = submission_nodes.len() as u128; - -// Network::reward_subnets(System::block_number(), epoch); -// let node_absent_count = SubnetNodePenalties::::get(subnet_id, total_subnet_nodes-1); -// assert_eq!(node_absent_count, 0); - -// let base_reward_per_mb: u128 = BaseRewardPerMB::::get(); -// let delegate_stake_rewards_percentage: u128 = DelegateStakeRewardsPercentage::::get(); -// let overall_subnet_reward: u128 = Network::percent_mul(base_reward_per_mb, DEFAULT_MEM_MB); -// let delegate_stake_reward: u128 = Network::percent_mul(overall_subnet_reward, delegate_stake_rewards_percentage); -// let subnet_reward: u128 = overall_subnet_reward.saturating_sub(delegate_stake_reward); - -// let sum = submission.data.iter().fold(0, |acc, x| acc + x.score); -// let reward_ratio: u128 = Network::percent_div(DEFAULT_SCORE, sum); -// let account_reward: u128 = Network::percent_mul(reward_ratio, subnet_reward); - -// let base_reward = BaseValidatorReward::::get(); - -// let submission_attestations: u128 = submission.attests.len() as u128; -// let attestation_percentage: u128 = Network::percent_div(submission_attestations, submission_nodes_count); - -// // check each subnet nodes balance increased -// for n in 1..total_subnet_nodes { -// if n == 1 { -// // validator -// let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); -// let validator_reward: u128 = Network::percent_mul(base_reward, attestation_percentage); -// assert_eq!(stake_balance, amount + (account_reward as u128) + (validator_reward as u128)); -// } else { -// // attestors -// let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); -// assert_eq!(stake_balance, amount + (account_reward as u128)); -// } -// } -// }); -// } - #[test] -fn test_reward_subnets_validator_slash() { +fn test_reward_subnets_check_balances() { new_test_ext().execute_with(|| { + let max_absent = MaxSubnetNodePenalties::::get(); + let subnet_path: Vec = "petals-team/StableBeluga2".into(); let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 15, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 15, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - // increase_epochs(1); + increase_epochs(1); let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - Network::do_epoch_preliminaries(System::block_number(), epoch, epoch_length); - let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); + + // --- Insert validator + SubnetRewardsValidator::::insert(subnet_id, epoch as u32, 0); - // --- Get validator - let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch).unwrap(); - let mut validator = SubnetNodeIdHotkey::::get(subnet_id, validator_id).unwrap(); - + // validate without n-1 assert_ok!( Network::validate( - RuntimeOrigin::signed(validator.clone()), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_data_vec.clone(), None, ) ); - // No attests to ensure validator is slashed + // Attest without n-1 + for n in 1..total_subnet_nodes { + assert_ok!( + Network::attest( + RuntimeOrigin::signed(account(n)), + subnet_id, + ) + ); + } - let before_slash_validator_stake_balance: u128 = AccountSubnetStake::::get(&validator.clone(), subnet_id); + // --- Get submission data and count before node is removed + // Check rewards + // Ensure only attestors, validators, and validated get rewards + let submission = SubnetRewardsSubmission::::get(subnet_id, epoch as u32).unwrap(); - Network::reward_subnets(System::block_number(), epoch); + // --- Any removals impact the following epochs attestation data unless removed ahead of rewards + let submission_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Validator, epoch); + let submission_nodes_count = submission_nodes.len() as u128; - let slashed_validator_stake_balance: u128 = AccountSubnetStake::::get(&validator.clone(), subnet_id); + Network::reward_subnets(System::block_number(), epoch as u32); + let node_absent_count = SubnetNodePenalties::::get(subnet_id, total_subnet_nodes-1); + assert_eq!(node_absent_count, 0); + + let base_reward_per_mb: u128 = BaseRewardPerMB::::get(); + let delegate_stake_rewards_percentage: u128 = DelegateStakeRewardsPercentage::::get(); + let overall_subnet_reward: u128 = Network::percent_mul(base_reward_per_mb, DEFAULT_MEM_MB); + let delegate_stake_reward: u128 = Network::percent_mul(overall_subnet_reward, delegate_stake_rewards_percentage); + let subnet_reward: u128 = overall_subnet_reward.saturating_sub(delegate_stake_reward); - // Ensure validator was slashed - assert!(before_slash_validator_stake_balance > slashed_validator_stake_balance, "Validator was not slashed") + let sum = submission.data.iter().fold(0, |acc, x| acc + x.score); + let reward_ratio: u128 = Network::percent_div(DEFAULT_SCORE, sum); + let account_reward: u128 = Network::percent_mul(reward_ratio, subnet_reward); + + let base_reward = BaseValidatorReward::::get(); + + let submission_attestations: u128 = submission.attests.len() as u128; + let attestation_percentage: u128 = Network::percent_div(submission_attestations, submission_nodes_count); + + // check each subnet nodes balance increased + for n in 0..total_subnet_nodes { + if n == 0 { + // validator + let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); + let validator_reward: u128 = Network::percent_mul(base_reward, attestation_percentage); + assert_eq!(stake_balance, amount + (account_reward as u128) + (validator_reward as u128)); + } else { + // attestors + let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); + assert!(stake_balance == amount + (account_reward as u128), "Invalid subnet node staking rewards") + } + } }); } #[test] -fn test_reward_subnets_v2_validator_slash() { +fn test_reward_subnets_validator_slash() { new_test_ext().execute_with(|| { let subnet_path: Vec = "petals-team/StableBeluga2".into(); let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 15, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 15, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1025,12 +849,12 @@ fn test_reward_subnets_v2_validator_slash() { let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - Network::do_epoch_preliminaries(System::block_number(), epoch, epoch_length); + Network::do_epoch_preliminaries(System::block_number(), epoch as u32, epoch_length); let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); // --- Get validator - let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch).unwrap(); + let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch as u32).unwrap(); let mut validator = SubnetNodeIdHotkey::::get(subnet_id, validator_id).unwrap(); assert_ok!( @@ -1046,7 +870,7 @@ fn test_reward_subnets_v2_validator_slash() { let before_slash_validator_stake_balance: u128 = AccountSubnetStake::::get(&validator.clone(), subnet_id); - Network::reward_subnets_v2(System::block_number(), epoch); + Network::reward_subnets(System::block_number(), epoch as u32); let slashed_validator_stake_balance: u128 = AccountSubnetStake::::get(&validator.clone(), subnet_id); @@ -1062,69 +886,7 @@ fn test_reward_subnets_subnet_penalty_count() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 15, deposit_amount, stake_amount); - - let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); - let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - - increase_epochs(1); - - let epoch_length = EpochLength::get(); - let epoch = System::block_number() / epoch_length; - - let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); - - // --- Insert validator - SubnetRewardsValidator::::insert(subnet_id, epoch, 1); - let validator = SubnetNodeIdHotkey::::get(subnet_id, 1).unwrap(); - - assert_ok!( - Network::validate( - RuntimeOrigin::signed(account(1)), - subnet_id, - Vec::new(), - None, - ) - ); - - // Attest - for n in 1..total_subnet_nodes+1 { - let attestor = SubnetNodeIdHotkey::::get(subnet_id, n).unwrap(); - if attestor == validator.clone() { - continue - } - assert_ok!( - Network::attest( - RuntimeOrigin::signed(account(n)), - subnet_id, - ) - ); - } - - Network::reward_subnets(System::block_number(), epoch); - - let subnet_penalty_count = SubnetPenaltyCount::::get(subnet_id); - assert_eq!(subnet_penalty_count, 1); - - let subnet_node_penalty_count = SubnetNodePenalties::::get(subnet_id, 0); - assert_eq!(subnet_node_penalty_count, 0); - }); -} - -#[test] -fn test_reward_subnets_v2_subnet_penalty_count() { - new_test_ext().execute_with(|| { - let _ = env_logger::builder().is_test(true).try_init(); - - let subnet_path: Vec = "petals-team/StableBeluga2".into(); - let deposit_amount: u128 = 10000000000000000000000; - let amount: u128 = 1000000000000000000000; - - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 15, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 15, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1137,12 +899,11 @@ fn test_reward_subnets_v2_subnet_penalty_count() { let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); // --- Insert validator - SubnetRewardsValidator::::insert(subnet_id, epoch, 1); - let validator = SubnetNodeIdHotkey::::get(subnet_id, 1).unwrap(); + SubnetRewardsValidator::::insert(subnet_id, epoch as u32, 0); assert_ok!( Network::validate( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, Vec::new(), None, @@ -1150,11 +911,7 @@ fn test_reward_subnets_v2_subnet_penalty_count() { ); // Attest - for n in 1..total_subnet_nodes+1 { - let attestor = SubnetNodeIdHotkey::::get(subnet_id, n).unwrap(); - if attestor == validator.clone() { - continue - } + for n in 1..total_subnet_nodes { assert_ok!( Network::attest( RuntimeOrigin::signed(account(n)), @@ -1163,7 +920,7 @@ fn test_reward_subnets_v2_subnet_penalty_count() { ); } - Network::reward_subnets_v2(System::block_number(), epoch); + Network::reward_subnets(System::block_number(), epoch as u32); let subnet_penalty_count = SubnetPenaltyCount::::get(subnet_id); assert_eq!(subnet_penalty_count, 1); @@ -1180,9 +937,7 @@ fn test_reward_subnets_account_penalty_count() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 15, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 15, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1195,11 +950,11 @@ fn test_reward_subnets_account_penalty_count() { let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); // --- Insert validator - SubnetRewardsValidator::::insert(subnet_id, epoch, 1); + SubnetRewardsValidator::::insert(subnet_id, epoch as u32, 0); assert_ok!( Network::validate( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, Vec::new(), None, @@ -1208,140 +963,98 @@ fn test_reward_subnets_account_penalty_count() { // No Attest - Network::reward_subnets(System::block_number(), epoch); + Network::reward_subnets(System::block_number(), epoch as u32); let subnet_penalty_count = SubnetPenaltyCount::::get(subnet_id); assert_eq!(subnet_penalty_count, 1); - let subnet_node_penalty_count = SubnetNodePenalties::::get(subnet_id, 1); + let subnet_node_penalty_count = SubnetNodePenalties::::get(subnet_id, 0); assert_eq!(subnet_node_penalty_count, 1); }); } -#[test] -fn test_reward_subnets_v2_account_penalty_count() { - new_test_ext().execute_with(|| { - let subnet_path: Vec = "petals-team/StableBeluga2".into(); - let deposit_amount: u128 = 10000000000000000000000; - let amount: u128 = 1000000000000000000000; +// /// - let stake_amount: u128 = MinStakeBalance::::get(); +// /// - build_activated_subnet(subnet_path.clone(), 0, 15, deposit_amount, stake_amount); - let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); - let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - increase_epochs(1); +#[test] +fn test_do_epoch_preliminaries_deactivate_subnet_enactment_period() { + new_test_ext().execute_with(|| { + let subnet_path: Vec = "petals-team/StableBeluga2".into(); let epoch_length = EpochLength::get(); - let epoch = System::block_number() / epoch_length; - - let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); - - // --- Insert validator - SubnetRewardsValidator::::insert(subnet_id, epoch, 1); + let block_number = System::block_number(); + let epoch = System::block_number().saturating_div(epoch_length); + + let cost = Network::registration_cost(epoch as u32); + + let _ = Balances::deposit_creating(&account(0), cost+1000); + + let registration_blocks = MinSubnetRegistrationBlocks::::get(); + + let add_subnet_data = RegistrationSubnetData { + path: subnet_path.clone().into(), + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, + }; + + let epoch_length = EpochLength::get(); + let block_number = System::block_number(); + let epoch = System::block_number().saturating_div(epoch_length); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); + // --- Register subnet for activation assert_ok!( - Network::validate( - RuntimeOrigin::signed(account(1)), - subnet_id, - Vec::new(), - None, + Network::register_subnet( + RuntimeOrigin::signed(account(0)), + add_subnet_data, ) ); - // No Attest - - Network::reward_subnets_v2(System::block_number(), epoch); - - let subnet_penalty_count = SubnetPenaltyCount::::get(subnet_id); - assert_eq!(subnet_penalty_count, 1); - - let subnet_node_penalty_count = SubnetNodePenalties::::get(subnet_id, 1); - assert_eq!(subnet_node_penalty_count, 1); - }); -} - -// /// - -// /// - - - -// #[test] -// fn test_do_epoch_preliminaries_deactivate_subnet_enactment_period() { -// new_test_ext().execute_with(|| { -// let subnet_path: Vec = "petals-team/StableBeluga2".into(); + let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); + let subnet = SubnetsData::::get(subnet_id).unwrap(); -// let epoch_length = EpochLength::get(); -// let block_number = System::block_number(); -// let epoch = System::block_number().saturating_div(epoch_length); - -// let cost = Network::registration_cost(epoch); - -// let _ = Balances::deposit_creating(&account(1), cost+1000); - -// let add_subnet_data = RegistrationSubnetData { -// path: subnet_path.clone().into(), -// max_node_registration_epochs: 16, -// node_registration_interval: 0, -// node_queue_period: 1, - // coldkey_whitelist: Some(BTreeSet::new()), - // coldkey_whitelist: None, -// }; - -// let epoch_length = EpochLength::get(); -// let block_number = System::block_number(); -// let epoch = System::block_number().saturating_div(epoch_length); -// let next_registration_epoch = Network::get_next_registration_epoch(epoch); -// increase_epochs(next_registration_epoch - epoch); - -// // --- Register subnet for activation -// assert_ok!( -// Network::register_subnet( -// RuntimeOrigin::signed(account(1)), -// add_subnet_data, -// ) -// ); - -// let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); -// let subnet = SubnetsData::::get(subnet_id).unwrap(); - -// let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance(); -// let _ = Balances::deposit_creating(&account(1), min_subnet_delegate_stake+1000); + let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance(subnet.min_nodes); + let _ = Balances::deposit_creating(&account(0), min_subnet_delegate_stake+1000); -// let mut subnet_registering = true; -// let subnet_activation_enactment_blocks = SubnetActivationEnactmentBlocks::::get(); + let registration_blocks = subnet.registration_blocks; + let max_registration_block = subnet.initialized + subnet.registration_blocks; -// while subnet_registering { -// increase_epochs(1); -// let block_number = System::block_number(); + let mut subnet_registering = true; + let subnet_activation_enactment_period = SubnetActivationEnactmentPeriod::::get(); -// let epoch_length = EpochLength::get(); -// let epoch = System::block_number() / epoch_length; + while subnet_registering { + increase_epochs(1); + let block_number = System::block_number(); -// Network::do_epoch_preliminaries(block_number, epoch, epoch_length); + let epoch_length = EpochLength::get(); + let epoch = System::block_number() / epoch_length; + + Network::do_epoch_preliminaries(block_number, epoch as u32, epoch_length); -// if block_number > max_registration_block + subnet_activation_enactment_blocks { -// assert_eq!( -// *network_events().last().unwrap(), -// Event::SubnetDeactivated { -// subnet_id: subnet_id, -// reason: SubnetRemovalReason::EnactmentPeriod -// } -// ); - -// let removed_subnet = SubnetsData::::try_get(subnet_id); -// assert_eq!(removed_subnet, Err(())); -// subnet_registering = false; -// } else { -// let registered_subnet = SubnetsData::::try_get(subnet_id).unwrap(); -// assert_eq!(registered_subnet.id, subnet_id); -// } -// } -// }); -// } + if block_number > max_registration_block + subnet_activation_enactment_period { + assert_eq!( + *network_events().last().unwrap(), + Event::SubnetDeactivated { + subnet_id: subnet_id, + reason: SubnetRemovalReason::EnactmentPeriod + } + ); + + let removed_subnet = SubnetsData::::try_get(subnet_id); + assert_eq!(removed_subnet, Err(())); + subnet_registering = false; + } else { + let registered_subnet = SubnetsData::::try_get(subnet_id).unwrap(); + assert_eq!(registered_subnet.id, subnet_id); + } + } + }); +} #[test] fn test_do_epoch_preliminaries_deactivate_min_subnet_delegate_stake() { @@ -1351,18 +1064,16 @@ fn test_do_epoch_preliminaries_deactivate_min_subnet_delegate_stake() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); // --- Remove delegate stake to force MinSubnetDelegateStake removal reason - let delegate_shares = AccountSubnetDelegateStakeShares::::get(account(1000), subnet_id); + let delegate_shares = AccountSubnetDelegateStakeShares::::get(account(1), subnet_id); assert_ok!( Network::remove_delegate_stake( - RuntimeOrigin::signed(account(1000)), + RuntimeOrigin::signed(account(1)), subnet_id, delegate_shares, ) @@ -1374,7 +1085,7 @@ fn test_do_epoch_preliminaries_deactivate_min_subnet_delegate_stake() { let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - Network::do_epoch_preliminaries(block_number, epoch, epoch_length); + Network::do_epoch_preliminaries(block_number, epoch as u32, epoch_length); assert_eq!( *network_events().last().unwrap(), Event::SubnetDeactivated { @@ -1393,9 +1104,7 @@ fn test_do_epoch_preliminaries_deactivate_max_penalties() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1409,7 +1118,7 @@ fn test_do_epoch_preliminaries_deactivate_max_penalties() { let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - Network::do_epoch_preliminaries(block_number, epoch, epoch_length); + Network::do_epoch_preliminaries(block_number, epoch as u32, epoch_length); assert_eq!( *network_events().last().unwrap(), Event::SubnetDeactivated { @@ -1428,9 +1137,7 @@ fn test_do_epoch_preliminaries_choose_validator() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1441,8 +1148,8 @@ fn test_do_epoch_preliminaries_choose_validator() { let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - Network::do_epoch_preliminaries(block_number, epoch, epoch_length); - let validator = SubnetRewardsValidator::::get(subnet_id, epoch); + Network::do_epoch_preliminaries(block_number, epoch as u32, epoch_length); + let validator = SubnetRewardsValidator::::get(subnet_id, epoch as u32); assert_ne!(validator, None); }); } @@ -1466,7 +1173,7 @@ fn test_do_epoch_preliminaries_choose_validator() { // // // let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); -// // // let encoded_peer_id = Encode::encode(&peer(1).0.to_vec()); +// // // let encoded_peer_id = Encode::encode(&peer(0).0.to_vec()); // // // let public = sr25519_generate(0.into(), None); // // // let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); // // // let signature = @@ -1474,17 +1181,17 @@ fn test_do_epoch_preliminaries_choose_validator() { // // // assert_ok!( // // // Network::add_subnet_node( -// // // RuntimeOrigin::signed(account(1)), -// // account(1), +// // // RuntimeOrigin::signed(account(0)), +// // account(0), // // // subnet_id, -// // // peer(1), +// // // peer(0), // // // amount, // // // // signature, // // // // who_account // // // ) // // // ); -// // // let node_set = SubnetNodesClasses::::get(subnet_id, SubnetNodeClass::Queue); +// // // let node_set = SubnetNodesClasses::::get(subnet_id, SubnetNodeClass::Idle); // // // assert_eq!(node_set.len(), n_peers as usize); // // // }) @@ -1498,7 +1205,7 @@ fn test_do_epoch_preliminaries_choose_validator() { // // // log::error!("user_1_signer {:?}", user_1_signer); // // // let user_1 = user_1_signer.clone().into_account(); // // // log::error!("user_1 {:?}", user_1); -// // // let peer_id: PeerId = peer(1); +// // // let peer_id: PeerId = peer(0); // // // let encoded_data = Encode::encode(&peer_id); // // // let signature = MultiSignature::Sr25519(user_1_pair.sign(&encoded_data)); // // // assert_ok!(Network::validate_signature(&encoded_data, &signature, &user_1)); @@ -1520,7 +1227,7 @@ fn test_do_epoch_preliminaries_choose_validator() { // // // let user_1_pair = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap(); // // // let user_1_signer = MultiSigner::Sr25519(user_1_pair.public()); // // // let user_1 = user_1_signer.clone().into_account(); -// // // let peer_id: PeerId = peer(1); +// // // let peer_id: PeerId = peer(0); // // // let encoded_data = Encode::encode(&peer_id); // // // let signature = MultiSignature::Sr25519(user_1_pair.sign(&encoded_data)); // // // assert_ok!(Network::validate_signature(&encoded_data, &signature, &user_1)); @@ -1551,299 +1258,9 @@ fn test_do_epoch_preliminaries_choose_validator() { // // // Network::add_subnet_node( // // // RuntimeOrigin::signed(user_1), // // // subnet_id, -// // // peer(1), +// // // peer(0), // // // amount, // // // ) // // // ); // // // }) // // // } - -#[test] -fn test_reward_subnets_check_balances() { - new_test_ext().execute_with(|| { - let _ = env_logger::builder().is_test(true).try_init(); - - let subnet_path: Vec = "petals-team/StableBeluga2".into(); - let deposit_amount: u128 = 10000000000000000000000; - let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet_with_delegator_rewards( - subnet_path.clone(), - 0, - 16, - deposit_amount, - stake_amount, - DEFAULT_DELEGATE_REWARD_RATE, - ); - - let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); - let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - - let _ = Balances::deposit_creating(&account(total_subnet_nodes+1), amount+500); - - assert_ok!( - Network::add_to_node_delegate_stake( - RuntimeOrigin::signed(account(total_subnet_nodes+1)), - subnet_id, - 0, - amount, - ) - ); - - increase_epochs(1); - - let epoch = get_epoch(); - - let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); - - // --- Insert validator - SubnetRewardsValidator::::insert(subnet_id, epoch, 1); - let validator = SubnetNodeIdHotkey::::get(subnet_id, 1).unwrap(); - - // validate without n-1 - assert_ok!( - Network::validate( - RuntimeOrigin::signed(account(1)), - subnet_id, - subnet_node_data_vec.clone(), - None, - ) - ); - - // Attest without n-1 - for n in 1..total_subnet_nodes+1 { - let attestor = SubnetNodeIdHotkey::::get(subnet_id, n).unwrap(); - if attestor == validator.clone() { - continue - } - assert_ok!( - Network::attest( - RuntimeOrigin::signed(account(n)), - subnet_id, - ) - ); - } - - // --- Get submission data and count before node is removed - // Check rewards - // Ensure only attestors, validators, and validated get rewards - let submission = SubnetRewardsSubmission::::get(subnet_id, epoch).unwrap(); - - assert_ok!(Network::reward_subnets_v2(System::block_number(), epoch)); - - let node_absent_count = SubnetNodePenalties::::get(subnet_id, total_subnet_nodes-1); - assert_eq!(node_absent_count, 0); - - let mut rewards: u128 = Network::get_epoch_emissions(epoch); - - let total_issuance: u128 = Network::get_total_network_issuance(); - - let subnet_owner_percentage = SubnetOwnerPercentage::::get(); - let delegate_stake_rewards_percentage: u128 = DelegateStakeRewardsPercentage::::get(); - - let weight = 1e+9 as u128; - - let overall_subnet_reward: u128 = Network::percent_mul(rewards, weight); - - // --- Get owner rewards - let subnet_owner_reward: u128 = Network::percent_mul(overall_subnet_reward, subnet_owner_percentage); - - // --- Get subnet rewards minus owner cut - let subnet_reward: u128 = overall_subnet_reward.saturating_sub(subnet_owner_reward); - - // --- Get delegators rewards - let delegate_stake_reward: u128 = Network::percent_mul(subnet_reward, delegate_stake_rewards_percentage); - - // --- Get subnet nodes rewards - let subnet_node_reward: u128 = subnet_reward.saturating_sub(delegate_stake_reward); - - // --- Any removals impact the following epochs attestation data unless removed ahead of rewards - let submission_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Validator, epoch); - let submission_nodes_count = submission_nodes.len() as u128; - - let attestations: u128 = submission.attests.len() as u128; - let attestation_percentage: u128 = Network::percent_div(attestations, submission_nodes_count); - assert_eq!(attestation_percentage, 1e+9 as u128); - - let sum = submission.data.iter().fold(0, |acc, x| acc + x.score); - let score_percentage: u128 = Network::percent_div(DEFAULT_SCORE, sum); - - let mut account_reward: u128 = Network::percent_mul(score_percentage, subnet_node_reward); - - - for n in 1..total_subnet_nodes+1 { - let hotkey_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n)).unwrap(); - let subnet_node_id_hotkey = SubnetNodeIdHotkey::::get(subnet_id, hotkey_subnet_node_id).unwrap(); - let subnet_node = SubnetNodesData::::get(subnet_id, hotkey_subnet_node_id); - let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); - - if subnet_node_id_hotkey == validator.clone() { - // validator - let validator_reward: u128 = Network::get_validator_reward(attestation_percentage); - let validator_total_reward: u128 = (account_reward as u128) + (validator_reward as u128); - assert_eq!(stake_balance, amount + validator_total_reward); - } else { - assert_eq!(stake_balance, amount + account_reward); - } - } - }); -} - -#[test] -fn test_reward_subnets_with_delegate_node_staking_check_balances() { - new_test_ext().execute_with(|| { - let _ = env_logger::builder().is_test(true).try_init(); - - let subnet_path: Vec = "petals-team/StableBeluga2".into(); - let deposit_amount: u128 = 10000000000000000000000; - let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet_with_delegator_rewards( - subnet_path.clone(), - 0, - 16, - deposit_amount, - stake_amount, - DEFAULT_DELEGATE_REWARD_RATE, - ); - - let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); - let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - - for n in 1..total_subnet_nodes+1 { - let _ = Balances::deposit_creating(&account(total_subnet_nodes+2), amount+500); - - assert_ok!( - Network::add_to_node_delegate_stake( - RuntimeOrigin::signed(account(total_subnet_nodes+2)), - subnet_id, - n, - amount, - ) - ); - } - - increase_epochs(1); - - let epoch = get_epoch(); - - let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); - - // --- Insert validator - SubnetRewardsValidator::::insert(subnet_id, epoch, 1); - let validator = SubnetNodeIdHotkey::::get(subnet_id, 1).unwrap(); - - // validate without n-1 - assert_ok!( - Network::validate( - RuntimeOrigin::signed(account(1)), - subnet_id, - subnet_node_data_vec.clone(), - None, - ) - ); - - // Attest without n-1 - for n in 1..total_subnet_nodes+1 { - let attestor = SubnetNodeIdHotkey::::get(subnet_id, n).unwrap(); - if attestor == validator.clone() { - continue - } - assert_ok!( - Network::attest( - RuntimeOrigin::signed(account(n)), - subnet_id, - ) - ); - } - - // --- Get submission data and count before node is removed - // Check rewards - // Ensure only attestors, validators, and validated get rewards - let submission = SubnetRewardsSubmission::::get(subnet_id, epoch).unwrap(); - - assert_ok!(Network::reward_subnets_v2(System::block_number(), epoch)); - - let node_absent_count = SubnetNodePenalties::::get(subnet_id, total_subnet_nodes-1); - assert_eq!(node_absent_count, 0); - - let mut rewards: u128 = Network::get_epoch_emissions(epoch); - - let total_issuance: u128 = Network::get_total_network_issuance(); - - let subnet_owner_percentage = SubnetOwnerPercentage::::get(); - let delegate_stake_rewards_percentage: u128 = DelegateStakeRewardsPercentage::::get(); - - let weight = 1e+9 as u128; - - let overall_subnet_reward: u128 = Network::percent_mul(rewards, weight); - - // --- Get owner rewards - let subnet_owner_reward: u128 = Network::percent_mul(overall_subnet_reward, subnet_owner_percentage); - - // --- Get subnet rewards minus owner cut - let subnet_reward: u128 = overall_subnet_reward.saturating_sub(subnet_owner_reward); - - // --- Get delegators rewards - let delegate_stake_reward: u128 = Network::percent_mul(subnet_reward, delegate_stake_rewards_percentage); - - // --- Get subnet nodes rewards - let subnet_node_reward: u128 = subnet_reward.saturating_sub(delegate_stake_reward); - - // --- Any removals impact the following epochs attestation data unless removed ahead of rewards - let submission_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Validator, epoch); - let submission_nodes_count = submission_nodes.len() as u128; - - let attestations: u128 = submission.attests.len() as u128; - let attestation_percentage: u128 = Network::percent_div(attestations, submission_nodes_count); - assert_eq!(attestation_percentage, 1e+9 as u128); - - let sum = submission.data.iter().fold(0, |acc, x| acc + x.score); - let score_percentage: u128 = Network::percent_div(DEFAULT_SCORE, sum); - - let mut account_reward: u128 = Network::percent_mul(score_percentage, subnet_node_reward); - log::error!("account_reward: {:?}", account_reward); - - - for n in 1..total_subnet_nodes+1 { - let mut node_reward = account_reward; - let hotkey_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n)).unwrap(); - let subnet_node_id_hotkey = SubnetNodeIdHotkey::::get(subnet_id, hotkey_subnet_node_id).unwrap(); - let subnet_node = SubnetNodesData::::get(subnet_id, hotkey_subnet_node_id); - let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); - - log::error!(" "); - log::error!("subnet_node ID: {:?}", hotkey_subnet_node_id); - log::error!("subnet_node.delegate_reward_rate: {:?}", subnet_node.delegate_reward_rate); - - assert_ne!(subnet_node.delegate_reward_rate, 0); - - if subnet_node_id_hotkey == validator.clone() { - // validator - let validator_reward: u128 = Network::get_validator_reward(attestation_percentage); - - if subnet_node.delegate_reward_rate != 0 { - let total_node_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(subnet_id, hotkey_subnet_node_id); - if total_node_delegated_stake_shares != 0 { - let node_delegate_reward = Network::percent_mul(node_reward, subnet_node.delegate_reward_rate); - node_reward = node_reward - node_delegate_reward; - } - } - let validator_total_reward: u128 = (node_reward as u128) + (validator_reward as u128); - - assert_eq!(stake_balance, amount + validator_total_reward); - } else { - if subnet_node.delegate_reward_rate != 0 { - let total_node_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(subnet_id, hotkey_subnet_node_id); - if total_node_delegated_stake_shares != 0 { - let node_delegate_reward = Network::percent_mul(node_reward, subnet_node.delegate_reward_rate); - node_reward = node_reward - node_delegate_reward; - } - } - assert_eq!(stake_balance, amount + node_reward); - } - } - }); -} \ No newline at end of file diff --git a/pallets/network/src/tests/inflation.rs b/pallets/network/src/tests/inflation.rs deleted file mode 100644 index 472eb36..0000000 --- a/pallets/network/src/tests/inflation.rs +++ /dev/null @@ -1,99 +0,0 @@ -use super::mock::*; -use crate::tests::test_utils::*; -use crate::Event; -use log::info; -use crate::inflation::Inflation; -// use crate::{ -// EpochsPerYear, -// }; -// -// -// -// -// -// -// -// Inflation -// -// -// -// -// -// -// - -#[test] -fn test_inflation_total() { - new_test_ext().execute_with(|| { - let _ = env_logger::builder().is_test(true).try_init(); - - let inflation = Inflation::default(); - - let mut last = inflation.total(0.0); - - for year in &[0.1, 0.5, 1.0, 2.0, 3.0, 4.0, 5.0, 100.0] { - log::error!("test_inflation_total year {:?}", year); - let total = inflation.total(*year); - log::error!("test_inflation_total total {:?}", total); - assert!(total < last); - assert!(total >= inflation.terminal); - last = total; - } - assert_eq!(last, inflation.terminal); - // assert!(false); - }); -} - -// #[test] -// fn test_inflation_test() { -// new_test_ext().execute_with(|| { -// let inflation = Inflation::default(); -// let x1 = Network::test(1.0); -// log::error!("test_inflation_test x1 {:?}", x1); -// // assert!(false); -// }); -// } - -#[test] -fn test_get_epoch_emissions() { - new_test_ext().execute_with(|| { - let inflation = Inflation::default(); - - Network::get_epoch_emissions(0); - }); -} - -// #[test] -// fn test_inflation_epoch() { -// new_test_ext().execute_with(|| { -// let _ = env_logger::builder().is_test(true).try_init(); - -// let inflation = Inflation::default(); - -// let mut last = inflation.total(0.0); - -// let epochs_per_year = EpochsPerYear::get(); -// log::error!("test_inflation_epoch epochs_per_year {:?}", epochs_per_year); - -// for epoch in &[1, 2, 3, 4, 5, 4, 5, 100] { -// let year = epoch / epochs_per_year; -// log::error!("test_inflation_epoch year {:?}", year); - -// log::error!("test_inflation_epoch epoch {:?}", epoch); -// let total = inflation.epoch(*epoch, epochs_per_year, 1e+9 as u128); -// log::error!("test_inflation_epoch total {:?}", total); -// assert!(total < last); -// assert!(total >= inflation.terminal); -// last = total; -// } -// assert_eq!(last, inflation.terminal); -// assert!(false); -// }); -// } - -#[test] -fn test_inflation_math() { - new_test_ext().execute_with(|| { - log::error!("test_inflation_math adassd"); - }); -} \ No newline at end of file diff --git a/pallets/network/src/tests/mock.rs b/pallets/network/src/tests/mock.rs index c86200a..6fd01db 100644 --- a/pallets/network/src/tests/mock.rs +++ b/pallets/network/src/tests/mock.rs @@ -17,10 +17,7 @@ use crate::*; use crate as pallet_network; use frame_support::{ parameter_types, - traits::{ - Everything, - tokens::{PayFromAccount, UnityAssetBalanceConversion}, - }, + traits::Everything, PalletId, derive_impl, weights::{ @@ -38,11 +35,10 @@ use sp_runtime::{ MultiSignature }; use sp_runtime::Perbill; -pub use frame_system::{EnsureRoot, EnsureRootWithSuccess}; -use sp_runtime::Permill; +use frame_system::EnsureRoot; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -type Block = frame_system::mocking::MockBlockU32; +type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( pub enum Test @@ -52,38 +48,15 @@ frame_support::construct_runtime!( Balances: pallet_balances, Network: pallet_network, Collective: pallet_collective::, - Treasury: pallet_treasury, } ); -// An index to a block. -pub type BlockNumber = u32; - pub type BalanceCall = pallet_balances::Call; pub const MILLISECS_PER_BLOCK: u64 = 6000; -// NOTE: Currently it is not possible to change the slot duration after the chain has started. -// Attempting to do so will brick block production. -pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; - -// Time is measured by number of blocks. -pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); -pub const HOURS: BlockNumber = MINUTES * 60; -pub const DAYS: BlockNumber = HOURS * 24; -pub const YEAR: BlockNumber = DAYS * 365; -pub const BLOCKS_PER_HALVING: BlockNumber = YEAR * 2; -pub const TARGET_MAX_TOTAL_SUPPLY: u128 = 2_800_000_000_000_000_000_000_000; -pub const INITIAL_REWARD_PER_BLOCK: u128 = (TARGET_MAX_TOTAL_SUPPLY / 2) / BLOCKS_PER_HALVING as u128; - -pub const SECS_PER_BLOCK: u32 = 6000 / 1000; - -pub const EPOCH_LENGTH: u32 = 10; -pub const BLOCKS_PER_EPOCH: u32 = SECS_PER_BLOCK * EPOCH_LENGTH; -pub const EPOCHS_PER_YEAR: u32 = YEAR as u32 / BLOCKS_PER_EPOCH; - parameter_types! { - pub const BlockHashCount: BlockNumber = 250; + pub const BlockHashCount: u64 = 250; pub const SS58Prefix: u8 = 42; } @@ -101,6 +74,23 @@ pub type Address = AccountId; // Balance of an account. pub type Balance = u128; +// An index to a block. +#[allow(dead_code)] +pub type BlockNumber = u64; + +// NOTE: Currently it is not possible to change the slot duration after the chain has started. +// Attempting to do so will brick block production. +pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + +// Time is measured by number of blocks. +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; + +pub const YEAR: BlockNumber = DAYS * 365; + +pub const SECS_PER_BLOCK: u64 = MILLISECS_PER_BLOCK / 1000; + pub const EXISTENTIAL_DEPOSIT: u128 = 500; impl pallet_insecure_randomness_collective_flip::Config for Test {} @@ -110,6 +100,8 @@ impl pallet_balances::Config for Test { type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU128; + // type AccountStore = AccountData; + // type AccountStore = StoredMap>; type AccountStore = System; type MaxLocks = (); type WeightInfo = (); @@ -117,10 +109,58 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = (); type FreezeIdentifier = (); + // type MaxHolds = (); type MaxFreezes = (); type RuntimeFreezeReason = (); } +// impl pallet_balances::Config for Runtime { +// type MaxLocks = ConstU32<50>; +// type MaxReserves = (); +// type ReserveIdentifier = [u8; 8]; +// /// The type for recording an account's balance. +// type Balance = Balance; +// /// The ubiquitous event type. +// type RuntimeEvent = RuntimeEvent; +// type DustRemoval = (); +// type ExistentialDeposit = ConstU128; +// type AccountStore = System; +// type WeightInfo = pallet_balances::weights::SubstrateWeight; +// type FreezeIdentifier = RuntimeFreezeReason; +// type MaxFreezes = VariantCountOf; +// type RuntimeHoldReason = RuntimeHoldReason; +// type RuntimeFreezeReason = RuntimeHoldReason; +// } + + +// impl system::Config for Test { +// type BaseCallFilter = Everything; +// type BlockWeights = (); +// type BlockLength = (); +// type Block = Block; +// type DbWeight = (); +// type RuntimeOrigin = RuntimeOrigin; +// type RuntimeCall = RuntimeCall; +// type Nonce = u64; +// type Hash = H256; +// type Hashing = BlakeTwo256; +// // type AccountId = U256; +// type AccountId = AccountId; +// // type Lookup = IdentityLookup; +// type Lookup = AccountIdLookup; +// type RuntimeEvent = RuntimeEvent; +// type BlockHashCount = BlockHashCount; +// type Version = (); +// type PalletInfo = PalletInfo; +// type AccountData = pallet_balances::AccountData; +// type OnNewAccount = (); +// type OnKilledAccount = (); +// type SystemWeightInfo = (); +// type SS58Prefix = SS58Prefix; +// type OnSetCode = (); +// type MaxConsumers = frame_support::traits::ConstU32<16>; +// } + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type BaseCallFilter = Everything; @@ -130,7 +170,7 @@ impl frame_system::Config for Test { type DbWeight = (); type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; - type Nonce = u32; + type Nonce = u64; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = AccountId; @@ -177,43 +217,12 @@ impl pallet_collective::Config for Test { } parameter_types! { - pub const Burn: Permill = Permill::from_percent(50); - pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); - pub const SpendLimit: Balance = u128::MAX; - pub TreasuryAccount: AccountId = Treasury::account_id(); -} - -impl pallet_treasury::Config for Test { - type PalletId = TreasuryPalletId; - type Currency = Balances; - type RejectOrigin = EnsureRoot; - type RuntimeEvent = RuntimeEvent; - type SpendPeriod = ConstU32<2>; - type Burn = Burn; - type BurnDestination = (); // Just gets burned. - type WeightInfo = (); - type SpendFunds = (); - type MaxApprovals = ConstU32<100>; - type SpendOrigin = EnsureRootWithSuccess; - type AssetKind = (); - type Beneficiary = AccountId; - type BeneficiaryLookup = IdentityLookup; - type Paymaster = PayFromAccount; - type BalanceConverter = UnityAssetBalanceConversion; - type PayoutPeriod = ConstU32<10>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); -} - -parameter_types! { - pub const EpochLength: u32 = EPOCH_LENGTH; // Testnet 600 blocks per erpoch / 69 mins per epoch, Local 10 - pub const EpochsPerYear: u32 = EPOCHS_PER_YEAR; // Testnet 600 blocks per erpoch / 69 mins per epoch, Local 10 + pub const EpochLength: u64 = 100; pub const NetworkPalletId: PalletId = PalletId(*b"/network"); pub const MinProposalStake: u128 = 1_000_000_000_000_000_000; - pub const DelegateStakeCooldownEpochs: u32 = 100; - pub const NodeDelegateStakeCooldownEpochs: u32 = 100; - pub const StakeCooldownEpochs: u32 = 100; - pub const DelegateStakeEpochsRemovalWindow: u32 = 10; + pub const DelegateStakeCooldownEpochs: u64 = 100; + pub const StakeCooldownEpochs: u64 = 100; + pub const DelegateStakeEpochsRemovalWindow: u64 = 10; pub const MaxDelegateStakeUnlockings: u32 = 32; pub const MaxStakeUnlockings: u32 = 32; } @@ -224,20 +233,19 @@ impl Config for Test { type Currency = Balances; type MajorityCollectiveOrigin = pallet_collective::EnsureProportionAtLeast; type SuperMajorityCollectiveOrigin = pallet_collective::EnsureProportionAtLeast; - type EpochLength = EpochLength; - type EpochsPerYear = EpochsPerYear; + type EpochLength = EpochLength; type StringLimit = ConstU32<100>; - type InitialTxRateLimit = ConstU32<0>; + type InitialTxRateLimit = ConstU64<0>; + // type OffchainSignature = Signature; + // type OffchainPublic = AccountPublic; type Randomness = InsecureRandomnessCollectiveFlip; type PalletId = NetworkPalletId; type DelegateStakeCooldownEpochs = DelegateStakeCooldownEpochs; - type NodeDelegateStakeCooldownEpochs = NodeDelegateStakeCooldownEpochs; type StakeCooldownEpochs = DelegateStakeCooldownEpochs; type DelegateStakeEpochsRemovalWindow = DelegateStakeEpochsRemovalWindow; type MaxDelegateStakeUnlockings = MaxDelegateStakeUnlockings; type MaxStakeUnlockings = MaxStakeUnlockings; type MinProposalStake = MinProposalStake; - type TreasuryAccount = TreasuryAccount; } pub fn new_test_ext() -> sp_io::TestExternalities { diff --git a/pallets/network/src/tests/mod.rs b/pallets/network/src/tests/mod.rs index 41183f3..3d881c2 100644 --- a/pallets/network/src/tests/mod.rs +++ b/pallets/network/src/tests/mod.rs @@ -1,14 +1,13 @@ mod mock; mod test_utils; -// mod subnet; -// mod subnet_node; -// mod staking; +mod subnet; +mod subnet_node; +mod staking; mod delegate_staking; -// mod node_delegate_staking; -// mod incentives_protocol; -// mod proposals; -// mod math; -// mod randomization; -// mod steps; -// mod utils; -// mod inflation; \ No newline at end of file +mod node_delegate_staking; +mod incentives_protocol; +mod proposals; +mod math; +mod randomization; +mod steps; +mod utils; diff --git a/pallets/network/src/tests/node_delegate_staking.rs b/pallets/network/src/tests/node_delegate_staking.rs index d7e3362..7820d02 100644 --- a/pallets/network/src/tests/node_delegate_staking.rs +++ b/pallets/network/src/tests/node_delegate_staking.rs @@ -21,6 +21,7 @@ use crate::{ SubnetRewardsValidator, SubnetRewardsSubmission, SubnetNodePenalties, + BaseRewardPerMB, DelegateStakeRewardsPercentage, BaseValidatorReward, SubnetNodesData, @@ -31,8 +32,6 @@ use crate::{ SubnetNodeClass, AccountNodeDelegateStakeShares, TotalNodeDelegateStakeBalance, - MinStakeBalance, - SubnetOwnerPercentage, }; // @@ -57,14 +56,13 @@ fn test_add_to_node_delegate_stake() { let subnet_path: Vec = "petals-team/StableBeluga2".into(); let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); build_activated_subnet_with_delegator_rewards( subnet_path.clone(), 0, 16, deposit_amount, - stake_amount, + amount, DEFAULT_DELEGATE_REWARD_RATE, ); @@ -93,7 +91,7 @@ fn test_add_to_node_delegate_stake() { ); assert!( - (account_node_delegate_stake_balance >= Network::percent_mul(amount, 990000000)) && + (account_node_delegate_stake_balance >= Network::percent_mul(amount, 9999)) && (account_node_delegate_stake_balance <= amount) ); }) @@ -106,14 +104,12 @@ fn test_remove_node_delegate_stake() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - build_activated_subnet_with_delegator_rewards( subnet_path.clone(), 0, 16, deposit_amount, - stake_amount, + amount, DEFAULT_DELEGATE_REWARD_RATE, ); @@ -142,7 +138,7 @@ fn test_remove_node_delegate_stake() { ); assert!( - (account_node_delegate_stake_balance >= Network::percent_mul(amount, 990000000)) && + (account_node_delegate_stake_balance >= Network::percent_mul(amount, 9999)) && (account_node_delegate_stake_balance <= amount) ); @@ -160,8 +156,6 @@ fn test_remove_node_delegate_stake() { total_node_delegate_stake_balance - expected_balance_to_be_removed ); - let epoch = System::block_number() / EpochLength::get(); - assert_ok!( Network::remove_node_delegate_stake( RuntimeOrigin::signed(account(total_subnet_nodes+1)), @@ -184,270 +178,213 @@ fn test_remove_node_delegate_stake() { ); assert_eq!(expected_post_balance, post_account_node_delegate_stake_balance); - - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); - assert_eq!(unbondings.len(), 1); - let (ledger_epoch, ledger_balance) = unbondings.iter().next().unwrap(); - assert_eq!(*ledger_epoch, &epoch + NodeDelegateStakeCooldownEpochs::get()); - assert_eq!(*ledger_balance, expected_balance_to_be_removed); - }) -} - -#[test] -fn test_transfer_node_delegate_stake() { - new_test_ext().execute_with(|| { - let subnet_path: Vec = "petals-team/StableBeluga2".into(); - let deposit_amount: u128 = 10000000000000000000000; - let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet_with_delegator_rewards( - subnet_path.clone(), - 0, - 16, - deposit_amount, - stake_amount, - DEFAULT_DELEGATE_REWARD_RATE, - ); - - let from_subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); - let total_from_subnet_nodes = TotalSubnetNodes::::get(from_subnet_id); - - let to_subnet_path: Vec = "petals-team/StableBeluga3".into(); - - build_activated_subnet_with_delegator_rewards( - to_subnet_path.clone(), - 0, - 16, - deposit_amount, - stake_amount, - DEFAULT_DELEGATE_REWARD_RATE, - ); - - let to_subnet_id = SubnetPaths::::get(to_subnet_path.clone()).unwrap(); - - let _ = Balances::deposit_creating(&account(total_from_subnet_nodes+1), amount+500); - - assert_ok!( - Network::add_to_node_delegate_stake( - RuntimeOrigin::signed(account(total_from_subnet_nodes+1)), - from_subnet_id, - 1, - amount, - ) - ); - - let account_node_delegate_stake_shares = AccountNodeDelegateStakeShares::::get((account(total_from_subnet_nodes+1), from_subnet_id, 1)); - let total_node_delegate_stake_balance = TotalNodeDelegateStakeBalance::::get(from_subnet_id, 1); - let total_node_delegate_stake_shares = TotalNodeDelegateStakeShares::::get(from_subnet_id, 1); - - let account_node_delegate_stake_balance = Network::convert_to_balance( - account_node_delegate_stake_shares, - total_node_delegate_stake_shares, - total_node_delegate_stake_balance - ); - - assert!( - (account_node_delegate_stake_balance >= Network::percent_mul(amount, 990000000)) && - (account_node_delegate_stake_balance <= amount) - ); - - let account_node_delegate_stake_shares_to_be_removed = account_node_delegate_stake_shares / 2; - let expected_node_delegate_stake_shares_balance = account_node_delegate_stake_shares - account_node_delegate_stake_shares_to_be_removed; - - let expected_balance_to_be_removed = Network::convert_to_balance( - account_node_delegate_stake_shares_to_be_removed, - total_node_delegate_stake_shares, - total_node_delegate_stake_balance - ); - - let expected_post_balance = Network::convert_to_balance( - account_node_delegate_stake_shares_to_be_removed, - total_node_delegate_stake_shares - account_node_delegate_stake_shares_to_be_removed, - total_node_delegate_stake_balance - expected_balance_to_be_removed - ); - - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_from_subnet_nodes+1)); - assert_eq!(unbondings.len(), 0); - - assert_ok!( - Network::transfer_node_delegate_stake( - RuntimeOrigin::signed(account(total_from_subnet_nodes+1)), - from_subnet_id, - 1, - to_subnet_id, - 2, - account_node_delegate_stake_shares_to_be_removed, - ) - ); - - let account_node_delegate_stake_shares = AccountNodeDelegateStakeShares::::get((account(total_from_subnet_nodes+1), from_subnet_id, 1)); - assert_eq!(expected_node_delegate_stake_shares_balance, account_node_delegate_stake_shares); - - let total_node_delegate_stake_balance = TotalNodeDelegateStakeBalance::::get(to_subnet_id, 1); - let total_node_delegate_stake_shares = TotalNodeDelegateStakeShares::::get(to_subnet_id, 1); - - let account_node_delegate_stake_balance = Network::convert_to_balance( - account_node_delegate_stake_shares, - total_node_delegate_stake_shares, - total_node_delegate_stake_balance - ); - - assert_eq!(account_node_delegate_stake_balance, expected_post_balance); - - let account_node_delegate_stake_shares = AccountNodeDelegateStakeShares::::get((account(total_from_subnet_nodes+1), to_subnet_id, 2)); - let total_node_delegate_stake_balance = TotalNodeDelegateStakeBalance::::get(to_subnet_id, 2); - let total_node_delegate_stake_shares = TotalNodeDelegateStakeShares::::get(to_subnet_id, 2); - - let account_node_delegate_stake_balance = Network::convert_to_balance( - account_node_delegate_stake_shares, - total_node_delegate_stake_shares, - total_node_delegate_stake_balance - ); - - assert_ne!(account_node_delegate_stake_balance, 0); - - assert!( - (account_node_delegate_stake_balance >= Network::percent_mul(expected_balance_to_be_removed, 990000000)) && - (account_node_delegate_stake_balance <= expected_balance_to_be_removed) - ); - - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_from_subnet_nodes+1)); - assert_eq!(unbondings.len(), 0); }) } // #[test] -// fn test_validate_with_delegate_rewards_rate() { +// fn test_transfer_node_delegate_stake() { // new_test_ext().execute_with(|| { // let subnet_path: Vec = "petals-team/StableBeluga2".into(); // let deposit_amount: u128 = 10000000000000000000000; -// let amount: u128 = 1000000000000000000000; -// let stake_amount: u128 = MinStakeBalance::::get(); +// let amount: u128 = 1000000000000000000000; // build_activated_subnet_with_delegator_rewards( // subnet_path.clone(), // 0, // 16, // deposit_amount, -// stake_amount, +// amount, +// DEFAULT_DELEGATE_REWARD_RATE, +// ); + +// let from_subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); +// let total_from_subnet_nodes = TotalSubnetNodes::::get(from_subnet_id); + +// let to_subnet_path: Vec = "petals-team/StableBeluga3".into(); + +// build_activated_subnet_with_delegator_rewards( +// to_subnet_path.clone(), +// 0, +// 16, +// deposit_amount, +// amount, // DEFAULT_DELEGATE_REWARD_RATE, // ); -// let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); -// let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); +// let to_subnet_id = SubnetPaths::::get(to_subnet_path.clone()).unwrap(); -// let _ = Balances::deposit_creating(&account(total_subnet_nodes+1), amount+500); +// let _ = Balances::deposit_creating(&account(total_from_subnet_nodes+1), amount+500); // assert_ok!( // Network::add_to_node_delegate_stake( -// RuntimeOrigin::signed(account(total_subnet_nodes+1)), -// subnet_id, +// RuntimeOrigin::signed(account(total_from_subnet_nodes+1)), +// from_subnet_id, // 0, // amount, // ) // ); -// increase_epochs(1); +// let account_node_delegate_stake_shares = AccountNodeDelegateStakeShares::::get((account(total_from_subnet_nodes+1), from_subnet_id, 0)); +// let total_node_delegate_stake_balance = TotalNodeDelegateStakeBalance::::get(from_subnet_id, 0); +// let total_node_delegate_stake_shares = TotalNodeDelegateStakeShares::::get(from_subnet_id, 0); + +// let account_node_delegate_stake_balance = Network::convert_to_balance( +// account_node_delegate_stake_shares, +// total_node_delegate_stake_shares, +// total_node_delegate_stake_balance +// ); + +// assert!( +// (account_node_delegate_stake_balance >= Network::percent_mul(amount, 9999)) && +// (account_node_delegate_stake_balance <= amount) +// ); -// let epoch_length = EpochLength::get(); -// let epoch = System::block_number() / epoch_length; +// let account_node_delegate_stake_shares_to_be_removed = account_node_delegate_stake_shares / 2; -// let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); - -// // --- Insert validator -// SubnetRewardsValidator::::insert(subnet_id, epoch, 1); -// let validator = SubnetNodeIdHotkey::::get(subnet_id, 1).unwrap(); +// let expected_balance_to_be_removed = Network::convert_to_balance( +// account_node_delegate_stake_shares_to_be_removed, +// total_node_delegate_stake_shares, +// total_node_delegate_stake_balance +// ); -// // validate without n-1 // assert_ok!( -// Network::validate( -// RuntimeOrigin::signed(account(1)), -// subnet_id, -// subnet_node_data_vec.clone(), -// None, +// Network::transfer_node_delegate_stake( +// RuntimeOrigin::signed(account(total_from_subnet_nodes+1)), +// from_subnet_id, +// 0, +// to_subnet_id, +// 0, +// account_node_delegate_stake_shares_to_be_removed, // ) // ); +// }) +// } + +#[test] +fn test_validate_with_delegate_rewards_rate() { + new_test_ext().execute_with(|| { + let subnet_path: Vec = "petals-team/StableBeluga2".into(); + let deposit_amount: u128 = 10000000000000000000000; + let amount: u128 = 1000000000000000000000; + + build_activated_subnet_with_delegator_rewards( + subnet_path.clone(), + 0, + 16, + deposit_amount, + amount, + DEFAULT_DELEGATE_REWARD_RATE, + ); + + let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); + let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); + + let _ = Balances::deposit_creating(&account(total_subnet_nodes+1), amount+500); + + assert_ok!( + Network::add_to_node_delegate_stake( + RuntimeOrigin::signed(account(total_subnet_nodes+1)), + subnet_id, + 0, + amount, + ) + ); + + increase_epochs(1); + + let epoch_length = EpochLength::get(); + let epoch = System::block_number() / epoch_length; + + let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); + + // --- Insert validator + SubnetRewardsValidator::::insert(subnet_id, epoch as u32, 0); + + // validate without n-1 + assert_ok!( + Network::validate( + RuntimeOrigin::signed(account(0)), + subnet_id, + subnet_node_data_vec.clone(), + None, + ) + ); -// // Attest without n-1 -// for n in 1..total_subnet_nodes+1 { -// let attestor = SubnetNodeIdHotkey::::get(subnet_id, n).unwrap(); -// if attestor == validator.clone() { -// continue -// } -// assert_ok!( -// Network::attest( -// RuntimeOrigin::signed(account(n)), -// subnet_id, -// ) -// ); -// } + // Attest without n-1 + for n in 1..total_subnet_nodes { + assert_ok!( + Network::attest( + RuntimeOrigin::signed(account(n)), + subnet_id, + ) + ); + } -// // --- Get submission data and count before node is removed -// // Check rewards -// // Ensure only attestors, validators, and validated get rewards -// let submission = SubnetRewardsSubmission::::get(subnet_id, epoch).unwrap(); - -// // --- Any removals impact the following epochs attestation data unless removed ahead of rewards -// let submission_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Validator, epoch); -// let submission_nodes_count = submission_nodes.len() as u128; - -// Network::reward_subnets(System::block_number(), epoch); -// let node_absent_count = SubnetNodePenalties::::get(subnet_id, total_subnet_nodes-1); -// assert_eq!(node_absent_count, 0); + // --- Get submission data and count before node is removed + // Check rewards + // Ensure only attestors, validators, and validated get rewards + let submission = SubnetRewardsSubmission::::get(subnet_id, epoch as u32).unwrap(); + + // --- Any removals impact the following epochs attestation data unless removed ahead of rewards + let submission_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Validator, epoch); + let submission_nodes_count = submission_nodes.len() as u128; + + Network::reward_subnets(System::block_number(), epoch as u32); + let node_absent_count = SubnetNodePenalties::::get(subnet_id, total_subnet_nodes-1); + assert_eq!(node_absent_count, 0); -// let base_reward_per_mb: u128 = BaseRewardPerMB::::get(); -// let delegate_stake_rewards_percentage: u128 = DelegateStakeRewardsPercentage::::get(); -// let overall_subnet_reward: u128 = Network::percent_mul(base_reward_per_mb, DEFAULT_MEM_MB); -// let delegate_stake_reward: u128 = Network::percent_mul(overall_subnet_reward, delegate_stake_rewards_percentage); -// let subnet_reward: u128 = overall_subnet_reward.saturating_sub(delegate_stake_reward); - -// let sum = submission.data.iter().fold(0, |acc, x| acc + x.score); -// let reward_ratio: u128 = Network::percent_div(DEFAULT_SCORE, sum); -// let account_reward: u128 = Network::percent_mul(reward_ratio, subnet_reward); - -// let base_reward = BaseValidatorReward::::get(); - -// let submission_attestations: u128 = submission.attests.len() as u128; -// let attestation_percentage: u128 = Network::percent_div(submission_attestations, submission_nodes_count); - -// // check each subnet nodes balance increased -// for n in 1..total_subnet_nodes+1 { -// let hotkey_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n)).unwrap(); -// let subnet_node_id_hotkey = SubnetNodeIdHotkey::::get(subnet_id, hotkey_subnet_node_id).unwrap(); -// let subnet_node = SubnetNodesData::::get(subnet_id, hotkey_subnet_node_id); - -// if n == 1 { -// // validator -// let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); -// let validator_reward: u128 = Network::percent_mul(base_reward, attestation_percentage); -// let mut validator_total_reward: u128 = (account_reward as u128) + (validator_reward as u128); - -// // --- Subtract node delegator rewards -// if subnet_node.delegate_reward_rate != 0 { -// let total_node_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(subnet_id, hotkey_subnet_node_id); -// if total_node_delegated_stake_shares != 0 { -// let node_delegate_reward = Network::percent_mul(validator_total_reward, subnet_node.delegate_reward_rate); -// validator_total_reward = validator_total_reward - node_delegate_reward; -// } -// } - -// assert_eq!(stake_balance, amount + validator_total_reward); -// } else { -// // attestors -// let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); -// let mut reward: u128 = account_reward; - -// if subnet_node.delegate_reward_rate != 0 { -// let total_node_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(subnet_id, hotkey_subnet_node_id); -// if total_node_delegated_stake_shares != 0 { -// let node_delegate_reward = Network::percent_mul(reward, subnet_node.delegate_reward_rate); -// reward = reward - node_delegate_reward; -// } -// } - -// assert!(stake_balance == amount + reward, "Invalid subnet node staking rewards") -// } -// } -// }); -// } \ No newline at end of file + let base_reward_per_mb: u128 = BaseRewardPerMB::::get(); + let delegate_stake_rewards_percentage: u128 = DelegateStakeRewardsPercentage::::get(); + let overall_subnet_reward: u128 = Network::percent_mul(base_reward_per_mb, DEFAULT_MEM_MB); + let delegate_stake_reward: u128 = Network::percent_mul(overall_subnet_reward, delegate_stake_rewards_percentage); + let subnet_reward: u128 = overall_subnet_reward.saturating_sub(delegate_stake_reward); + + let sum = submission.data.iter().fold(0, |acc, x| acc + x.score); + let reward_ratio: u128 = Network::percent_div(DEFAULT_SCORE, sum); + let account_reward: u128 = Network::percent_mul(reward_ratio, subnet_reward); + + let base_reward = BaseValidatorReward::::get(); + + let submission_attestations: u128 = submission.attests.len() as u128; + let attestation_percentage: u128 = Network::percent_div(submission_attestations, submission_nodes_count); + + // check each subnet nodes balance increased + for n in 0..total_subnet_nodes { + let hotkey_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n)).unwrap(); + let subnet_node_id_hotkey = SubnetNodeIdHotkey::::get(subnet_id, hotkey_subnet_node_id).unwrap(); + let subnet_node = SubnetNodesData::::get(subnet_id, hotkey_subnet_node_id); + + if n == 0 { + // validator + let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); + let validator_reward: u128 = Network::percent_mul(base_reward, attestation_percentage); + let mut validator_total_reward: u128 = (account_reward as u128) + (validator_reward as u128); + + // --- Subtract node delegator rewards + if subnet_node.delegate_reward_rate != 0 { + let total_node_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(subnet_id, hotkey_subnet_node_id); + if total_node_delegated_stake_shares != 0 { + let node_delegate_reward = Network::percent_mul(validator_total_reward, subnet_node.delegate_reward_rate); + validator_total_reward = validator_total_reward - node_delegate_reward; + } + } + + assert_eq!(stake_balance, amount + validator_total_reward); + } else { + // attestors + let stake_balance: u128 = AccountSubnetStake::::get(&account(n), subnet_id); + let mut reward: u128 = account_reward; + + if subnet_node.delegate_reward_rate != 0 { + let total_node_delegated_stake_shares = TotalNodeDelegateStakeShares::::get(subnet_id, hotkey_subnet_node_id); + if total_node_delegated_stake_shares != 0 { + let node_delegate_reward = Network::percent_mul(reward, subnet_node.delegate_reward_rate); + reward = reward - node_delegate_reward; + } + } + + assert!(stake_balance == amount + reward, "Invalid subnet node staking rewards") + } + } + }); +} \ No newline at end of file diff --git a/pallets/network/src/tests/owner.rs b/pallets/network/src/tests/owner.rs deleted file mode 100644 index 68e9628..0000000 --- a/pallets/network/src/tests/owner.rs +++ /dev/null @@ -1,60 +0,0 @@ -use super::mock::*; -use crate::tests::test_utils::*; -use crate::Event; -use frame_support::{ - assert_noop, assert_ok, assert_err -}; -use log::info; -use frame_support::traits::{OnInitialize, Currency}; -use sp_std::collections::btree_set::BTreeSet; -use crate::{ - Error, - SubnetPaths, - MinSubnetNodes, - TotalSubnetNodes, - SubnetsData, - RegistrationSubnetData, - SubnetRemovalReason, - MinSubnetRegistrationBlocks, - MaxSubnetRegistrationBlocks, - SubnetActivationEnactmentBlocks, - HotkeySubnetNodeId, - SubnetRegistrationEpochs, - SubnetState, -}; - -// -// -// -// -// -// -// -// Subnets Add/Remove -// -// -// -// -// -// -// - -#[test] -fn test_register_subnet() { - new_test_ext().execute_with(|| { - let subnet_path: Vec = "petals-team/StableBeluga2".into(); - - let deposit_amount: u128 = 10000000000000000000000; - let amount: u128 = 1000000000000000000000; - - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); - - let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); - let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - - let n_account = total_subnet_nodes + 1; - - }) -} \ No newline at end of file diff --git a/pallets/network/src/tests/randomization.rs b/pallets/network/src/tests/randomization.rs index 1ae80a7..a07040c 100644 --- a/pallets/network/src/tests/randomization.rs +++ b/pallets/network/src/tests/randomization.rs @@ -20,7 +20,7 @@ use log::info; // /// // /// -pub fn setup_blocks(blocks: u32) { +pub fn setup_blocks(blocks: u64) { let mut parent_hash = System::parent_hash(); for i in 1..(blocks + 1) { diff --git a/pallets/network/src/tests/staking.rs b/pallets/network/src/tests/staking.rs index 9fbcd20..c9c0b46 100644 --- a/pallets/network/src/tests/staking.rs +++ b/pallets/network/src/tests/staking.rs @@ -15,7 +15,6 @@ use crate::{ TotalSubnetStake, SubnetNode, HotkeySubnetNodeId, - MinStakeBalance, }; // /// @@ -39,14 +38,14 @@ fn test_add_to_stake_err() { new_test_ext().execute_with(|| { let deposit_amount: u128 = 1000000000000000000000000; let amount: u128 = 1000000000000000000000; - let _ = Balances::deposit_creating(&account(1), deposit_amount); + let _ = Balances::deposit_creating(&account(0), deposit_amount); assert_err!( Network::add_to_stake( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), 0, 0, - account(1), + account(0), amount, ), Error::::SubnetNotExist, @@ -56,14 +55,12 @@ fn test_add_to_stake_err() { let deposit_amount: u128 = 1000000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - let _ = Balances::deposit_creating(&account(1), deposit_amount); + let _ = Balances::deposit_creating(&account(0), deposit_amount); assert_err!( Network::add_to_stake( @@ -86,32 +83,30 @@ fn test_add_to_stake() { let deposit_amount: u128 = 1000000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); let amount_staked = TotalSubnetStake::::get(subnet_id); - let _ = Balances::deposit_creating(&account(1), deposit_amount); + let _ = Balances::deposit_creating(&account(0), deposit_amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); assert_ok!( Network::add_to_stake( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, - account(1), + account(0), amount, ) ); - assert_eq!(Network::account_subnet_stake(account(1), subnet_id), amount + amount); - // assert_eq!(Network::total_account_stake(account(1)), amount + amount); + assert_eq!(Network::account_subnet_stake(account(0), subnet_id), amount + amount); + // assert_eq!(Network::total_account_stake(account(0)), amount + amount); assert_eq!(Network::total_stake(), amount_staked + amount); assert_eq!(Network::total_subnet_stake(subnet_id), amount_staked + amount); }); @@ -136,9 +131,7 @@ fn test_add_to_stake() { // // let subnet_path: Vec = "petals-team/StableBeluga2".into(); -// // let stake_amount: u128 = MinStakeBalance::::get(); - -// // build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); +// // build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); // // let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); // // let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -156,8 +149,8 @@ fn test_add_to_stake() { // // assert_err!( // // Network::remove_stake( -// // RuntimeOrigin::signed(account(1)), -// // account(1), +// // RuntimeOrigin::signed(account(0)), +// // account(0), // // subnet_id, // // 0, // // ), @@ -173,31 +166,29 @@ fn test_remove_stake() { let deposit_amount: u128 = 1000000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - let _ = Balances::deposit_creating(&account(1), deposit_amount); + let _ = Balances::deposit_creating(&account(0), deposit_amount); let subnet_path: Vec = "petals-team/StableBeluga2".into(); - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); // add double amount to stake assert_ok!( Network::add_to_stake( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, - account(1), + account(0), amount, ) ); - assert_eq!(Network::account_subnet_stake(account(1), subnet_id), amount + amount); - // assert_eq!(Network::total_account_stake(account(1)), amount + amount); + assert_eq!(Network::account_subnet_stake(account(0), subnet_id), amount + amount); + // assert_eq!(Network::total_account_stake(account(0)), amount + amount); // let epoch_length = EpochLength::get(); // let min_required_unstake_epochs = StakeCooldownEpochs::get(); @@ -206,15 +197,15 @@ fn test_remove_stake() { // remove amount ontop assert_ok!( Network::remove_stake( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, - account(1), + account(0), amount, ) ); - assert_eq!(Network::account_subnet_stake(account(1), subnet_id), amount); - // assert_eq!(Network::total_account_stake(account(1)), amount); + assert_eq!(Network::account_subnet_stake(account(0), subnet_id), amount); + // assert_eq!(Network::total_account_stake(account(0)), amount); }); } @@ -230,11 +221,11 @@ fn test_remove_stake() { // // let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); // // let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); -// // let _ = Balances::deposit_creating(&account(1), deposit_amount); +// // let _ = Balances::deposit_creating(&account(0), deposit_amount); // // assert_ok!( // // Network::remove_subnet_node( -// // RuntimeOrigin::signed(account(1)), +// // RuntimeOrigin::signed(account(0)), // // subnet_id, // // ) // // ); @@ -246,15 +237,15 @@ fn test_remove_stake() { // // // remove amount ontop // // assert_ok!( // // Network::remove_stake( -// // RuntimeOrigin::signed(account(1)), -// // account(1), +// // RuntimeOrigin::signed(account(0)), +// // account(0), // // subnet_id, // // amount, // // ) // // ); -// // assert_eq!(Network::account_subnet_stake(account(1), 1), 0); -// // assert_eq!(Network::total_account_stake(account(1)), 0); +// // assert_eq!(Network::account_subnet_stake(account(0), 1), 0); +// // assert_eq!(Network::total_account_stake(account(0)), 0); // // assert_eq!(Network::total_stake(), 0); // // assert_eq!(Network::total_subnet_stake(1), 0); // // }); diff --git a/pallets/network/src/tests/steps.rs b/pallets/network/src/tests/steps.rs index e040b12..9bfd481 100644 --- a/pallets/network/src/tests/steps.rs +++ b/pallets/network/src/tests/steps.rs @@ -20,121 +20,121 @@ use crate::{ SubnetNodeClass, }; -// #[test] -// fn test_epoch_steps() { -// new_test_ext().execute_with(|| { -// let subnet_path: Vec = "petals-team/StableBeluga2".into(); -// let deposit_amount: u128 = 10000000000000000000000; -// let amount: u128 = 1000000000000000000000; +#[test] +fn test_epoch_steps() { + new_test_ext().execute_with(|| { + let subnet_path: Vec = "petals-team/StableBeluga2".into(); + let deposit_amount: u128 = 10000000000000000000000; + let amount: u128 = 1000000000000000000000; -// let n_peers = 8; -// build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, amount); + let n_peers = 8; + build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, amount); -// let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); + let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); -// let epoch_length = EpochLength::get(); -// let epoch = System::block_number() / epoch_length; + let epoch_length = EpochLength::get(); + let epoch = System::block_number() / epoch_length; -// let included_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Included, epoch); -// let initial_total_subnet_nodes = included_nodes.len() as u32; + let included_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Included, epoch); + let initial_total_subnet_nodes = included_nodes.len() as u32; -// for n in 1..6+1 { -// let epoch = System::block_number() / epoch_length; -// log::error!("test_epoch_steps epoch: {:?}", epoch); + for n in 0..6 { + let epoch = System::block_number() / epoch_length; + log::error!("test_epoch_steps epoch: {:?}", epoch); -// Network::do_epoch_preliminaries(System::block_number(), epoch, epoch_length); + Network::do_epoch_preliminaries(System::block_number(), epoch as u32, epoch_length); -// let included_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Included, epoch); -// let included_nodes_count = included_nodes.len() as u128; + let included_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Included, epoch); + let included_nodes_count = included_nodes.len() as u128; -// log::error!("included_nodes_count {:?}", included_nodes_count); + log::error!("included_nodes_count {:?}", included_nodes_count); -// let submittable_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Validator, epoch); -// let submittable_nodes_count = submittable_nodes.len() as u128; + let submittable_nodes: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Validator, epoch); + let submittable_nodes_count = submittable_nodes.len() as u128; -// // --- Get validator -// let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch).unwrap(); -// let mut validator = SubnetNodeIdHotkey::::get(subnet_id, validator_id).unwrap(); + // --- Get validator + let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch as u32).unwrap(); + let mut validator = SubnetNodeIdHotkey::::get(subnet_id, validator_id).unwrap(); -// let subnet_node_data_vec = subnet_node_data(0, (included_nodes_count) as u32); -// let subnet_node_data_vec_len = subnet_node_data_vec.len(); -// log::error!("subnet_node_data_vec_len {:?}", subnet_node_data_vec_len); + let subnet_node_data_vec = subnet_node_data(0, (included_nodes_count) as u32); + let subnet_node_data_vec_len = subnet_node_data_vec.len(); + log::error!("subnet_node_data_vec_len {:?}", subnet_node_data_vec_len); -// for node in &subnet_node_data_vec { + for node in &subnet_node_data_vec { -// if node.peer_id == peer(n_peers) { -// log::error!("node in subnet_node_data_vec"); + if node.peer_id == peer(n_peers) { + log::error!("node in subnet_node_data_vec"); -// } -// } + } + } -// assert_ok!( -// Network::validate( -// RuntimeOrigin::signed(validator.clone()), -// subnet_id, -// subnet_node_data_vec.clone(), -// None, -// ) -// ); + assert_ok!( + Network::validate( + RuntimeOrigin::signed(validator.clone()), + subnet_id, + subnet_node_data_vec.clone(), + None, + ) + ); -// // Attest -// for n in 1..(submittable_nodes_count as u32)+1 { -// if account(n) == validator.clone() { -// continue -// } -// assert_ok!( -// Network::attest( -// RuntimeOrigin::signed(account(n)), -// subnet_id, -// ) -// ); -// } + // Attest + for n in 0..(submittable_nodes_count as u32) { + if account(n) == validator.clone() { + continue + } + assert_ok!( + Network::attest( + RuntimeOrigin::signed(account(n)), + subnet_id, + ) + ); + } -// let submission = SubnetRewardsSubmission::::get(subnet_id, epoch).unwrap(); + let submission = SubnetRewardsSubmission::::get(subnet_id, epoch as u32).unwrap(); -// assert_eq!(submission.validator_id, validator_id); -// assert_eq!(submission.data.len(), subnet_node_data_vec.len()); -// assert_eq!(submission.attests.len(), submittable_nodes_count as usize); - -// Network::reward_subnets(System::block_number(), epoch); - -// // Add new subnet node and check if they're inclusion on next epoch -// if n == 0 { -// let _ = Balances::deposit_creating(&account(n_peers), deposit_amount); -// assert_ok!( -// Network::add_subnet_node( -// RuntimeOrigin::signed(account(n_peers)), -// subnet_id, -// account(n_peers), -// peer(n_peers), -// 0, -// amount, -// None, -// None, -// None, -// ) -// ); -// // activated as Queue -// let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n_peers)).unwrap(); -// let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); -// assert_eq!(subnet_node.classification.class, SubnetNodeClass::Queue); -// } else if n == 1 { -// let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n_peers)).unwrap(); -// // automatically upgraded to Included after first next epoch -// let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); -// assert_eq!(subnet_node.classification.class, SubnetNodeClass::Included); -// } else if n == 2 { -// let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n_peers)).unwrap(); -// // automatically upgraded to Validator after first next epoch -// let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); -// assert_eq!(subnet_node.classification.class, SubnetNodeClass::Validator); -// } else { -// let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n_peers)).unwrap(); -// let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); -// assert_eq!(subnet_node.classification.class, SubnetNodeClass::Validator); -// } + assert_eq!(submission.validator_id, validator_id); + assert_eq!(submission.data.len(), subnet_node_data_vec.len()); + assert_eq!(submission.attests.len(), submittable_nodes_count as usize); + + Network::reward_subnets(System::block_number(), epoch as u32); + + // Add new subnet node and check if they're inclusion on next epoch + if n == 0 { + let _ = Balances::deposit_creating(&account(n_peers), deposit_amount); + assert_ok!( + Network::add_subnet_node( + RuntimeOrigin::signed(account(n_peers)), + subnet_id, + account(n_peers), + peer(n_peers), + 0, + amount, + None, + None, + None, + ) + ); + // activated as Idle + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n_peers)).unwrap(); + let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); + assert_eq!(subnet_node.classification.class, SubnetNodeClass::Idle); + } else if n == 1 { + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n_peers)).unwrap(); + // automatically upgraded to Included after first next epoch + let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); + assert_eq!(subnet_node.classification.class, SubnetNodeClass::Included); + } else if n == 2 { + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n_peers)).unwrap(); + // automatically upgraded to Validator after first next epoch + let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); + assert_eq!(subnet_node.classification.class, SubnetNodeClass::Validator); + } else { + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n_peers)).unwrap(); + let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); + assert_eq!(subnet_node.classification.class, SubnetNodeClass::Validator); + } -// increase_epochs(1); -// } -// }); -// } + increase_epochs(1); + } + }); +} diff --git a/pallets/network/src/tests/subnet.rs b/pallets/network/src/tests/subnet.rs index 692cb96..2436506 100644 --- a/pallets/network/src/tests/subnet.rs +++ b/pallets/network/src/tests/subnet.rs @@ -6,22 +6,17 @@ use frame_support::{ }; use log::info; use frame_support::traits::{OnInitialize, Currency}; -use sp_std::collections::btree_set::BTreeSet; + use crate::{ Error, - SubnetPaths, - MinSubnetNodes, - TotalSubnetNodes, + SubnetPaths, MinSubnetNodes, TotalSubnetNodes, SubnetsData, RegistrationSubnetData, - SubnetRemovalReason, - MinSubnetRegistrationBlocks, - MaxSubnetRegistrationBlocks, - SubnetActivationEnactmentBlocks, + SubnetRemovalReason, BaseSubnetNodeMemoryMB, + MinSubnetDelegateStakePercentage, + MaxSubnetMemoryMB, TotalSubnetMemoryMB, MaxTotalSubnetMemoryMB, + MinSubnetRegistrationBlocks, MaxSubnetRegistrationBlocks, SubnetActivationEnactmentPeriod, HotkeySubnetNodeId, - SubnetRegistrationEpochs, - SubnetState, - MinStakeBalance, }; // @@ -49,30 +44,24 @@ fn test_register_subnet() { let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); let _ = Balances::deposit_creating(&account(0), cost+1000); - let min_nodes = MinSubnetNodes::::get(); - - let whitelist = get_coldkey_whitelist(0, min_nodes+1); - + let registration_blocks = MinSubnetRegistrationBlocks::::get(); + let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); // --- Register subnet for activation assert_ok!( @@ -84,11 +73,8 @@ fn test_register_subnet() { let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let subnet = SubnetsData::::get(subnet_id).unwrap(); - - // Check treasury pot - let minimum_balance = Balances::minimum_balance(); - let pot = Treasury::pot(); - assert_eq!(cost, pot + minimum_balance); + + let min_nodes = subnet.min_nodes; }) } @@ -103,30 +89,24 @@ fn test_register_subnet_subnet_registration_cooldown() { let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); let _ = Balances::deposit_creating(&account(0), cost+1000); - let min_nodes = MinSubnetNodes::::get(); - - let whitelist = get_coldkey_whitelist(0, min_nodes+1); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist.clone(), - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - // increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + // increase_epochs(next_registration_epoch - epoch as u32); // --- Register subnet for activation assert_ok!( @@ -143,13 +123,9 @@ fn test_register_subnet_subnet_registration_cooldown() { let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist.clone(), - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; assert_err!( @@ -163,14 +139,14 @@ fn test_register_subnet_subnet_registration_cooldown() { let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); increase_epochs(next_registration_epoch); let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); let _ = Balances::deposit_creating(&account(0), cost+1000); @@ -187,13 +163,9 @@ fn test_register_subnet_subnet_registration_cooldown() { let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist.clone(), - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; assert_err!( @@ -215,30 +187,24 @@ fn test_register_subnet_exists_error() { let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); let _ = Balances::deposit_creating(&account(0), cost+1000); - let min_nodes = MinSubnetNodes::::get(); - - let whitelist = get_coldkey_whitelist(0, min_nodes+1); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); // --- Register subnet for activation assert_ok!( @@ -259,143 +225,176 @@ fn test_register_subnet_exists_error() { }) } -// #[test] -// fn test_register_subnet_registration_blocks_err() { -// new_test_ext().execute_with(|| { -// let subnet_path: Vec = "petals-team/StableBeluga2".into(); +#[test] +fn test_register_subnet_registration_blocks_err() { + new_test_ext().execute_with(|| { + let subnet_path: Vec = "petals-team/StableBeluga2".into(); -// let epoch_length = EpochLength::get(); -// let block_number = System::block_number(); -// let epoch = System::block_number().saturating_div(epoch_length); + let epoch_length = EpochLength::get(); + let block_number = System::block_number(); + let epoch = System::block_number().saturating_div(epoch_length); -// let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); -// let _ = Balances::deposit_creating(&account(0), cost+1000); + let _ = Balances::deposit_creating(&account(0), cost+1000); -// let add_subnet_data = RegistrationSubnetData { -// path: subnet_path.clone().into(), -// max_node_registration_epochs: 16, -// node_registration_interval: 0, -// // coldkey_whitelist: Some(BTreeSet::new()), -// coldkey_whitelist: None, -// }; + let add_subnet_data = RegistrationSubnetData { + path: subnet_path.clone().into(), + memory_mb: DEFAULT_MEM_MB, + registration_blocks: MinSubnetRegistrationBlocks::::get() - 1, + entry_interval: 0, + }; -// let epoch_length = EpochLength::get(); -// let block_number = System::block_number(); -// let epoch = System::block_number().saturating_div(epoch_length); -// let next_registration_epoch = Network::get_next_registration_epoch(epoch); -// increase_epochs(next_registration_epoch - epoch); - -// assert_err!( -// Network::register_subnet( -// RuntimeOrigin::signed(account(0)), -// add_subnet_data, -// ), -// Error::::InvalidSubnetRegistrationBlocks -// ); + let epoch_length = EpochLength::get(); + let block_number = System::block_number(); + let epoch = System::block_number().saturating_div(epoch_length); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); -// let add_subnet_data = RegistrationSubnetData { -// path: subnet_path.clone().into(), -// max_node_registration_epochs: 16, -// node_registration_interval: 0, -// // coldkey_whitelist: Some(BTreeSet::new()), -// coldkey_whitelist: None, -// }; + assert_err!( + Network::register_subnet( + RuntimeOrigin::signed(account(0)), + add_subnet_data, + ), + Error::::InvalidSubnetRegistrationBlocks + ); -// assert_err!( -// Network::register_subnet( -// RuntimeOrigin::signed(account(0)), -// add_subnet_data, -// ), -// Error::::InvalidSubnetRegistrationBlocks -// ); -// }) -// } + let add_subnet_data = RegistrationSubnetData { + path: subnet_path.clone().into(), + memory_mb: DEFAULT_MEM_MB, + registration_blocks: MaxSubnetRegistrationBlocks::::get() + 1, + entry_interval: 0, + }; -// #[test] -// fn test_register_subnet_max_total_subnet_mem_err() { -// new_test_ext().execute_with(|| { -// let epoch_length = EpochLength::get(); -// let block_number = System::block_number(); -// let epoch = System::block_number().saturating_div(epoch_length); + assert_err!( + Network::register_subnet( + RuntimeOrigin::signed(account(0)), + add_subnet_data, + ), + Error::::InvalidSubnetRegistrationBlocks + ); + }) +} + +#[test] +fn test_register_subnet_max_subnet_mem_err() { + new_test_ext().execute_with(|| { + let epoch_length = EpochLength::get(); + let block_number = System::block_number(); + let epoch = System::block_number().saturating_div(epoch_length); + + let cost = Network::registration_cost(epoch as u32); -// let cost = Network::registration_cost(epoch); + let _ = Balances::deposit_creating(&account(0), cost+1000); + + let max_subnet_mem = MaxSubnetMemoryMB::::get(); + + let registration_blocks = MinSubnetRegistrationBlocks::::get(); + + let subnet_path: Vec = "petals-team/StableBeluga2".into(); + let add_subnet_data = RegistrationSubnetData { + path: subnet_path.into(), + memory_mb: max_subnet_mem+1, + registration_blocks: registration_blocks, + entry_interval: 0, + }; + + let epoch_length = EpochLength::get(); + let block_number = System::block_number(); + let epoch = System::block_number().saturating_div(epoch_length); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); + + assert_err!( + Network::register_subnet( + RuntimeOrigin::signed(account(0)), + add_subnet_data, + ), + Error::::MaxSubnetMemory + ); + }) +} + +#[test] +fn test_register_subnet_max_total_subnet_mem_err() { + new_test_ext().execute_with(|| { + let epoch_length = EpochLength::get(); + let block_number = System::block_number(); + let epoch = System::block_number().saturating_div(epoch_length); + + let cost = Network::registration_cost(epoch as u32); -// let total_subnet_memory_mb = TotalSubnetMemoryMB::::get(); - -// // Limit while loop to 10 ierations -// let iterations = 11; -// let epoch_length = EpochLength::get(); - -// let mut current_total_subnet_memory_mb = total_subnet_memory_mb; - -// for n in 0..iterations { -// let epoch_length = EpochLength::get(); -// let block_number = System::block_number(); -// let epoch = System::block_number().saturating_div(epoch_length); -// let next_registration_epoch = Network::get_next_registration_epoch(epoch); -// increase_epochs(next_registration_epoch - epoch); - -// let _ = Balances::deposit_creating(&account(0), cost+1000); - -// let path: Vec = format!("model-name-{n}").into(); - -// let add_subnet_data = RegistrationSubnetData { -// path: path, -// max_node_registration_epochs: 16, -// node_registration_interval: 0, - // coldkey_whitelist: Some(BTreeSet::new()), - // coldkey_whitelist: None, -// }; - -// let next_subnet_total_memory_mb = TotalSubnetMemoryMB::::get() + subnet_mem_mb; - -// if next_subnet_total_memory_mb <= max_total_subnet_memory_mb { -// assert_ok!( -// Network::register_subnet( -// RuntimeOrigin::signed(account(0)), -// add_subnet_data, -// ) -// ); -// } else { -// assert_err!( -// Network::register_subnet( -// RuntimeOrigin::signed(account(0)), -// add_subnet_data, -// ), -// Error::::MaxTotalSubnetMemory -// ); -// } -// } -// }) -// } + let max_total_subnet_memory_mb = MaxTotalSubnetMemoryMB::::get(); + let total_subnet_memory_mb = TotalSubnetMemoryMB::::get(); + + // Limit while loop to 10 ierations + let iterations = 11; + let subnet_mem_mb = max_total_subnet_memory_mb / (iterations-1); + let epoch_length = EpochLength::get(); + + let mut current_total_subnet_memory_mb = total_subnet_memory_mb; + + for n in 0..iterations { + let epoch_length = EpochLength::get(); + let block_number = System::block_number(); + let epoch = System::block_number().saturating_div(epoch_length); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); + + let _ = Balances::deposit_creating(&account(0), cost+1000); + + let path: Vec = format!("model-name-{n}").into(); + + let registration_blocks = MinSubnetRegistrationBlocks::::get(); + + let add_subnet_data = RegistrationSubnetData { + path: path, + memory_mb: subnet_mem_mb, + registration_blocks: registration_blocks, + entry_interval: 0, + }; + + let next_subnet_total_memory_mb = TotalSubnetMemoryMB::::get() + subnet_mem_mb; + + if next_subnet_total_memory_mb <= max_total_subnet_memory_mb { + assert_ok!( + Network::register_subnet( + RuntimeOrigin::signed(account(0)), + add_subnet_data, + ) + ); + } else { + assert_err!( + Network::register_subnet( + RuntimeOrigin::signed(account(0)), + add_subnet_data, + ), + Error::::MaxTotalSubnetMemory + ); + } + } + }) +} #[test] fn test_register_subnet_not_enough_balance_err() { new_test_ext().execute_with(|| { // let _ = Balances::deposit_creating(&account(0), cost+1000); let subnet_path: Vec = "petals-team/StableBeluga2".into(); - - let min_nodes = MinSubnetNodes::::get(); - - let whitelist = get_coldkey_whitelist(0, min_nodes+1); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); assert_err!( Network::register_subnet( @@ -416,30 +415,24 @@ fn test_activate_subnet() { let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); let _ = Balances::deposit_creating(&account(0), cost+1000); - let min_nodes = MinSubnetNodes::::get(); - - let whitelist = get_coldkey_whitelist(0, min_nodes+1); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); // --- Register subnet for activation assert_ok!( @@ -454,12 +447,17 @@ fn test_activate_subnet() { let id = subnet.id; let path = subnet.path; - let min_nodes = MinSubnetNodes::::get(); + let min_nodes = subnet.min_nodes; + let target_nodes = subnet.target_nodes; + let memory_mb = subnet.memory_mb; + let initialized = subnet.initialized; + let registration_blocks = subnet.registration_blocks; + let activated = subnet.activated; // --- Add subnet nodes let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - for n in 1..min_nodes+1 { + for n in 0..min_nodes { let _ = Balances::deposit_creating(&account(n), deposit_amount); assert_ok!( Network::add_subnet_node( @@ -467,7 +465,6 @@ fn test_activate_subnet() { subnet_id, account(n), peer(n), - peer(n), 0, amount, None, @@ -477,7 +474,7 @@ fn test_activate_subnet() { ); } - let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance(); + let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance(min_nodes); // --- Add the minimum required delegate stake balance to activate the subnet assert_ok!( Network::add_to_delegate_stake( @@ -488,9 +485,8 @@ fn test_activate_subnet() { ); // --- Increase blocks to max registration block - let epochs = SubnetRegistrationEpochs::::get(); - increase_epochs(epochs + 1); - let current_epoch = get_epoch(); + System::set_block_number(System::block_number() + subnet.registration_blocks + 1); + let current_block_number = System::block_number(); assert_ok!( Network::activate_subnet( @@ -506,7 +502,13 @@ fn test_activate_subnet() { // ensure subnet exists and nothing changed but the activation block assert_eq!(subnet.id, id); assert_eq!(subnet.path, path); - assert_eq!(subnet.state, SubnetState::Active); + assert_eq!(subnet.min_nodes, min_nodes); + assert_eq!(subnet.target_nodes, target_nodes); + assert_eq!(subnet.memory_mb, memory_mb); + assert_eq!(subnet.initialized, initialized); + assert_eq!(subnet.registration_blocks, registration_blocks); + // ensure activated block updated + assert_eq!(subnet.activated, current_block_number); }) } @@ -519,30 +521,24 @@ fn test_activate_subnet_invalid_subnet_id_error() { let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); let _ = Balances::deposit_creating(&account(0), cost+1000); - let min_nodes = MinSubnetNodes::::get(); - - let whitelist = get_coldkey_whitelist(0, min_nodes+1); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); // --- Register subnet for activation assert_ok!( @@ -557,12 +553,17 @@ fn test_activate_subnet_invalid_subnet_id_error() { let id = subnet.id; let path = subnet.path; - let min_nodes = MinSubnetNodes::::get(); + let min_nodes = subnet.min_nodes; + let target_nodes = subnet.target_nodes; + let memory_mb = subnet.memory_mb; + let initialized = subnet.initialized; + let registration_blocks = subnet.registration_blocks; + let activated = subnet.activated; // --- Add subnet nodes let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - for n in 1..min_nodes+1 { + for n in 0..min_nodes { let _ = Balances::deposit_creating(&account(n), deposit_amount); assert_ok!( Network::add_subnet_node( @@ -570,7 +571,6 @@ fn test_activate_subnet_invalid_subnet_id_error() { subnet_id, account(n), peer(n), - peer(n), 0, amount, None, @@ -599,30 +599,24 @@ fn test_activate_subnet_already_activated_err() { let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); let _ = Balances::deposit_creating(&account(0), cost+1000); - let min_nodes = MinSubnetNodes::::get(); - - let whitelist = get_coldkey_whitelist(0, min_nodes+1); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); // --- Register subnet for activation assert_ok!( @@ -637,12 +631,17 @@ fn test_activate_subnet_already_activated_err() { let id = subnet.id; let path = subnet.path; - let min_nodes = MinSubnetNodes::::get(); + let min_nodes = subnet.min_nodes; + let target_nodes = subnet.target_nodes; + let memory_mb = subnet.memory_mb; + let initialized = subnet.initialized; + let registration_blocks = subnet.registration_blocks; + let activated = subnet.activated; // --- Add subnet nodes let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - for n in 1..min_nodes+1 { + for n in 0..min_nodes { let _ = Balances::deposit_creating(&account(n), deposit_amount); assert_ok!( Network::add_subnet_node( @@ -650,7 +649,6 @@ fn test_activate_subnet_already_activated_err() { subnet_id, account(n), peer(n), - peer(n), 0, amount, None, @@ -660,7 +658,7 @@ fn test_activate_subnet_already_activated_err() { ); } - let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance(); + let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance(min_nodes); // --- Add the minimum required delegate stake balance to activate the subnet assert_ok!( Network::add_to_delegate_stake( @@ -671,9 +669,8 @@ fn test_activate_subnet_already_activated_err() { ); // --- Increase blocks to max registration block - let epochs = SubnetRegistrationEpochs::::get(); - increase_epochs(epochs + 1); - let current_epoch = get_epoch(); + System::set_block_number(System::block_number() + subnet.registration_blocks + 1); + let current_block_number = System::block_number(); assert_ok!( Network::activate_subnet( @@ -701,30 +698,24 @@ fn test_activate_subnet_enactment_period_remove_subnet() { let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); let _ = Balances::deposit_creating(&account(0), cost+1000); - let min_nodes = MinSubnetNodes::::get(); - - let whitelist = get_coldkey_whitelist(0, min_nodes+1); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); // --- Register subnet for activation assert_ok!( @@ -739,12 +730,17 @@ fn test_activate_subnet_enactment_period_remove_subnet() { let id = subnet.id; let path = subnet.path; - let min_nodes = MinSubnetNodes::::get(); + let min_nodes = subnet.min_nodes; + let target_nodes = subnet.target_nodes; + let memory_mb = subnet.memory_mb; + let initialized = subnet.initialized; + let registration_blocks = subnet.registration_blocks; + let activated = subnet.activated; // --- Add subnet nodes let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - for n in 1..min_nodes+1 { + for n in 0..min_nodes { let _ = Balances::deposit_creating(&account(n), deposit_amount); assert_ok!( Network::add_subnet_node( @@ -752,7 +748,6 @@ fn test_activate_subnet_enactment_period_remove_subnet() { subnet_id, account(n), peer(n), - peer(n), 0, amount, None, @@ -764,7 +759,7 @@ fn test_activate_subnet_enactment_period_remove_subnet() { let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance(); + let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance(min_nodes); // --- Add the minimum required delegate stake balance to activate the subnet assert_ok!( Network::add_to_delegate_stake( @@ -775,9 +770,8 @@ fn test_activate_subnet_enactment_period_remove_subnet() { ); // --- Increase blocks to max registration block - let registration_epochs = SubnetRegistrationEpochs::::get(); - let enactment_epochs = SubnetActivationEnactmentBlocks::::get(); - increase_epochs(registration_epochs + enactment_epochs + 1); + System::set_block_number(System::block_number() + subnet.registration_blocks + SubnetActivationEnactmentPeriod::::get() + 1); + let current_block_number = System::block_number(); assert_ok!( Network::activate_subnet( @@ -800,7 +794,7 @@ fn test_activate_subnet_enactment_period_remove_subnet() { assert_eq!(subnet, Err(())); // --- Ensure nodes can be removed and unstake - post_subnet_removal_ensures(subnet_id, subnet_path, 0, total_subnet_nodes); + post_subnet_removal_ensures(subnet_id, 0, total_subnet_nodes); }) } @@ -814,30 +808,24 @@ fn test_activate_subnet_initializing_error() { let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); let _ = Balances::deposit_creating(&account(0), cost+1000); - let min_nodes = MinSubnetNodes::::get(); - - let whitelist = get_coldkey_whitelist(0, min_nodes+1); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); // --- Register subnet for activation assert_ok!( @@ -852,12 +840,17 @@ fn test_activate_subnet_initializing_error() { let id = subnet.id; let path = subnet.path; - let min_nodes = MinSubnetNodes::::get(); + let min_nodes = subnet.min_nodes; + let target_nodes = subnet.target_nodes; + let memory_mb = subnet.memory_mb; + let initialized = subnet.initialized; + let registration_blocks = subnet.registration_blocks; + let activated = subnet.activated; // --- Add subnet nodes let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - for n in 1..min_nodes+1 { + for n in 0..min_nodes { let _ = Balances::deposit_creating(&account(n), deposit_amount); assert_ok!( Network::add_subnet_node( @@ -865,7 +858,6 @@ fn test_activate_subnet_initializing_error() { subnet_id, account(n), peer(n), - peer(n), 0, amount, None, @@ -875,7 +867,7 @@ fn test_activate_subnet_initializing_error() { ); } - let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance(); + let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance(min_nodes); // --- Add the minimum required delegate stake balance to activate the subnet assert_ok!( Network::add_to_delegate_stake( @@ -885,6 +877,10 @@ fn test_activate_subnet_initializing_error() { ) ); + // --- Increase blocks to max registration block + // System::set_block_number(System::block_number() + subnet.registration_blocks + 1); + // let current_block_number = System::block_number(); + assert_err!( Network::activate_subnet( RuntimeOrigin::signed(account(0)), @@ -902,9 +898,7 @@ fn test_not_subnet_node_owner() { let deposit_amount: u128 = 1000000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -920,7 +914,6 @@ fn test_not_subnet_node_owner() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -966,30 +959,24 @@ fn test_activate_subnet_min_subnet_nodes_remove_subnet() { let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); let _ = Balances::deposit_creating(&account(0), cost+1000); - let min_nodes = MinSubnetNodes::::get(); - - let whitelist = get_coldkey_whitelist(0, min_nodes+1); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); // --- Register subnet for activation assert_ok!( @@ -1004,11 +991,16 @@ fn test_activate_subnet_min_subnet_nodes_remove_subnet() { let id = subnet.id; let path = subnet.path; - let min_nodes = MinSubnetNodes::::get(); + let min_nodes = subnet.min_nodes; + let target_nodes = subnet.target_nodes; + let memory_mb = subnet.memory_mb; + let initialized = subnet.initialized; + let registration_blocks = subnet.registration_blocks; + let activated = subnet.activated; - // --- Increase epochs to max registration epoch - let epochs = SubnetRegistrationEpochs::::get(); - increase_epochs(epochs + 1); + // --- Increase blocks to max registration block + System::set_block_number(System::block_number() + subnet.registration_blocks + 1); + let current_block_number = System::block_number(); assert_ok!( Network::activate_subnet( @@ -1041,30 +1033,24 @@ fn test_activate_subnet_min_delegate_balance_remove_subnet() { let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); let _ = Balances::deposit_creating(&account(0), cost+1000); - let min_nodes = MinSubnetNodes::::get(); - - let whitelist = get_coldkey_whitelist(0, min_nodes+1); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); // --- Register subnet for activation assert_ok!( @@ -1079,12 +1065,17 @@ fn test_activate_subnet_min_delegate_balance_remove_subnet() { let id = subnet.id; let path = subnet.path; - let min_nodes = MinSubnetNodes::::get(); + let min_nodes = subnet.min_nodes; + let target_nodes = subnet.target_nodes; + let memory_mb = subnet.memory_mb; + let initialized = subnet.initialized; + let registration_blocks = subnet.registration_blocks; + let activated = subnet.activated; // --- Add subnet nodes let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - for n in 1..min_nodes+1 { + for n in 0..min_nodes { let _ = Balances::deposit_creating(&account(n), deposit_amount); assert_ok!( Network::add_subnet_node( @@ -1092,7 +1083,6 @@ fn test_activate_subnet_min_delegate_balance_remove_subnet() { subnet_id, account(n), peer(n), - peer(n), 0, amount, None, @@ -1102,9 +1092,9 @@ fn test_activate_subnet_min_delegate_balance_remove_subnet() { ); } - // --- Increase epochs to max registration epoch - let epochs = SubnetRegistrationEpochs::::get(); - increase_epochs(epochs + 1); + // --- Increase blocks to max registration block + System::set_block_number(System::block_number() + subnet.registration_blocks + 1); + let current_block_number = System::block_number(); assert_ok!( Network::activate_subnet( @@ -1126,4 +1116,50 @@ fn test_activate_subnet_min_delegate_balance_remove_subnet() { let subnet = SubnetsData::::try_get(subnet_id); assert_eq!(subnet, Err(())); }) +} + +// #[test] +// fn test_get_min_subnet_delegate_stake_balance() { +// new_test_ext().execute_with(|| { +// let subnet_path: Vec = "petals-team/StableBeluga2".into(); +// let cost = Network::registration_cost(0); +// let _ = Balances::deposit_creating(&account(0), cost+1000); + +// let add_subnet_data = RegistrationSubnetData { +// path: subnet_path.clone().into(), +// memory_mb: 500_000, +// registration_blocks: DEFAULT_REGISTRATION_BLOCKS, +// entry_interval: 0, +// }; +// assert_ok!( +// Network::activate_subnet( +// RuntimeOrigin::signed(account(0)), +// account(0), +// add_subnet_data, +// ) +// ); + +// let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); +// let min_stake_balance = get_min_stake_balance(); +// let subnet = SubnetsData::::get(subnet_id).unwrap(); +// let min_subnet_delegate_stake_percentage = MinSubnetDelegateStakePercentage::::get(); + +// let subnet_min_stake_supply = min_stake_balance * subnet.min_nodes as u128; +// let presumed_min = Network::percent_mul(subnet_min_stake_supply, min_subnet_delegate_stake_percentage); + +// let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance(subnet.min_nodes); + +// assert_eq!(presumed_min, min_subnet_delegate_stake); +// }) +// } + +#[test] +fn test_get_min_subnet_nodes() { + new_test_ext().execute_with(|| { + let base_node_memory: u128 = BaseSubnetNodeMemoryMB::::get(); + let min_subnet_nodes = Network::get_min_subnet_nodes(base_node_memory, 500_000); + log::error!("min_subnet_nodes: {:?}", min_subnet_nodes); + + // assert_eq!(value, 333333333, "percent_div didn't round down"); + }); } \ No newline at end of file diff --git a/pallets/network/src/tests/subnet_node.rs b/pallets/network/src/tests/subnet_node.rs index bf96c3d..54d53a7 100644 --- a/pallets/network/src/tests/subnet_node.rs +++ b/pallets/network/src/tests/subnet_node.rs @@ -28,14 +28,11 @@ use crate::{ HotkeySubnetNodeId, SubnetNodeIdHotkey, SubnetNodesData, - PeerIdSubnetNode, + SubnetNodeAccount, DeactivationLedger, SubnetNodeDeactivation, MaxRewardRateDecrease, - RewardRateUpdatePeriod, - SubnetRegistrationEpochs, - MinStakeBalance, - RegisteredStakeCooldownEpochs, + RewardRateUpdatePeriod }; /// @@ -62,9 +59,7 @@ fn test_register_subnet_node() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -77,7 +72,6 @@ fn test_register_subnet_node() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -88,7 +82,7 @@ fn test_register_subnet_node() { let total_subnet_node_uids = TotalSubnetNodeUids::::get(subnet_id); let hotkey_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(total_subnet_nodes+1)).unwrap(); - assert_eq!(total_subnet_node_uids, hotkey_subnet_node_id); + assert_eq!(total_subnet_node_uids - 1, hotkey_subnet_node_id); let new_total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); assert_eq!(new_total_subnet_nodes, total_subnet_nodes + 1); @@ -97,9 +91,10 @@ fn test_register_subnet_node() { // assert_eq!(subnet_node.coldkey, account(total_subnet_nodes+1)); assert_eq!(subnet_node.hotkey, account(total_subnet_nodes+1)); assert_eq!(subnet_node.peer_id, peer(total_subnet_nodes+1)); + assert_eq!(subnet_node.initialized, 0); assert_eq!(subnet_node.classification.class, SubnetNodeClass::Registered); - let subnet_node_account = PeerIdSubnetNode::::get(subnet_id, peer(total_subnet_nodes+1)); + let subnet_node_account = SubnetNodeAccount::::get(subnet_id, peer(total_subnet_nodes+1)); assert_eq!(subnet_node_account, hotkey_subnet_node_id); let account_subnet_stake = AccountSubnetStake::::get(account(total_subnet_nodes+1), subnet_id); @@ -115,102 +110,85 @@ fn test_update_coldkey() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 16, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - let hotkey_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); - let starting_account_subnet_stake = AccountSubnetStake::::get(account(1), subnet_id); + let hotkey_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); + let starting_account_subnet_stake = AccountSubnetStake::::get(account(0), subnet_id); // add extra stake and then add to ledger to check if it swapped let add_stake_amount = 1000000000000000000000; - let _ = Balances::deposit_creating(&account(1), deposit_amount); - - // - // - // Coldkey = 1 - // Hotkey = 1 - // - // + let _ = Balances::deposit_creating(&account(0), deposit_amount); assert_ok!( Network::add_to_stake( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, hotkey_subnet_node_id, - account(1), + account(0), add_stake_amount, ) ); - let stake_balance = AccountSubnetStake::::get(&account(1), subnet_id); + let stake_balance = AccountSubnetStake::::get(&account(0), subnet_id); assert_eq!(stake_balance, starting_account_subnet_stake + add_stake_amount); assert_ok!( Network::remove_stake( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, - account(1), + account(0), amount, ) ); - let original_unbondings: BTreeMap = StakeUnbondingLedger::::get(account(1)); + let original_unbondings: BTreeMap = StakeUnbondingLedger::::get(account(0)); let original_ledger_balance: u128 = original_unbondings.values().copied().sum(); assert_eq!(original_unbondings.len() as u32, 1); assert_eq!(original_ledger_balance, amount); - /// Update the coldkey to unused key - // - // - // Coldkey = total_subnet_nodes+1 - // Hotkey = 1 - // - // - assert_ok!( Network::update_coldkey( - RuntimeOrigin::signed(account(1)), - account(1), + RuntimeOrigin::signed(account(0)), + account(0), account(total_subnet_nodes+1), ) ); // check old coldkey balance is now removed because it was swapped to the new one - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(1)); + let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(0)); let ledger_balance: u128 = unbondings.values().copied().sum(); assert_eq!(unbondings.len() as u32, 0); assert_eq!(ledger_balance, 0); // check new coldkey balance matches original - let new_unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); + let new_unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); let new_ledger_balance: u128 = new_unbondings.values().copied().sum(); assert_eq!(new_unbondings.len() as u32, original_unbondings.len() as u32); assert_eq!(new_ledger_balance, original_ledger_balance); let subnet_node_id_hotkey = SubnetNodeIdHotkey::::get(subnet_id, hotkey_subnet_node_id).unwrap(); - assert_eq!(subnet_node_id_hotkey, account(1)); + assert_eq!(subnet_node_id_hotkey, account(0)); let subnet_node_data = SubnetNodesData::::try_get(subnet_id, hotkey_subnet_node_id).unwrap(); - assert_eq!(subnet_node_data.hotkey, account(1)); + assert_eq!(subnet_node_data.hotkey, account(0)); - let key_owner = HotkeyOwner::::get(account(1)); + let key_owner = HotkeyOwner::::get(account(0)); assert_eq!(key_owner, account(total_subnet_nodes+1)); // Cold key is updated, shouldn't be able to make changes anywhere using coldkey let add_stake_amount: u128 = 1000000000000000000000; - let _ = Balances::deposit_creating(&account(1), add_stake_amount); + let _ = Balances::deposit_creating(&account(0), add_stake_amount); assert_err!( Network::add_to_stake( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, hotkey_subnet_node_id, - account(1), + account(0), add_stake_amount, ), Error::::NotKeyOwner, @@ -218,9 +196,9 @@ fn test_update_coldkey() { assert_err!( Network::remove_stake( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, - account(1), + account(0), 1000, ), Error::::NotKeyOwner @@ -229,7 +207,7 @@ fn test_update_coldkey() { // `do_deactivate_subnet_node` allows both hotkey and coldkey assert_err!( Network::do_deactivate_subnet_node( - RuntimeOrigin::signed(account(2)), + RuntimeOrigin::signed(account(1)), subnet_id, hotkey_subnet_node_id ), @@ -238,8 +216,8 @@ fn test_update_coldkey() { assert_err!( Network::update_coldkey( - RuntimeOrigin::signed(account(1)), - account(2), + RuntimeOrigin::signed(account(0)), + account(0), account(total_subnet_nodes+1), ), Error::::NotKeyOwner @@ -247,8 +225,8 @@ fn test_update_coldkey() { assert_err!( Network::update_hotkey( - RuntimeOrigin::signed(account(1)), - account(2), + RuntimeOrigin::signed(account(0)), + account(0), account(total_subnet_nodes+1), ), Error::::NotKeyOwner @@ -264,7 +242,7 @@ fn test_update_coldkey() { RuntimeOrigin::signed(account(total_subnet_nodes+1)), subnet_id, hotkey_subnet_node_id, - account(1), + account(0), add_stake_amount, ) ); @@ -273,7 +251,7 @@ fn test_update_coldkey() { Network::remove_stake( RuntimeOrigin::signed(account(total_subnet_nodes+1)), subnet_id, - account(1), + account(0), add_stake_amount, ) ); @@ -290,7 +268,7 @@ fn test_update_coldkey() { assert_ok!( Network::update_hotkey( RuntimeOrigin::signed(account(total_subnet_nodes+1)), - account(1), + account(0), account(total_subnet_nodes+15), ) ); @@ -322,9 +300,7 @@ fn test_update_coldkey_key_taken_err() { let amount: u128 = 1000000000000000000000; let n_peers = 8; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -332,7 +308,7 @@ fn test_update_coldkey_key_taken_err() { assert_err!( Network::update_coldkey( RuntimeOrigin::signed(account(1)), - account(2), + account(0), account(1), ), Error::::NotKeyOwner @@ -348,20 +324,18 @@ fn test_update_hotkey() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - let hotkey_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); - let starting_account_subnet_stake = AccountSubnetStake::::get(account(1), subnet_id); + let hotkey_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); + let starting_account_subnet_stake = AccountSubnetStake::::get(account(0), subnet_id); assert_ok!( Network::update_hotkey( - RuntimeOrigin::signed(account(1)), - account(1), + RuntimeOrigin::signed(account(0)), + account(0), account(total_subnet_nodes+1), ) ); @@ -373,9 +347,9 @@ fn test_update_hotkey() { assert_eq!(subnet_node_data.hotkey, account(total_subnet_nodes+1)); let key_owner = HotkeyOwner::::get(account(total_subnet_nodes+1)); - assert_eq!(key_owner, account(1)); + assert_eq!(key_owner, account(0)); - let account_subnet_stake = AccountSubnetStake::::get(account(1), subnet_id); + let account_subnet_stake = AccountSubnetStake::::get(account(0), subnet_id); assert_eq!(account_subnet_stake, 0); let account_subnet_stake = AccountSubnetStake::::get(account(total_subnet_nodes+1), subnet_id); @@ -386,7 +360,6 @@ fn test_update_hotkey() { #[test] fn test_register_subnet_node_subnet_registering_or_activated_error() { new_test_ext().execute_with(|| { - let _ = env_logger::builder().is_test(true).try_init(); let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; @@ -395,35 +368,31 @@ fn test_register_subnet_node_subnet_registering_or_activated_error() { let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); - let _ = Balances::deposit_creating(&account(1), cost+1000); + let _ = Balances::deposit_creating(&account(0), cost+1000); let subnet_path: Vec = "petals-team/StableBeluga2".into(); - let whitelist = get_coldkey_whitelist(0, 1); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); // --- Register subnet for activation assert_ok!( Network::register_subnet( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), add_subnet_data, ) ); @@ -431,17 +400,19 @@ fn test_register_subnet_node_subnet_registering_or_activated_error() { let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let subnet = SubnetsData::::get(subnet_id).unwrap(); - // push out of registration period and into enactment period - let epochs = SubnetRegistrationEpochs::::get(); - increase_epochs(epochs + 1); + log::error!("subnet.activated {:?}",subnet.activated ); + log::error!("subnet.initialized {:?}",subnet.initialized ); + log::error!("subnet.registration_blocks {:?}",subnet.registration_blocks ); + + System::set_block_number(System::block_number() + subnet.initialized + subnet.registration_blocks + 1); + assert_err!( Network::register_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, - account(1), - peer(1), - peer(1), + account(0), + peer(0), 0, amount, None, @@ -464,34 +435,31 @@ fn test_register_subnet_node_then_activate() { let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); - let _ = Balances::deposit_creating(&account(1), cost+deposit_amount); + let _ = Balances::deposit_creating(&account(0), cost+deposit_amount); let subnet_path: Vec = "petals-team/StableBeluga2".into(); - let whitelist = get_coldkey_whitelist(0, 1); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); // --- Register subnet for activation assert_ok!( Network::register_subnet( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), add_subnet_data, ) ); @@ -501,11 +469,10 @@ fn test_register_subnet_node_then_activate() { assert_ok!( Network::register_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, - account(1), - peer(1), - peer(1), + account(0), + peer(0), 0, amount, None, @@ -514,11 +481,11 @@ fn test_register_subnet_node_then_activate() { ), ); - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); assert_ok!( Network::activate_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id ), @@ -534,9 +501,7 @@ fn test_activate_subnet_then_register_subnet_node_then_activate() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -550,7 +515,6 @@ fn test_activate_subnet_then_register_subnet_node_then_activate() { subnet_id, account(n_account), peer(n_account), - peer(n_account), 0, amount, None, @@ -582,35 +546,31 @@ fn test_activate_subnet_node_subnet_registering_or_activated_error() { let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); - let _ = Balances::deposit_creating(&account(1), cost+1000+deposit_amount); + let _ = Balances::deposit_creating(&account(0), cost+1000+deposit_amount); let subnet_path: Vec = "petals-team/StableBeluga2".into(); - let whitelist = get_coldkey_whitelist(0, 1); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, - // coldkey_whitelist: None, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch - epoch); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); // --- Register subnet for activation assert_ok!( Network::register_subnet( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), add_subnet_data, ) ); @@ -620,11 +580,10 @@ fn test_activate_subnet_node_subnet_registering_or_activated_error() { assert_ok!( Network::register_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, - account(1), - peer(1), - peer(1), + account(0), + peer(0), 0, amount, None, @@ -633,11 +592,13 @@ fn test_activate_subnet_node_subnet_registering_or_activated_error() { ) ); - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); + + System::set_block_number(System::block_number() + registration_blocks + 1); // assert_err!( // Network::activate_subnet_node( - // RuntimeOrigin::signed(account(1)), + // RuntimeOrigin::signed(account(0)), // subnet_id, // subnet_node_id, // ), @@ -655,9 +616,7 @@ fn test_register_subnet_node_activate_subnet_node() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -670,7 +629,6 @@ fn test_register_subnet_node_activate_subnet_node() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -688,9 +646,10 @@ fn test_register_subnet_node_activate_subnet_node() { let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); assert_eq!(subnet_node.hotkey, account(total_subnet_nodes+1)); assert_eq!(subnet_node.peer_id, peer(total_subnet_nodes+1)); + assert_eq!(subnet_node.initialized, 0); assert_eq!(subnet_node.classification.class, SubnetNodeClass::Registered); - let subnet_node_account = PeerIdSubnetNode::::get(subnet_id, peer(total_subnet_nodes+1)); + let subnet_node_account = SubnetNodeAccount::::get(subnet_id, peer(total_subnet_nodes+1)); assert_eq!(subnet_node_account, subnet_node_id); let account_subnet_stake = AccountSubnetStake::::get(account(total_subnet_nodes+1), subnet_id); @@ -710,7 +669,8 @@ fn test_register_subnet_node_activate_subnet_node() { let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); - assert_eq!(subnet_node.classification.class, SubnetNodeClass::Queue); + assert_eq!(subnet_node.initialized, block_number); + assert_eq!(subnet_node.classification.class, SubnetNodeClass::Idle); assert_eq!(subnet_node.classification.start_epoch, epoch + 1); }) } @@ -723,14 +683,12 @@ fn test_deactivate_subnet_node_reactivate() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); assert_eq!(subnet_node.classification.class, SubnetNodeClass::Validator); @@ -740,7 +698,7 @@ fn test_deactivate_subnet_node_reactivate() { assert_ok!( Network::deactivate_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, ) @@ -755,7 +713,7 @@ fn test_deactivate_subnet_node_reactivate() { assert_ok!( Network::activate_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, ) @@ -775,11 +733,10 @@ fn test_add_subnet_node_subnet_err() { let amount: u128 = 1000; assert_err!( Network::add_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, - account(1), - peer(1), - peer(1), + account(0), + peer(0), 0, amount, None, @@ -792,11 +749,10 @@ fn test_add_subnet_node_subnet_err() { let subnet_id = 1; assert_err!(Network::add_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, - account(1), - peer(1), - peer(1), + account(0), + peer(0), 0, amount, None, @@ -816,16 +772,14 @@ fn test_get_classification_subnet_nodes() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - let submittable = Network::get_classified_subnet_nodes(subnet_id, &SubnetNodeClass::Validator, epoch); + let submittable = Network::get_classified_subnet_nodes(subnet_id, &SubnetNodeClass::Validator, epoch as u64); assert_eq!(submittable.len() as u32, total_subnet_nodes); }) @@ -839,9 +793,7 @@ fn test_add_subnet_node_not_exists_err() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -849,10 +801,9 @@ fn test_add_subnet_node_not_exists_err() { // add new peer_id under same account error assert_err!( Network::add_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, - account(1), - peer(1), + account(0), peer(1), 0, amount, @@ -871,8 +822,7 @@ fn test_add_subnet_node_not_exists_err() { RuntimeOrigin::signed(account(total_subnet_nodes+1)), subnet_id, account(total_subnet_nodes+1), - peer(1), - peer(1), + peer(0), 0, amount, None, @@ -887,10 +837,9 @@ fn test_add_subnet_node_not_exists_err() { // add new peer_id under same account error assert_err!( Network::add_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, - account(1), - peer(1), + account(0), peer(1), 0, amount, @@ -913,14 +862,12 @@ fn test_add_subnet_node_stake_err() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let deposit_amount: u128 = 100000; let amount: u128 = 1; - let _ = Balances::deposit_creating(&account(1), deposit_amount); + let _ = Balances::deposit_creating(&account(0), deposit_amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -930,7 +877,6 @@ fn test_add_subnet_node_stake_err() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -950,9 +896,7 @@ fn test_add_subnet_node_stake_not_enough_balance_err() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let deposit_amount: u128 = 999999999999999999999; @@ -966,7 +910,6 @@ fn test_add_subnet_node_stake_not_enough_balance_err() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -985,9 +928,7 @@ fn test_add_subnet_node_invalid_peer_id_err() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -995,15 +936,13 @@ fn test_add_subnet_node_invalid_peer_id_err() { let _ = Balances::deposit_creating(&account(total_subnet_nodes+1), deposit_amount); let peer_id = format!("2"); - let peer: PeerId = PeerId(peer_id.clone().into()); - let bootstrap_peer: PeerId = PeerId(peer_id.clone().into()); + let peer: PeerId = PeerId(peer_id.into()); assert_err!( Network::add_subnet_node( RuntimeOrigin::signed(account(total_subnet_nodes+1)), subnet_id, account(total_subnet_nodes+1), peer, - bootstrap_peer, 0, amount, None, @@ -1068,9 +1007,7 @@ fn test_add_subnet_node_remove_readd() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 16, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1085,7 +1022,6 @@ fn test_add_subnet_node_remove_readd() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1121,7 +1057,6 @@ fn test_add_subnet_node_remove_readd() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1139,9 +1074,7 @@ fn test_add_subnet_node_not_key_owner() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1156,7 +1089,6 @@ fn test_add_subnet_node_not_key_owner() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1186,9 +1118,7 @@ fn test_add_subnet_node_remove_readd_must_unstake_error() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 16, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1203,7 +1133,6 @@ fn test_add_subnet_node_remove_readd_must_unstake_error() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1228,7 +1157,6 @@ fn test_add_subnet_node_remove_readd_must_unstake_error() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1247,9 +1175,7 @@ fn test_add_subnet_node_remove_stake_partial_readd() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 16, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1264,7 +1190,6 @@ fn test_add_subnet_node_remove_stake_partial_readd() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1290,8 +1215,7 @@ fn test_add_subnet_node_remove_stake_partial_readd() { let epoch_length = EpochLength::get(); let min_required_unstake_epochs = StakeCooldownEpochs::get(); - // System::set_block_number(System::block_number() + epoch_length * min_required_unstake_epochs); - increase_epochs(min_required_unstake_epochs); + System::set_block_number(System::block_number() + epoch_length * min_required_unstake_epochs); let account_subnet_stake = AccountSubnetStake::::get(&account(total_subnet_nodes+1), subnet_id); @@ -1311,7 +1235,6 @@ fn test_add_subnet_node_remove_stake_partial_readd() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1329,9 +1252,7 @@ fn test_add_subnet_node_remove_stake_readd() { let deposit_amount: u128 = 1000000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 16, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1344,7 +1265,6 @@ fn test_add_subnet_node_remove_stake_readd() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1366,10 +1286,9 @@ fn test_add_subnet_node_remove_stake_readd() { // once blocks have been increased, account can either remove stake in part or in full or readd subnet peer let epoch_length = EpochLength::get(); let min_required_unstake_epochs = StakeCooldownEpochs::get(); - // System::set_block_number(System::block_number() + epoch_length * min_required_unstake_epochs); - increase_epochs(min_required_unstake_epochs); + System::set_block_number(System::block_number() + epoch_length * min_required_unstake_epochs); - let remaining_account_stake_balance: u128 = AccountSubnetStake::::get(&account(1), subnet_id); + let remaining_account_stake_balance: u128 = AccountSubnetStake::::get(&account(0), subnet_id); assert_ok!( Network::remove_stake( @@ -1387,7 +1306,6 @@ fn test_add_subnet_node_remove_stake_readd() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1406,9 +1324,7 @@ fn test_register_subnet_node_with_a_param() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1424,7 +1340,6 @@ fn test_register_subnet_node_with_a_param() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, Some(bounded_a.clone()), @@ -1448,9 +1363,7 @@ fn test_register_subnet_node_and_then_update_a_param() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1463,7 +1376,6 @@ fn test_register_subnet_node_and_then_update_a_param() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1533,9 +1445,7 @@ fn test_register_subnet_node_with_non_unique_param() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1554,7 +1464,6 @@ fn test_register_subnet_node_with_non_unique_param() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1580,26 +1489,24 @@ fn test_update_subnet_node_with_non_unique_param() { let deposit_amount: u128 = 10000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); - let _ = Balances::deposit_creating(&account(1), deposit_amount); + let _ = Balances::deposit_creating(&account(0), deposit_amount); let b: Vec = "b".into(); let bounded_b: BoundedVec = b.try_into().expect("String too long"); let c: Vec = "c".into(); let bounded_c: BoundedVec = c.try_into().expect("String too long"); - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); increase_epochs(1); assert_ok!( Network::set_subnet_node_non_unique_parameter( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, Some(bounded_b.clone()), @@ -1607,7 +1514,7 @@ fn test_update_subnet_node_with_non_unique_param() { ) ); - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); assert_eq!(subnet_node.b, Some(bounded_b.clone())); @@ -1615,7 +1522,7 @@ fn test_update_subnet_node_with_non_unique_param() { assert_err!( Network::set_subnet_node_non_unique_parameter( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, Some(bounded_b.clone()), @@ -1628,7 +1535,7 @@ fn test_update_subnet_node_with_non_unique_param() { assert_err!( Network::set_subnet_node_non_unique_parameter( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, None, @@ -1645,7 +1552,7 @@ fn test_update_subnet_node_with_non_unique_param() { assert_ok!( Network::set_subnet_node_non_unique_parameter( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, Some(bounded_b2.clone()), @@ -1713,7 +1620,7 @@ fn test_update_subnet_node_with_non_unique_param() { // // // build_subnet(subnet_path.clone()); // // // let deposit_amount: u128 = 1000000000000000000000000; // // // let amount: u128 = 1000000000000000000000; -// // // let _ = Balances::deposit_creating(&account(1), deposit_amount); +// // // let _ = Balances::deposit_creating(&account(0), deposit_amount); // // // let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); @@ -1723,17 +1630,17 @@ fn test_update_subnet_node_with_non_unique_param() { // // // assert_ok!( // // // Network::add_subnet_node( -// // // RuntimeOrigin::signed(account(1)), -// // account(1), +// // // RuntimeOrigin::signed(account(0)), +// // account(0), // // // subnet_id, -// // // peer(1), +// // // peer(0), // // // amount, // // // ) // // // ); // // // post_successful_add_subnet_node_asserts(0, subnet_id, amount); // // // assert_eq!(Network::total_subnet_nodes(1), 1); -// // // assert_eq!(Network::account_subnet_stake(account(1), 1), amount); -// // // assert_eq!(Network::total_account_stake(account(1)), amount); +// // // assert_eq!(Network::account_subnet_stake(account(0), 1), amount); +// // // assert_eq!(Network::total_account_stake(account(0)), amount); // // // assert_eq!(Network::total_stake(), amount); // // // assert_eq!(Network::total_subnet_stake(1), amount); @@ -1744,7 +1651,7 @@ fn test_update_subnet_node_with_non_unique_param() { // // // assert_ok!( // // // Network::remove_subnet_node( -// // // RuntimeOrigin::signed(account(1)), +// // // RuntimeOrigin::signed(account(0)), // // // subnet_id, // // // ) // // // ); @@ -1755,8 +1662,8 @@ fn test_update_subnet_node_with_non_unique_param() { // // // assert_err!( // // // Network::remove_stake( -// // // RuntimeOrigin::signed(account(1)), -// // account(1), +// // // RuntimeOrigin::signed(account(0)), +// // account(0), // // // subnet_id, // // // amount, // // // ), @@ -1769,8 +1676,8 @@ fn test_update_subnet_node_with_non_unique_param() { // // // assert_ok!( // // // Network::remove_stake( -// // // RuntimeOrigin::signed(account(1)), -// // account(1), +// // // RuntimeOrigin::signed(account(0)), +// // account(0), // // // subnet_id, // // // amount, // // // ) @@ -1785,9 +1692,7 @@ fn test_remove_peer_unstake_total_balance() { let deposit_amount: u128 = 1000000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1799,7 +1704,6 @@ fn test_remove_peer_unstake_total_balance() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1810,8 +1714,8 @@ fn test_remove_peer_unstake_total_balance() { // post_successful_add_subnet_node_asserts(0, subnet_id, amount); assert_eq!(Network::total_subnet_nodes(subnet_id), total_subnet_nodes+1); - assert_eq!(Network::account_subnet_stake(account(1), subnet_id), amount); - // assert_eq!(Network::total_account_stake(account(1)), amount); + assert_eq!(Network::account_subnet_stake(account(0), subnet_id), amount); + // assert_eq!(Network::total_account_stake(account(0)), amount); assert_eq!(Network::total_stake(), amount * (total_subnet_nodes as u128 +1)); assert_eq!(Network::total_subnet_stake(subnet_id), amount * (total_subnet_nodes as u128 +1)); @@ -1831,8 +1735,7 @@ fn test_remove_peer_unstake_total_balance() { let epoch_length = EpochLength::get(); let min_required_unstake_epochs = StakeCooldownEpochs::get(); - // System::set_block_number(System::block_number() + epoch_length * min_required_unstake_epochs); - increase_epochs(min_required_unstake_epochs + 1); + System::set_block_number(System::block_number() + epoch_length * min_required_unstake_epochs); let remaining_account_stake_balance: u128 = AccountSubnetStake::::get(&account(total_subnet_nodes+1), subnet_id); @@ -1856,9 +1759,7 @@ fn test_claim_stake_unbondings() { let deposit_amount: u128 = 1000000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1874,7 +1775,6 @@ fn test_claim_stake_unbondings() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1917,20 +1817,16 @@ fn test_claim_stake_unbondings() { let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); + let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); assert_eq!(unbondings.len(), 1); let (first_key, first_value) = unbondings.iter().next().unwrap(); - - // assert_eq!(*first_key, &epoch + StakeCooldownEpochs::get()); - assert_eq!(*first_key, &epoch + RegisteredStakeCooldownEpochs::::get()); + assert_eq!(first_key, &epoch); assert!(*first_value <= stake_balance); - - // let stake_cooldown_epochs = StakeCooldownEpochs::get(); - let stake_cooldown_epochs = RegisteredStakeCooldownEpochs::::get(); - increase_epochs(stake_cooldown_epochs + 1); - // System::set_block_number(System::block_number() + ((epoch_length + 1) * stake_cooldown_epochs)); + let stake_cooldown_epochs = StakeCooldownEpochs::get(); + + System::set_block_number(System::block_number() + ((epoch_length + 1) * stake_cooldown_epochs)); assert_ok!( Network::claim_unbondings( @@ -1942,7 +1838,7 @@ fn test_claim_stake_unbondings() { assert_eq!(post_balance, starting_balance); - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); + let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); assert_eq!(unbondings.len(), 0); }); @@ -1955,9 +1851,7 @@ fn test_remove_stake_twice_in_epoch() { let deposit_amount: u128 = 1000000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -1973,7 +1867,6 @@ fn test_remove_stake_twice_in_epoch() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -1990,7 +1883,7 @@ fn test_remove_stake_twice_in_epoch() { let after_stake_balance = Balances::free_balance(&account(total_subnet_nodes+1)); assert_eq!(after_stake_balance, starting_balance - amount); - let _ = Balances::deposit_creating(&account(1), amount*2); + let _ = Balances::deposit_creating(&account(0), amount*2); assert_ok!( Network::add_to_stake( @@ -2005,8 +1898,6 @@ fn test_remove_stake_twice_in_epoch() { let stake_balance = AccountSubnetStake::::get(&account(total_subnet_nodes+1), subnet_id); assert_eq!(stake_balance, amount + amount*3); - let epoch = System::block_number() / EpochLength::get(); - assert_ok!( Network::remove_stake( RuntimeOrigin::signed(account(total_subnet_nodes+1)), @@ -2016,14 +1907,11 @@ fn test_remove_stake_twice_in_epoch() { ) ); - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); + let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); let ledger_balance: u128 = unbondings.values().copied().sum(); assert_eq!(unbondings.len() as u32, 1); assert_eq!(ledger_balance, amount); - let (ledger_epoch, ledger_balance) = unbondings.iter().next().unwrap(); - assert_eq!(*ledger_epoch, &epoch + StakeCooldownEpochs::get()); - assert_ok!( Network::remove_stake( RuntimeOrigin::signed(account(total_subnet_nodes+1)), @@ -2033,18 +1921,13 @@ fn test_remove_stake_twice_in_epoch() { ) ); - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); + let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); let ledger_balance: u128 = unbondings.values().copied().sum(); assert_eq!(unbondings.len() as u32, 1); assert_eq!(ledger_balance, amount*2); - let (ledger_epoch, ledger_balance) = unbondings.iter().next().unwrap(); - assert_eq!(*ledger_epoch, &epoch + StakeCooldownEpochs::get()); - increase_epochs(1); - let epoch = System::block_number() / EpochLength::get(); - assert_ok!( Network::remove_stake( RuntimeOrigin::signed(account(total_subnet_nodes+1)), @@ -2054,18 +1937,12 @@ fn test_remove_stake_twice_in_epoch() { ) ); - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); - let total_ledger_balance: u128 = unbondings.values().copied().sum(); + let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); + let ledger_balance: u128 = unbondings.values().copied().sum(); assert_eq!(unbondings.len() as u32, 2); - assert_eq!(total_ledger_balance, amount*3); - - let (ledger_epoch, ledger_balance) = unbondings.iter().last().unwrap(); - assert_eq!(*ledger_epoch, &epoch + StakeCooldownEpochs::get()); - assert_eq!(*ledger_balance, amount); + assert_eq!(ledger_balance, amount*3); - System::set_block_number(System::block_number() + ((EpochLength::get() + 1) * StakeCooldownEpochs::get())); - // increase_epochs(StakeCooldownEpochs::get() + 11); - + System::set_block_number(System::block_number() + ((EpochLength::get() + 1) * DelegateStakeCooldownEpochs::get())); let starting_balance = Balances::free_balance(&account(total_subnet_nodes+1)); assert_ok!( @@ -2075,7 +1952,7 @@ fn test_remove_stake_twice_in_epoch() { ); let ending_balance = Balances::free_balance(&account(total_subnet_nodes+1)); - assert_eq!(starting_balance + total_ledger_balance, ending_balance); + assert_eq!(starting_balance + ledger_balance, ending_balance); }); } @@ -2088,9 +1965,7 @@ fn test_claim_stake_unbondings_no_unbondings_err() { let deposit_amount: u128 = 1000000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -2106,7 +1981,6 @@ fn test_claim_stake_unbondings_no_unbondings_err() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount, None, @@ -2137,9 +2011,7 @@ fn test_remove_to_stake_max_unlockings_reached_err() { let deposit_amount: u128 = 1000000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -2154,7 +2026,6 @@ fn test_remove_to_stake_max_unlockings_reached_err() { subnet_id, account(total_subnet_nodes+1), peer(total_subnet_nodes+1), - peer(total_subnet_nodes+1), 0, amount*2, None, @@ -2164,10 +2035,9 @@ fn test_remove_to_stake_max_unlockings_reached_err() { ); let max_unlockings = MaxStakeUnlockings::get(); - for n in 1..max_unlockings+2 { - // System::set_block_number(System::block_number() + EpochLength::get() + 1); - increase_epochs(1); - if n > max_unlockings { + for n in 0..max_unlockings+1 { + System::set_block_number(System::block_number() + EpochLength::get() + 1); + if n+1 > max_unlockings { assert_err!( Network::remove_stake( RuntimeOrigin::signed(account(total_subnet_nodes+1)), @@ -2187,9 +2057,9 @@ fn test_remove_to_stake_max_unlockings_reached_err() { ) ); - let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); + let unbondings: BTreeMap = StakeUnbondingLedger::::get(account(total_subnet_nodes+1)); - assert_eq!(unbondings.len() as u32, n); + assert_eq!(unbondings.len() as u32, n+1); } } }); @@ -2202,9 +2072,7 @@ fn test_remove_subnet_node() { let deposit_amount: u128 = 1000000000000000000000000; let amount: u128 = 1000000000000000000000; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, 0, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -2215,7 +2083,7 @@ fn test_remove_subnet_node() { let epoch_length = EpochLength::get(); let epoch = block_number / epoch_length; - for n in 1..remove_n_peers+1 { + for n in 0..remove_n_peers { let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n)).unwrap(); assert_ok!( Network::remove_subnet_node( @@ -2228,19 +2096,19 @@ fn test_remove_subnet_node() { assert_eq!(subnet_node_data, Err(())); } - // let node_set = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Queue, epoch); - let node_set: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Queue, epoch); + // let node_set = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Idle, epoch); + let node_set: BTreeSet<::AccountId> = Network::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Idle, epoch); assert_eq!(node_set.len(), (total_subnet_nodes - remove_n_peers) as usize); assert_eq!(Network::total_stake(), amount_staked); assert_eq!(Network::total_subnet_stake(subnet_id), amount_staked); assert_eq!(TotalSubnetNodes::::get(subnet_id), total_subnet_nodes - remove_n_peers); - for n in 1..remove_n_peers+1 { + for n in 0..remove_n_peers { let subnet_node_id = HotkeySubnetNodeId::::try_get(subnet_id, account(n)); assert_eq!(subnet_node_id, Err(())); - let subnet_node_account = PeerIdSubnetNode::::try_get(subnet_id, peer(n)); + let subnet_node_account = SubnetNodeAccount::::try_get(subnet_id, peer(n)); assert_eq!(subnet_node_account, Err(())); let account_subnet_stake = AccountSubnetStake::::get(account(n), subnet_id); @@ -2263,17 +2131,15 @@ fn test_deactivate_subnet_node_and_reactivate() { let amount: u128 = 1000000000000000000000; let n_peers = 8; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); assert_ok!( Network::deactivate_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, ) @@ -2292,17 +2158,15 @@ fn test_deactivate_subnet_node() { let amount: u128 = 1000000000000000000000; let n_peers = 8; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); assert_ok!( Network::deactivate_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, ) @@ -2322,9 +2186,7 @@ fn test_deactivation_ledger_as_attestor() { let amount: u128 = 1000000000000000000000; let n_peers = 8; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); @@ -2333,8 +2195,8 @@ fn test_deactivation_ledger_as_attestor() { let epoch = System::block_number() / epoch_length; // insert node as validator to place them into the ledger - SubnetRewardsValidator::::insert(subnet_id, epoch, 1); - let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch); + SubnetRewardsValidator::::insert(subnet_id, epoch as u32, 1); + let validator_id = SubnetRewardsValidator::::get(subnet_id, epoch as u32); let mut validator = SubnetNodeIdHotkey::::get(subnet_id, validator_id.unwrap()).unwrap(); let subnet_node_data_vec = subnet_node_data(0, total_subnet_nodes); @@ -2349,7 +2211,7 @@ fn test_deactivation_ledger_as_attestor() { ); // Attest - for n in 1..total_subnet_nodes+1 { + for n in 0..total_subnet_nodes { if account(n) == validator.clone() { continue } @@ -2361,11 +2223,11 @@ fn test_deactivation_ledger_as_attestor() { ); } - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); assert_ok!( Network::deactivate_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, ) @@ -2405,18 +2267,17 @@ fn test_deactivation_ledger_as_chosen_validator() { let amount: u128 = 1000000000000000000000; let n_peers = 8; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); // let mut ledger = BTreeSet::new(); // let subnet_node = SubnetNode { - // coldkey: account(1), - // hotkey: account(1), - // peer_id: peer(1), + // coldkey: account(0), + // hotkey: account(0), + // peer_id: peer(0), + // initialized: 1, // classification: SubnetNodeClassification { // class: SubnetNodeClass::Validator, // start_epoch: 1, @@ -2430,19 +2291,19 @@ fn test_deactivation_ledger_as_chosen_validator() { let epoch = System::block_number() / epoch_length; // insert node as validator to place them into the ledger - SubnetRewardsValidator::::insert(subnet_id, epoch, 1); + SubnetRewardsValidator::::insert(subnet_id, epoch as u32, 0); - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); assert_ok!( Network::deactivate_subnet_node( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, ) ); - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); assert_eq!(subnet_node.classification.class, SubnetNodeClass::Validator); let subnet_node_deactivation_validator = SubnetNodeDeactivation { @@ -2486,16 +2347,15 @@ fn test_update_delegate_reward_rate() { let amount: u128 = 1000000000000000000000; let n_peers = 8; - let stake_amount: u128 = MinStakeBalance::::get(); - - build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, stake_amount); + build_activated_subnet(subnet_path.clone(), 0, n_peers, deposit_amount, amount); let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let total_subnet_nodes = TotalSubnetNodes::::get(subnet_id); - let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(1)).unwrap(); + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(0)).unwrap(); let subnet_node = SubnetNodesData::::get(subnet_id, subnet_node_id); assert_eq!(subnet_node.delegate_reward_rate, 0); + // build_activated_subnet increases blocks by 10,000 (not anymore) assert_eq!(subnet_node.last_delegate_reward_rate_update, 0); @@ -2510,7 +2370,7 @@ fn test_update_delegate_reward_rate() { // Increase reward rate to 5% then test decreasing assert_ok!( Network::update_delegate_reward_rate( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, new_delegate_reward_rate @@ -2528,7 +2388,7 @@ fn test_update_delegate_reward_rate() { // allow decreasing by 1% assert_ok!( Network::update_delegate_reward_rate( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, new_delegate_reward_rate @@ -2537,7 +2397,7 @@ fn test_update_delegate_reward_rate() { assert_err!( Network::update_delegate_reward_rate( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, 1000000001 @@ -2547,7 +2407,7 @@ fn test_update_delegate_reward_rate() { assert_err!( Network::update_delegate_reward_rate( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, new_delegate_reward_rate+1 @@ -2559,7 +2419,7 @@ fn test_update_delegate_reward_rate() { assert_err!( Network::update_delegate_reward_rate( - RuntimeOrigin::signed(account(1)), + RuntimeOrigin::signed(account(0)), subnet_id, subnet_node_id, new_delegate_reward_rate diff --git a/pallets/network/src/tests/test_utils.rs b/pallets/network/src/tests/test_utils.rs index 7a78139..01ab8df 100644 --- a/pallets/network/src/tests/test_utils.rs +++ b/pallets/network/src/tests/test_utils.rs @@ -1,47 +1,20 @@ use super::mock::*; -use crate::Event; use sp_core::OpaquePeerId as PeerId; use frame_support::assert_ok; use log::info; use crate::{ - SubnetNodeData, - TotalStake, - SubnetRewardsValidator, + SubnetNodeData, TotalStake, SubnetRewardsValidator, SubnetPaths, SubnetNodeClass, SubnetsData, - AccountSubnetStake, - MinStakeBalance, - TotalSubnetDelegateStakeBalance, - AccountSubnetDelegateStakeShares, - RegistrationSubnetData, + AccountSubnetStake, MinStakeBalance, + AccountSubnetDelegateStakeShares, RegistrationSubnetData, StakeUnbondingLedger, - TotalSubnetStake, - MinSubnetRegistrationBlocks, - HotkeySubnetNodeId, - SubnetNodeIdHotkey, - SubnetNodesData, - PeerIdSubnetNode, + TotalSubnetStake, MinSubnetRegistrationBlocks, + HotkeySubnetNodeId, SubnetNodeIdHotkey, SubnetNodesData, SubnetNodeAccount, HotkeyOwner, - MinSubnetNodes, - LastSubnetRegistration, - TotalSubnetNodes, - TotalSubnetNodeUids, - BootstrapPeerIdSubnetNode, - SubnetNodeUniqueParam, - SubnetPenaltyCount, - SubnetRewardsSubmission, - Proposals, - SubnetRegistrationColdkeyWhitelist, - SubnetNodeNonUniqueParamLastSet, - SubnetNodePenalties, - SubnetNodeRegistrationInterval, - SubnetRegistrationEpochs, - SubnetOwner, - SubnetRegistrationEpoch, }; use frame_support::traits::{OnInitialize, Currency}; -use sp_std::collections::btree_set::BTreeSet; pub type AccountIdOf = ::AccountId; @@ -71,37 +44,32 @@ pub fn get_min_stake_balance() -> u128 { pub const PERCENTAGE_FACTOR: u128 = 10000; pub const DEFAULT_SCORE: u128 = 5000; +pub const CONSENSUS_STEPS: u64 = 2; pub const DEFAULT_MEM_MB: u128 = 50000; pub const MAX_SUBNET_NODES: u32 = 254; -pub const DEFAULT_REGISTRATION_BLOCKS: u32 = 130_000; +pub const DEFAULT_REGISTRATION_BLOCKS: u64 = 130_000; pub const DEFAULT_DELEGATE_REWARD_RATE: u128 = 100_000_000; // 10% pub fn build_activated_subnet(subnet_path: Vec, start: u32, mut end: u32, deposit_amount: u128, amount: u128) { + // System::set_block_number(System::block_number() + 1); + let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch.saturating_sub(epoch)); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + log::error!("next_registration_epoch {:?}", next_registration_epoch); + increase_epochs(next_registration_epoch - epoch as u32); - let cost = Network::registration_cost(epoch); + let cost = Network::registration_cost(epoch as u32); let _ = Balances::deposit_creating(&account(0), cost+1000); - let min_nodes = MinSubnetNodes::::get(); - - if end == 0 { - end = min_nodes; - } - - let whitelist = get_coldkey_whitelist(start, end); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; // --- Register subnet for activation @@ -114,8 +82,12 @@ pub fn build_activated_subnet(subnet_path: Vec, start: u32, mut end: u32, de let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let subnet = SubnetsData::::get(subnet_id).unwrap(); - let owner = SubnetOwner::::get(subnet_id).unwrap(); - assert_eq!(owner, account(0)); + + let min_nodes = subnet.min_nodes; + + if end == 0 { + end = min_nodes; + } let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; @@ -123,7 +95,7 @@ pub fn build_activated_subnet(subnet_path: Vec, start: u32, mut end: u32, de // --- Add subnet nodes let block_number = System::block_number(); let mut amount_staked = 0; - for n in start+1..end+1 { + for n in start..end { let _ = Balances::deposit_creating(&account(n), deposit_amount); amount_staked += amount; assert_ok!( @@ -132,7 +104,6 @@ pub fn build_activated_subnet(subnet_path: Vec, start: u32, mut end: u32, de subnet_id, account(n), peer(n), - peer(n), 0, amount, None, @@ -141,14 +112,6 @@ pub fn build_activated_subnet(subnet_path: Vec, start: u32, mut end: u32, de ) ); - // assert_eq!( - // *network_events().last().unwrap(), - // Event::SubnetNodeActivated { - // subnet_id: subnet_id, - // subnet_node_id: n - // } - // ); - let hotkey_subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n)).unwrap(); let subnet_node_id_hotkey = SubnetNodeIdHotkey::::get(subnet_id, hotkey_subnet_node_id).unwrap(); @@ -161,12 +124,13 @@ pub fn build_activated_subnet(subnet_path: Vec, start: u32, mut end: u32, de assert_eq!(key_owner, account(n)); assert_eq!(subnet_node_data.peer_id, peer(n)); + assert_eq!(subnet_node_data.initialized, block_number); // --- Is ``Validator`` if registered before subnet activation assert_eq!(subnet_node_data.classification.class, SubnetNodeClass::Validator); assert!(subnet_node_data.has_classification(&SubnetNodeClass::Validator, epoch)); - let subnet_node_account = PeerIdSubnetNode::::get(subnet_id, peer(n)); + let subnet_node_account = SubnetNodeAccount::::get(subnet_id, peer(n)); assert_eq!(subnet_node_account, hotkey_subnet_node_id); let account_subnet_stake = AccountSubnetStake::::get(account(n), subnet_id); @@ -180,30 +144,24 @@ pub fn build_activated_subnet(subnet_path: Vec, start: u32, mut end: u32, de assert_eq!(total_subnet_stake, amount_staked); - let delegate_staker_account = 1000; - // Add 100e18 to account for block increase on activation - let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance() + 100e+18 as u128; - let _ = Balances::deposit_creating(&account(delegate_staker_account), min_subnet_delegate_stake+500); + let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance(min_nodes); // --- Add the minimum required delegate stake balance to activate the subnet assert_ok!( Network::add_to_delegate_stake( - RuntimeOrigin::signed(account(delegate_staker_account)), + RuntimeOrigin::signed(account(1)), subnet_id, min_subnet_delegate_stake, ) ); - let total_delegate_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); - assert_eq!(total_delegate_stake_balance, min_subnet_delegate_stake); - - // let delegate_shares = AccountSubnetDelegateStakeShares::::get(account(delegate_staker_account), subnet_id); + let delegate_shares = AccountSubnetDelegateStakeShares::::get(account(1), subnet_id); // 1000 is for inflation attack mitigation - // assert_eq!(min_subnet_delegate_stake - 1000, delegate_shares); - - // --- Increase epochs to max registration epoch - let epochs = SubnetRegistrationEpochs::::get(); - increase_epochs(epochs + 1); + assert_eq!(min_subnet_delegate_stake - 1000, delegate_shares); + // --- Increase blocks to max registration block + System::set_block_number(System::block_number() + subnet.registration_blocks + 1); + let current_block_number = System::block_number(); + assert_ok!( Network::activate_subnet( RuntimeOrigin::signed(account(0)), @@ -211,13 +169,6 @@ pub fn build_activated_subnet(subnet_path: Vec, start: u32, mut end: u32, de ) ); - assert_eq!( - *network_events().last().unwrap(), - Event::SubnetActivated { - subnet_id: subnet_id, - } - ); - // --- Check validator chosen on activation // let next_epoch = System::block_number() / epoch_length + 1; // let validator = SubnetRewardsValidator::::get(subnet_id, next_epoch as u32); @@ -235,28 +186,19 @@ pub fn build_activated_subnet_with_delegator_rewards( let epoch_length = EpochLength::get(); let block_number = System::block_number(); let epoch = System::block_number().saturating_div(epoch_length); - let next_registration_epoch = Network::get_next_registration_epoch(epoch); - increase_epochs(next_registration_epoch.saturating_sub(epoch)); + let next_registration_epoch = Network::get_next_registration_epoch(epoch as u32); + increase_epochs(next_registration_epoch - epoch as u32); let cost = Network::registration_cost(0); let _ = Balances::deposit_creating(&account(0), cost+1000); - let min_nodes = MinSubnetNodes::::get(); - - if end == 0 { - end = min_nodes; - } - - let whitelist = get_coldkey_whitelist(start, end); + let registration_blocks = MinSubnetRegistrationBlocks::::get(); let add_subnet_data = RegistrationSubnetData { path: subnet_path.clone().into(), - max_node_registration_epochs: 16, - node_registration_interval: 0, - node_activation_interval: 0, - node_queue_period: 1, - max_node_penalties: 3, - coldkey_whitelist: whitelist, + memory_mb: DEFAULT_MEM_MB, + registration_blocks: registration_blocks, + entry_interval: 0, }; // --- Register subnet for activation @@ -269,8 +211,12 @@ pub fn build_activated_subnet_with_delegator_rewards( let subnet_id = SubnetPaths::::get(subnet_path.clone()).unwrap(); let subnet = SubnetsData::::get(subnet_id).unwrap(); - let owner = SubnetOwner::::get(subnet_id).unwrap(); - assert_eq!(owner, account(0)); + + let min_nodes = subnet.min_nodes; + + if end == 0 { + end = min_nodes; + } let epoch_length = EpochLength::get(); let epoch = System::block_number() / epoch_length; @@ -278,8 +224,8 @@ pub fn build_activated_subnet_with_delegator_rewards( // --- Add subnet nodes let block_number = System::block_number(); let mut amount_staked = 0; - for n in start+1..end+1 { - let _ = Balances::deposit_creating(&account(n), amount+500); + for n in start..end { + let _ = Balances::deposit_creating(&account(n), deposit_amount); amount_staked += amount; assert_ok!( Network::add_subnet_node( @@ -287,7 +233,6 @@ pub fn build_activated_subnet_with_delegator_rewards( subnet_id, account(n), peer(n), - peer(n), delegate_reward_rate, amount, None, @@ -304,18 +249,18 @@ pub fn build_activated_subnet_with_delegator_rewards( let subnet_node_data = SubnetNodesData::::try_get(subnet_id, hotkey_subnet_node_id).unwrap(); assert_eq!(subnet_node_data.hotkey, account(n)); - assert_eq!(subnet_node_data.delegate_reward_rate, delegate_reward_rate); let key_owner = HotkeyOwner::::get(subnet_node_data.hotkey.clone()); assert_eq!(key_owner, account(n)); assert_eq!(subnet_node_data.peer_id, peer(n)); + assert_eq!(subnet_node_data.initialized, block_number); // --- Is ``Validator`` if registered before subnet activation assert_eq!(subnet_node_data.classification.class, SubnetNodeClass::Validator); assert!(subnet_node_data.has_classification(&SubnetNodeClass::Validator, epoch)); - let subnet_node_account = PeerIdSubnetNode::::get(subnet_id, peer(n)); + let subnet_node_account = SubnetNodeAccount::::get(subnet_id, peer(n)); assert_eq!(subnet_node_account, hotkey_subnet_node_id); let account_subnet_stake = AccountSubnetStake::::get(account(n), subnet_id); @@ -328,29 +273,24 @@ pub fn build_activated_subnet_with_delegator_rewards( let total_stake = TotalStake::::get(); assert_eq!(total_subnet_stake, amount_staked); - let delegate_staker_account = 1000; - // Add 100e18 to account for block increase on activation - let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance() + 100e+18 as u128; - let _ = Balances::deposit_creating(&account(delegate_staker_account), min_subnet_delegate_stake+500); + + let min_subnet_delegate_stake = Network::get_min_subnet_delegate_stake_balance(min_nodes); // --- Add the minimum required delegate stake balance to activate the subnet assert_ok!( Network::add_to_delegate_stake( - RuntimeOrigin::signed(account(delegate_staker_account)), + RuntimeOrigin::signed(account(1)), subnet_id, min_subnet_delegate_stake, ) ); - let total_delegate_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); - assert_eq!(total_delegate_stake_balance, min_subnet_delegate_stake); - - let delegate_shares = AccountSubnetDelegateStakeShares::::get(account(delegate_staker_account), subnet_id); + let delegate_shares = AccountSubnetDelegateStakeShares::::get(account(1), subnet_id); // 1000 is for inflation attack mitigation - // assert_eq!(min_subnet_delegate_stake - 1000, delegate_shares); + assert_eq!(min_subnet_delegate_stake - 1000, delegate_shares); - // --- Increase epochs to max registration epoch - let epochs = SubnetRegistrationEpochs::::get(); - increase_epochs(epochs + 1); + // --- Increase blocks to max registration block + System::set_block_number(System::block_number() + subnet.registration_blocks + 1); + let current_block_number = System::block_number(); assert_ok!( Network::activate_subnet( @@ -358,27 +298,12 @@ pub fn build_activated_subnet_with_delegator_rewards( subnet_id, ) ); - - assert_eq!( - *network_events().last().unwrap(), - Event::SubnetActivated { - subnet_id: subnet_id, - } - ); -} - -pub fn get_coldkey_whitelist(start: u32, end: u32) -> BTreeSet { - let mut whitelist = BTreeSet::new(); - for n in start+1..end+1 { - whitelist.insert(account(n)); - } - whitelist } // Returns total staked on subnet pub fn build_subnet_nodes(subnet_id: u32, start: u32, end: u32, deposit_amount: u128, amount: u128) -> u128 { let mut amount_staked = 0; - for n in start+1..end+1 { + for n in start..end { let _ = Balances::deposit_creating(&account(n), deposit_amount); amount_staked += amount; assert_ok!( @@ -387,7 +312,6 @@ pub fn build_subnet_nodes(subnet_id: u32, start: u32, end: u32, deposit_amount: subnet_id, account(n), peer(n), - peer(n), 0, amount, None, @@ -400,32 +324,17 @@ pub fn build_subnet_nodes(subnet_id: u32, start: u32, end: u32, deposit_amount: amount_staked } -pub fn post_subnet_removal_ensures(subnet_id: u32, path: Vec, start: u32, end: u32) { - assert_eq!(SubnetsData::::try_get(subnet_id), Err(())); - assert_eq!(SubnetPaths::::try_get(path), Err(())); - assert_eq!(LastSubnetRegistration::::try_get(subnet_id), Err(())); - assert_eq!(SubnetRegistrationEpoch::::try_get(subnet_id), Err(())); - assert_eq!(SubnetRegistrationColdkeyWhitelist::::try_get(subnet_id), Err(())); - assert_eq!(SubnetNodesData::::iter_prefix(subnet_id).count(), 0); - assert_eq!(TotalSubnetNodes::::contains_key(subnet_id), false); - assert_eq!(TotalSubnetNodeUids::::contains_key(subnet_id), false); - assert_eq!(PeerIdSubnetNode::::iter_prefix(subnet_id).count(), 0); - assert_eq!(BootstrapPeerIdSubnetNode::::iter_prefix(subnet_id).count(), 0); - assert_eq!(SubnetNodeUniqueParam::::iter_prefix(subnet_id).count(), 0); - assert_eq!(HotkeySubnetNodeId::::iter_prefix(subnet_id).count(), 0); - assert_eq!(SubnetNodeIdHotkey::::iter_prefix(subnet_id).count(), 0); - assert_eq!(SubnetPenaltyCount::::contains_key(subnet_id), false); - assert_eq!(SubnetRewardsValidator::::iter_prefix(subnet_id).count(), 0); - assert_eq!(SubnetRewardsSubmission::::iter_prefix(subnet_id).count(), 0); - assert_eq!(Proposals::::iter_prefix(subnet_id).count(), 0); - assert_eq!(SubnetNodeNonUniqueParamLastSet::::iter_prefix(subnet_id).count(), 0); - assert_eq!(SubnetNodePenalties::::iter_prefix(subnet_id).count(), 0); - assert_eq!(SubnetNodeRegistrationInterval::::contains_key(subnet_id), false); - +pub fn post_subnet_removal_ensures(subnet_id: u32, start: u32, end: u32) { + let subnet = SubnetsData::::try_get(subnet_id); + assert_eq!(subnet, Err(())); + + for n in start..end { + let subnet_node_id = HotkeySubnetNodeId::::get(subnet_id, account(n)); + assert_eq!(subnet_node_id, None); - for n in start+1..end+1 { - assert_eq!(HotkeySubnetNodeId::::get(subnet_id, account(n)), None); - assert_eq!(PeerIdSubnetNode::::try_get(subnet_id, peer(n)), Err(())); + // ensure SubnetNodeAccount removed + let subnet_node_account = SubnetNodeAccount::::try_get(subnet_id, peer(n)); + assert_eq!(subnet_node_account, Err(())); let stake_balance = AccountSubnetStake::::get(account(n), subnet_id); assert_ok!( @@ -460,7 +369,7 @@ pub fn post_subnet_removal_ensures(subnet_id: u32, path: Vec, start: u32, en // --- Ensure unstaking is stable - for n in start+1..end+1 { + for n in start..end { System::set_block_number(System::block_number() + ((epoch_length + 1) * stake_cooldown_epochs)); let starting_balance = Balances::free_balance(&account(n)); let unbondings = StakeUnbondingLedger::::get(account(n)); @@ -476,12 +385,33 @@ pub fn post_subnet_removal_ensures(subnet_id: u32, path: Vec, start: u32, en assert_eq!(starting_balance + ledger_balance, ending_balance); System::set_block_number(starting_block_number); } + + // for n in start..end { + // System::set_block_number(System::block_number() + ((epoch_length + 1) * DelegateStakeCooldownEpochs::get())); + // let starting_balance = Balances::free_balance(&account(n)); + // let unbondings = StakeUnbondingLedger::::get(account(n)); + // if unbondings.len() == 0 { + // continue + // } + // assert_eq!(unbondings.len(), 1); + // let (ledger_epoch, ledger_balance) = unbondings.iter().next().unwrap(); + + // assert_ok!( + // Network::claim_unbondings( + // RuntimeOrigin::signed(account(n)), + // ) + // ); + + // let ending_balance = Balances::free_balance(&account(n)); + // assert_eq!(starting_balance + ledger_balance, ending_balance); + // System::set_block_number(starting_block_number); + // } } // pub fn build_for_submit_consensus_data(subnet_id: u32, start: u32, end: u32, start_data: u32, end_data: u32) { // let subnet_node_data_vec = subnet_node_data(start_data, end_data); -// for n in start+1..end+1 { +// for n in start..end { // assert_ok!( // Network::submit_consensus_data( // RuntimeOrigin::signed(account(n)), @@ -496,25 +426,17 @@ pub fn increase_epochs(epochs: u32) { if epochs == 0 { return } - let block = System::block_number(); - let epoch_length = EpochLength::get(); - - let next_epoch_start_block = (epoch_length * epochs) + block - (block % (epoch_length * epochs)); + let next_epoch_start_block = (epoch_length * epochs as u64) + block - (block % (epoch_length * epochs as u64)); System::set_block_number(next_epoch_start_block); } pub fn set_epoch(epoch: u32) { let epoch_length = EpochLength::get(); - System::set_block_number(epoch * epoch_length); + System::set_block_number(epoch as u64 * epoch_length); } -pub fn get_epoch() -> u32 { - let current_block = System::block_number(); - let epoch_length: u32 = EpochLength::get(); - current_block.saturating_div(epoch_length) -} pub fn make_subnet_submittable() { // increase blocks @@ -522,7 +444,7 @@ pub fn make_subnet_submittable() { // let epoch_length = EpochLength::get(); - // let min_required_subnet_consensus_submit_epochs: u32 = MinRequiredSubnetConsensusSubmitEpochs::::get(); + // let min_required_subnet_consensus_submit_epochs: u64 = MinRequiredSubnetConsensusSubmitEpochs::::get(); // System::set_block_number(System::block_number() + epoch_length * min_required_subnet_consensus_submit_epochs); } @@ -535,7 +457,7 @@ pub fn make_subnet_submittable() { // let start_block_can_remove_peer = epoch_length as u128 * subnet_node_removal_percentage / PERCENTAGE_FACTOR; -// let max_remove_subnet_node_block = start_block_can_remove_peer + (current_block_number - (current_block_number % epoch_length)); +// let max_remove_subnet_node_block = start_block_can_remove_peer as u64 + (current_block_number - (current_block_number % epoch_length)); // if current_block_number < max_remove_subnet_node_block { // System::set_block_number(max_remove_subnet_node_block + 1); @@ -563,10 +485,29 @@ pub fn make_subnet_submittable() { // System::set_block_number(System::block_number() + epoch_length * epochs); // } +// pub fn make_subnet_node_removable() { +// // increase blocks +// let current_block_number = System::block_number(); +// let subnet_node_removal_percentage = RemoveSubnetNodeEpochPercentage::::get(); +// let epoch_length = EpochLength::get(); + +// let block_span_can_remove_peer = (epoch_length as u128 * subnet_node_removal_percentage / PERCENTAGE_FACTOR) as u64; + +// let start_removal_block = (CONSENSUS_STEPS + (current_block_number - (current_block_number % epoch_length))) as u64; + +// let end_removal_block = block_span_can_remove_peer + (current_block_number - (current_block_number % epoch_length)); + +// if current_block_number < start_removal_block { +// System::set_block_number(start_removal_block); +// } else if current_block_number > end_removal_block { +// System::set_block_number(start_removal_block + epoch_length); +// } +// } + pub fn subnet_node_data(start: u32, end: u32) -> Vec { // initialize peer consensus data array let mut subnet_node_data: Vec = Vec::new(); - for n in start+1..end+1 { + for n in start..end { // let peer_subnet_node_data: SubnetNodeData<::AccountId> = SubnetNodeData { // // account_id: account(n), // peer_id: peer(n), @@ -586,7 +527,7 @@ pub fn subnet_node_data_invalid_scores(start: u32, end: u32) -> Vec::AccountId>> = Vec::new(); let mut subnet_node_data: Vec = Vec::new(); - for n in start+1..end+1 { + for n in start..end { // let peer_subnet_node_data: SubnetNodeData<::AccountId> = SubnetNodeData { // // account_id: account(n), // peer_id: peer(n), @@ -627,12 +568,21 @@ pub fn post_remove_subnet_node_ensures(n: u32, subnet_id: u32) { let subnet_node_id = HotkeySubnetNodeId::::try_get(subnet_id, account(n)); assert_eq!(subnet_node_id, Err(())); - assert_eq!(SubnetNodesData::::iter_prefix(subnet_id).count(), 0); + // let subnet_node_data = SubnetNodesData::::try_get(subnet_id, account(n)); // assert_eq!(subnet_node_hotkey, Err(())); - // ensure PeerIdSubnetNode removed - let subnet_node_account = PeerIdSubnetNode::::try_get(subnet_id, peer(n)); + // ensure SubnetNodeAccount removed + let subnet_node_account = SubnetNodeAccount::::try_get(subnet_id, peer(n)); assert_eq!(subnet_node_account, Err(())); + + // // ensure SubnetNodeConsensusResults removed + // let subnet_node_consensus_results = SubnetNodeConsensusResults::::try_get(subnet_id, account(n)); + // assert_eq!(subnet_node_consensus_results, Err(())); + + // for class_id in SubnetNodeClass::iter() { + // let node_sets = SubnetNodesClasses::::get(subnet_id, class_id); + // assert_eq!(node_sets.get(&account(n)), None); + // } } pub fn post_remove_unstake_ensures(n: u32, subnet_id: u32) { @@ -651,7 +601,6 @@ pub fn add_subnet_node( subnet_id, account(account_id), peer(peer_id), - peer(peer_id), 0, amount, None, diff --git a/pallets/network/src/tests/utils.rs b/pallets/network/src/tests/utils.rs index 0ba2031..addbd6d 100644 --- a/pallets/network/src/tests/utils.rs +++ b/pallets/network/src/tests/utils.rs @@ -11,12 +11,47 @@ use frame_support::BoundedVec; use sp_core::OpaquePeerId as PeerId; use crate::{ Error, + BaseSubnetNodeMemoryMB, + MaxSubnetMemoryMB, LastSubnetRegistrationEpoch, MinSubnetRegistrationFee, MaxSubnetRegistrationFee, SubnetRegistrationInterval, }; +// #[test] +// fn test_get_min_subnet_nodes_scaled() { +// new_test_ext().execute_with(|| { +// let base_node_memory: u128 = BaseSubnetNodeMemoryMB::::get(); +// let max_subnet_memory: u128 = MaxSubnetMemoryMB::::get(); + +// let step = max_subnet_memory / 100; +// let mut i = step; + +// let mut last_min_subnet_nodes = 0; + +// while i < max_subnet_memory { +// let min_subnet_nodes = Network::get_min_subnet_nodes(base_node_memory, i); +// log::error!( +// "Min: {:?} Last Min: {:?} step: {:?}", +// min_subnet_nodes, +// last_min_subnet_nodes, +// step +// ); + +// assert!( +// min_subnet_nodes >= last_min_subnet_nodes, +// "Min: {:?} Last Min: {:?} step: {:?}", +// min_subnet_nodes, +// last_min_subnet_nodes, +// step +// ); +// last_min_subnet_nodes = min_subnet_nodes; +// i += step; +// } +// }); +// } + // #[test] // fn test_registration_cost() { // new_test_ext().execute_with(|| { @@ -201,4 +236,14 @@ fn test_get_next_registration_epoch() { let next_registration_epoch = Network::get_next_registration_epoch(period + period/2); assert_eq!(next_registration_epoch, period*2); }) -} \ No newline at end of file +} + +// #[test] +// fn test_get_target_subnet_nodes() { +// new_test_ext().execute_with(|| { +// let target_nodes = Network::get_target_subnet_nodes(10); +// log::error!("target_nodes: {:?}", target_nodes); +// assert!(target_nodes < 100); +// }); +// } + diff --git a/pallets/network/src/utilities/delegate_staking.rs b/pallets/network/src/utilities/delegate_staking.rs index c67e279..8e39500 100644 --- a/pallets/network/src/utilities/delegate_staking.rs +++ b/pallets/network/src/utilities/delegate_staking.rs @@ -17,11 +17,23 @@ use super::*; impl Pallet { /// The minimum delegate stake balance for a subnet to stay live - pub fn get_min_subnet_delegate_stake_balance() -> u128 { - let total_network_issuance = Self::get_total_network_issuance(); - let factor: u128 = MinSubnetDelegateStakeFactor::::get(); - Self::percent_mul(total_network_issuance, factor) + pub fn get_min_subnet_delegate_stake_balance(min_subnet_nodes: u32) -> u128 { + // --- Get minimum stake balance per subnet node + let min_stake_balance = MinStakeBalance::::get(); + // --- Get minimum subnet stake balance + let min_subnet_stake_balance = min_stake_balance * min_subnet_nodes as u128; + // --- Get required delegate stake balance for a subnet to have to stay live + let min_subnet_delegate_stake_balance = Self::percent_mul( + min_subnet_stake_balance, + MinSubnetDelegateStakePercentage::::get() + ); + // --- Get absolute minimum required subnet delegate stake balance + let min_subnet_delegate_stake = MinSubnetDelegateStake::::get(); + // --- Return here if the absolute minimum required subnet delegate stake balance is greater + // than the calculated minimum requirement + if min_subnet_delegate_stake > min_subnet_delegate_stake_balance { + return min_subnet_delegate_stake + } + min_subnet_delegate_stake_balance } - - // TODO: Get min delegate stake on any epoch or block } \ No newline at end of file diff --git a/pallets/network/src/utilities/era.rs b/pallets/network/src/utilities/era.rs index b0987ee..cc0f704 100644 --- a/pallets/network/src/utilities/era.rs +++ b/pallets/network/src/utilities/era.rs @@ -17,41 +17,9 @@ use super::*; use frame_system::pallet_prelude::BlockNumberFor; impl Pallet { - pub fn get_current_block_as_u64() -> u64 { - TryInto::try_into(>::block_number()) - .ok() - .expect("blockchain will not exceed 2^64 blocks; QED.") - } - - pub fn convert_block_as_u64(block: BlockNumberFor) -> u64 { - TryInto::try_into(block) - .ok() - .expect("blockchain will not exceed 2^64 blocks; QED.") - } - - pub fn get_current_block_as_u32() -> u32 { - TryInto::try_into(>::block_number()) - .ok() - .expect("blockchain will not exceed 2^32 blocks; QED.") - } - - pub fn convert_block_as_u32(block: BlockNumberFor) -> u32 { - TryInto::try_into(block) - .ok() - .expect("blockchain will not exceed 2^32 blocks; QED.") - } - - pub fn get_current_epoch_as_u32() -> u32 { - let current_block = Self::get_current_block_as_u32(); - let epoch_length: u32 = T::EpochLength::get(); - current_block.saturating_div(epoch_length) - } - - pub fn do_epoch_preliminaries(block: u32, epoch: u32, epoch_length: u32) { + pub fn do_epoch_preliminaries(block: u64, epoch: u32, epoch_length: u64) { let max_subnet_penalty_count = MaxSubnetPenaltyCount::::get(); - let subnet_registration_epochs = SubnetRegistrationEpochs::::get(); - let subnet_activation_enactment_epochs = SubnetActivationEnactmentEpochs::::get(); - let min_subnet_delegate_stake_balance = Self::get_min_subnet_delegate_stake_balance(); + let subnet_activation_enactment_period = SubnetActivationEnactmentPeriod::::get(); let subnets: Vec<_> = SubnetsData::::iter().collect(); let total_subnets: u32 = subnets.len() as u32; @@ -59,71 +27,47 @@ impl Pallet { let mut subnet_delegate_stake: Vec<(Vec, u128)> = Vec::new(); for (subnet_id, data) in subnets { - // ========================== - // # Logic - // - // *Registration Period: - // - Can exist no matter what - // - // *Enactment Period: - // - Must have min nodes. - // *We don't check on min delegate stake balance here. - // - We allow being under min delegate stake to allow delegate stake conditions to be met before - // the end of the enactment period. + // - // *Out of Enactment Period: - // - Remove if not activated. // - // ========================== - let min_subnet_nodes = MinSubnetNodes::::get(); - - let is_registering = data.state == SubnetState::Registered; - if is_registering { - match SubnetRegistrationEpoch::::try_get(subnet_id) { - Ok(registered_epoch) => { - - let max_registration_epoch = registered_epoch.saturating_add(subnet_registration_epochs); - let max_enactment_epoch = max_registration_epoch.saturating_add(subnet_activation_enactment_epochs); - - if is_registering && epoch <= max_registration_epoch { - // --- Registration Period - // If in registration period, do nothing - continue - } else if is_registering && epoch <= max_enactment_epoch { - // --- Enactment Period - // If in enactment period, ensure min nodes - let subnet_node_ids: Vec = Self::get_classified_subnet_node_ids(subnet_id, &SubnetNodeClass::Validator, epoch); - let subnet_nodes_count = subnet_node_ids.len(); - if (subnet_nodes_count as u32) < min_subnet_nodes { - Self::do_remove_subnet( - data.path, - SubnetRemovalReason::MinSubnetNodes, - ); - } - continue - } else if is_registering && epoch > max_enactment_epoch { - // --- Out of Enactment Period - // If out of enactment period, ensure activated - Self::do_remove_subnet( - data.path, - SubnetRemovalReason::EnactmentPeriod, - ); - continue - } - }, - Err(()) => (), - }; - } + // TODO: Check Registration and Enactment period separately: + // Registration Period: + // - Can exist no matter what + // Enactment Period: + // - Once out of registration, if must have min nodes and min delegate stake. + // Out of Enactment Period: + // - Remove if not activated, althought should be automatically removed in Enactment if it didn't + // meet HT requirements. + // let max_registration_block = data.initialized + data.registration_blocks; + // let max_enactment_block = max_registration_block + subnet_activation_enactment_period; + + // --- Ensure subnet is active is able to submit consensus + let max_registration_block = data.initialized + data.registration_blocks + subnet_activation_enactment_period; + if data.activated == 0 && block <= max_registration_block { + // We check if the subnet is still in registration phase and not yet out of the enactment phase + continue + } else if data.activated == 0 && block > max_registration_block { + // --- Ensure subnet is in registration period and hasn't passed enactment period + // If subnet hasn't been activated after the enacement period, then remove subnet + Self::deactivate_subnet( + data.path, + SubnetRemovalReason::EnactmentPeriod, + ); + continue + } // --- All subnets are now activated and passed the registration period // Must have: - // - Minimum nodes (increases penalties if less than - later removed if over max penalties) + // - Minimum nodes (increases penalties if less than) // - Minimum delegate stake balance (remove subnet if less than) + + let min_subnet_nodes = data.min_nodes; let subnet_delegate_stake_balance = TotalSubnetDelegateStakeBalance::::get(subnet_id); + let min_subnet_delegate_stake_balance = Self::get_min_subnet_delegate_stake_balance(min_subnet_nodes); // --- Ensure min delegate stake balance is met if subnet_delegate_stake_balance < min_subnet_delegate_stake_balance { - Self::do_remove_subnet( + Self::deactivate_subnet( data.path, SubnetRemovalReason::MinSubnetDelegateStake, ); @@ -131,7 +75,7 @@ impl Pallet { } // --- Get all possible validators - let subnet_node_ids: Vec = Self::get_classified_subnet_node_ids(subnet_id, &SubnetNodeClass::Validator, epoch); + let subnet_node_ids: Vec = Self::get_classified_subnet_node_ids(subnet_id, &SubnetNodeClass::Validator, epoch as u64); let subnet_nodes_count = subnet_node_ids.len(); // --- Ensure min nodes are active @@ -144,7 +88,7 @@ impl Pallet { // --- Check penalties and remove subnet is threshold is breached let penalties = SubnetPenaltyCount::::get(subnet_id); if penalties > max_subnet_penalty_count { - Self::do_remove_subnet( + Self::deactivate_subnet( data.path, SubnetRemovalReason::MaxPenalties, ); @@ -158,22 +102,36 @@ impl Pallet { Self::choose_validator( block, subnet_id, - subnet_node_ids, + subnet_node_ids.clone(), min_subnet_nodes, epoch, ); } - // --- If over max subnets, remove the subnet with the lowest delegate stake if excess_subnets { subnet_delegate_stake.sort_by_key(|&(_, value)| value); - Self::do_remove_subnet( + Self::deactivate_subnet( subnet_delegate_stake[0].0.clone(), SubnetRemovalReason::MaxSubnets, ); } + } + + pub fn get_current_block_as_u64() -> u64 { + TryInto::try_into(>::block_number()) + .ok() + .expect("blockchain will not exceed 2^64 blocks; QED.") + } - // --- TODO: Push subnet_ids and subnet_nodes into mapping and choose validator after possible removal of subnet - // Avoid randomization if there are max subnets + pub fn convert_block_as_u64(block: BlockNumberFor) -> u64 { + TryInto::try_into(block) + .ok() + .expect("blockchain will not exceed 2^64 blocks; QED.") + } + + pub fn get_current_epoch_as_u32() -> u32 { + let current_block = Self::get_current_block_as_u64(); + let epoch_length: u64 = T::EpochLength::get(); + (current_block / epoch_length) as u32 } } \ No newline at end of file diff --git a/pallets/network/src/utilities/math.rs b/pallets/network/src/utilities/math.rs index 3ff754c..29fa159 100644 --- a/pallets/network/src/utilities/math.rs +++ b/pallets/network/src/utilities/math.rs @@ -19,8 +19,6 @@ // @to-do: Increase precision to 100.0000 use super::*; -use libm::pow; -use sp_core::U256; impl Pallet { // Percentages are defined by default with 2 decimals of precision (100.00). @@ -91,25 +89,11 @@ impl Pallet { x.saturating_mul(Self::PERCENTAGE_FACTOR).saturating_div(y).saturating_add(u128::from(x % y == 0)) } - /// Get percentage in decimal format that uses `PERCENTAGE_FACTOR` as f64 - pub fn get_percent_as_f64(v: u128) -> f64 { - v as f64 / Self::PERCENTAGE_FACTOR as f64 - } - - pub fn pow(x: f64, exp: f64) -> f64 { - pow(x, exp) - } - - - /// 1e18 version pub const PERCENTAGE_FACTOR_V2: u128 = 1e+18 as u128; pub const HALF_PERCENT_V2: u128 = Self::PERCENTAGE_FACTOR_V2 / 2; - - pub const PERCENTAGE_FACTOR_V2_TEST: U256 = U256([0x8ac7230489e80000, 0x0, 0x0, 0x0]); - pub const HALF_PERCENT_V2_TEST: U256 = U256([0x6f05b59d3b200000, 0x0, 0x0, 0x0]); - + /// Percentage Math - /// Inspired by Aave PercentageMath + // Inspired by Aave PercentageMath /// `x` is value /// `y` is percentage @@ -118,17 +102,13 @@ impl Pallet { if x == 0 || y == 0 { return 0 } - - let x = U256::from(x); - let y = U256::from(y); - if x > ((U256::MAX - Self::HALF_PERCENT_V2_TEST) / y) { + if x > ((u128::MAX - Self::HALF_PERCENT_V2) / y) { return 0 } // x * y / 100.0 - let result = x * y / Self::PERCENTAGE_FACTOR_V2_TEST; - result.try_into().unwrap_or(u128::MAX) + x.saturating_mul(y).saturating_div(Self::PERCENTAGE_FACTOR_V2) } /// `x` is value diff --git a/pallets/network/src/utilities/misc.rs b/pallets/network/src/utilities/misc.rs index 3b090ad..adc155d 100644 --- a/pallets/network/src/utilities/misc.rs +++ b/pallets/network/src/utilities/misc.rs @@ -17,8 +17,8 @@ use super::*; impl Pallet { // Loosely validates Node ID - pub fn validate_peer_id(peer_id: &PeerId) -> bool { - let peer_id_0 = &peer_id.0; + pub fn validate_peer_id(peer_id: PeerId) -> bool { + let peer_id_0 = peer_id.0; let len = peer_id_0.len(); // PeerId must be equal to or greater than 32 chars @@ -43,77 +43,24 @@ impl Pallet { false } - pub fn get_tx_rate_limit() -> u32 { + pub fn get_tx_rate_limit() -> u64 { TxRateLimit::::get() } - pub fn set_last_tx_block(key: &T::AccountId, block: u32) { + pub fn set_last_tx_block(key: &T::AccountId, block: u64) { LastTxBlock::::insert(key, block) } - pub fn get_last_tx_block(key: &T::AccountId) -> u32 { + pub fn get_last_tx_block(key: &T::AccountId) -> u64 { LastTxBlock::::get(key) } - pub fn exceeds_tx_rate_limit(prev_tx_block: u32, current_block: u32) -> bool { - let rate_limit: u32 = Self::get_tx_rate_limit(); + pub fn exceeds_tx_rate_limit(prev_tx_block: u64, current_block: u64) -> bool { + let rate_limit: u64 = Self::get_tx_rate_limit(); if rate_limit == 0 || prev_tx_block == 0 { return false; } return current_block - prev_tx_block <= rate_limit; } - - pub fn balance_to_u128( - input: <::Currency as frame_support::traits::Currency<::AccountId>>::Balance, - ) -> Option { - input.try_into().ok() - } - - /// Get total tokens in circulation - pub fn get_total_network_issuance() -> u128 { - let total_issuance_as_balance = T::Currency::total_issuance(); - let total_issuance: u128 = total_issuance_as_balance.try_into().unwrap_or(0); - let total_staked: u128 = TotalStake::::get(); - let total_delegate_staked: u128 = TotalDelegateStake::::get(); - let total_node_delegate_staked: u128 = TotalNodeDelegateStake::::get(); - total_issuance - .saturating_add(total_staked) - .saturating_add(total_delegate_staked) - .saturating_add(total_node_delegate_staked) - } - - pub fn send_to_treasury( - who: &T::AccountId, - amount: <::Currency as Currency<::AccountId>>::Balance - ) -> DispatchResult { - let treasury_account = T::TreasuryAccount::get(); - - T::Currency::transfer( - who, - &treasury_account, - amount, - ExistenceRequirement::KeepAlive, - )?; - - Ok(()) - } - - pub fn is_paused() -> DispatchResult { - ensure!( - !TxPause::::get(), - Error::::Paused - ); - Ok(()) - } - - // pub fn calculate_registration_delay( - // subnet_id: u32, - // base_delay: u32, - // scaling_factor: f64, - // current_nodes: u32 - // ) -> u32 { - // let delay = base_delay as f64 / (1.0 + scaling_factor * (1.0 + current_nodes as f64).log2()); - // delay.round() as u32 - // } } \ No newline at end of file diff --git a/pallets/network/src/utilities/mod.rs b/pallets/network/src/utilities/mod.rs index e4a33b7..7f06de4 100644 --- a/pallets/network/src/utilities/mod.rs +++ b/pallets/network/src/utilities/mod.rs @@ -1,9 +1,8 @@ use super::*; -pub mod owner; pub mod era; pub mod misc; pub mod subnet_node; pub mod subnet; pub mod delegate_staking; pub mod randomness; -pub mod math; +pub mod math; \ No newline at end of file diff --git a/pallets/network/src/utilities/owner.rs b/pallets/network/src/utilities/owner.rs deleted file mode 100644 index 374109a..0000000 --- a/pallets/network/src/utilities/owner.rs +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (C) Hypertensor. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::*; - -impl Pallet { - pub fn do_owner_deactivate_subnet(origin: T::RuntimeOrigin, subnet_id: u32, path: Vec) -> DispatchResult { - let coldkey: T::AccountId = ensure_signed(origin)?; - - ensure!( - Self::is_subnet_owner(&coldkey, subnet_id), - Error::::NotSubnetOwner - ); - - Self::do_remove_subnet( - path, - SubnetRemovalReason::Owner, - ).map_err(|e| e)?; - - Ok(()) - } - - pub fn do_owner_remove_subnet_node(origin: T::RuntimeOrigin, subnet_id: u32, subnet_node_id: u32) -> DispatchResult { - let coldkey: T::AccountId = ensure_signed(origin)?; - - ensure!( - Self::is_subnet_owner(&coldkey, subnet_id), - Error::::NotSubnetOwner - ); - - - Ok(()) - } - - pub fn do_owner_update_registration_interval(origin: T::RuntimeOrigin, subnet_id: u32, value: u32) -> DispatchResult { - let coldkey: T::AccountId = ensure_signed(origin)?; - - ensure!( - Self::is_subnet_owner(&coldkey, subnet_id), - Error::::NotSubnetOwner - ); - - ensure!( - value <= MaxSubnetRegistrationInterval::::get(), - Error::::MaxSubnetRegistration - ); - - SubnetNodeRegistrationInterval::::insert(subnet_id, value); - - Self::deposit_event(Event::SubnetEntryIntervalUpdate { - subnet_id: subnet_id, - owner: coldkey, - value: value - }); - - Ok(()) - } - - pub fn do_owner_update_activation_interval(origin: T::RuntimeOrigin, subnet_id: u32, value: u32) -> DispatchResult { - let coldkey: T::AccountId = ensure_signed(origin)?; - - ensure!( - Self::is_subnet_owner(&coldkey, subnet_id), - Error::::NotSubnetOwner - ); - - ensure!( - value <= MaxSubnetActivationInterval::::get(), - Error::::MaxSubnetActivation - ); - - SubnetNodeActivationInterval::::insert(subnet_id, value); - - Self::deposit_event(Event::SubnetEntryIntervalUpdate { - subnet_id: subnet_id, - owner: coldkey, - value: value - }); - - Ok(()) - } - - pub fn do_owner_add_to_coldkey_whitelist(origin: T::RuntimeOrigin, subnet_id: u32, coldkeys: BTreeSet) -> DispatchResult { - let coldkey: T::AccountId = ensure_signed(origin)?; - - ensure!( - Self::is_subnet_owner(&coldkey, subnet_id), - Error::::NotSubnetOwner - ); - - ensure!( - !Self::is_subnet_active(subnet_id), - Error::::SubnetMustBeRegistering - ); - - Ok(()) - } - - pub fn do_owner_remove_from_coldkey_whitelist(origin: T::RuntimeOrigin, subnet_id: u32, coldkeys: BTreeSet) -> DispatchResult { - let coldkey: T::AccountId = ensure_signed(origin)?; - - ensure!( - Self::is_subnet_owner(&coldkey, subnet_id), - Error::::NotSubnetOwner - ); - - ensure!( - !Self::is_subnet_active(subnet_id), - Error::::SubnetMustBeRegistering - ); - - Ok(()) - } - - pub fn do_owner_set_max_subnet_registration_epochs(origin: T::RuntimeOrigin, subnet_id: u32, value: u32) -> DispatchResult { - let coldkey: T::AccountId = ensure_signed(origin)?; - - ensure!( - Self::is_subnet_owner(&coldkey, subnet_id), - Error::::NotSubnetOwner - ); - - ensure!( - !Self::is_subnet_active(subnet_id), - Error::::SubnetMustBeRegistering - ); - - SubnetNodeRegistrationEpochs::::insert(subnet_id, value); - - Ok(()) - } - - pub fn do_owner_update_queue_period(origin: T::RuntimeOrigin, subnet_id: u32, value: u32) -> DispatchResult { - let coldkey: T::AccountId = ensure_signed(origin)?; - - ensure!( - Self::is_subnet_owner(&coldkey, subnet_id), - Error::::NotSubnetOwner - ); - - SubnetNodeQueuePeriod::::insert(subnet_id, value); - - Ok(()) - } - - pub fn do_owner_update_included_period(origin: T::RuntimeOrigin, subnet_id: u32, value: u32) -> DispatchResult { - let coldkey: T::AccountId = ensure_signed(origin)?; - - ensure!( - Self::is_subnet_owner(&coldkey, subnet_id), - Error::::NotSubnetOwner - ); - - Ok(()) - } - - /// Gives owner the ability to rearrange the queue, for instance, the owner can order the queue based on - /// a validators performance - pub fn do_owner_rearrange_queue(origin: T::RuntimeOrigin, subnet_id: u32, value: u32) -> DispatchResult { - let coldkey: T::AccountId = ensure_signed(origin)?; - - ensure!( - Self::is_subnet_owner(&coldkey, subnet_id), - Error::::NotSubnetOwner - ); - - Ok(()) - } - -} \ No newline at end of file diff --git a/pallets/network/src/utilities/subnet.rs b/pallets/network/src/utilities/subnet.rs index af10658..b43599a 100644 --- a/pallets/network/src/utilities/subnet.rs +++ b/pallets/network/src/utilities/subnet.rs @@ -17,11 +17,87 @@ use super::*; impl Pallet { pub fn get_min_subnet_nodes(base_node_memory: u128, memory_mb: u128) -> u32 { - 0 + // TODO: Needs to be updated for smoother curve + // + // + // + // + + // --- DEFAULT + // --- Get min nodes based on default memory settings + let simple_min_subnet_nodes: u128 = Self::percent_div( + memory_mb * Self::PERCENTAGE_FACTOR, + base_node_memory * Self::PERCENTAGE_FACTOR + ); + + // --- Parameters + let params: CurveParametersSet = MinNodesCurveParameters::::get(); + let one_hundred = Self::PERCENTAGE_FACTOR; + let x_curve_start = params.x_curve_start; + let y_end = params.y_end; + let y_start = params.y_start; + let x_rise = Self::PERCENTAGE_FACTOR / 100; + let max_x = params.max_x; + + let max_subnet_memory = MaxSubnetMemoryMB::::get(); + + let mut subnet_mem_position = Self::PERCENTAGE_FACTOR; + + // --- Get the x axis of the memory based on min and max + // Redundant since subnet memory cannot be surpassed beyond the max subnet memory + // If max subnet memory in curve is surpassed + if memory_mb < max_subnet_memory { + subnet_mem_position = memory_mb * Self::PERCENTAGE_FACTOR / max_subnet_memory; + } + + let mut min_subnet_nodes: u128 = MinSubnetNodes::::get() as u128 * Self::PERCENTAGE_FACTOR; + + if subnet_mem_position <= x_curve_start { + if simple_min_subnet_nodes > min_subnet_nodes { + min_subnet_nodes = simple_min_subnet_nodes; + } + return (min_subnet_nodes / Self::PERCENTAGE_FACTOR) as u32 + } + + let mut x = 0; + + if subnet_mem_position >= x_curve_start && subnet_mem_position <= Self::PERCENTAGE_FACTOR { + // If subnet memory position is in between range + x = (subnet_mem_position-x_curve_start) * Self::PERCENTAGE_FACTOR / (Self::PERCENTAGE_FACTOR-x_curve_start); + } else if subnet_mem_position > Self::PERCENTAGE_FACTOR { + // If subnet memory is greater than 100% + x = Self::PERCENTAGE_FACTOR; + } + + let y = (y_start - y_end) * (Self::PERCENTAGE_FACTOR - x) / Self::PERCENTAGE_FACTOR + y_end; + + let y_ratio = Self::percent_div(y, y_start); + + let mut min_subnet_nodes_on_curve = Self::percent_mul(simple_min_subnet_nodes, y_ratio); + + // --- If over the max x position, we increase the min nodes to ensure the amount is never less than the previous position + if subnet_mem_position > max_x { + let x_max_x_ratio = Self::percent_div(max_x, subnet_mem_position); + let comp_fraction = Self::PERCENTAGE_FACTOR - x_max_x_ratio; + min_subnet_nodes_on_curve = Self::percent_mul( + simple_min_subnet_nodes, + comp_fraction + ) + min_subnet_nodes_on_curve; + } + + // Redundant + if min_subnet_nodes_on_curve > min_subnet_nodes { + min_subnet_nodes = min_subnet_nodes_on_curve; + } + + (min_subnet_nodes / Self::PERCENTAGE_FACTOR) as u32 } pub fn get_target_subnet_nodes(min_subnet_nodes: u32) -> u32 { - min_subnet_nodes + Self::percent_mul( + min_subnet_nodes.into(), + TargetSubnetNodesMultiplier::::get() + ) as u32 + min_subnet_nodes } pub fn registration_cost(epoch: u32) -> u128 { @@ -40,18 +116,53 @@ impl Pallet { } // Calculate the current position within the registration period - let cycle_epoch = epoch.saturating_sub(next_registration_lower_bound_epoch); + let cycle_epoch = epoch - next_registration_lower_bound_epoch; // Calculate the fee decrease per epoch - let decrease_per_epoch = (fee_max.saturating_sub(fee_min)).saturating_div(period as u128); + let decrease_per_epoch = (fee_max - fee_min) / period as u128; // Calculate the current fee - let cost = fee_max.saturating_sub(decrease_per_epoch.saturating_mul(cycle_epoch as u128)); + let cost = fee_max - (decrease_per_epoch * cycle_epoch as u128); // Ensure the fee doesn't go below the minimum cost.max(fee_min) } + // pub fn registration_cost(epoch: u32) -> u128 { + // let last_registration_epoch = LastSubnetRegistrationEpoch::::get(); + // let fee_min: u128 = MinSubnetRegistrationFee::::get(); + + // // First registration is min fee (possibly fix this) + // if last_registration_epoch == 0 { + // return fee_min + // } + + // // --- Get the nexr registration epoch based on the last subnet registered epoch + // // This can be lower than the current epoch if no registrations were in the previous period or prior to the previous period + // let next_registration_lower_bound_epoch = Self::get_next_registration_epoch(last_registration_epoch); + // let period: u32 = SubnetRegistrationInterval::::get(); + // let next_registration_upper_bound_epoch = next_registration_lower_bound_epoch + period; + + // // If no registration within period or previous periods, keep at `fee_min` + // // # Example + // // *`epoch`: 100 + // // *`next_registration_upper_bound_epoch`: 200 + // // *`period`: 100 + // if next_registration_upper_bound_epoch <= epoch { + // return fee_min + // } + + // let fee_max: u128 = MaxSubnetRegistrationFee::::get(); + + // // Epoch within the cycle + // let cycle_epoch = epoch % period; + // let decrease_per_epoch = (fee_max.saturating_sub(fee_min)).saturating_div(period as u128); + // let cost = fee_max.saturating_sub(decrease_per_epoch.saturating_mul(cycle_epoch as u128)); + + // // Ensures cost doesn't go below min + // cost.max(fee_min) + // } + fn get_registration_cost( current_epoch: u32, last_registration_epoch: u32, @@ -74,75 +185,8 @@ impl Pallet { return 0 } let period: u32 = SubnetRegistrationInterval::::get(); - last_registration_epoch.saturating_add( - period.saturating_sub(last_registration_epoch % period) + last_registration_epoch + ( + period - (last_registration_epoch % period) ) } - - pub fn is_subnet_registering(subnet_id: u32, state: SubnetState, epoch: u32) -> bool { - let subnet_registration_epochs = SubnetRegistrationEpochs::::get(); - let is_registering: bool = state == SubnetState::Registered; - - match SubnetRegistrationEpoch::::try_get(subnet_id) { - Ok(registered_epoch) => { - let max_registration_epoch = registered_epoch.saturating_add(subnet_registration_epochs); - if is_registering && epoch <= max_registration_epoch { - return true - } - false - }, - Err(()) => false, - } - } - - pub fn is_subnet_in_enactment(subnet_id: u32, state: SubnetState, epoch: u32) -> bool { - let subnet_registration_epochs = SubnetRegistrationEpochs::::get(); - let subnet_activation_enactment_epochs = SubnetActivationEnactmentEpochs::::get(); - - let is_registering: bool = state == SubnetState::Registered; - - match SubnetRegistrationEpoch::::try_get(subnet_id) { - Ok(registered_epoch) => { - let max_registration_epoch = registered_epoch.saturating_add(subnet_registration_epochs); - let max_enactment_epoch = max_registration_epoch.saturating_add(subnet_activation_enactment_epochs); - - if is_registering && epoch <= max_registration_epoch { - return false - } else if is_registering && epoch <= max_enactment_epoch { - return true - } - false - }, - Err(()) => false, - } - - - - - - // let registered_epoch: u32 = subnet_data.registered; - // let max_registration_epoch = registered_epoch.saturating_add(subnet_registration_epochs); - // let max_enactment_epoch = max_registration_epoch.saturating_add(subnet_activation_enactment_epochs); - - // if is_registering && epoch <= max_registration_epoch { - // return false - // } else if is_registering && epoch <= max_enactment_epoch { - // return true - // } - // false - } - - pub fn is_subnet_active(subnet_id: u32) -> bool { - match SubnetsData::::try_get(subnet_id) { - Ok(subnet) => subnet.state == SubnetState::Active, - Err(()) => false, - } - } - - pub fn is_subnet_owner(account_id: &T::AccountId, subnet_id: u32) -> bool { - match SubnetOwner::::try_get(subnet_id) { - Ok(owner) => &owner == account_id, - Err(()) => false, - } - } } \ No newline at end of file diff --git a/pallets/network/src/utilities/subnet_node.rs b/pallets/network/src/utilities/subnet_node.rs index 599ebe2..06d7638 100644 --- a/pallets/network/src/utilities/subnet_node.rs +++ b/pallets/network/src/utilities/subnet_node.rs @@ -18,14 +18,14 @@ use super::*; impl Pallet { /// Remove subnet peer from subnet // to-do: Add slashing to subnet peers stake balance - pub fn perform_remove_subnet_node(block: u32, subnet_id: u32, subnet_node_id: u32) { + pub fn perform_remove_subnet_node(block: u64, subnet_id: u32, subnet_node_id: u32) { if let Ok(subnet_node) = SubnetNodesData::::try_get(subnet_id, subnet_node_id) { let hotkey = subnet_node.hotkey; let peer_id = subnet_node.peer_id; // Remove from attestations - let epoch_length: u32 = T::EpochLength::get(); - let epoch: u32 = block / epoch_length; + let epoch_length: u64 = T::EpochLength::get(); + let epoch: u64 = block / epoch_length; let submittable_nodes: BTreeSet = Self::get_classified_hotkeys(subnet_id, &SubnetNodeClass::Validator, epoch); @@ -56,9 +56,8 @@ impl Pallet { } // Remove all subnet node elements - PeerIdSubnetNode::::remove(subnet_id, &peer_id); - BootstrapPeerIdSubnetNode::::remove(subnet_id, subnet_node.bootstrap_peer_id); - HotkeySubnetNodeId::::remove(subnet_id, &hotkey); + SubnetNodeAccount::::remove(subnet_id, peer_id.clone()); + HotkeySubnetNodeId::::remove(subnet_id, hotkey.clone()); SubnetNodeIdHotkey::::remove(subnet_id, subnet_node_id); // Update total subnet peers by substracting 1 @@ -67,8 +66,6 @@ impl Pallet { // Reset sequential absent subnet node count SubnetNodePenalties::::remove(subnet_id, subnet_node_id); - TotalActiveNodes::::mutate(|n: &mut u32| n.saturating_dec()); - Self::deposit_event(Event::SubnetNodeRemoved { subnet_id: subnet_id, subnet_node_id: subnet_node_id }); } } @@ -76,7 +73,7 @@ impl Pallet { pub fn get_classified_subnet_node_ids( subnet_id: u32, classification: &SubnetNodeClass, - epoch: u32, + epoch: u64, ) -> C where C: FromIterator, @@ -88,19 +85,19 @@ impl Pallet { } /// Get subnet nodes by classification - pub fn get_classified_subnet_nodes(subnet_id: u32, classification: &SubnetNodeClass, epoch: u32) -> Vec> { + pub fn get_classified_subnet_nodes(subnet_id: u32, classification: &SubnetNodeClass, epoch: u64) -> Vec> { SubnetNodesData::::iter_prefix_values(subnet_id) .filter(|subnet_node| subnet_node.has_classification(classification, epoch)) .collect() } - pub fn get_classified_subnet_node_info(subnet_id: u32, classification: &SubnetNodeClass, epoch: u32) -> Vec> { + pub fn get_classified_subnet_node_info(subnet_id: u32, classification: &SubnetNodeClass, epoch: u64) -> Vec> { SubnetNodesData::::iter_prefix(subnet_id) .filter(|(subnet_node_id, subnet_node)| subnet_node.has_classification(classification, epoch)) .map(|(subnet_node_id, subnet_node)| { SubnetNodeInfo { subnet_node_id: subnet_node_id, - coldkey: HotkeyOwner::::get(&subnet_node.hotkey), + coldkey: HotkeyOwner::::get(subnet_node.hotkey.clone()), hotkey: subnet_node.hotkey, peer_id: subnet_node.peer_id, classification: subnet_node.classification, @@ -116,7 +113,7 @@ impl Pallet { pub fn get_classified_hotkeys( subnet_id: u32, classification: &SubnetNodeClass, - epoch: u32, + epoch: u64, ) -> C where C: FromIterator, @@ -142,7 +139,7 @@ impl Pallet { subnet_node_id: u32, ) -> Option<(T::AccountId, T::AccountId)> { let hotkey = SubnetNodeIdHotkey::::try_get(subnet_id, subnet_node_id).ok()?; - let coldkey = HotkeyOwner::::try_get(&hotkey).ok()?; + let coldkey = HotkeyOwner::::try_get(hotkey.clone()).ok()?; Some((hotkey, coldkey)) } @@ -178,56 +175,4 @@ impl Pallet { Err(()) => return false } } - - pub fn increase_class( - subnet_id: u32, - subnet_node_id: u32, - start_epoch: u32, - ) { - // TODO: Add querying epoch here - SubnetNodesData::::mutate( - subnet_id, - subnet_node_id, - |params: &mut SubnetNode| { - params.classification = SubnetNodeClassification { - class: params.classification.class.next(), - start_epoch: start_epoch, - }; - }, - ); - } - - pub fn is_owner_of_peer_or_ownerless(subnet_id: u32, subnet_node_id: u32, peer_id: &PeerId) -> bool { - let is_peer_owner_or_ownerless = match PeerIdSubnetNode::::try_get(subnet_id, peer_id) { - Ok(peer_subnet_node_id) => { - if peer_subnet_node_id == subnet_node_id { - return true - } - false - }, - Err(()) => true, - }; - - is_peer_owner_or_ownerless && match BootstrapPeerIdSubnetNode::::try_get(subnet_id, peer_id) { - Ok(bootstrap_subnet_node_id) => { - if bootstrap_subnet_node_id == subnet_node_id { - return true - } - false - }, - Err(()) => true, - } - } - - pub fn calculate_max_activation_epoch(subnet_id: u32) -> u32 { - let prev_registration_epoch = 10; - 0 - } - - pub fn get_subnet_churn_limit(subnet_id: u32) -> u32 { - let min_churn = 4; - let active_nodes = TotalActiveSubnetNodes::::get(subnet_id); - let churn_denominator = ChurnDenominator::::get(subnet_id); - min_churn.max(active_nodes.saturating_div(churn_denominator)) - } } \ No newline at end of file diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 6cbd3e8..06d9e51 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -35,8 +35,6 @@ pallet-utility.workspace = true pallet-proxy.workspace = true pallet-preimage.workspace = true pallet-scheduler.workspace = true -pallet-treasury.workspace = true -pallet-tx-pause.workspace = true sp-api.workspace = true sp-block-builder.workspace = true @@ -102,10 +100,8 @@ std = [ "pallet-proxy/std", "pallet-preimage/std", "pallet-scheduler/std", - "pallet-treasury/std", "pallet-collective/std", "pallet-atomic-swap/std", - "pallet-tx-pause/std", "sp-api/std", "sp-block-builder/std", @@ -139,7 +135,6 @@ runtime-benchmarks = [ "pallet-network/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-collective/runtime-benchmarks", - "pallet-treasury/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] @@ -160,5 +155,4 @@ try-runtime = [ "pallet-multisig/try-runtime", "pallet-proxy/try-runtime", "pallet-collective/try-runtime", - "pallet-treasury/try-runtime", ] diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 70e7329..c8f8ef6 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -12,22 +12,21 @@ use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, One, Verify, IdentityLookup}, + traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, One, Verify}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, MultiSignature, RuntimeDebug }; use codec::{Encode, Decode, MaxEncodedLen}; -use sp_runtime::traits::Get; + #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use alloc::collections::BTreeMap; + pub use frame_support::{ construct_runtime, derive_impl, parameter_types, ord_parameter_types, traits::{ fungible::HoldConsideration, - tokens::{ConversionFromAssetBalance, PaymentStatus, Pay, PayFromAccount, UnityAssetBalanceConversion}, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, KeyOwnerProofSystem, StorageInfo, InstanceFilter, @@ -48,8 +47,8 @@ pub use frame_support::{ genesis_builder_helper::{build_state, get_preset}, storage::bounded_vec::BoundedVec, }; -use core::{cell::RefCell, marker::PhantomData}; -pub use frame_system::{EnsureRoot, EnsureRootWithSuccess, EnsureWithSuccess}; + +pub use frame_system::EnsureRoot; pub use pallet_balances::Call as BalancesCall; pub use frame_system::Call as SystemCall; pub use pallet_timestamp::Call as TimestampCall; @@ -57,7 +56,6 @@ use pallet_transaction_payment::{ConstFeeMultiplier, FungibleAdapter, Multiplier #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; - use pallet_network::DefaultSubnetNodeUniqueParamLimit; pub use pallet_network; @@ -140,22 +138,19 @@ pub const MILLISECS_PER_BLOCK: u64 = 6000; pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; // Time is measured by number of blocks. -// e.g. How many blocks in a minutes, hours, day, year -pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); // 10 -pub const HOURS: BlockNumber = MINUTES * 60; // 600 -pub const DAYS: BlockNumber = HOURS * 24; // 14400 -pub const YEAR: BlockNumber = DAYS * 365; // 5256000 - -// Rewards pallet variables +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; +pub const YEAR: BlockNumber = DAYS * 365; pub const BLOCKS_PER_HALVING: BlockNumber = YEAR * 2; pub const TARGET_MAX_TOTAL_SUPPLY: u128 = 2_800_000_000_000_000_000_000_000; pub const INITIAL_REWARD_PER_BLOCK: u128 = (TARGET_MAX_TOTAL_SUPPLY / 2) / BLOCKS_PER_HALVING as u128; -pub const SECS_PER_BLOCK: u32 = (MILLISECS_PER_BLOCK as BlockNumber) / 1000; // 6 +pub const SECS_PER_BLOCK: u64 = 6000 / 1000; -// Blocks per epoch -pub const BLOCKS_PER_EPOCH: u32 = 10; -pub const EPOCHS_PER_YEAR: u32 = YEAR as u32 / BLOCKS_PER_EPOCH; +pub const EPOCH_LENGTH: u64 = 10; +pub const BLOCKS_PER_EPOCH: u64 = SECS_PER_BLOCK * EPOCH_LENGTH; +pub const EPOCHS_PER_YEAR: u64 = YEAR as u64 / BLOCKS_PER_EPOCH; /// The version information used to identify this runtime when compiled natively. #[cfg(feature = "std")] @@ -498,15 +493,13 @@ impl pallet_collective::Config for Runtime { } parameter_types! { - pub const InitialTxRateLimit: u32 = 0; - pub const EpochLength: u32 = BLOCKS_PER_EPOCH; // Testnet 600 blocks per erpoch / 69 mins per epoch, Local 10 - pub const EpochsPerYear: u32 = EPOCHS_PER_YEAR; // Testnet 600 blocks per erpoch / 69 mins per epoch, Local 10 + pub const InitialTxRateLimit: u64 = 0; + pub const EpochLength: u64 = EPOCH_LENGTH; // Testnet 600 blocks per erpoch / 69 mins per epoch, Local 10 pub const NetworkPalletId: PalletId = PalletId(*b"/network"); pub const MinProposalStake: u128 = 1_000_000_000_000_000_000; // 1 * 1e18 - pub const DelegateStakeCooldownEpochs: u32 = 100; - pub const NodeDelegateStakeCooldownEpochs: u32 = 100; - pub const StakeCooldownEpochs: u32 = 100; - pub const DelegateStakeEpochsRemovalWindow: u32 = 10; + pub const DelegateStakeCooldownEpochs: u64 = 100; + pub const StakeCooldownEpochs: u64 = 100; + pub const DelegateStakeEpochsRemovalWindow: u64 = 10; pub const MaxDelegateStakeUnlockings: u32 = 32; pub const MaxStakeUnlockings: u32 = 32; } @@ -518,21 +511,18 @@ impl pallet_network::Config for Runtime { type MajorityCollectiveOrigin = pallet_collective::EnsureProportionAtLeast; type SuperMajorityCollectiveOrigin = pallet_collective::EnsureProportionAtLeast; type EpochLength = EpochLength; - type EpochsPerYear = EpochsPerYear; type StringLimit = ConstU32<12288>; type InitialTxRateLimit = InitialTxRateLimit; // type OffchainSignature = Signature; // type OffchainPublic = AccountPublic; type PalletId = NetworkPalletId; type DelegateStakeCooldownEpochs = DelegateStakeCooldownEpochs; - type NodeDelegateStakeCooldownEpochs = NodeDelegateStakeCooldownEpochs; type DelegateStakeEpochsRemovalWindow = DelegateStakeEpochsRemovalWindow; type MaxDelegateStakeUnlockings = MaxDelegateStakeUnlockings; type MaxStakeUnlockings = MaxStakeUnlockings; type StakeCooldownEpochs = StakeCooldownEpochs; type Randomness = InsecureRandomnessCollectiveFlip; type MinProposalStake = MinProposalStake; - type TreasuryAccount = TreasuryAccount; } pub struct AuraAccountAdapter; @@ -551,20 +541,6 @@ impl pallet_authorship::Config for Runtime { type EventHandler = (); } -parameter_types! { - pub const MaxNameLen: u32 = 50; -} - -impl pallet_tx_pause::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PauseOrigin = EnsureRoot; - type UnpauseOrigin = EnsureRoot; - type WhitelistedCalls = (); - type MaxNameLen = MaxNameLen; - type WeightInfo = (); -} - parameter_types! { pub const HalvingInterval: BlockNumber = BLOCKS_PER_HALVING; pub const InitialBlockSubsidy: u128 = INITIAL_REWARD_PER_BLOCK; @@ -585,35 +561,6 @@ impl pallet_atomic_swap::Config for Runtime { type ProofLimit = ConstU32<1024>; } -parameter_types! { - pub const Burn: Permill = Permill::from_percent(50); - pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); - pub const SpendLimit: Balance = u128::MAX; - pub TreasuryAccount: AccountId = Treasury::account_id(); -} - -impl pallet_treasury::Config for Runtime { - type PalletId = TreasuryPalletId; - type Currency = Balances; - type RejectOrigin = EnsureRoot; - type RuntimeEvent = RuntimeEvent; - type SpendPeriod = ConstU32<2>; - type Burn = Burn; - type BurnDestination = (); // Just gets burned. - type WeightInfo = (); - type SpendFunds = (); - type MaxApprovals = ConstU32<100>; - type SpendOrigin = EnsureRootWithSuccess; - type AssetKind = (); - type Beneficiary = AccountId; - type BeneficiaryLookup = IdentityLookup; - type Paymaster = PayFromAccount; - type BalanceConverter = UnityAssetBalanceConversion; - type PayoutPeriod = ConstU32<10>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); -} - // Create the runtime by composing the FRAME pallets that were previously configured. #[frame_support::runtime] mod runtime { @@ -687,12 +634,6 @@ mod runtime { // #[runtime::pallet_index(18)] // pub type NodeAuthorization = pallet_node_authorization; - - #[runtime::pallet_index(18)] - pub type Treasury = pallet_treasury; - - #[runtime::pallet_index(19)] - pub type TxPause = pallet_tx_pause; } /// The address format for describing accounts. @@ -744,7 +685,6 @@ mod benches { [pallet_sudo, Sudo] [pallet_network, Network] [pallet_collective, Collective] - [pallet_treasury, Treasury] ); }