diff --git a/README.md b/README.md index 30f36ffab5..4d1cdf645a 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,12 @@ This repository contains Bittensor's substrate-chain. Subtensor contains the tru * The binaries in ./bin/release are x86_64 binaries to be used with the Linux kernel. * Subtensor needs ~286 MiB to run. -* Architectures other than x86_64 are currently not supported. +* Supported Architectures: + - Linux: x86_64 + - MacOS: x86_64 and ARM64 (M series Macs) * OSs other than Linux and MacOS are currently not supported. + ## Architectures Subtensor support the following architectures: @@ -34,9 +37,10 @@ Requirements: * glibc 2.11+ A fresh FRAME-based [Substrate](https://www.substrate.io/) node, ready for hacking :rocket: -## MacOS x86_64 +## MacOS x86_64 & arm64 (Apple Silicon) Requirements: -* MacOS 10.7+ (Lion+) +* macOS 10.7+ (Lion+) for x86_64 +* macOS 11+ (Big Sur+) for Apple Silicon (M1, M2, and later) with arm64 architecture support. ## Network requirements * Subtensor needs access to the public internet @@ -49,7 +53,7 @@ Requirements: --- -## For Subnet Development +## For Subnet Development If you are developing and testing subnet incentive mechanism, you will need to run a local subtensor node. Follow the detailed step-by-step instructions provided in the [**Subtensor Nodes** section in Bittensor Developer Documentation](https://docs.bittensor.com/subtensor-nodes). @@ -216,7 +220,7 @@ If you want to see the multi-node consensus algorithm in action, refer to our A Substrate project such as this consists of a number of components that are spread across a few directories. -### Node Capabilities +### Node Capabilities A blockchain node is an application that allows users to participate in a blockchain network. Substrate-based blockchain nodes expose a number of capabilities: @@ -232,7 +236,7 @@ Substrate-based blockchain nodes expose a number of capabilities: **Directory structure** -There are several files in the [`node`](./node/) directory. Make a note of the following important files: +There are several files in the [`node`](./node/) directory. Make a note of the following important files: - [`chain_spec.rs`](./node/src/chain_spec.rs): A [chain specification](https://docs.substrate.io/main-docs/build/chain-spec/) is a diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index e8f37526e0..9cb51e1b27 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -158,7 +158,7 @@ pub mod pallet { netuid: u16, min_difficulty: u64, ) -> DispatchResult { - pallet_subtensor::Pallet::::ensure_subnet_owner_or_root(origin, netuid)?; + ensure_root(origin)?; ensure!( pallet_subtensor::Pallet::::if_subnet_exist(netuid), diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index d0a668f92c..9b119f1786 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -87,7 +87,7 @@ impl Pallet { let alpha_out_i = alpha_emission_i; // Only emit TAO if the subnetwork allows registration. if !Self::get_network_registration_allowed(*netuid_i) - && Self::get_network_pow_registration_allowed(*netuid_i) + && !Self::get_network_pow_registration_allowed(*netuid_i) { tao_in_i = asfloat!(0.0); } @@ -249,11 +249,6 @@ impl Pallet { BlocksSinceLastStep::::mutate(netuid, |total| *total = total.saturating_add(1)); } } - - // --- 8. Apply pending childkeys of this subnet for the next epoch - for netuid in subnets.iter() { - Self::do_set_pending_children(*netuid); - } } pub fn drain_pending_emission( diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 58406e516a..0ad75ea200 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1550,6 +1550,18 @@ pub mod pallet { pub type RevealPeriodEpochs = StorageMap<_, Twox64Concat, u16, u64, ValueQuery, DefaultRevealPeriodEpochs>; + #[pallet::storage] + /// --- Map (coldkey, hotkey) --> u64 the last block at which stake was added/removed. + pub type LastColdkeyHotkeyStakeBlock = StorageDoubleMap< + _, + Twox64Concat, + T::AccountId, + Twox64Concat, + T::AccountId, + u64, + OptionQuery, + >; + /// ================== /// ==== Genesis ===== /// ================== @@ -1588,6 +1600,19 @@ pub mod pallet { 0 } + /// Returns the transaction priority for stake operations. + pub fn get_priority_staking(coldkey: &T::AccountId, hotkey: &T::AccountId) -> u64 { + match LastColdkeyHotkeyStakeBlock::::get(coldkey, hotkey) { + Some(last_stake_block) => { + let current_block_number = Self::get_current_block_as_u64(); + let default_priority = current_block_number.saturating_sub(last_stake_block); + + default_priority.saturating_add(u32::MAX as u64) + } + None => 0, + } + } + /// Is the caller allowed to set weights pub fn check_weights_min_stake(hotkey: &T::AccountId, netuid: u16) -> bool { // Blacklist weights transactions for low stake peers. @@ -1705,11 +1730,15 @@ where Pallet::::get_priority_set_weights(who, netuid) } + pub fn get_priority_staking(coldkey: &T::AccountId, hotkey: &T::AccountId) -> u64 { + Pallet::::get_priority_staking(coldkey, hotkey) + } + pub fn check_weights_min_stake(who: &T::AccountId, netuid: u16) -> bool { Pallet::::check_weights_min_stake(who, netuid) } - pub fn result_to_validity(result: Result<(), Error>) -> TransactionValidity { + pub fn result_to_validity(result: Result<(), Error>, priority: u64) -> TransactionValidity { if let Err(err) = result { match err { Error::::AmountTooLow => Err(InvalidTransaction::Custom( @@ -1750,7 +1779,7 @@ where } } else { Ok(ValidTransaction { - priority: Self::get_priority_vanilla(), + priority, ..Default::default() }) } @@ -1885,15 +1914,24 @@ where netuid, amount_staked, }) => { + if ColdkeySwapScheduled::::contains_key(who) { + return InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into(), + ) + .into(); + } // Fully validate the user input - Self::result_to_validity(Pallet::::validate_add_stake( - who, - hotkey, - *netuid, - *amount_staked, - *amount_staked, - false, - )) + Self::result_to_validity( + Pallet::::validate_add_stake( + who, + hotkey, + *netuid, + *amount_staked, + *amount_staked, + false, + ), + Self::get_priority_staking(who, hotkey), + ) } Some(Call::add_stake_limit { hotkey, @@ -1902,18 +1940,28 @@ where limit_price, allow_partial, }) => { + if ColdkeySwapScheduled::::contains_key(who) { + return InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into(), + ) + .into(); + } + // Calcaulate the maximum amount that can be executed with price limit let max_amount = Pallet::::get_max_amount_add(*netuid, *limit_price); // Fully validate the user input - Self::result_to_validity(Pallet::::validate_add_stake( - who, - hotkey, - *netuid, - *amount_staked, - max_amount, - *allow_partial, - )) + Self::result_to_validity( + Pallet::::validate_add_stake( + who, + hotkey, + *netuid, + *amount_staked, + max_amount, + *allow_partial, + ), + Self::get_priority_staking(who, hotkey), + ) } Some(Call::remove_stake { hotkey, @@ -1921,14 +1969,17 @@ where amount_unstaked, }) => { // Fully validate the user input - Self::result_to_validity(Pallet::::validate_remove_stake( - who, - hotkey, - *netuid, - *amount_unstaked, - *amount_unstaked, - false, - )) + Self::result_to_validity( + Pallet::::validate_remove_stake( + who, + hotkey, + *netuid, + *amount_unstaked, + *amount_unstaked, + false, + ), + Self::get_priority_staking(who, hotkey), + ) } Some(Call::remove_stake_limit { hotkey, @@ -1941,14 +1992,17 @@ where let max_amount = Pallet::::get_max_amount_remove(*netuid, *limit_price); // Fully validate the user input - Self::result_to_validity(Pallet::::validate_remove_stake( - who, - hotkey, - *netuid, - *amount_unstaked, - max_amount, - *allow_partial, - )) + Self::result_to_validity( + Pallet::::validate_remove_stake( + who, + hotkey, + *netuid, + *amount_unstaked, + max_amount, + *allow_partial, + ), + Self::get_priority_staking(who, hotkey), + ) } Some(Call::move_stake { origin_hotkey, @@ -1957,19 +2011,29 @@ where destination_netuid, alpha_amount, }) => { + if ColdkeySwapScheduled::::contains_key(who) { + return InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into(), + ) + .into(); + } + // Fully validate the user input - Self::result_to_validity(Pallet::::validate_stake_transition( - who, - who, - origin_hotkey, - destination_hotkey, - *origin_netuid, - *destination_netuid, - *alpha_amount, - *alpha_amount, - None, - false, - )) + Self::result_to_validity( + Pallet::::validate_stake_transition( + who, + who, + origin_hotkey, + destination_hotkey, + *origin_netuid, + *destination_netuid, + *alpha_amount, + *alpha_amount, + None, + false, + ), + Self::get_priority_staking(who, origin_hotkey), + ) } Some(Call::transfer_stake { destination_coldkey, @@ -1978,19 +2042,29 @@ where destination_netuid, alpha_amount, }) => { + if ColdkeySwapScheduled::::contains_key(who) { + return InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into(), + ) + .into(); + } + // Fully validate the user input - Self::result_to_validity(Pallet::::validate_stake_transition( - who, - destination_coldkey, - hotkey, - hotkey, - *origin_netuid, - *destination_netuid, - *alpha_amount, - *alpha_amount, - None, - true, - )) + Self::result_to_validity( + Pallet::::validate_stake_transition( + who, + destination_coldkey, + hotkey, + hotkey, + *origin_netuid, + *destination_netuid, + *alpha_amount, + *alpha_amount, + None, + true, + ), + Self::get_priority_staking(who, hotkey), + ) } Some(Call::swap_stake { hotkey, @@ -1998,19 +2072,29 @@ where destination_netuid, alpha_amount, }) => { + if ColdkeySwapScheduled::::contains_key(who) { + return InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into(), + ) + .into(); + } + // Fully validate the user input - Self::result_to_validity(Pallet::::validate_stake_transition( - who, - who, - hotkey, - hotkey, - *origin_netuid, - *destination_netuid, - *alpha_amount, - *alpha_amount, - None, - false, - )) + Self::result_to_validity( + Pallet::::validate_stake_transition( + who, + who, + hotkey, + hotkey, + *origin_netuid, + *destination_netuid, + *alpha_amount, + *alpha_amount, + None, + false, + ), + Self::get_priority_staking(who, hotkey), + ) } Some(Call::swap_stake_limit { hotkey, @@ -2020,6 +2104,13 @@ where limit_price, allow_partial, }) => { + if ColdkeySwapScheduled::::contains_key(who) { + return InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into(), + ) + .into(); + } + // Get the max amount possible to exchange let max_amount = Pallet::::get_max_amount_move( *origin_netuid, @@ -2028,20 +2119,30 @@ where ); // Fully validate the user input - Self::result_to_validity(Pallet::::validate_stake_transition( - who, - who, - hotkey, - hotkey, - *origin_netuid, - *destination_netuid, - *alpha_amount, - max_amount, - Some(*allow_partial), - false, - )) + Self::result_to_validity( + Pallet::::validate_stake_transition( + who, + who, + hotkey, + hotkey, + *origin_netuid, + *destination_netuid, + *alpha_amount, + max_amount, + Some(*allow_partial), + false, + ), + Self::get_priority_staking(who, hotkey), + ) } Some(Call::register { netuid, .. } | Call::burned_register { netuid, .. }) => { + if ColdkeySwapScheduled::::contains_key(who) { + return InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into(), + ) + .into(); + } + let registrations_this_interval = Pallet::::get_registrations_this_interval(*netuid); let max_registrations_per_interval = diff --git a/pallets/subtensor/src/rpc_info/stake_info.rs b/pallets/subtensor/src/rpc_info/stake_info.rs index 631e3a167a..bda619596a 100644 --- a/pallets/subtensor/src/rpc_info/stake_info.rs +++ b/pallets/subtensor/src/rpc_info/stake_info.rs @@ -3,7 +3,7 @@ use frame_support::pallet_prelude::{Decode, Encode}; extern crate alloc; use codec::Compact; -#[freeze_struct("4f16c654467bc8b6")] +#[freeze_struct("5cfb3c84c3af3116")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, TypeInfo)] pub struct StakeInfo { hotkey: AccountId, @@ -12,6 +12,7 @@ pub struct StakeInfo { stake: Compact, locked: Compact, emission: Compact, + tao_emission: Compact, drain: Compact, is_registered: bool, } @@ -38,6 +39,7 @@ impl Pallet { continue; } let emission: u64 = AlphaDividendsPerSubnet::::get(*netuid_i, &hotkey_i); + let tao_emission: u64 = TaoDividendsPerSubnet::::get(*netuid_i, &hotkey_i); let is_registered: bool = Self::is_hotkey_registered_on_network(*netuid_i, hotkey_i); stake_info_for_coldkey.push(StakeInfo { @@ -47,6 +49,7 @@ impl Pallet { stake: alpha.into(), locked: 0.into(), emission: emission.into(), + tao_emission: tao_emission.into(), drain: 0.into(), is_registered, }); @@ -94,6 +97,7 @@ impl Pallet { netuid, ); let emission: u64 = AlphaDividendsPerSubnet::::get(netuid, &hotkey_account); + let tao_emission: u64 = TaoDividendsPerSubnet::::get(netuid, &hotkey_account); let is_registered: bool = Self::is_hotkey_registered_on_network(netuid, &hotkey_account); Some(StakeInfo { @@ -103,6 +107,7 @@ impl Pallet { stake: alpha.into(), locked: 0.into(), emission: emission.into(), + tao_emission: tao_emission.into(), drain: 0.into(), is_registered, }) diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index 1be858529d..854fb07cb9 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -59,7 +59,8 @@ impl Pallet { pub fn update_moving_price(netuid: u16) { let alpha: I96F32 = SubnetMovingAlpha::::get(); let minus_alpha: I96F32 = I96F32::saturating_from_num(1.0).saturating_sub(alpha); - let current_price: I96F32 = alpha.saturating_mul(Self::get_alpha_price(netuid)); + let current_price: I96F32 = alpha + .saturating_mul(Self::get_alpha_price(netuid).min(I96F32::saturating_from_num(1.0))); let current_moving: I96F32 = minus_alpha.saturating_mul(Self::get_moving_alpha_price(netuid)); let new_moving: I96F32 = current_price.saturating_add(current_moving); @@ -748,6 +749,7 @@ impl Pallet { TotalStake::::mutate(|total| { *total = total.saturating_add(actual_fee); }); + LastColdkeyHotkeyStakeBlock::::insert(coldkey, hotkey, Self::get_current_block_as_u64()); // Step 5. Deposit and log the unstaking event. Self::deposit_event(Event::StakeRemoved( @@ -807,6 +809,7 @@ impl Pallet { TotalStake::::mutate(|total| { *total = total.saturating_add(actual_fee); }); + LastColdkeyHotkeyStakeBlock::::insert(coldkey, hotkey, Self::get_current_block_as_u64()); // Step 6. Deposit and log the staking event. Self::deposit_event(Event::StakeAdded( @@ -960,12 +963,6 @@ impl Pallet { Error::::HotKeyAccountNotExists ); - // Ensure origin coldkey owns the origin hotkey. - ensure!( - Self::coldkey_owns_hotkey(origin_coldkey, origin_hotkey), - Error::::NonAssociatedColdKey - ); - // Ensure there is enough stake in the origin subnet. let origin_alpha = Self::get_stake_for_hotkey_and_coldkey_on_subnet( origin_hotkey, diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs index ce0ce37fce..15832b93fe 100644 --- a/pallets/subtensor/src/tests/move_stake.rs +++ b/pallets/subtensor/src/tests/move_stake.rs @@ -541,7 +541,7 @@ fn test_do_move_wrong_origin() { netuid, alpha, ), - Error::::NonAssociatedColdKey + Error::::NotEnoughStakeToWithdraw ); // Check that no stake was moved @@ -981,7 +981,7 @@ fn test_do_transfer_wrong_origin() { netuid, stake_amount ), - Error::::NonAssociatedColdKey + Error::::NotEnoughStakeToWithdraw ); }); } @@ -1245,7 +1245,7 @@ fn test_do_swap_wrong_origin() { netuid2, stake_amount ), - Error::::NonAssociatedColdKey + Error::::NotEnoughStakeToWithdraw ); }); } @@ -1486,6 +1486,38 @@ fn test_do_swap_multiple_times() { }); } +// cargo test --package pallet-subtensor --lib -- tests::move_stake::test_do_swap_allows_non_owned_hotkey --exact --show-output +#[test] +fn test_do_swap_allows_non_owned_hotkey() { + new_test_ext(1).execute_with(|| { + let subnet_owner_coldkey = U256::from(1001); + let subnet_owner_hotkey = U256::from(1002); + let origin_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + let destination_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let foreign_coldkey = U256::from(3); + let stake_amount = DefaultMinStake::::get() * 10; + + SubtensorModule::create_account_if_non_existent(&foreign_coldkey, &hotkey); + SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount, 0); + let alpha_before = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey, + &coldkey, + origin_netuid, + ); + + assert_ok!(SubtensorModule::do_swap_stake( + RuntimeOrigin::signed(coldkey), + hotkey, + origin_netuid, + destination_netuid, + alpha_before, + )); + }); +} + // cargo test --package pallet-subtensor --lib -- tests::move_stake::test_swap_stake_limit_validate --exact --show-output #[test] fn test_swap_stake_limit_validate() { diff --git a/pallets/subtensor/src/tests/swap_coldkey.rs b/pallets/subtensor/src/tests/swap_coldkey.rs index 7761005780..d7f7123341 100644 --- a/pallets/subtensor/src/tests/swap_coldkey.rs +++ b/pallets/subtensor/src/tests/swap_coldkey.rs @@ -1726,7 +1726,7 @@ fn test_schedule_swap_coldkey_duplicate() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_schedule_swap_coldkey_execution --exact --nocapture +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --package pallet-subtensor --lib -- tests::swap_coldkey::test_schedule_swap_coldkey_execution --exact --show-output --nocapture #[test] fn test_schedule_swap_coldkey_execution() { new_test_ext(1).execute_with(|| { @@ -2022,3 +2022,328 @@ fn test_cant_schedule_swap_without_enough_to_burn() { ); }); } + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --package pallet-subtensor --lib -- tests::swap_coldkey::test_coldkey_in_swap_schedule_prevents_funds_usage --exact --show-output --nocapture +#[test] +fn test_coldkey_in_swap_schedule_prevents_funds_usage() { + // Testing the signed extension validate function + // correctly filters transactions that attempt to use funds + // while a coldkey swap is scheduled. + + new_test_ext(0).execute_with(|| { + let netuid: u16 = 1; + let version_key: u64 = 0; + let coldkey = U256::from(0); + let new_coldkey = U256::from(1); + let hotkey: U256 = U256::from(2); // Add the hotkey field + assert_ne!(hotkey, coldkey); // Ensure hotkey is NOT the same as coldkey !!! + let fee = DefaultStakingFee::::get(); + + let who = coldkey; // The coldkey signs this transaction + + // Disallowed transactions are + // - add_stake + // - add_stake_limit + // - swap_stake + // - swap_stake_limit + // - move_stake + // - transfer_stake + // - balances.transfer_all + // - balances.transfer_allow_death + // - balances.transfer_keep_alive + + // Allowed transactions are: + // - remove_stake + // - remove_stake_limit + // others... + + // Create netuid + add_network(netuid, 1, 0); + // Register the hotkey + SubtensorModule::append_neuron(netuid, &hotkey, 0); + crate::Owner::::insert(hotkey, coldkey); + + SubtensorModule::add_balance_to_coldkey_account(&who, u64::MAX); + + // Set the minimum stake to 0. + SubtensorModule::set_stake_threshold(0); + // Add stake to the hotkey + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(who), + hotkey, + netuid, + 100_000_000_000 + )); + + // Schedule the coldkey for a swap + assert_ok!(SubtensorModule::schedule_swap_coldkey( + <::RuntimeOrigin>::signed(who), + new_coldkey + )); + + assert!(ColdkeySwapScheduled::::contains_key(who)); + + // Setup the extension + let info: crate::DispatchInfo = + crate::DispatchInfoOf::<::RuntimeCall>::default(); + let extension = crate::SubtensorSignedExtension::::new(); + + // Try each call + + // Add stake + let call = RuntimeCall::SubtensorModule(SubtensorCall::add_stake { + hotkey, + netuid, + amount_staked: 100_000_000_000, + }); + let result: Result = + extension.validate(&who, &call.clone(), &info, 10); + // Should fail + assert_err!( + // Should get an invalid transaction error + result, + crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into() + )) + ); + + // Add stake limit + let call = RuntimeCall::SubtensorModule(SubtensorCall::add_stake_limit { + hotkey, + netuid, + amount_staked: 100_000_000_000, + limit_price: 100_000_000_000, + allow_partial: false, + }); + let result = extension.validate(&who, &call.clone(), &info, 10); + // Should fail + assert_err!( + // Should get an invalid transaction error + result, + crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into() + )) + ); + + // Swap stake + let call = RuntimeCall::SubtensorModule(SubtensorCall::swap_stake { + hotkey, + origin_netuid: netuid, + destination_netuid: netuid, + alpha_amount: 100_000_000_000, + }); + let result = extension.validate(&who, &call.clone(), &info, 10); + // Should fail + assert_err!( + // Should get an invalid transaction error + result, + crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into() + )) + ); + + // Swap stake limit + let call = RuntimeCall::SubtensorModule(SubtensorCall::swap_stake_limit { + hotkey, + origin_netuid: netuid, + destination_netuid: netuid, + alpha_amount: 100_000_000_000, + limit_price: 100_000_000_000, + allow_partial: false, + }); + let result = extension.validate(&who, &call.clone(), &info, 10); + // Should fail + assert_err!( + // Should get an invalid transaction error + result, + crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into() + )) + ); + + // Move stake + let call = RuntimeCall::SubtensorModule(SubtensorCall::move_stake { + origin_hotkey: hotkey, + destination_hotkey: hotkey, + origin_netuid: netuid, + destination_netuid: netuid, + alpha_amount: 100_000_000_000, + }); + let result = extension.validate(&who, &call.clone(), &info, 10); + // Should fail + assert_err!( + // Should get an invalid transaction error + result, + crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into() + )) + ); + + // Transfer stake + let call = RuntimeCall::SubtensorModule(SubtensorCall::transfer_stake { + destination_coldkey: new_coldkey, + hotkey, + origin_netuid: netuid, + destination_netuid: netuid, + alpha_amount: 100_000_000_000, + }); + let result = extension.validate(&who, &call.clone(), &info, 10); + // Should fail + assert_err!( + // Should get an invalid transaction error + result, + crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into() + )) + ); + + // Transfer all + let call = RuntimeCall::Balances(BalancesCall::transfer_all { + dest: new_coldkey, + keep_alive: false, + }); + let result = extension.validate(&who, &call.clone(), &info, 10); + // Should fail + assert_err!( + // Should get an invalid transaction error + result, + crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into() + )) + ); + + // Transfer keep alive + let call = RuntimeCall::Balances(BalancesCall::transfer_keep_alive { + dest: new_coldkey, + value: 100_000_000_000, + }); + let result = extension.validate(&who, &call.clone(), &info, 10); + // Should fail + assert_err!( + // Should get an invalid transaction error + result, + crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into() + )) + ); + + // Transfer allow death + let call = RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: new_coldkey, + value: 100_000_000_000, + }); + let result = extension.validate(&who, &call.clone(), &info, 10); + // Should fail + assert_err!( + // Should get an invalid transaction error + result, + crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into() + )) + ); + + // Burned register + let call = RuntimeCall::SubtensorModule(SubtensorCall::burned_register { netuid, hotkey }); + let result = extension.validate(&who, &call.clone(), &info, 10); + // Should fail + assert_err!( + // Should get an invalid transaction error + result, + crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into() + )) + ); + + // Remove stake + let call = RuntimeCall::SubtensorModule(SubtensorCall::remove_stake { + hotkey, + netuid, + amount_unstaked: 1_000_000, + }); + let result = extension.validate(&who, &call.clone(), &info, 10); + // Should pass, not in list. + assert_ok!(result); + + // Remove stake limit + let call = RuntimeCall::SubtensorModule(SubtensorCall::remove_stake_limit { + hotkey, + netuid, + amount_unstaked: 1_000_000, + limit_price: 123456789, // should be low enough + allow_partial: true, + }); + let result = extension.validate(&who, &call.clone(), &info, 10); + // Should pass, not in list. + assert_ok!(result); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --package pallet-subtensor --lib -- tests::swap_coldkey::test_coldkey_in_swap_schedule_prevents_critical_calls --exact --show-output --nocapture +#[test] +fn test_coldkey_in_swap_schedule_prevents_critical_calls() { + // Testing the signed extension validate function + // correctly filters transactions that are critical + // while a coldkey swap is scheduled. + + new_test_ext(0).execute_with(|| { + let netuid: u16 = 1; + let version_key: u64 = 0; + let coldkey = U256::from(0); + let new_coldkey = U256::from(1); + let hotkey: U256 = U256::from(2); // Add the hotkey field + assert_ne!(hotkey, coldkey); // Ensure hotkey is NOT the same as coldkey !!! + let fee = DefaultStakingFee::::get(); + + let who = coldkey; // The coldkey signs this transaction + + // Disallowed transactions are + // - dissolve_network + + // Create netuid + add_network(netuid, 1, 0); + // Register the hotkey + SubtensorModule::append_neuron(netuid, &hotkey, 0); + crate::Owner::::insert(hotkey, coldkey); + + SubtensorModule::add_balance_to_coldkey_account(&who, u64::MAX); + + // Set the minimum stake to 0. + SubtensorModule::set_stake_threshold(0); + // Add stake to the hotkey + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(who), + hotkey, + netuid, + 100_000_000_000 + )); + + // Schedule the coldkey for a swap + assert_ok!(SubtensorModule::schedule_swap_coldkey( + <::RuntimeOrigin>::signed(who), + new_coldkey + )); + + assert!(ColdkeySwapScheduled::::contains_key(who)); + + // Setup the extension + let info: crate::DispatchInfo = + crate::DispatchInfoOf::<::RuntimeCall>::default(); + let extension = crate::SubtensorSignedExtension::::new(); + + // Try each call + + // Dissolve network + let call = + RuntimeCall::SubtensorModule(SubtensorCall::dissolve_network { netuid, coldkey }); + let result: Result = + extension.validate(&who, &call.clone(), &info, 10); + // Should fail + assert_err!( + // Should get an invalid transaction error + result, + crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom( + CustomTransactionError::ColdkeyInSwapSchedule.into() + )) + ); + }); +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 26bf16206f..fbe7d54614 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -229,7 +229,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 233, + spec_version: 234, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -726,17 +726,38 @@ impl InstanceFilter for ProxyType { fn filter(&self, c: &RuntimeCall) -> bool { match self { ProxyType::Any => true, - ProxyType::NonTransfer => !matches!(c, RuntimeCall::Balances(..)), + ProxyType::NonTransfer => !matches!( + c, + RuntimeCall::Balances(..) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::transfer_stake { .. }) + | RuntimeCall::SubtensorModule( + pallet_subtensor::Call::schedule_swap_coldkey { .. } + ) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::swap_coldkey { .. }) + ), ProxyType::NonFungibile => !matches!( c, RuntimeCall::Balances(..) | RuntimeCall::SubtensorModule(pallet_subtensor::Call::add_stake { .. }) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::add_stake_limit { .. }) | RuntimeCall::SubtensorModule(pallet_subtensor::Call::remove_stake { .. }) + | RuntimeCall::SubtensorModule( + pallet_subtensor::Call::remove_stake_limit { .. } + ) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::unstake_all { .. }) + | RuntimeCall::SubtensorModule( + pallet_subtensor::Call::unstake_all_alpha { .. } + ) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::swap_stake { .. }) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::swap_stake_limit { .. }) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::move_stake { .. }) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::transfer_stake { .. }) | RuntimeCall::SubtensorModule(pallet_subtensor::Call::burned_register { .. }) | RuntimeCall::SubtensorModule(pallet_subtensor::Call::root_register { .. }) | RuntimeCall::SubtensorModule( pallet_subtensor::Call::schedule_swap_coldkey { .. } ) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::swap_coldkey { .. }) | RuntimeCall::SubtensorModule(pallet_subtensor::Call::swap_hotkey { .. }) ), ProxyType::Transfer => matches!( @@ -744,6 +765,7 @@ impl InstanceFilter for ProxyType { RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { .. }) | RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { .. }) | RuntimeCall::Balances(pallet_balances::Call::transfer_all { .. }) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::transfer_stake { .. }) ), ProxyType::SmallTransfer => match c { RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { @@ -753,6 +775,10 @@ impl InstanceFilter for ProxyType { value, .. }) => *value < SMALL_TRANSFER_LIMIT, + RuntimeCall::SubtensorModule(pallet_subtensor::Call::transfer_stake { + alpha_amount, + .. + }) => *alpha_amount < SMALL_TRANSFER_LIMIT, _ => false, }, ProxyType::Owner => matches!(c, RuntimeCall::AdminUtils(..)), @@ -780,6 +806,17 @@ impl InstanceFilter for ProxyType { c, RuntimeCall::SubtensorModule(pallet_subtensor::Call::add_stake { .. }) | RuntimeCall::SubtensorModule(pallet_subtensor::Call::remove_stake { .. }) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::unstake_all { .. }) + | RuntimeCall::SubtensorModule( + pallet_subtensor::Call::unstake_all_alpha { .. } + ) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::swap_stake { .. }) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::swap_stake_limit { .. }) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::move_stake { .. }) + | RuntimeCall::SubtensorModule(pallet_subtensor::Call::add_stake_limit { .. }) + | RuntimeCall::SubtensorModule( + pallet_subtensor::Call::remove_stake_limit { .. } + ) ), ProxyType::Registration => matches!( c, diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs index 29e05cb003..933f476539 100644 --- a/runtime/src/precompiles/mod.rs +++ b/runtime/src/precompiles/mod.rs @@ -236,3 +236,22 @@ fn try_dispatch_runtime_call( } } } + +/// Retrieves a single u8 value from the given data slice at the specified index. +/// +/// # Args +/// * `data`: The slice of bytes from which to retrieve the u8 value. +/// * `index`: The index within the `data` slice where the u8 value is located. +/// +/// # Returns +/// A `Result` containing the u8 value at the specified index if successful, or a `PrecompileFailure` if the index is out of range. +pub fn get_single_u8(data: &[u8], index: usize) -> Result { + if let Some(result) = data.get(index) { + Ok(*result) + } else { + log::error!("fail to get data from data, {:?}, at {}", &data, index); + Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }) + } +} diff --git a/runtime/src/precompiles/neuron.rs b/runtime/src/precompiles/neuron.rs index 317f99242c..38fb701fbe 100644 --- a/runtime/src/precompiles/neuron.rs +++ b/runtime/src/precompiles/neuron.rs @@ -4,7 +4,7 @@ use pallet_evm::{ }; use crate::precompiles::{ - get_method_id, get_pubkey, get_slice, parse_netuid, try_dispatch_runtime_call, + get_method_id, get_pubkey, get_single_u8, get_slice, parse_netuid, try_dispatch_runtime_call, }; use crate::{Runtime, RuntimeCall}; use frame_system::RawOrigin; @@ -60,6 +60,23 @@ impl NeuronPrecompile { id if id == get_method_id("burnedRegister(uint16,bytes32)") => { Self::burned_register(handle, &method_input) } + id if id + == get_method_id( + "serveAxon(uint16,uint32,uint128,uint16,uint8,uint8,uint8,uint8)", + ) => + { + Self::serve_axon(handle, &method_input) + } + id if id + == get_method_id( + "serveAxonTls(uint16,uint32,uint128,uint16,uint8,uint8,uint8,uint8,bytes)", + ) => + { + Self::serve_axon_tls(handle, &method_input) + } + id if id == get_method_id("servePrometheus(uint16,uint32,uint128,uint16,uint8)") => { + Self::serve_prometheus(handle, &method_input) + } _ => Err(PrecompileFailure::Error { exit_status: ExitError::InvalidRange, @@ -123,11 +140,74 @@ impl NeuronPrecompile { netuid, hotkey, }); + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + pub fn serve_axon(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, version, ip, port, ip_type, protocol, placeholder1, placeholder2) = + Self::parse_serve_axon_parameters(data)?; + let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::::serve_axon { + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2, + }); let account_id = as AddressMapping>::into_account_id( handle.context().caller, ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + pub fn serve_axon_tls(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, version, ip, port, ip_type, protocol, placeholder1, placeholder2, certificate) = + Self::parse_serve_axon_tls_parameters(data)?; + let call = + RuntimeCall::SubtensorModule(pallet_subtensor::Call::::serve_axon_tls { + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2, + certificate, + }); + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + pub fn serve_prometheus(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, version, ip, port, ip_type) = Self::parse_serve_prometheus_parameters(data)?; + let call = + RuntimeCall::SubtensorModule(pallet_subtensor::Call::::serve_prometheus { + netuid, + version, + ip, + port, + ip_type, + }); + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + // Dispatch the register_network call try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) } @@ -412,4 +492,138 @@ impl NeuronPrecompile { Ok((netuid, uids, values, salt, version_key)) } + + fn parse_serve_axon_parameters( + data: &[u8], + ) -> Result<(u16, u32, u128, u16, u8, u8, u8, u8), PrecompileFailure> { + if data.len() < 256 { + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + + let netuid = parse_netuid(data, 30)?; + + let mut version_vec = [0u8; 4]; + version_vec.copy_from_slice(get_slice(data, 60, 64)?); + let version = u32::from_be_bytes(version_vec); + + let mut ip_vec = [0u8; 16]; + ip_vec.copy_from_slice(get_slice(data, 80, 96)?); + let ip = u128::from_be_bytes(ip_vec); + + let mut port_vec = [0u8; 2]; + port_vec.copy_from_slice(get_slice(data, 126, 128)?); + let port = u16::from_be_bytes(port_vec); + + let ip_type = get_single_u8(data, 159)?; + let protocol = get_single_u8(data, 191)?; + let placeholder1 = get_single_u8(data, 223)?; + let placeholder2 = get_single_u8(data, 255)?; + Ok(( + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2, + )) + } + + fn parse_serve_axon_tls_parameters( + data: &[u8], + ) -> Result<(u16, u32, u128, u16, u8, u8, u8, u8, vec::Vec), PrecompileFailure> { + let data_len = data.len(); + if data_len < 288 { + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + + let netuid = parse_netuid(data, 30)?; + + let mut version_vec = [0u8; 4]; + version_vec.copy_from_slice(get_slice(data, 60, 64)?); + let version = u32::from_be_bytes(version_vec); + + let mut ip_vec = [0u8; 16]; + ip_vec.copy_from_slice(get_slice(data, 80, 96)?); + let ip = u128::from_be_bytes(ip_vec); + + let mut port_vec = [0u8; 2]; + port_vec.copy_from_slice(get_slice(data, 126, 128)?); + let port = u16::from_be_bytes(port_vec); + + let ip_type = get_single_u8(data, 159)?; + let protocol = get_single_u8(data, 191)?; + let placeholder1 = get_single_u8(data, 223)?; + let placeholder2 = get_single_u8(data, 255)?; + + let mut len_position_vec = [0u8; 2]; + len_position_vec.copy_from_slice(get_slice(data, 286, 288)?); + let len_position = u16::from_be_bytes(len_position_vec) as usize; + + if len_position > data_len { + log::error!( + "the start position of certificate as {} is bigger than whole data len {}", + len_position, + data_len + ); + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + + let mut len_vec = [0u8; 2]; + len_vec.copy_from_slice(get_slice(data, len_position + 30, len_position + 32)?); + let vec_len = u16::from_be_bytes(len_vec) as usize; + + let vec_result = get_slice( + data, + len_position + 32, + len_position.saturating_add(32).saturating_add(vec_len), + )? + .to_vec(); + + Ok(( + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2, + vec_result, + )) + } + + fn parse_serve_prometheus_parameters( + data: &[u8], + ) -> Result<(u16, u32, u128, u16, u8), PrecompileFailure> { + if data.len() < 160 { + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + + let netuid = parse_netuid(data, 30)?; + + let mut version_vec = [0u8; 4]; + version_vec.copy_from_slice(get_slice(data, 60, 64)?); + let version = u32::from_be_bytes(version_vec); + + let mut ip_vec = [0u8; 16]; + ip_vec.copy_from_slice(get_slice(data, 80, 96)?); + let ip = u128::from_be_bytes(ip_vec); + + let mut port_vec = [0u8; 2]; + port_vec.copy_from_slice(get_slice(data, 126, 128)?); + let port = u16::from_be_bytes(port_vec); + + let ip_type = get_single_u8(data, 159)?; + Ok((netuid, version, ip, port, ip_type)) + } } diff --git a/runtime/src/precompiles/solidity/neuron.abi b/runtime/src/precompiles/solidity/neuron.abi index 804c9e8f16..e12685f99f 100644 --- a/runtime/src/precompiles/solidity/neuron.abi +++ b/runtime/src/precompiles/solidity/neuron.abi @@ -1,4 +1,3 @@ - [ { "inputs": [ @@ -69,6 +68,140 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "version", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ip", + "type": "uint128" + }, + { + "internalType": "uint16", + "name": "port", + "type": "uint16" + }, + { + "internalType": "uint8", + "name": "ipType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "protocol", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "placeholder1", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "placeholder2", + "type": "uint8" + } + ], + "name": "serveAxon", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "version", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ip", + "type": "uint128" + }, + { + "internalType": "uint16", + "name": "port", + "type": "uint16" + }, + { + "internalType": "uint8", + "name": "ipType", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "protocol", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "placeholder1", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "placeholder2", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "certificate", + "type": "bytes" + } + ], + "name": "serveAxonTls", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "version", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "ip", + "type": "uint128" + }, + { + "internalType": "uint16", + "name": "port", + "type": "uint16" + }, + { + "internalType": "uint8", + "name": "ipType", + "type": "uint8" + } + ], + "name": "servePrometheus", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { diff --git a/runtime/src/precompiles/solidity/neuron.sol b/runtime/src/precompiles/solidity/neuron.sol index ae002c47ab..772f290638 100644 --- a/runtime/src/precompiles/solidity/neuron.sol +++ b/runtime/src/precompiles/solidity/neuron.sol @@ -12,6 +12,74 @@ interface INeuron { */ function burnedRegister(uint16 netuid, bytes32 hotkey) external payable; + /** + * @dev Registers axon information for a neuron. + * This function is used to serve axon information, including the subnet to register to, version, IP address, port, IP type, protocol, and placeholders for future use. + * + * @param netuid The subnet to register the axon to (uint16). + * @param version The version of the axon (uint32). + * @param ip The IP address of the axon (uint128). + * @param port The port number of the axon (uint16). + * @param ipType The type of IP address (uint8). + * @param protocol The protocol used by the axon (uint8). + * @param placeholder1 Placeholder for future use (uint8). + * @param placeholder2 Placeholder for future use (uint8). + */ + function serveAxon( + uint16 netuid, + uint32 version, + uint128 ip, + uint16 port, + uint8 ipType, + uint8 protocol, + uint8 placeholder1, + uint8 placeholder2 + ) external payable; + + /** + * @dev Serves axon information for a neuron over TLS. + * This function is used to serve axon information, including the subnet to register to, version, IP address, port, IP type, protocol, and placeholders for future use. + * + * @param netuid The subnet to register the axon to (uint16). + * @param version The version of the axon (uint32). + * @param ip The IP address of the axon (uint128). + * @param port The port number of the axon (uint16). + * @param ipType The type of IP address (uint8). + * @param protocol The protocol used by the axon (uint8). + * @param placeholder1 Placeholder for future use (uint8). + * @param placeholder2 Placeholder for future use (uint8). + * @param certificate The TLS certificate for the axon (bytes). + */ + function serveAxonTls( + uint16 netuid, + uint32 version, + uint128 ip, + uint16 port, + uint8 ipType, + uint8 protocol, + uint8 placeholder1, + uint8 placeholder2, + bytes memory certificate + ) external payable; + + /** + * @dev Serves Prometheus information for a neuron. + * This function is used to serve Prometheus information, including the subnet to register to, version, IP address, port, and IP type. + * + * @param netuid The subnet to register the Prometheus information to (uint16). + * @param version The version of the Prometheus information (uint32). + * @param ip The IP address of the Prometheus information (uint128). + * @param port The port number of the Prometheus information (uint16). + * @param ipType The type of IP address (uint8). + */ + function servePrometheus( + uint16 netuid, + uint32 version, + uint128 ip, + uint16 port, + uint8 ipType + ) external payable; + /** * @dev Sets the weights for a neuron. * diff --git a/runtime/src/precompiles/solidity/subnet.abi b/runtime/src/precompiles/solidity/subnet.abi index a118792414..fd81850b74 100644 --- a/runtime/src/precompiles/solidity/subnet.abi +++ b/runtime/src/precompiles/solidity/subnet.abi @@ -1,43 +1,887 @@ [ - { - "inputs": [ - { - "internalType": "bytes32", - "name": "hotkey", - "type": "bytes32" - } - ], - "name": "registerNetwork", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "hotkey", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "subnetName", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "githubRepo", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "subnetContact", - "type": "bytes" - } - ], - "name": "registerNetwork", - "outputs": [], - "stateMutability": "payable", - "type": "function" - } + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getActivityCutoff", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getAdjustmentAlpha", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getAlphaValues", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getBondsMovingAverage", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getCommitRevealWeightsEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getCommitRevealWeightsInterval", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getDifficulty", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "name": "getImmunityPeriod", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "name": "getKappa", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getLiquidAlphaEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getMaxBurn", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getMaxDifficulty", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getMaxWeightLimit", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getMinAllowedWeights", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getMinBurn", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getMinDifficulty", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getNetworkPowRegistrationAllowed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getNetworkRegistrationAllowed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "name": "getRho", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getServingRateLimit", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getWeightsSetRateLimit", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + } + ], + "name": "getWeightsVersionKey", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hotkey", + "type": "bytes32" + } + ], + "name": "registerNetwork", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hotkey", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "subnetName", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "githubRepo", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "subnetContact", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "subnetUrl", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "discord", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "description", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "additional", + "type": "bytes" + } + ], + "name": "registerNetwork", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "activityCutoff", + "type": "uint16" + } + ], + "name": "setActivityCutoff", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "adjustmentAlpha", + "type": "uint64" + } + ], + "name": "setAdjustmentAlpha", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "alphaLow", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "alphaHigh", + "type": "uint16" + } + ], + "name": "setAlphaValues", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "bondsMovingAverage", + "type": "uint64" + } + ], + "name": "setBondsMovingAverage", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "commitRevealWeightsEnabled", + "type": "bool" + } + ], + "name": "setCommitRevealWeightsEnabled", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "commitRevealWeightsInterval", + "type": "uint64" + } + ], + "name": "setCommitRevealWeightsInterval", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "difficulty", + "type": "uint64" + } + ], + "name": "setDifficulty", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "immunityPeriod", + "type": "uint64" + } + ], + "name": "setImmunityPeriod", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "kappa", + "type": "uint16" + } + ], + "name": "setKappa", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "liquidAlphaEnabled", + "type": "bool" + } + ], + "name": "setLiquidAlphaEnabled", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "maxBurn", + "type": "uint64" + } + ], + "name": "setMaxBurn", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "maxDifficulty", + "type": "uint64" + } + ], + "name": "setMaxDifficulty", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "maxWeightLimit", + "type": "uint64" + } + ], + "name": "setMaxWeightLimit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "minAllowedWeights", + "type": "uint16" + } + ], + "name": "setMinAllowedWeights", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "minBurn", + "type": "uint64" + } + ], + "name": "setMinBurn", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "minDifficulty", + "type": "uint64" + } + ], + "name": "setMinDifficulty", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "networkPowRegistrationAllowed", + "type": "bool" + } + ], + "name": "setNetworkPowRegistrationAllowed", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "networkRegistrationAllowed", + "type": "bool" + } + ], + "name": "setNetworkRegistrationAllowed", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "rho", + "type": "uint16" + } + ], + "name": "setRho", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "servingRateLimit", + "type": "uint64" + } + ], + "name": "setServingRateLimit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "weightsSetRateLimit", + "type": "uint64" + } + ], + "name": "setWeightsSetRateLimit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "netuid", + "type": "uint16" + }, + { + "internalType": "uint64", + "name": "weightsVersionKey", + "type": "uint64" + } + ], + "name": "setWeightsVersionKey", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } ] \ No newline at end of file diff --git a/runtime/src/precompiles/solidity/subnet.sol b/runtime/src/precompiles/solidity/subnet.sol index c6639891ae..1afeced493 100644 --- a/runtime/src/precompiles/solidity/subnet.sol +++ b/runtime/src/precompiles/solidity/subnet.sol @@ -10,6 +10,164 @@ interface ISubnet { bytes32 hotkey, bytes memory subnetName, bytes memory githubRepo, - bytes memory subnetContact + bytes memory subnetContact, + bytes memory subnetUrl, + bytes memory discord, + bytes memory description, + bytes memory additional + ) external payable; + + function getServingRateLimit(uint16 netuid) external view returns (uint64); + + function setServingRateLimit( + uint16 netuid, + uint64 servingRateLimit + ) external payable; + + function getMinDifficulty(uint16 netuid) external view returns (uint64); + + function setMinDifficulty( + uint16 netuid, + uint64 minDifficulty + ) external payable; + + function getMaxDifficulty(uint16 netuid) external view returns (uint64); + + function setMaxDifficulty( + uint16 netuid, + uint64 maxDifficulty + ) external payable; + + function getWeightsVersionKey(uint16 netuid) external view returns (uint64); + + function setWeightsVersionKey( + uint16 netuid, + uint64 weightsVersionKey + ) external payable; + + function getWeightsSetRateLimit( + uint16 netuid + ) external view returns (uint64); + + function setWeightsSetRateLimit( + uint16 netuid, + uint64 weightsSetRateLimit + ) external payable; + + function getAdjustmentAlpha(uint16 netuid) external view returns (uint64); + + function setAdjustmentAlpha( + uint16 netuid, + uint64 adjustmentAlpha + ) external payable; + + function getMaxWeightLimit(uint16 netuid) external view returns (uint64); + + function setMaxWeightLimit( + uint16 netuid, + uint64 maxWeightLimit + ) external payable; + + function getImmunityPeriod(uint16) external view returns (uint64); + + function setImmunityPeriod( + uint16 netuid, + uint64 immunityPeriod + ) external payable; + + function getMinAllowedWeights(uint16 netuid) external view returns (uint16); + + function setMinAllowedWeights( + uint16 netuid, + uint16 minAllowedWeights + ) external payable; + + function getKappa(uint16) external view returns (uint16); + + function setKappa(uint16 netuid, uint16 kappa) external payable; + + function getRho(uint16) external view returns (uint16); + + function setRho(uint16 netuid, uint16 rho) external payable; + + function getActivityCutoff(uint16 netuid) external view returns (uint16); + + function setActivityCutoff( + uint16 netuid, + uint16 activityCutoff + ) external payable; + + function getNetworkRegistrationAllowed( + uint16 netuid + ) external view returns (bool); + + function setNetworkRegistrationAllowed( + uint16 netuid, + bool networkRegistrationAllowed + ) external payable; + + function getNetworkPowRegistrationAllowed( + uint16 netuid + ) external view returns (bool); + + function setNetworkPowRegistrationAllowed( + uint16 netuid, + bool networkPowRegistrationAllowed + ) external payable; + + function getMinBurn(uint16 netuid) external view returns (uint64); + + function setMinBurn(uint16 netuid, uint64 minBurn) external payable; + + function getMaxBurn(uint16 netuid) external view returns (uint64); + + function setMaxBurn(uint16 netuid, uint64 maxBurn) external payable; + + function getDifficulty(uint16 netuid) external view returns (uint64); + + function setDifficulty(uint16 netuid, uint64 difficulty) external payable; + + function getBondsMovingAverage( + uint16 netuid + ) external view returns (uint64); + + function setBondsMovingAverage( + uint16 netuid, + uint64 bondsMovingAverage + ) external payable; + + function getCommitRevealWeightsEnabled( + uint16 netuid + ) external view returns (bool); + + function setCommitRevealWeightsEnabled( + uint16 netuid, + bool commitRevealWeightsEnabled + ) external payable; + + function getLiquidAlphaEnabled(uint16 netuid) external view returns (bool); + + function setLiquidAlphaEnabled( + uint16 netuid, + bool liquidAlphaEnabled + ) external payable; + + function getAlphaValues( + uint16 netuid + ) external view returns (uint16, uint16); + + function setAlphaValues( + uint16 netuid, + uint16 alphaLow, + uint16 alphaHigh + ) external payable; + + function getCommitRevealWeightsInterval( + uint16 netuid + ) external view returns (uint64); + + function setCommitRevealWeightsInterval( + uint16 netuid, + uint64 commitRevealWeightsInterval ) external payable; } diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs index d62a0efd04..ee85a3f864 100644 --- a/runtime/src/precompiles/subnet.rs +++ b/runtime/src/precompiles/subnet.rs @@ -1,21 +1,23 @@ -use crate::precompiles::{get_method_id, get_pubkey, get_slice, try_dispatch_runtime_call}; +use crate::precompiles::{ + get_method_id, get_pubkey, get_slice, parse_netuid, try_dispatch_runtime_call, +}; use crate::{Runtime, RuntimeCall}; use frame_system::RawOrigin; use pallet_evm::{ - AddressMapping, ExitError, HashedAddressMapping, PrecompileFailure, PrecompileHandle, - PrecompileResult, + AddressMapping, ExitError, ExitSucceed, HashedAddressMapping, PrecompileFailure, + PrecompileHandle, PrecompileOutput, PrecompileResult, }; -use sp_runtime::AccountId32; -use sp_runtime::{traits::BlakeTwo256, Vec}; + +use sp_core::U256; +use sp_runtime::{traits::BlakeTwo256, AccountId32, Vec}; use sp_std::vec; + pub const SUBNET_PRECOMPILE_INDEX: u64 = 2051; // bytes with max lenght 1K pub const MAX_SINGLE_PARAMETER_SIZE: usize = 1024; -// three bytes with max lenght 1K -pub const MAX_PARAMETER_SIZE: usize = 3 * MAX_SINGLE_PARAMETER_SIZE; - +// seven bytes with max lenght 1K +pub const MAX_PARAMETER_SIZE: usize = 7 * MAX_SINGLE_PARAMETER_SIZE; // ss58 public key i.e., the contract sends funds it received to the destination address from the -// method parameter. #[allow(dead_code)] const CONTRACT_ADDRESS_SS58: [u8; 32] = [ 0x3a, 0x86, 0x18, 0xfb, 0xbb, 0x1b, 0xbc, 0x47, 0x86, 0x64, 0xff, 0x53, 0x46, 0x18, 0x0c, 0x35, @@ -38,12 +40,162 @@ impl SubnetPrecompile { .map_or_else(vec::Vec::new, |slice| slice.to_vec()); // Avoiding borrowing conflicts match method_id { - id if id == get_method_id("registerNetwork(bytes32,bytes,bytes,bytes)") => { + id if id + == get_method_id( + "registerNetwork(bytes32,bytes,bytes,bytes,bytes,bytes,bytes,bytes)", + ) => + { Self::register_network(handle, &method_input) } id if id == get_method_id("registerNetwork(bytes32)") => { Self::register_network(handle, &method_input) } + + id if id == get_method_id("getServingRateLimit(uint16)") => { + Self::get_serving_rate_limit(&method_input) + } + id if id == get_method_id("setServingRateLimit(uint16,uint64)") => { + Self::set_serving_rate_limit(handle, &method_input) + } + + id if id == get_method_id("getMinDifficulty(uint16)") => { + Self::get_min_difficulty(&method_input) + } + id if id == get_method_id("setMinDifficulty(uint16,uint64)") => { + Self::set_min_difficulty(handle, &method_input) + } + + id if id == get_method_id("getMaxDifficulty(uint16)") => { + Self::get_max_difficulty(&method_input) + } + id if id == get_method_id("setMaxDifficulty(uint16,uint64)") => { + Self::set_max_difficulty(handle, &method_input) + } + + id if id == get_method_id("getWeightsVersionKey(uint16)") => { + Self::get_weights_version_key(&method_input) + } + id if id == get_method_id("setWeightsVersionKey(uint16,uint64)") => { + Self::set_weights_version_key(handle, &method_input) + } + + id if id == get_method_id("getWeightsSetRateLimit(uint16)") => { + Self::get_weights_set_rate_limit(&method_input) + } + id if id == get_method_id("setWeightsSetRateLimit(uint16,uint64)") => { + Self::set_weights_set_rate_limit(handle, &method_input) + } + + id if id == get_method_id("getAdjustmentAlpha(uint16)") => { + Self::get_adjustment_alpha(&method_input) + } + id if id == get_method_id("setAdjustmentAlpha(uint16,uint64)") => { + Self::set_adjustment_alpha(handle, &method_input) + } + + id if id == get_method_id("getMaxWeightLimit(uint16)") => { + Self::get_max_weight_limit(&method_input) + } + id if id == get_method_id("setMaxWeightLimit(uint16,uint64)") => { + Self::set_max_weight_limit(handle, &method_input) + } + + id if id == get_method_id("getImmunityPeriod(uint16)") => { + Self::get_immunity_period(&method_input) + } + id if id == get_method_id("setImmunityPeriod(uint16,uint64)") => { + Self::set_immunity_period(handle, &method_input) + } + + id if id == get_method_id("getMinAllowedWeights(uint16)") => { + Self::get_min_allowed_weights(&method_input) + } + id if id == get_method_id("setMinAllowedWeights(uint16,uint16)") => { + Self::set_min_allowed_weights(handle, &method_input) + } + + id if id == get_method_id("getKappa(uint16)") => Self::get_kappa(&method_input), + id if id == get_method_id("setKappa(uint16,uint16)") => { + Self::set_kappa(handle, &method_input) + } + + id if id == get_method_id("getRho(uint16)") => Self::get_rho(&method_input), + id if id == get_method_id("setRho(uint16,uint16)") => { + Self::set_rho(handle, &method_input) + } + + id if id == get_method_id("getActivityCutoff(uint16)") => { + Self::get_activity_cutoff(&method_input) + } + id if id == get_method_id("setActivityCutoff(uint16,uint16)") => { + Self::set_activity_cutoff(handle, &method_input) + } + + id if id == get_method_id("getNetworkRegistrationAllowed(uint16)") => { + Self::get_network_registration_allowed(&method_input) + } + id if id == get_method_id("setNetworkRegistrationAllowed(uint16,bool)") => { + Self::set_network_registration_allowed(handle, &method_input) + } + + id if id == get_method_id("getNetworkPowRegistrationAllowed(uint16)") => { + Self::get_network_pow_registration_allowed(&method_input) + } + id if id == get_method_id("setNetworkPowRegistrationAllowed(uint16,bool)") => { + Self::set_network_pow_registration_allowed(handle, &method_input) + } + + id if id == get_method_id("getMinBurn(uint16)") => Self::get_min_burn(&method_input), + id if id == get_method_id("setMinBurn(uint16,uint64)") => { + Self::set_min_burn(handle, &method_input) + } + + id if id == get_method_id("getMaxBurn(uint16)") => Self::get_max_burn(&method_input), + id if id == get_method_id("setMaxBurn(uint16,uint64)") => { + Self::set_max_burn(handle, &method_input) + } + + id if id == get_method_id("getDifficulty(uint16)") => { + Self::get_difficulty(&method_input) + } + id if id == get_method_id("setDifficulty(uint16,uint64)") => { + Self::set_difficulty(handle, &method_input) + } + + id if id == get_method_id("getBondsMovingAverage(uint16)") => { + Self::get_bonds_moving_average(&method_input) + } + id if id == get_method_id("setBondsMovingAverage(uint16,uint64)") => { + Self::set_bonds_moving_average(handle, &method_input) + } + + id if id == get_method_id("getCommitRevealWeightsEnabled(uint16)") => { + Self::get_commit_reveal_weights_enabled(&method_input) + } + id if id == get_method_id("setCommitRevealWeightsEnabled(uint16,bool)") => { + Self::set_commit_reveal_weights_enabled(handle, &method_input) + } + + id if id == get_method_id("getLiquidAlphaEnabled(uint16)") => { + Self::get_liquid_alpha_enabled(&method_input) + } + id if id == get_method_id("setLiquidAlphaEnabled(uint16,bool)") => { + Self::set_liquid_alpha_enabled(handle, &method_input) + } + + id if id == get_method_id("getAlphaValues(uint16)") => { + Self::get_alpha_values(&method_input) + } + id if id == get_method_id("setAlphaValues(uint16,uint16,uint16)") => { + Self::set_alpha_values(handle, &method_input) + } + + id if id == get_method_id("getCommitRevealWeightsInterval(uint16)") => { + Self::get_commit_reveal_weights_interval(&method_input) + } + id if id == get_method_id("setCommitRevealWeightsInterval(uint16,uint64)") => { + Self::set_commit_reveal_weights_interval(handle, &method_input) + } _ => Err(PrecompileFailure::Error { exit_status: ExitError::InvalidRange, }), @@ -104,7 +256,731 @@ impl SubnetPrecompile { handle.context().caller, ); - // Dispatch the register_network call + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_serving_rate_limit(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::ServingRateLimit::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_serving_rate_limit(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, serving_rate_limit) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_serving_rate_limit { + netuid, + serving_rate_limit, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_min_difficulty(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::MinDifficulty::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_min_difficulty(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, min_difficulty) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_min_difficulty { + netuid, + min_difficulty, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_max_difficulty(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::MaxDifficulty::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_max_difficulty(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, max_difficulty) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_max_difficulty { + netuid, + max_difficulty, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_weights_version_key(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::WeightsVersionKey::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_weights_version_key( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, weights_version_key) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_weights_version_key { + netuid, + weights_version_key, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_weights_set_rate_limit(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::WeightsSetRateLimit::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_weights_set_rate_limit( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, weights_set_rate_limit) = Self::parse_netuid_u64_parameter(data)?; + + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_weights_set_rate_limit { + netuid, + weights_set_rate_limit, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_adjustment_alpha(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::AdjustmentAlpha::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_adjustment_alpha(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, adjustment_alpha) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_adjustment_alpha { + netuid, + adjustment_alpha, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_max_weight_limit(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::MaxWeightsLimit::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_max_weight_limit(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, max_weight_limit) = Self::parse_netuid_u16_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_max_weight_limit { + netuid, + max_weight_limit, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_immunity_period(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::ImmunityPeriod::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_immunity_period(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, immunity_period) = Self::parse_netuid_u16_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_immunity_period { + netuid, + immunity_period, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_min_allowed_weights(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::MinAllowedWeights::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_min_allowed_weights( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, min_allowed_weights) = Self::parse_netuid_u16_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_min_allowed_weights { + netuid, + min_allowed_weights, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_kappa(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::Kappa::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_kappa(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, kappa) = Self::parse_netuid_u16_parameter(data)?; + let call = RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_kappa { + netuid, + kappa, + }); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_rho(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::Rho::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_rho(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, rho) = Self::parse_netuid_u16_parameter(data)?; + let call = RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_rho { + netuid, + rho, + }); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_activity_cutoff(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::ActivityCutoff::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_activity_cutoff(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, activity_cutoff) = Self::parse_netuid_u16_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_activity_cutoff { + netuid, + activity_cutoff, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_network_registration_allowed(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::NetworkRegistrationAllowed::::get(netuid); + + let value_u256 = if value { U256::from(1) } else { U256::from(0) }; + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_network_registration_allowed( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, registration_allowed) = Self::parse_netuid_bool_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_network_registration_allowed { + netuid, + registration_allowed, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_network_pow_registration_allowed(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::NetworkPowRegistrationAllowed::::get(netuid); + + let value_u256 = if value { U256::from(1) } else { U256::from(0) }; + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_network_pow_registration_allowed( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, registration_allowed) = Self::parse_netuid_bool_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_network_pow_registration_allowed { + netuid, + registration_allowed, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_min_burn(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::MinBurn::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_min_burn(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, min_burn) = Self::parse_netuid_u64_parameter(data)?; + let call = + RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_min_burn { + netuid, + min_burn, + }); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_max_burn(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::MaxBurn::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_max_burn(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, max_burn) = Self::parse_netuid_u64_parameter(data)?; + let call = + RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_max_burn { + netuid, + max_burn, + }); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_difficulty(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::Difficulty::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_difficulty(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, difficulty) = Self::parse_netuid_u64_parameter(data)?; + let call = + RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_difficulty { + netuid, + difficulty, + }); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_bonds_moving_average(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::BondsMovingAverage::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_bonds_moving_average( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, bonds_moving_average) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_bonds_moving_average { + netuid, + bonds_moving_average, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_commit_reveal_weights_enabled(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::CommitRevealWeightsEnabled::::get(netuid); + + let value_u256 = if value { U256::from(1) } else { U256::from(0) }; + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_commit_reveal_weights_enabled( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, enabled) = Self::parse_netuid_bool_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_commit_reveal_weights_enabled { + netuid, + enabled, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_liquid_alpha_enabled(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::LiquidAlphaOn::::get(netuid); + + let value_u256 = if value { U256::from(1) } else { U256::from(0) }; + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_liquid_alpha_enabled( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, enabled) = Self::parse_netuid_bool_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_liquid_alpha_enabled { netuid, enabled }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_alpha_values(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let (alpha_low, alpha_high) = pallet_subtensor::AlphaValues::::get(netuid); + + let mut value_u256 = U256::from(alpha_low); + let mut result = [0_u8; 64]; + U256::to_big_endian(&value_u256, &mut result[0..]); + + value_u256 = U256::from(alpha_high); + U256::to_big_endian(&value_u256, &mut result[32..]); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_alpha_values(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + let (netuid, alpha_low, alpha_high) = Self::parse_netuid_u16_u16_parameter(data)?; + let call = + RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_alpha_values { + netuid, + alpha_low, + alpha_high, + }); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + } + + fn get_commit_reveal_weights_interval(data: &[u8]) -> PrecompileResult { + let netuid = parse_netuid(data, 30)?; + + let value = pallet_subtensor::RevealPeriodEpochs::::get(netuid); + + let value_u256 = U256::from(value); + let mut result = [0_u8; 32]; + U256::to_big_endian(&value_u256, &mut result); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result.into(), + }) + } + + fn set_commit_reveal_weights_interval( + handle: &mut impl PrecompileHandle, + data: &[u8], + ) -> PrecompileResult { + let (netuid, interval) = Self::parse_netuid_u64_parameter(data)?; + let call = RuntimeCall::AdminUtils( + pallet_admin_utils::Call::::sudo_set_commit_reveal_weights_interval { + netuid, + interval, + }, + ); + + let account_id = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) } @@ -375,4 +1251,69 @@ impl SubnetPrecompile { additional_vec, )) } + + fn parse_netuid_u64_parameter(data: &[u8]) -> Result<(u16, u64), PrecompileFailure> { + if data.len() < 64 { + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + let netuid = parse_netuid(data, 30)?; + + let mut parameter_vec = [0u8; 8]; + parameter_vec.copy_from_slice(get_slice(data, 56, 64)?); + let parameter = u64::from_be_bytes(parameter_vec); + + Ok((netuid, parameter)) + } + + fn parse_netuid_u16_parameter(data: &[u8]) -> Result<(u16, u16), PrecompileFailure> { + if data.len() < 64 { + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + let netuid = parse_netuid(data, 30)?; + + let mut parameter_vec = [0u8; 2]; + parameter_vec.copy_from_slice(get_slice(data, 62, 64)?); + let parameter = u16::from_be_bytes(parameter_vec); + + Ok((netuid, parameter)) + } + + fn parse_netuid_u16_u16_parameter(data: &[u8]) -> Result<(u16, u16, u16), PrecompileFailure> { + if data.len() < 96 { + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + let netuid = parse_netuid(data, 30)?; + + let mut parameter_1_vec = [0u8; 2]; + parameter_1_vec.copy_from_slice(get_slice(data, 62, 64)?); + let parameter_1 = u16::from_be_bytes(parameter_1_vec); + + let mut parameter_2_vec = [0u8; 2]; + parameter_2_vec.copy_from_slice(get_slice(data, 94, 96)?); + let parameter_2 = u16::from_be_bytes(parameter_2_vec); + + Ok((netuid, parameter_1, parameter_2)) + } + + fn parse_netuid_bool_parameter(data: &[u8]) -> Result<(u16, bool), PrecompileFailure> { + if data.len() < 64 { + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + let netuid = parse_netuid(data, 30)?; + + let mut parameter_vec = [0_u8]; + parameter_vec.copy_from_slice(get_slice(data, 63, 64)?); + + let parameter = parameter_vec[0] != 0; + + Ok((netuid, parameter)) + } }