From 58ed35d0b76fdea26e51089306d22429366272fa Mon Sep 17 00:00:00 2001 From: Aliaksandr Tsurko Date: Tue, 4 Feb 2025 17:17:59 +0100 Subject: [PATCH 01/47] Rewrite balance transfer precompile with precompile utils --- Cargo.lock | 45 +++++++++++++++++++++ runtime/Cargo.toml | 2 + runtime/src/precompiles/balance_transfer.rs | 41 +++++++++---------- runtime/src/precompiles/mod.rs | 8 ++-- 4 files changed, 68 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 42522da32..ed9e74c9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1068,6 +1068,12 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "case" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6c0e7b807d60291f42f33f58480c0bfafe28ed08286446f45e463728cf9c1c" + [[package]] name = "cc" version = "1.2.10" @@ -5866,6 +5872,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pallet-utility", "parity-scale-codec", + "precompile-utils", "rand_chacha", "scale-info", "serde_json", @@ -7253,6 +7260,44 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "precompile-utils" +version = "0.1.0" +source = "git+https://github.com/opentensor/frontier?rev=635bdac882#635bdac882333afed827053f31ef56ab739f7a2e" +dependencies = [ + "environmental", + "evm", + "fp-evm", + "frame-support", + "frame-system", + "hex", + "impl-trait-for-tuples", + "log", + "num_enum", + "pallet-evm", + "parity-scale-codec", + "precompile-utils-macro", + "sp-core", + "sp-io", + "sp-runtime", + "sp-weights", + "staging-xcm", +] + +[[package]] +name = "precompile-utils-macro" +version = "0.1.0" +source = "git+https://github.com/opentensor/frontier?rev=635bdac882#635bdac882333afed827053f31ef56ab739f7a2e" +dependencies = [ + "case", + "num_enum", + "prettyplease 0.2.29", + "proc-macro2", + "quote", + "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409)", + "syn 1.0.109", +] + [[package]] name = "predicates" version = "2.1.5" diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 171ef3c47..f329fa121 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -100,6 +100,7 @@ pallet-commitments = { default-features = false, path = "../pallets/commitments" fp-evm = { workspace = true } fp-rpc = { workspace = true } fp-self-contained = { workspace = true } +precompile-utils = { workspace = true } # Frontier FRAME pallet-base-fee = { workspace = true } @@ -164,6 +165,7 @@ std = [ "pallet-scheduler/std", "pallet-preimage/std", "pallet-commitments/std", + "precompile-utils/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", diff --git a/runtime/src/precompiles/balance_transfer.rs b/runtime/src/precompiles/balance_transfer.rs index 6154cf8a5..f0185a75e 100644 --- a/runtime/src/precompiles/balance_transfer.rs +++ b/runtime/src/precompiles/balance_transfer.rs @@ -1,8 +1,14 @@ +use core::marker::PhantomData; + use pallet_evm::{ - BalanceConverter, ExitError, ExitSucceed, PrecompileHandle, PrecompileOutput, PrecompileResult, + BalanceConverter, ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle, + PrecompileOutput, PrecompileResult, }; +use precompile_utils::EvmResult; +use sp_core::H256; use sp_runtime::traits::UniqueSaturatedInto; -use sp_std::vec; +use sp_runtime::AccountId32; +use sp_std::vec::Vec; use crate::precompiles::{ contract_to_origin, get_method_id, get_pubkey, get_slice, try_dispatch_runtime_call, @@ -19,20 +25,11 @@ const CONTRACT_ADDRESS_SS58: [u8; 32] = [ pub struct BalanceTransferPrecompile; +#[precompile_utils::precompile] impl BalanceTransferPrecompile { - pub fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { - let txdata = handle.input(); - - // Match method ID: keccak256("transfer(bytes32)") - let method = get_slice(txdata, 0, 4)?; - if get_method_id("transfer(bytes32)") != method { - return Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: vec![], - }); - } - - // Forward all received value to the destination address + #[precompile::public("transfer(bytes32)")] + #[precompile::payable] + fn transfer(handle: &mut impl PrecompileHandle, address: H256) -> EvmResult<()> { let amount = handle.context().apparent_value; // Use BalanceConverter to convert EVM amount to Substrate balance @@ -41,20 +38,18 @@ impl BalanceTransferPrecompile { .ok_or(ExitError::OutOfFund)?; if amount_sub.is_zero() { - return Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: vec![], - }); + return Ok(()); } - let address_bytes_dst = get_slice(txdata, 4, 36)?; - let (account_id_dst, _) = get_pubkey(address_bytes_dst)?; + let dest = get_pubkey(address.as_bytes())?.0.into(); let call = pallet_balances::Call::::transfer_allow_death { - dest: account_id_dst.into(), + dest, value: amount_sub.unique_saturated_into(), }; - try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?) + try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)?; + + Ok(()) } } diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs index d820f50ec..5934ab90a 100644 --- a/runtime/src/precompiles/mod.rs +++ b/runtime/src/precompiles/mod.rs @@ -4,7 +4,7 @@ use alloc::format; use core::marker::PhantomData; use frame_support::dispatch::{GetDispatchInfo, Pays}; - +use frame_system::RawOrigin; use pallet_evm::{ ExitError, ExitSucceed, GasWeightMapping, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet, @@ -14,13 +14,10 @@ use pallet_evm_precompile_sha3fips::Sha3FIPS256; use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; use sp_core::{hashing::keccak_256, H160}; use sp_runtime::{traits::Dispatchable, AccountId32}; +use sp_std::vec; use crate::{Runtime, RuntimeCall}; -use frame_system::RawOrigin; - -use sp_std::vec; - // Include custom precompiles mod balance_transfer; mod ed25519; @@ -35,6 +32,7 @@ use metagraph::*; use neuron::*; use staking::*; use subnet::*; + pub struct FrontierPrecompiles(PhantomData); impl Default for FrontierPrecompiles where From fa8d0b098fd422e7b5946afeb8d180602ed4b860 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Fri, 7 Feb 2025 10:56:42 -0500 Subject: [PATCH 02/47] Remove DefaultMaxTempo, MaxTempo, AvgTempo, and outdated comments about min stake --- pallets/subtensor/src/lib.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index f9c1364a9..e47ada0e2 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -337,11 +337,6 @@ pub mod pallet { 0 } #[pallet::type_value] - /// Default value for max tempo - pub fn DefaultMaxTempo() -> u16 { - 30 // 1 hour. - } - #[pallet::type_value] /// Default value for global weight. pub fn DefaultTaoWeight() -> u64 { T::InitialTaoWeight::get() @@ -753,14 +748,12 @@ pub mod pallet { #[pallet::type_value] /// Default minimum stake. - /// 500k rao matches $0.25 at $500/TAO pub fn DefaultMinStake() -> u64 { 500_000 } #[pallet::type_value] /// Default staking fee. - /// 500k rao matches $0.25 at $500/TAO pub fn DefaultStakingFee() -> u64 { 50_000 } @@ -1127,10 +1120,6 @@ pub mod pallet { /// ================= /// ==== Tempos ===== /// ================= - #[pallet::storage] // --- ITEM( max_tempo ) - pub type AvgTempo = StorageValue<_, u16, ValueQuery, DefaultTempo>; - #[pallet::storage] // --- ITEM( max_tempo ) - pub type MaxTempo = StorageValue<_, u16, ValueQuery, DefaultMaxTempo>; #[pallet::storage] // --- MAP ( netuid ) --> tempo pub type Tempo = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultTempo>; From f1d70db1a4c86a6a85dc3c1351b03996916bb391 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Fri, 7 Feb 2025 11:08:43 -0500 Subject: [PATCH 03/47] Bump spec version --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 7b5a71601..bae918fe4 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: 228, + spec_version: 229, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 126f78049d888c086f8f0e9dec66262710c28383 Mon Sep 17 00:00:00 2001 From: Aliaksandr Tsurko Date: Thu, 6 Feb 2025 20:49:10 +0100 Subject: [PATCH 04/47] Refactor staking and neuron precompile with precompile-utils --- runtime/src/precompiles/balance_transfer.rs | 4 +- runtime/src/precompiles/mod.rs | 16 +-- runtime/src/precompiles/neuron.rs | 67 ++++-------- runtime/src/precompiles/staking.rs | 110 ++++++++------------ runtime/src/precompiles/subnet.rs | 17 ++- 5 files changed, 90 insertions(+), 124 deletions(-) diff --git a/runtime/src/precompiles/balance_transfer.rs b/runtime/src/precompiles/balance_transfer.rs index f0185a75e..ac4282056 100644 --- a/runtime/src/precompiles/balance_transfer.rs +++ b/runtime/src/precompiles/balance_transfer.rs @@ -48,8 +48,6 @@ impl BalanceTransferPrecompile { value: amount_sub.unique_saturated_into(), }; - try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?)?; - - Ok(()) + try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?) } } diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs index 5934ab90a..b2a2fa595 100644 --- a/runtime/src/precompiles/mod.rs +++ b/runtime/src/precompiles/mod.rs @@ -12,7 +12,8 @@ use pallet_evm::{ use pallet_evm_precompile_modexp::Modexp; use pallet_evm_precompile_sha3fips::Sha3FIPS256; use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; -use sp_core::{hashing::keccak_256, H160}; +use precompile_utils::EvmResult; +use sp_core::{hashing::keccak_256, H160, U256}; use sp_runtime::{traits::Dispatchable, AccountId32}; use sp_std::vec; @@ -151,6 +152,12 @@ pub fn get_pubkey(data: &[u8]) -> Result<(AccountId32, vec::Vec), Precompile )) } +fn try_u16_from_u256(value: U256) -> Result { + u16::try_from(value.as_u32()).map_err(|_| PrecompileFailure::Error { + exit_status: ExitError::Other("the value is outside of u16 bounds".into()), + }) +} + fn parse_netuid(data: &[u8], offset: usize) -> Result { if data.len() < offset + 2 { return Err(PrecompileFailure::Error { @@ -175,7 +182,7 @@ fn try_dispatch_runtime_call( handle: &mut impl PrecompileHandle, call: impl Into, origin: RawOrigin, -) -> PrecompileResult { +) -> EvmResult<()> { let call = Into::::into(call); let info = call.get_dispatch_info(); @@ -220,10 +227,7 @@ fn try_dispatch_runtime_call( log::info!("Dispatch succeeded. Post info: {:?}", post_info); - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: Default::default(), - }) + Ok(()) } Err(e) => { log::error!("Dispatch failed. Error: {:?}", e); diff --git a/runtime/src/precompiles/neuron.rs b/runtime/src/precompiles/neuron.rs index 97167c900..a9770241f 100644 --- a/runtime/src/precompiles/neuron.rs +++ b/runtime/src/precompiles/neuron.rs @@ -1,62 +1,39 @@ -use pallet_evm::{ExitError, PrecompileFailure, PrecompileHandle, PrecompileResult}; - -use crate::precompiles::{ - contract_to_origin, get_method_id, get_pubkey, get_slice, parse_netuid, - try_dispatch_runtime_call, -}; +use frame_system::RawOrigin; +use pallet_evm::{AddressMapping, HashedAddressMapping, PrecompileHandle}; +use precompile_utils::EvmResult; +use sp_core::H256; +use sp_runtime::traits::BlakeTwo256; use sp_runtime::AccountId32; -use sp_std::vec; +use crate::precompiles::{get_pubkey, try_dispatch_runtime_call}; use crate::{Runtime, RuntimeCall}; + pub const NEURON_PRECOMPILE_INDEX: u64 = 2052; -// ss58 public key i.e., the contract sends funds it received to the destination address from the -// method parameter. -const CONTRACT_ADDRESS_SS58: [u8; 32] = [ - 0xbc, 0x46, 0x35, 0x79, 0xbc, 0x99, 0xf9, 0xee, 0x7c, 0x59, 0xed, 0xee, 0x20, 0x61, 0xa3, 0x09, - 0xd2, 0x1e, 0x68, 0xd5, 0x39, 0xb6, 0x40, 0xec, 0x66, 0x46, 0x90, 0x30, 0xab, 0x74, 0xc1, 0xdb, -]; pub struct NeuronPrecompile; +#[precompile_utils::precompile] impl NeuronPrecompile { - pub fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { - let txdata = handle.input(); - let method_id = get_slice(txdata, 0, 4)?; - let method_input = txdata - .get(4..) - .map_or_else(vec::Vec::new, |slice| slice.to_vec()); // Avoiding borrowing conflicts - - match method_id { - id if id == get_method_id("burnedRegister(uint16,bytes32)") => { - Self::burned_register(handle, &method_input) - } - - _ => Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }), - } - } - - pub fn burned_register(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - let (netuid, hotkey) = Self::parse_netuid_hotkey_parameter(data)?; + #[precompile::public("burnedRegister(uint16,bytes32)")] + #[precompile::payable] + fn burned_register( + handle: &mut impl PrecompileHandle, + netuid: u16, + hotkey: H256, + ) -> EvmResult<()> { + let coldkey = + as AddressMapping>::into_account_id( + handle.context().caller, + ); + let (hotkey, _) = get_pubkey(hotkey.as_bytes())?; let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::::burned_register { netuid, hotkey, }); - try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?) - } - - fn parse_netuid_hotkey_parameter(data: &[u8]) -> Result<(u16, AccountId32), PrecompileFailure> { - if data.len() < 64 { - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - let netuid = parse_netuid(data, 30)?; - let (hotkey, _) = get_pubkey(get_slice(data, 32, 64)?)?; + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(coldkey))?; - Ok((netuid, hotkey)) + Ok(()) } } diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs index 8cc1c879a..3374dfbf7 100644 --- a/runtime/src/precompiles/staking.rs +++ b/runtime/src/precompiles/staking.rs @@ -25,20 +25,23 @@ // - Precompile checks the result of do_remove_stake and, in case of a failure, reverts the transaction. // -use crate::precompiles::{ - get_method_id, get_pubkey, get_slice, parse_netuid, try_dispatch_runtime_call, -}; -use crate::{ProxyType, Runtime, RuntimeCall}; use frame_system::RawOrigin; use pallet_evm::{ AddressMapping, BalanceConverter, ExitError, ExitSucceed, HashedAddressMapping, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, }; -use sp_core::U256; +use precompile_utils::EvmResult; +use sp_core::{H256, U256}; use sp_runtime::traits::{BlakeTwo256, Dispatchable, StaticLookup, UniqueSaturatedInto}; use sp_runtime::AccountId32; use sp_std::vec; +use crate::precompiles::{ + get_method_id, get_pubkey, get_slice, parse_netuid, try_dispatch_runtime_call, + try_u16_from_u256, +}; +use crate::{ProxyType, Runtime, RuntimeCall}; + pub const STAKING_PRECOMPILE_INDEX: u64 = 2049; // ss58 public key i.e., the contract sends funds it received to the destination address from the @@ -50,40 +53,17 @@ const CONTRACT_ADDRESS_SS58: [u8; 32] = [ pub struct StakingPrecompile; +#[precompile_utils::precompile] impl StakingPrecompile { - pub fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { - let txdata = handle.input(); - let method_id = get_slice(txdata, 0, 4)?; - let method_input = txdata - .get(4..) - .map_or_else(vec::Vec::new, |slice| slice.to_vec()); // Avoiding borrowing conflicts - - if method_id == get_method_id("addStake(bytes32,uint256)") { - Self::add_stake(handle, &method_input) - } else if method_id == get_method_id("removeStake(bytes32,uint256,uint256)") { - Self::remove_stake(handle, &method_input) - } else if method_id == get_method_id("getStake(bytes32,bytes32,uint256)") { - Self::get_stake(&method_input) - } else if method_id == get_method_id("addProxy(bytes32)") { - Self::add_proxy(handle, &method_input) - } else if method_id == get_method_id("removeProxy(bytes32)") { - Self::remove_proxy(handle, &method_input) - } else { - Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }) - } - } - - fn add_stake(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + #[precompile::public("addStake(bytes32,uint256)")] + #[precompile::payable] + fn add_stake(handle: &mut impl PrecompileHandle, address: H256, netuid: U256) -> EvmResult<()> { let account_id = as AddressMapping>::into_account_id( handle.context().caller, ); - let (hotkey, _) = get_pubkey(data)?; - let amount: U256 = handle.context().apparent_value; - let netuid = parse_netuid(data, 0x3E)?; + let amount = handle.context().apparent_value; if !amount.is_zero() { Self::transfer_back_to_caller(&account_id, amount)?; @@ -93,6 +73,8 @@ impl StakingPrecompile { ::BalanceConverter::into_substrate_balance(amount) .ok_or(ExitError::OutOfFund)?; + let (hotkey, _) = get_pubkey(address.as_bytes())?; + let netuid = try_u16_from_u256(netuid)?; let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::::add_stake { hotkey, netuid, @@ -102,39 +84,40 @@ impl StakingPrecompile { try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) } - fn remove_stake(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + #[precompile::public("removeStake(bytes32,uint256,uint256)")] + fn remove_stake( + handle: &mut impl PrecompileHandle, + address: H256, + amount: U256, + netuid: U256, + ) -> EvmResult<()> { let account_id = as AddressMapping>::into_account_id( handle.context().caller, ); - let (hotkey, _) = get_pubkey(data)?; - let netuid = parse_netuid(data, 0x5E)?; - - // We have to treat this as uint256 (because of Solidity ABI encoding rules, it pads uint64), - // but this will never exceed 8 bytes, se we will ignore higher bytes and will only use lower - // 8 bytes. - let amount = data - .get(56..64) - .map(U256::from_big_endian) - .ok_or(ExitError::OutOfFund)?; + let amount_sub = ::BalanceConverter::into_substrate_balance(amount) .ok_or(ExitError::OutOfFund)?; + let (hotkey, _) = get_pubkey(address.as_bytes())?; + let netuid = try_u16_from_u256(netuid)?; let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::::remove_stake { hotkey, netuid, amount_unstaked: amount_sub.unique_saturated_into(), }); + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) } - fn add_proxy(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + #[precompile::public("addProxy(bytes32)")] + fn add_proxy(handle: &mut impl PrecompileHandle, delegate: H256) -> EvmResult<()> { let account_id = as AddressMapping>::into_account_id( handle.context().caller, ); - let (delegate, _) = get_pubkey(data)?; + let (delegate, _) = get_pubkey(delegate.as_bytes())?; let delegate = ::Lookup::unlookup(delegate); let call = RuntimeCall::Proxy(pallet_proxy::Call::::add_proxy { delegate, @@ -145,12 +128,13 @@ impl StakingPrecompile { try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) } - fn remove_proxy(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { + #[precompile::public("removeProxy(bytes32)")] + fn remove_proxy(handle: &mut impl PrecompileHandle, delegate: H256) -> EvmResult<()> { let account_id = as AddressMapping>::into_account_id( handle.context().caller, ); - let (delegate, _) = get_pubkey(data)?; + let (delegate, _) = get_pubkey(delegate.as_bytes())?; let delegate = ::Lookup::unlookup(delegate); let call = RuntimeCall::Proxy(pallet_proxy::Call::::remove_proxy { delegate, @@ -161,29 +145,25 @@ impl StakingPrecompile { try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) } - fn get_stake(data: &[u8]) -> PrecompileResult { - let (hotkey, left_data) = get_pubkey(data)?; - let (coldkey, _) = get_pubkey(&left_data)?; - let netuid = parse_netuid(data, 0x5E)?; + #[precompile::public("getStake(bytes32,bytes32,uint256)")] + #[precompile::view] + fn get_stake( + _: &mut impl PrecompileHandle, + hotkey: H256, + coldkey: H256, + netuid: U256, + ) -> EvmResult { + let (hotkey, _) = get_pubkey(hotkey.as_bytes())?; + let (coldkey, _) = get_pubkey(coldkey.as_bytes())?; + let netuid = try_u16_from_u256(netuid)?; let stake = pallet_subtensor::Pallet::::get_stake_for_hotkey_and_coldkey_on_subnet( &hotkey, &coldkey, netuid, ); // Convert to EVM decimals - let stake_u256 = U256::from(stake); - let stake_eth = - ::BalanceConverter::into_evm_balance(stake_u256) - .ok_or(ExitError::InvalidRange)?; - - // Format output - let mut result = [0_u8; 32]; - U256::to_big_endian(&stake_eth, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + ::BalanceConverter::into_evm_balance(stake.into()) + .ok_or(ExitError::InvalidRange.into()) } fn transfer_back_to_caller( diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs index 9944572c5..c730de7a7 100644 --- a/runtime/src/precompiles/subnet.rs +++ b/runtime/src/precompiles/subnet.rs @@ -1,13 +1,15 @@ -use crate::precompiles::{get_method_id, get_pubkey, get_slice, 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::traits::BlakeTwo256; use sp_runtime::AccountId32; use sp_std::vec; + +use crate::precompiles::{get_method_id, get_pubkey, get_slice, try_dispatch_runtime_call}; +use crate::{Runtime, RuntimeCall}; + pub const SUBNET_PRECOMPILE_INDEX: u64 = 2051; // bytes with max lenght 1K pub const MAX_SINGLE_PARAMETER_SIZE: usize = 1024; @@ -21,6 +23,7 @@ const CONTRACT_ADDRESS_SS58: [u8; 32] = [ 0x3a, 0x86, 0x18, 0xfb, 0xbb, 0x1b, 0xbc, 0x47, 0x86, 0x64, 0xff, 0x53, 0x46, 0x18, 0x0c, 0x35, 0xd0, 0x9f, 0xac, 0x26, 0xf2, 0x02, 0x70, 0x85, 0xb3, 0x1c, 0x56, 0xc1, 0x06, 0x3c, 0x1c, 0xd3, ]; + pub struct SubnetPrecompile; impl SubnetPrecompile { @@ -93,7 +96,11 @@ impl SubnetPrecompile { ); // Dispatch the register_network call - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id))?; + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: Default::default(), + }) } fn parse_register_network_parameters( From fc3beb29d2bca9eae6fb889d04402a663b2dfeb4 Mon Sep 17 00:00:00 2001 From: Aliaksandr Tsurko Date: Thu, 13 Feb 2025 17:56:09 +0100 Subject: [PATCH 05/47] Fix number conversion issues in staking precompile --- runtime/src/precompiles/neuron.rs | 1 - runtime/src/precompiles/staking.rs | 17 ++++++++--------- runtime/src/precompiles/subnet.rs | 1 + 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/runtime/src/precompiles/neuron.rs b/runtime/src/precompiles/neuron.rs index a24b506c7..2951f190b 100644 --- a/runtime/src/precompiles/neuron.rs +++ b/runtime/src/precompiles/neuron.rs @@ -12,7 +12,6 @@ use sp_std::vec::Vec; use crate::precompiles::{ get_method_id, get_pubkey, get_slice, parse_netuid, try_dispatch_runtime_call, - try_dispatch_runtime_call, }; use crate::{Runtime, RuntimeCall}; diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs index 3374dfbf7..c368df6ad 100644 --- a/runtime/src/precompiles/staking.rs +++ b/runtime/src/precompiles/staking.rs @@ -71,7 +71,11 @@ impl StakingPrecompile { let amount_sub = ::BalanceConverter::into_substrate_balance(amount) - .ok_or(ExitError::OutOfFund)?; + .ok_or(PrecompileFailure::Error { + exit_status: ExitError::Other( + "error converting balance from ETH to subtensor".into(), + ), + })?; let (hotkey, _) = get_pubkey(address.as_bytes())?; let netuid = try_u16_from_u256(netuid)?; @@ -96,16 +100,13 @@ impl StakingPrecompile { handle.context().caller, ); - let amount_sub = - ::BalanceConverter::into_substrate_balance(amount) - .ok_or(ExitError::OutOfFund)?; - let (hotkey, _) = get_pubkey(address.as_bytes())?; let netuid = try_u16_from_u256(netuid)?; + let amount_unstaked = amount.unique_saturated_into(); let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::::remove_stake { hotkey, netuid, - amount_unstaked: amount_sub.unique_saturated_into(), + amount_unstaked, }); try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) @@ -161,9 +162,7 @@ impl StakingPrecompile { &hotkey, &coldkey, netuid, ); - // Convert to EVM decimals - ::BalanceConverter::into_evm_balance(stake.into()) - .ok_or(ExitError::InvalidRange.into()) + Ok(stake.into()) } fn transfer_back_to_caller( diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs index 56b47335c..dbaad74e0 100644 --- a/runtime/src/precompiles/subnet.rs +++ b/runtime/src/precompiles/subnet.rs @@ -25,6 +25,7 @@ const CONTRACT_ADDRESS_SS58: [u8; 32] = [ pub struct SubnetPrecompile; +#[precompile_utils::precompile] impl SubnetPrecompile { // pub fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { // let txdata = handle.input(); From 49e5336b53c71d91d4c4d3b73d0b3c7544e4a787 Mon Sep 17 00:00:00 2001 From: Aliaksandr Tsurko Date: Fri, 14 Feb 2025 16:08:48 +0100 Subject: [PATCH 06/47] Refactor neuron precompil - introduce PrecompileHandle and Precompile trait extensions --- runtime/src/precompiles/balance_transfer.rs | 30 +- runtime/src/precompiles/ed25519.rs | 14 +- runtime/src/precompiles/metagraph.rs | 144 ++++--- runtime/src/precompiles/mod.rs | 180 ++++---- runtime/src/precompiles/neuron.rs | 445 +++----------------- runtime/src/precompiles/staking.rs | 93 ++-- runtime/src/precompiles/subnet.rs | 24 +- 7 files changed, 317 insertions(+), 613 deletions(-) diff --git a/runtime/src/precompiles/balance_transfer.rs b/runtime/src/precompiles/balance_transfer.rs index ac4282056..14966867d 100644 --- a/runtime/src/precompiles/balance_transfer.rs +++ b/runtime/src/precompiles/balance_transfer.rs @@ -11,18 +11,10 @@ use sp_runtime::AccountId32; use sp_std::vec::Vec; use crate::precompiles::{ - contract_to_origin, get_method_id, get_pubkey, get_slice, try_dispatch_runtime_call, + contract_to_origin, get_method_id, parse_slice, parse_pubkey, PrecompileExt, PrecompileHandleExt, }; use crate::Runtime; -pub const BALANCE_TRANSFER_INDEX: u64 = 2048; -// ss58 public key i.e., the contract sends funds it received to the destination address from the -// method parameter. -const CONTRACT_ADDRESS_SS58: [u8; 32] = [ - 0x07, 0xec, 0x71, 0x2a, 0x5d, 0x38, 0x43, 0x4d, 0xdd, 0x03, 0x3f, 0x8f, 0x02, 0x4e, 0xcd, 0xfc, - 0x4b, 0xb5, 0x95, 0x1c, 0x13, 0xc3, 0x08, 0x5c, 0x39, 0x9c, 0x8a, 0x5f, 0x62, 0x93, 0x70, 0x5d, -]; - pub struct BalanceTransferPrecompile; #[precompile_utils::precompile] @@ -30,24 +22,28 @@ impl BalanceTransferPrecompile { #[precompile::public("transfer(bytes32)")] #[precompile::payable] fn transfer(handle: &mut impl PrecompileHandle, address: H256) -> EvmResult<()> { - let amount = handle.context().apparent_value; - - // Use BalanceConverter to convert EVM amount to Substrate balance - let amount_sub = - ::BalanceConverter::into_substrate_balance(amount) - .ok_or(ExitError::OutOfFund)?; + let amount_sub = handle.try_convert_apparent_value()?; if amount_sub.is_zero() { return Ok(()); } - let dest = get_pubkey(address.as_bytes())?.0.into(); + let dest = parse_pubkey(address.as_bytes())?.0.into(); let call = pallet_balances::Call::::transfer_allow_death { dest, value: amount_sub.unique_saturated_into(), }; - try_dispatch_runtime_call(handle, call, contract_to_origin(&CONTRACT_ADDRESS_SS58)?) + handle.try_dispatch_runtime_call(call, contract_to_origin(&Self::ADDRESS_SS58)?) } } + +impl PrecompileExt for BalanceTransferPrecompile { + const INDEX: u64 = 2048; + const ADDRESS_SS58: [u8; 32] = [ + 0x07, 0xec, 0x71, 0x2a, 0x5d, 0x38, 0x43, 0x4d, 0xdd, 0x03, 0x3f, 0x8f, 0x02, 0x4e, 0xcd, + 0xfc, 0x4b, 0xb5, 0x95, 0x1c, 0x13, 0xc3, 0x08, 0x5c, 0x39, 0x9c, 0x8a, 0x5f, 0x62, 0x93, + 0x70, 0x5d, + ]; +} diff --git a/runtime/src/precompiles/ed25519.rs b/runtime/src/precompiles/ed25519.rs index 83be4ca77..6ad082029 100644 --- a/runtime/src/precompiles/ed25519.rs +++ b/runtime/src/precompiles/ed25519.rs @@ -2,11 +2,10 @@ extern crate alloc; use alloc::vec::Vec; -use crate::precompiles::get_slice; use ed25519_dalek::{Signature, Verifier, VerifyingKey}; use fp_evm::{ExitError, ExitSucceed, LinearCostPrecompile, PrecompileFailure}; -pub const EDVERIFY_PRECOMPILE_INDEX: u64 = 1026; +use crate::precompiles::{parse_slice, PrecompileExt}; pub struct Ed25519Verify; @@ -23,13 +22,13 @@ impl LinearCostPrecompile for Ed25519Verify { let mut buf = [0u8; 32]; - let msg = get_slice(input, 4, 36)?; - let pk = VerifyingKey::try_from(get_slice(input, 36, 68)?).map_err(|_| { + let msg = parse_slice(input, 4, 36)?; + let pk = VerifyingKey::try_from(parse_slice(input, 36, 68)?).map_err(|_| { PrecompileFailure::Error { exit_status: ExitError::Other("Public key recover failed".into()), } })?; - let sig = Signature::try_from(get_slice(input, 68, 132)?).map_err(|_| { + let sig = Signature::try_from(parse_slice(input, 68, 132)?).map_err(|_| { PrecompileFailure::Error { exit_status: ExitError::Other("Signature recover failed".into()), } @@ -42,3 +41,8 @@ impl LinearCostPrecompile for Ed25519Verify { Ok((ExitSucceed::Returned, buf.to_vec())) } } + +impl PrecompileExt for Ed25519Verify { + const INDEX: u64 = 1026; + const ADDRESS_SS58: [u8; 32] = [0; 32]; +} diff --git a/runtime/src/precompiles/metagraph.rs b/runtime/src/precompiles/metagraph.rs index ffc4cbed7..365e55144 100644 --- a/runtime/src/precompiles/metagraph.rs +++ b/runtime/src/precompiles/metagraph.rs @@ -1,66 +1,67 @@ -extern crate alloc; -use crate::precompiles::{get_method_id, get_slice}; -use crate::Runtime; use fp_evm::{ ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, }; use sp_core::{ByteArray, U256}; use sp_std::vec; -pub const METAGRAPH_PRECOMPILE_INDEX: u64 = 2050; + +use crate::precompiles::{get_method_id, parse_slice, PrecompileExt, PrecompileHandleExt}; +use crate::Runtime; + pub struct MetagraphPrecompile; const NO_HOTKEY: &str = "no hotkey"; +#[precompile_utils::precompile] impl MetagraphPrecompile { - pub fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { - let txdata = handle.input(); - let method_id = get_slice(txdata, 0, 4)?; - let method_input = txdata - .get(4..) - .map_or_else(vec::Vec::new, |slice| slice.to_vec()); // Avoiding borrowing conflicts - - match method_id { - id if id == get_method_id("getUidCount(uint16)") => Self::get_uid_count(&method_input), - id if id == get_method_id("getStake(uint16,uint16)") => Self::get_stake(&method_input), - id if id == get_method_id("getRank(uint16,uint16)") => Self::get_rank(&method_input), - id if id == get_method_id("getTrust(uint16,uint16)") => Self::get_trust(&method_input), - id if id == get_method_id("getConsensus(uint16,uint16)") => { - Self::get_consensus(&method_input) - } - id if id == get_method_id("getIncentive(uint16,uint16)") => { - Self::get_incentive(&method_input) - } - id if id == get_method_id("getDividends(uint16,uint16)") => { - Self::get_dividends(&method_input) - } - id if id == get_method_id("getEmission(uint16,uint16)") => { - Self::get_emission(&method_input) - } - id if id == get_method_id("getVtrust(uint16,uint16)") => { - Self::get_vtrust(&method_input) - } - id if id == get_method_id("getValidatorStatus(uint16,uint16)") => { - Self::get_validator_status(&method_input) - } - id if id == get_method_id("getLastUpdate(uint16,uint16)") => { - Self::get_last_update(&method_input) - } - id if id == get_method_id("getIsActive(uint16,uint16)") => { - Self::get_is_active(&method_input) - } - id if id == get_method_id("getAxon(uint16,uint16)") => Self::get_axon(&method_input), - id if id == get_method_id("getHotkey(uint16,uint16)") => { - Self::get_hotkey(&method_input) - } - id if id == get_method_id("getColdkey(uint16,uint16)") => { - Self::get_coldkey(&method_input) - } - - _ => Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }), - } - } + // pub fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + // let txdata = handle.input(); + // let method_id = get_slice(txdata, 0, 4)?; + // let method_input = txdata + // .get(4..) + // .map_or_else(vec::Vec::new, |slice| slice.to_vec()); // Avoiding borrowing conflicts + + // match method_id { + // id if id == get_method_id("getUidCount(uint16)") => Self::get_uid_count(&method_input), + // id if id == get_method_id("getStake(uint16,uint16)") => Self::get_stake(&method_input), + // id if id == get_method_id("getRank(uint16,uint16)") => Self::get_rank(&method_input), + // id if id == get_method_id("getTrust(uint16,uint16)") => Self::get_trust(&method_input), + // id if id == get_method_id("getConsensus(uint16,uint16)") => { + // Self::get_consensus(&method_input) + // } + // id if id == get_method_id("getIncentive(uint16,uint16)") => { + // Self::get_incentive(&method_input) + // } + // id if id == get_method_id("getDividends(uint16,uint16)") => { + // Self::get_dividends(&method_input) + // } + // id if id == get_method_id("getEmission(uint16,uint16)") => { + // Self::get_emission(&method_input) + // } + // id if id == get_method_id("getVtrust(uint16,uint16)") => { + // Self::get_vtrust(&method_input) + // } + // id if id == get_method_id("getValidatorStatus(uint16,uint16)") => { + // Self::get_validator_status(&method_input) + // } + // id if id == get_method_id("getLastUpdate(uint16,uint16)") => { + // Self::get_last_update(&method_input) + // } + // id if id == get_method_id("getIsActive(uint16,uint16)") => { + // Self::get_is_active(&method_input) + // } + // id if id == get_method_id("getAxon(uint16,uint16)") => Self::get_axon(&method_input), + // id if id == get_method_id("getHotkey(uint16,uint16)") => { + // Self::get_hotkey(&method_input) + // } + // id if id == get_method_id("getColdkey(uint16,uint16)") => { + // Self::get_coldkey(&method_input) + // } + + // _ => Err(PrecompileFailure::Error { + // exit_status: ExitError::InvalidRange, + // }), + // } + // } fn get_uid_count(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; @@ -78,7 +79,7 @@ impl MetagraphPrecompile { fn get_stake(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let hotkey = pallet_subtensor::Pallet::::get_hotkey_for_net_and_uid(netuid, uid) .map_err(|_| PrecompileFailure::Error { exit_status: ExitError::InvalidRange, @@ -97,7 +98,7 @@ impl MetagraphPrecompile { fn get_rank(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let rank = pallet_subtensor::Pallet::::get_rank_for_uid(netuid, uid); let result_u256 = U256::from(rank); @@ -112,7 +113,7 @@ impl MetagraphPrecompile { fn get_trust(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let trust = pallet_subtensor::Pallet::::get_trust_for_uid(netuid, uid); @@ -128,7 +129,7 @@ impl MetagraphPrecompile { fn get_consensus(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let consensus = pallet_subtensor::Pallet::::get_consensus_for_uid(netuid, uid); @@ -144,7 +145,7 @@ impl MetagraphPrecompile { fn get_incentive(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let incentive = pallet_subtensor::Pallet::::get_incentive_for_uid(netuid, uid); @@ -160,7 +161,7 @@ impl MetagraphPrecompile { fn get_dividends(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let dividends = pallet_subtensor::Pallet::::get_dividends_for_uid(netuid, uid); @@ -176,7 +177,7 @@ impl MetagraphPrecompile { fn get_emission(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let emission = pallet_subtensor::Pallet::::get_emission_for_uid(netuid, uid); @@ -192,7 +193,7 @@ impl MetagraphPrecompile { fn get_vtrust(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let vtrust = pallet_subtensor::Pallet::::get_validator_trust_for_uid(netuid, uid); @@ -208,7 +209,7 @@ impl MetagraphPrecompile { fn get_validator_status(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let validator_permit = pallet_subtensor::Pallet::::get_validator_permit_for_uid(netuid, uid); @@ -229,7 +230,7 @@ impl MetagraphPrecompile { fn get_last_update(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let last_update = pallet_subtensor::Pallet::::get_last_update_for_uid(netuid, uid); @@ -245,7 +246,7 @@ impl MetagraphPrecompile { fn get_is_active(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let active = pallet_subtensor::Pallet::::get_active_for_uid(netuid, uid); @@ -261,7 +262,7 @@ impl MetagraphPrecompile { fn get_axon(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let hotkey = pallet_subtensor::Pallet::::get_hotkey_for_net_and_uid(netuid, uid) .map_err(|_| PrecompileFailure::Error { @@ -304,7 +305,7 @@ impl MetagraphPrecompile { fn get_hotkey(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let hotkey = pallet_subtensor::Pallet::::get_hotkey_for_net_and_uid(netuid, uid) .map_err(|_| PrecompileFailure::Error { @@ -319,7 +320,7 @@ impl MetagraphPrecompile { fn get_coldkey(data: &[u8]) -> PrecompileResult { let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(get_slice(data, 32, 64)?)?; + let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; let hotkey = pallet_subtensor::Pallet::::get_hotkey_for_net_and_uid(netuid, uid) .map_err(|_| PrecompileFailure::Error { @@ -341,7 +342,7 @@ impl MetagraphPrecompile { }); } let mut netuid = [0u8; 2]; - netuid.copy_from_slice(get_slice(data, 30, 32)?); + netuid.copy_from_slice(parse_slice(data, 30, 32)?); let result = u16::from_be_bytes(netuid); Ok(result) } @@ -353,8 +354,13 @@ impl MetagraphPrecompile { }); } let mut uid = [0u8; 2]; - uid.copy_from_slice(get_slice(data, 30, 32)?); + uid.copy_from_slice(parse_slice(data, 30, 32)?); let result = u16::from_be_bytes(uid); Ok(result) } } + +impl PrecompileExt for MetagraphPrecompile { + const INDEX: u64 = 2050; + const ADDRESS_SS58: [u8; 32] = [0; 32]; +} diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs index e963d6031..76bf110d8 100644 --- a/runtime/src/precompiles/mod.rs +++ b/runtime/src/precompiles/mod.rs @@ -6,14 +6,16 @@ use core::marker::PhantomData; use frame_support::dispatch::{GetDispatchInfo, Pays}; use frame_system::RawOrigin; use pallet_evm::{ - ExitError, ExitSucceed, GasWeightMapping, IsPrecompileResult, Precompile, PrecompileFailure, - PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet, + AddressMapping, BalanceConverter, ExitError, ExitSucceed, GasWeightMapping, + HashedAddressMapping, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle, + PrecompileOutput, PrecompileResult, PrecompileSet, }; use pallet_evm_precompile_modexp::Modexp; use pallet_evm_precompile_sha3fips::Sha3FIPS256; use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; use precompile_utils::EvmResult; use sp_core::{hashing::keccak_256, H160, U256}; +use sp_runtime::traits::BlakeTwo256; use sp_runtime::{traits::Dispatchable, AccountId32}; use sp_std::vec; @@ -60,12 +62,12 @@ where hash(5), hash(1024), hash(1025), - hash(EDVERIFY_PRECOMPILE_INDEX), - hash(BALANCE_TRANSFER_INDEX), - hash(STAKING_PRECOMPILE_INDEX), - hash(SUBNET_PRECOMPILE_INDEX), - hash(METAGRAPH_PRECOMPILE_INDEX), - hash(NEURON_PRECOMPILE_INDEX), + hash(Ed25519Verify::INDEX), + hash(BalanceTransferPrecompile::INDEX), + hash(StakingPrecompile::INDEX), + hash(SubnetPrecompile::INDEX), + hash(MetagraphPrecompile::INDEX), + hash(NeuronPrecompile::INDEX), ] } } @@ -84,17 +86,17 @@ where // Non-Frontier specific nor Ethereum precompiles : a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)), a if a == hash(1025) => Some(ECRecoverPublicKey::execute(handle)), - a if a == hash(EDVERIFY_PRECOMPILE_INDEX) => Some(Ed25519Verify::execute(handle)), + a if a == hash(Ed25519Verify::INDEX) => Some(Ed25519Verify::execute(handle)), // Subtensor specific precompiles : - a if a == hash(BALANCE_TRANSFER_INDEX) => { + a if a == hash(BalanceTransferPrecompile::INDEX) => { Some(BalanceTransferPrecompile::execute(handle)) } - a if a == hash(STAKING_PRECOMPILE_INDEX) => Some(StakingPrecompile::execute(handle)), - a if a == hash(SUBNET_PRECOMPILE_INDEX) => Some(SubnetPrecompile::execute(handle)), - a if a == hash(METAGRAPH_PRECOMPILE_INDEX) => { + a if a == hash(StakingPrecompile::INDEX) => Some(StakingPrecompile::execute(handle)), + a if a == hash(SubnetPrecompile::INDEX) => Some(SubnetPrecompile::execute(handle)), + a if a == hash(MetagraphPrecompile::INDEX) => { Some(MetagraphPrecompile::execute(handle)) } - a if a == hash(NEURON_PRECOMPILE_INDEX) => Some(NeuronPrecompile::execute(handle)), + a if a == hash(NeuronPrecompile::INDEX) => Some(NeuronPrecompile::execute(handle)), _ => None, } @@ -124,7 +126,7 @@ pub fn get_method_id(method_signature: &str) -> [u8; 4] { /// Takes a slice from bytes with PrecompileFailure as Error /// -pub fn get_slice(data: &[u8], from: usize, to: usize) -> Result<&[u8], PrecompileFailure> { +pub fn parse_slice(data: &[u8], from: usize, to: usize) -> Result<&[u8], PrecompileFailure> { let maybe_slice = data.get(from..to); if let Some(slice) = maybe_slice { Ok(slice) @@ -141,9 +143,9 @@ pub fn get_slice(data: &[u8], from: usize, to: usize) -> Result<&[u8], Precompil } } -pub fn get_pubkey(data: &[u8]) -> Result<(AccountId32, vec::Vec), PrecompileFailure> { +pub fn parse_pubkey(data: &[u8]) -> Result<(AccountId32, vec::Vec), PrecompileFailure> { let mut pubkey = [0u8; 32]; - pubkey.copy_from_slice(get_slice(data, 0, 32)?); + pubkey.copy_from_slice(parse_slice(data, 0, 32)?); Ok(( pubkey.into(), @@ -166,77 +168,107 @@ fn parse_netuid(data: &[u8], offset: usize) -> Result { } let mut netuid_bytes = [0u8; 2]; - netuid_bytes.copy_from_slice(get_slice(data, offset, offset + 2)?); + netuid_bytes.copy_from_slice(parse_slice(data, offset, offset + 2)?); let netuid: u16 = netuid_bytes[1] as u16 | ((netuid_bytes[0] as u16) << 8u16); Ok(netuid) } fn contract_to_origin(contract: &[u8; 32]) -> Result, PrecompileFailure> { - let (account_id, _) = get_pubkey(contract)?; + let (account_id, _) = parse_pubkey(contract)?; Ok(RawOrigin::Signed(account_id)) } -/// Dispatches a runtime call, but also checks and records the gas costs. -fn try_dispatch_runtime_call( - handle: &mut impl PrecompileHandle, - call: impl Into, - origin: RawOrigin, -) -> EvmResult<()> { - let call = Into::::into(call); - let info = call.get_dispatch_info(); - - let target_gas = handle.gas_limit(); - if let Some(gas) = target_gas { - let valid_weight = - ::GasWeightMapping::gas_to_weight(gas, false).ref_time(); - if info.weight.ref_time() > valid_weight { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } +pub(crate) trait PrecompileHandleExt: PrecompileHandle { + fn caller_account_id(&self) -> AccountId32 { + as AddressMapping>::into_account_id( + self.context().caller, + ) } - handle.record_external_cost( - Some(info.weight.ref_time()), - Some(info.weight.proof_size()), - None, - )?; - - match call.dispatch(origin.into()) { - Ok(post_info) => { - if post_info.pays_fee(&info) == Pays::Yes { - let actual_weight = post_info.actual_weight.unwrap_or(info.weight); - let cost = - ::GasWeightMapping::weight_to_gas(actual_weight); - handle.record_cost(cost)?; - - handle.refund_external_cost( - Some( - info.weight - .ref_time() - .saturating_sub(actual_weight.ref_time()), - ), - Some( - info.weight - .proof_size() - .saturating_sub(actual_weight.proof_size()), - ), - ); - } + fn try_convert_apparent_value(&self) -> EvmResult { + let amount = self.context().apparent_value; + ::BalanceConverter::into_substrate_balance(amount).ok_or( + PrecompileFailure::Error { + exit_status: ExitError::Other( + "error converting balance from ETH to subtensor".into(), + ), + }, + ) + } - log::info!("Dispatch succeeded. Post info: {:?}", post_info); + /// Dispatches a runtime call, but also checks and records the gas costs. + fn try_dispatch_runtime_call( + &mut self, + call: impl Into, + origin: RawOrigin, + ) -> EvmResult<()> { + let call = Into::::into(call); + let info = call.get_dispatch_info(); - Ok(()) + let target_gas = self.gas_limit(); + if let Some(gas) = target_gas { + let valid_weight = + ::GasWeightMapping::gas_to_weight(gas, false) + .ref_time(); + if info.weight.ref_time() > valid_weight { + return Err(PrecompileFailure::Error { + exit_status: ExitError::OutOfGas, + }); + } } - Err(e) => { - log::error!("Dispatch failed. Error: {:?}", e); - log::warn!("Returning error PrecompileFailure::Error"); - Err(PrecompileFailure::Error { - exit_status: ExitError::Other( - format!("dispatch execution failed: {}", <&'static str>::from(e)).into(), - ), - }) + + self.record_external_cost( + Some(info.weight.ref_time()), + Some(info.weight.proof_size()), + None, + )?; + + match call.dispatch(origin.into()) { + Ok(post_info) => { + if post_info.pays_fee(&info) == Pays::Yes { + let actual_weight = post_info.actual_weight.unwrap_or(info.weight); + let cost = ::GasWeightMapping::weight_to_gas( + actual_weight, + ); + self.record_cost(cost)?; + + self.refund_external_cost( + Some( + info.weight + .ref_time() + .saturating_sub(actual_weight.ref_time()), + ), + Some( + info.weight + .proof_size() + .saturating_sub(actual_weight.proof_size()), + ), + ); + } + + log::info!("Dispatch succeeded. Post info: {:?}", post_info); + + Ok(()) + } + Err(e) => { + log::error!("Dispatch failed. Error: {:?}", e); + log::warn!("Returning error PrecompileFailure::Error"); + Err(PrecompileFailure::Error { + exit_status: ExitError::Other( + format!("dispatch execution failed: {}", <&'static str>::from(e)).into(), + ), + }) + } } } } + +impl PrecompileHandleExt for T where T: PrecompileHandle {} + +pub(crate) trait PrecompileExt: Precompile { + const INDEX: u64; + // ss58 public key i.e., the contract sends funds it received to the destination address from + // the method parameter. + const ADDRESS_SS58: [u8; 32]; +} diff --git a/runtime/src/precompiles/neuron.rs b/runtime/src/precompiles/neuron.rs index 2951f190b..cb92a5dfd 100644 --- a/runtime/src/precompiles/neuron.rs +++ b/runtime/src/precompiles/neuron.rs @@ -11,108 +11,71 @@ use sp_std::vec; use sp_std::vec::Vec; use crate::precompiles::{ - get_method_id, get_pubkey, get_slice, parse_netuid, try_dispatch_runtime_call, + get_method_id, parse_netuid, parse_pubkey, parse_slice, PrecompileExt, PrecompileHandleExt, }; use crate::{Runtime, RuntimeCall}; -pub const NEURON_PRECOMPILE_INDEX: u64 = 2052; // max paramter lenght 4K pub const MAX_PARAMETER_SIZE: usize = 4 * 1024; -// 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] = [ - 0xbc, 0x46, 0x35, 0x79, 0xbc, 0x99, 0xf9, 0xee, 0x7c, 0x59, 0xed, 0xee, 0x20, 0x61, 0xa3, 0x09, - 0xd2, 0x1e, 0x68, 0xd5, 0x39, 0xb6, 0x40, 0xec, 0x66, 0x46, 0x90, 0x30, 0xab, 0x74, 0xc1, 0xdb, -]; + pub struct NeuronPrecompile; #[precompile_utils::precompile] impl NeuronPrecompile { - // pub fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { - // let txdata = handle.input(); - // let method_id = get_slice(txdata, 0, 4)?; - // let method_input = txdata - // .get(4..) - // .map_or_else(vec::Vec::new, |slice| slice.to_vec()); // Avoiding borrowing conflicts - - // if method_input.len() > MAX_PARAMETER_SIZE { - // log::error!( - // "method parameter data length as {} is too long", - // method_input.len() - // ); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - - // match method_id { - // id if id == get_method_id("setWeights(uint16,uint16[],uint16[],uint64)") => { - // Self::set_weights(handle, &method_input) - // } - // id if id == get_method_id("commitWeights(uint16,uint256)") => { - // Self::commit_weights(handle, &method_input) - // } - // id if id - // == get_method_id("revealWeights(uint16,uint16[],uint16[],uint16[],uint64)") => - // { - // Self::reveal_weights(handle, &method_input) - // } - - // _ => Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }), - // } - // } - - // pub fn set_weights(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - // let (netuid, dests, weights, version_key) = Self::parse_netuid_dests_weights(data)?; - // let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::::set_weights { - // netuid, - // dests, - // weights, - // version_key, - // }); - // let account_id = - // as AddressMapping>::into_account_id( - // handle.context().caller, - // ); - - // try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - // } + #[precompile::public("setWeights(uint16,uint16[],uint16[],uint64)")] + #[precompile::payable] + pub fn set_weights( + handle: &mut impl PrecompileHandle, + netuid: u16, + dests: Vec, + weights: Vec, + version_key: u64, + ) -> EvmResult<()> { + let call = pallet_subtensor::Call::::set_weights { + netuid, + dests, + weights, + version_key, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } - // pub fn commit_weights(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - // let (netuid, commit_hash) = Self::parse_netuid_commit_hash(data)?; + #[precompile::public("commitWeights(uint16,uint256)")] + #[precompile::payable] + pub fn commit_weights( + handle: &mut impl PrecompileHandle, + netuid: u16, + commit_hash: H256, + ) -> EvmResult<()> { + let call = pallet_subtensor::Call::::commit_weights { + netuid, + commit_hash, + }; - // let call = - // RuntimeCall::SubtensorModule(pallet_subtensor::Call::::commit_weights { - // netuid, - // commit_hash, - // }); - // let account_id = - // as AddressMapping>::into_account_id( - // handle.context().caller, - // ); - // try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - // } + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } - // pub fn reveal_weights(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - // let (netuid, uids, values, salt, version_key) = - // Self::parse_netuid_dests_weights_salt(data)?; - // let call = - // RuntimeCall::SubtensorModule(pallet_subtensor::Call::::reveal_weights { - // netuid, - // uids, - // values, - // salt, - // version_key, - // }); - // let account_id = - // as AddressMapping>::into_account_id( - // handle.context().caller, - // ); - // try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - // } + #[precompile::public("revealWeights(uint16,uint16[],uint16[],uint16[],uint64)")] + #[precompile::payable] + pub fn reveal_weights( + handle: &mut impl PrecompileHandle, + netuid: u16, + uids: Vec, + values: Vec, + salt: Vec, + version_key: u64, + ) -> EvmResult<()> { + let call = pallet_subtensor::Call::::reveal_weights { + netuid, + uids, + values, + salt, + version_key, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } #[precompile::public("burnedRegister(uint16,bytes32)")] #[precompile::payable] @@ -121,297 +84,19 @@ impl NeuronPrecompile { netuid: u16, hotkey: H256, ) -> EvmResult<()> { - let coldkey = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - let (hotkey, _) = get_pubkey(hotkey.as_bytes())?; - let call = - RuntimeCall::SubtensorModule(pallet_subtensor::Call::::burned_register { - netuid, - hotkey, - }); - - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(coldkey)) - } - - // fn parse_netuid_hotkey_parameter(data: &[u8]) -> Result<(u16, AccountId32), PrecompileFailure> { - // if data.len() < 64 { - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - - // let netuid = parse_netuid(data, 30)?; - - // Ok(()) - // } - - fn parse_netuid_dests_weights( - data: &[u8], - ) -> Result<(u16, Vec, Vec, u64), PrecompileFailure> { - let data_len = data.len(); - if data_len < 4 * 32 { - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - let mut netuid_vec = [0u8; 2]; - netuid_vec.copy_from_slice(get_slice(data, 30, 32)?); - let netuid = u16::from_be_bytes(netuid_vec); - - // get the neuron amount in sebnet - let subnet_size = pallet_subtensor::Pallet::::get_subnetwork_n(netuid) as usize; - - let mut first_position_vec = [0u8; 2]; - first_position_vec.copy_from_slice(get_slice(data, 62, 64)?); - let first_position = u16::from_be_bytes(first_position_vec) as usize; - - if first_position > data_len { - log::error!("position for uids data as {} is too large", first_position); - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - let mut second_position_vec = [0u8; 2]; - second_position_vec.copy_from_slice(get_slice(data, 94, 96)?); - let second_position = u16::from_be_bytes(second_position_vec) as usize; - - if second_position > data_len { - log::error!("position for uids data as {} is too large", first_position); - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - let mut version_key_vec = [0u8; 8]; - version_key_vec.copy_from_slice(get_slice(data, 120, 128)?); - let version_key = u64::from_be_bytes(version_key_vec); + let coldkey = handle.caller_account_id(); + let (hotkey, _) = parse_pubkey(hotkey.as_bytes())?; + let call = pallet_subtensor::Call::::burned_register { netuid, hotkey }; - let mut dests = vec![]; - let mut weights = vec![]; - - let mut dests_len_vec = [0u8; 2]; - dests_len_vec.copy_from_slice(get_slice(data, first_position + 30, first_position + 32)?); - let dests_len = u16::from_be_bytes(dests_len_vec) as usize; - - if dests_len > subnet_size { - log::error!( - "uids len as {} in set weight is more than neurons {} in subnet {}", - dests_len, - subnet_size, - netuid - ); - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - for i in 0..dests_len { - let mut tmp_vec = [0u8; 2]; - let from = first_position - .saturating_add(62) - .saturating_add(i.saturating_mul(32)); - let to = from.saturating_add(2); - tmp_vec.copy_from_slice(get_slice(data, from, to)?); - let dest = u16::from_be_bytes(tmp_vec); - dests.push(dest); - } - - let mut weights_len_vec = [0u8; 2]; - weights_len_vec.copy_from_slice(get_slice( - data, - second_position + 30, - second_position + 32, - )?); - let weights_len = u16::from_be_bytes(weights_len_vec) as usize; - - if weights_len > subnet_size { - log::error!( - "weights len as {} in set weight is more than neurons {} in subnet {}", - weights_len, - subnet_size, - netuid - ); - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - for i in 0..weights_len { - let mut tmp_vec = [0u8; 2]; - let from = second_position - .saturating_add(62) - .saturating_add(i.saturating_mul(32)); - let to = from.saturating_add(2); - tmp_vec.copy_from_slice(get_slice(data, from, to)?); - let weight = u16::from_be_bytes(tmp_vec); - weights.push(weight); - } - - Ok((netuid, dests, weights, version_key)) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(coldkey)) } +} - fn parse_netuid_commit_hash(data: &[u8]) -> Result<(u16, H256), PrecompileFailure> { - if data.len() < 2 * 32 { - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - let mut netuid_vec = [0u8; 2]; - netuid_vec.copy_from_slice(get_slice(data, 30, 32)?); - let netuid = u16::from_be_bytes(netuid_vec); - let commit_hash = H256::from_slice(get_slice(data, 32, 64)?); - - Ok((netuid, commit_hash)) - } - - fn parse_netuid_dests_weights_salt( - data: &[u8], - ) -> Result<(u16, Vec, Vec, Vec, u64), PrecompileFailure> { - let data_len = data.len(); - if data_len < 5 * 32 { - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - let netuid = parse_netuid(data, 30)?; - - // get the neuron amount in sebnet - let subnet_size = pallet_subtensor::Pallet::::get_subnetwork_n(netuid) as usize; - - let mut first_position_vec = [0u8; 2]; - first_position_vec.copy_from_slice(get_slice(data, 62, 64)?); - let first_position = u16::from_be_bytes(first_position_vec) as usize; - - if first_position > data_len { - log::error!("position for uids data as {} is too large", first_position); - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - let mut second_position_vec = [0u8; 2]; - second_position_vec.copy_from_slice(get_slice(data, 94, 96)?); - let second_position = u16::from_be_bytes(second_position_vec) as usize; - - if second_position > data_len { - log::error!( - "position for values data as {} is too large", - first_position - ); - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - let mut third_position_vec = [0u8; 2]; - third_position_vec.copy_from_slice(get_slice(data, 126, 128)?); - let third_position = u16::from_be_bytes(third_position_vec) as usize; - - if third_position > data_len { - log::error!("position for salt data as {} is too large", first_position); - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - let mut version_key_vec = [0u8; 8]; - version_key_vec.copy_from_slice(get_slice(data, 152, 160)?); - let version_key = u64::from_be_bytes(version_key_vec); - - let mut uids = vec![]; - let mut values = vec![]; - let mut salt = vec![]; - - let mut uids_len_vec = [0u8; 2]; - uids_len_vec.copy_from_slice(get_slice(data, first_position + 30, first_position + 32)?); - let uids_len = u16::from_be_bytes(uids_len_vec) as usize; - - if uids_len > subnet_size { - log::error!( - "uids len as {} in reveal weight is more than neurons {} in subnet {}", - uids_len, - subnet_size, - netuid - ); - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - for i in 0..uids_len { - let mut tmp_vec = [0u8; 2]; - let from = first_position - .saturating_add(62) - .saturating_add(i.saturating_mul(32)); - let to = from.saturating_add(2); - tmp_vec.copy_from_slice(get_slice(data, from, to)?); - let uid = u16::from_be_bytes(tmp_vec); - uids.push(uid); - } - - let mut values_len_vec = [0u8; 2]; - values_len_vec.copy_from_slice(get_slice( - data, - second_position + 30, - second_position + 32, - )?); - let values_len = u16::from_be_bytes(values_len_vec) as usize; - - if values_len > subnet_size { - log::error!( - "values len as {} in reveal weight is more than neurons {} in subnet {}", - values_len, - subnet_size, - netuid - ); - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - for i in 0..values_len { - let mut tmp_vec = [0u8; 2]; - let from = second_position - .saturating_add(62) - .saturating_add(i.saturating_mul(32)); - let to = from.saturating_add(2); - tmp_vec.copy_from_slice(get_slice(data, from, to)?); - let value = u16::from_be_bytes(tmp_vec); - values.push(value); - } - - let mut salt_len_vec = [0u8; 2]; - salt_len_vec.copy_from_slice(get_slice(data, third_position + 30, third_position + 32)?); - let salt_len = u16::from_be_bytes(salt_len_vec) as usize; - - if salt_len > subnet_size { - log::error!( - "salt len as {} in reveal weight is more than neurons {} in subnet {}", - salt_len, - subnet_size, - netuid - ); - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - for i in 0..salt_len { - let mut tmp_vec = [0u8; 2]; - let from = third_position - .saturating_add(62) - .saturating_add(i.saturating_mul(32)); - let to = from.saturating_add(2); - tmp_vec.copy_from_slice(get_slice(data, from, to)?); - let value = u16::from_be_bytes(tmp_vec); - salt.push(value); - } - - Ok((netuid, uids, values, salt, version_key)) - } +impl PrecompileExt for NeuronPrecompile { + const INDEX: u64 = 2052; + const ADDRESS_SS58: [u8; 32] = [ + 0xbc, 0x46, 0x35, 0x79, 0xbc, 0x99, 0xf9, 0xee, 0x7c, 0x59, 0xed, 0xee, 0x20, 0x61, 0xa3, + 0x09, 0xd2, 0x1e, 0x68, 0xd5, 0x39, 0xb6, 0x40, 0xec, 0x66, 0x46, 0x90, 0x30, 0xab, 0x74, + 0xc1, 0xdb, + ]; } diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs index c368df6ad..d99b0199e 100644 --- a/runtime/src/precompiles/staking.rs +++ b/runtime/src/precompiles/staking.rs @@ -37,20 +37,11 @@ use sp_runtime::AccountId32; use sp_std::vec; use crate::precompiles::{ - get_method_id, get_pubkey, get_slice, parse_netuid, try_dispatch_runtime_call, - try_u16_from_u256, + get_method_id, parse_slice, parse_netuid, parse_pubkey, try_u16_from_u256, PrecompileExt, + PrecompileHandleExt, }; use crate::{ProxyType, Runtime, RuntimeCall}; -pub const STAKING_PRECOMPILE_INDEX: u64 = 2049; - -// ss58 public key i.e., the contract sends funds it received to the destination address from the -// method parameter. -const CONTRACT_ADDRESS_SS58: [u8; 32] = [ - 0x26, 0xf4, 0x10, 0x1e, 0x52, 0xb7, 0x57, 0x34, 0x33, 0x24, 0x5b, 0xc3, 0x0a, 0xe1, 0x8b, 0x63, - 0x99, 0x53, 0xd8, 0x41, 0x79, 0x33, 0x03, 0x61, 0x4d, 0xfa, 0xcf, 0xf0, 0x37, 0xf7, 0x12, 0x94, -]; - pub struct StakingPrecompile; #[precompile_utils::precompile] @@ -58,34 +49,23 @@ impl StakingPrecompile { #[precompile::public("addStake(bytes32,uint256)")] #[precompile::payable] fn add_stake(handle: &mut impl PrecompileHandle, address: H256, netuid: U256) -> EvmResult<()> { - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - + let account_id = handle.caller_account_id(); let amount = handle.context().apparent_value; if !amount.is_zero() { Self::transfer_back_to_caller(&account_id, amount)?; } - let amount_sub = - ::BalanceConverter::into_substrate_balance(amount) - .ok_or(PrecompileFailure::Error { - exit_status: ExitError::Other( - "error converting balance from ETH to subtensor".into(), - ), - })?; - - let (hotkey, _) = get_pubkey(address.as_bytes())?; + let amount_sub = handle.try_convert_apparent_value()?; + let (hotkey, _) = parse_pubkey(address.as_bytes())?; let netuid = try_u16_from_u256(netuid)?; - let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::::add_stake { + let call = pallet_subtensor::Call::::add_stake { hotkey, netuid, amount_staked: amount_sub.unique_saturated_into(), - }); + }; - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(account_id)) } #[precompile::public("removeStake(bytes32,uint256,uint256)")] @@ -95,55 +75,45 @@ impl StakingPrecompile { amount: U256, netuid: U256, ) -> EvmResult<()> { - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - - let (hotkey, _) = get_pubkey(address.as_bytes())?; + let account_id = handle.caller_account_id(); + let (hotkey, _) = parse_pubkey(address.as_bytes())?; let netuid = try_u16_from_u256(netuid)?; let amount_unstaked = amount.unique_saturated_into(); - let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::::remove_stake { + let call = pallet_subtensor::Call::::remove_stake { hotkey, netuid, amount_unstaked, - }); + }; - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(account_id)) } #[precompile::public("addProxy(bytes32)")] fn add_proxy(handle: &mut impl PrecompileHandle, delegate: H256) -> EvmResult<()> { - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - let (delegate, _) = get_pubkey(delegate.as_bytes())?; + let account_id = handle.caller_account_id(); + let (delegate, _) = parse_pubkey(delegate.as_bytes())?; let delegate = ::Lookup::unlookup(delegate); - let call = RuntimeCall::Proxy(pallet_proxy::Call::::add_proxy { + let call = pallet_proxy::Call::::add_proxy { delegate, proxy_type: ProxyType::Staking, delay: 0, - }); + }; - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(account_id)) } #[precompile::public("removeProxy(bytes32)")] fn remove_proxy(handle: &mut impl PrecompileHandle, delegate: H256) -> EvmResult<()> { - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - let (delegate, _) = get_pubkey(delegate.as_bytes())?; + let account_id = handle.caller_account_id(); + let (delegate, _) = parse_pubkey(delegate.as_bytes())?; let delegate = ::Lookup::unlookup(delegate); - let call = RuntimeCall::Proxy(pallet_proxy::Call::::remove_proxy { + let call = pallet_proxy::Call::::remove_proxy { delegate, proxy_type: ProxyType::Staking, delay: 0, - }); + }; - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(account_id)) } #[precompile::public("getStake(bytes32,bytes32,uint256)")] @@ -154,10 +124,9 @@ impl StakingPrecompile { coldkey: H256, netuid: U256, ) -> EvmResult { - let (hotkey, _) = get_pubkey(hotkey.as_bytes())?; - let (coldkey, _) = get_pubkey(coldkey.as_bytes())?; + let (hotkey, _) = parse_pubkey(hotkey.as_bytes())?; + let (coldkey, _) = parse_pubkey(coldkey.as_bytes())?; let netuid = try_u16_from_u256(netuid)?; - let stake = pallet_subtensor::Pallet::::get_stake_for_hotkey_and_coldkey_on_subnet( &hotkey, &coldkey, netuid, ); @@ -169,8 +138,7 @@ impl StakingPrecompile { account_id: &AccountId32, amount: U256, ) -> Result<(), PrecompileFailure> { - let smart_contract_account_id: AccountId32 = CONTRACT_ADDRESS_SS58.into(); - + let smart_contract_account_id: AccountId32 = Self::ADDRESS_SS58.into(); let amount_sub = ::BalanceConverter::into_substrate_balance(amount) .ok_or(ExitError::OutOfFund)?; @@ -199,3 +167,12 @@ impl StakingPrecompile { Ok(()) } } + +impl PrecompileExt for StakingPrecompile { + const INDEX: u64 = 2049; + const ADDRESS_SS58: [u8; 32] = [ + 0x26, 0xf4, 0x10, 0x1e, 0x52, 0xb7, 0x57, 0x34, 0x33, 0x24, 0x5b, 0xc3, 0x0a, 0xe1, 0x8b, + 0x63, 0x99, 0x53, 0xd8, 0x41, 0x79, 0x33, 0x03, 0x61, 0x4d, 0xfa, 0xcf, 0xf0, 0x37, 0xf7, + 0x12, 0x94, + ]; +} diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs index dbaad74e0..8a46cc7dc 100644 --- a/runtime/src/precompiles/subnet.rs +++ b/runtime/src/precompiles/subnet.rs @@ -8,20 +8,15 @@ use sp_core::U256; use sp_runtime::{traits::BlakeTwo256, AccountId32, Vec}; use sp_std::vec; -use crate::precompiles::{get_method_id, get_pubkey, get_slice, try_dispatch_runtime_call}; +use crate::precompiles::{ + get_method_id, parse_slice, parse_pubkey, PrecompileExt, PrecompileHandleExt, +}; use crate::{Runtime, RuntimeCall}; -pub const SUBNET_PRECOMPILE_INDEX: u64 = 2051; // bytes with max lenght 1K -pub const MAX_SINGLE_PARAMETER_SIZE: usize = 1024; +const MAX_SINGLE_PARAMETER_SIZE: usize = 1024; // 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 -#[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, - 0xd0, 0x9f, 0xac, 0x26, 0xf2, 0x02, 0x70, 0x85, 0xb3, 0x1c, 0x56, 0xc1, 0x06, 0x3c, 0x1c, 0xd3, -]; +const MAX_PARAMETER_SIZE: usize = 7 * MAX_SINGLE_PARAMETER_SIZE; pub struct SubnetPrecompile; @@ -1413,3 +1408,12 @@ impl SubnetPrecompile { // Ok((netuid, parameter)) // } } + +impl PrecompileExt for SubnetPrecompile { + const INDEX: u64 = 2051; + const ADDRESS_SS58: [u8; 32] = [ + 0x3a, 0x86, 0x18, 0xfb, 0xbb, 0x1b, 0xbc, 0x47, 0x86, 0x64, 0xff, 0x53, 0x46, 0x18, 0x0c, + 0x35, 0xd0, 0x9f, 0xac, 0x26, 0xf2, 0x02, 0x70, 0x85, 0xb3, 0x1c, 0x56, 0xc1, 0x06, 0x3c, + 0x1c, 0xd3, + ]; +} From 2cfdb41ba29174cad3ae1e46808b1f2fa8c53c12 Mon Sep 17 00:00:00 2001 From: Aliaksandr Tsurko Date: Fri, 14 Feb 2025 17:43:19 +0100 Subject: [PATCH 07/47] Refactor metagraph precompile --- runtime/src/precompiles/metagraph.rs | 418 ++++++++------------------- 1 file changed, 115 insertions(+), 303 deletions(-) diff --git a/runtime/src/precompiles/metagraph.rs b/runtime/src/precompiles/metagraph.rs index 365e55144..bf20f05bc 100644 --- a/runtime/src/precompiles/metagraph.rs +++ b/runtime/src/precompiles/metagraph.rs @@ -1,7 +1,12 @@ +extern crate alloc; +use alloc::string::String; + use fp_evm::{ ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, }; -use sp_core::{ByteArray, U256}; +use pallet_subtensor::AxonInfo as SubtensorModuleAxonInfo; +use precompile_utils::{solidity::Codec, EvmResult}; +use sp_core::{ByteArray, H256, U256}; use sp_std::vec; use crate::precompiles::{get_method_id, parse_slice, PrecompileExt, PrecompileHandleExt}; @@ -9,354 +14,138 @@ use crate::Runtime; pub struct MetagraphPrecompile; -const NO_HOTKEY: &str = "no hotkey"; - #[precompile_utils::precompile] impl MetagraphPrecompile { - // pub fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { - // let txdata = handle.input(); - // let method_id = get_slice(txdata, 0, 4)?; - // let method_input = txdata - // .get(4..) - // .map_or_else(vec::Vec::new, |slice| slice.to_vec()); // Avoiding borrowing conflicts - - // match method_id { - // id if id == get_method_id("getUidCount(uint16)") => Self::get_uid_count(&method_input), - // id if id == get_method_id("getStake(uint16,uint16)") => Self::get_stake(&method_input), - // id if id == get_method_id("getRank(uint16,uint16)") => Self::get_rank(&method_input), - // id if id == get_method_id("getTrust(uint16,uint16)") => Self::get_trust(&method_input), - // id if id == get_method_id("getConsensus(uint16,uint16)") => { - // Self::get_consensus(&method_input) - // } - // id if id == get_method_id("getIncentive(uint16,uint16)") => { - // Self::get_incentive(&method_input) - // } - // id if id == get_method_id("getDividends(uint16,uint16)") => { - // Self::get_dividends(&method_input) - // } - // id if id == get_method_id("getEmission(uint16,uint16)") => { - // Self::get_emission(&method_input) - // } - // id if id == get_method_id("getVtrust(uint16,uint16)") => { - // Self::get_vtrust(&method_input) - // } - // id if id == get_method_id("getValidatorStatus(uint16,uint16)") => { - // Self::get_validator_status(&method_input) - // } - // id if id == get_method_id("getLastUpdate(uint16,uint16)") => { - // Self::get_last_update(&method_input) - // } - // id if id == get_method_id("getIsActive(uint16,uint16)") => { - // Self::get_is_active(&method_input) - // } - // id if id == get_method_id("getAxon(uint16,uint16)") => Self::get_axon(&method_input), - // id if id == get_method_id("getHotkey(uint16,uint16)") => { - // Self::get_hotkey(&method_input) - // } - // id if id == get_method_id("getColdkey(uint16,uint16)") => { - // Self::get_coldkey(&method_input) - // } - - // _ => Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }), - // } - // } - - fn get_uid_count(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid_count = pallet_subtensor::SubnetworkN::::get(netuid); - - let uid_count_u256 = U256::from(uid_count); - let mut result = [0_u8; 32]; - U256::to_big_endian(&uid_count_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getUidCount(uint16)")] + #[precompile::view] + fn get_uid_count(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::SubnetworkN::::get(netuid)) } - fn get_stake(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; + #[precompile::public("getStake(uint16,uint16)")] + #[precompile::view] + fn get_stake(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { let hotkey = pallet_subtensor::Pallet::::get_hotkey_for_net_and_uid(netuid, uid) .map_err(|_| PrecompileFailure::Error { exit_status: ExitError::InvalidRange, })?; - let stake = pallet_subtensor::Pallet::::get_total_stake_for_hotkey(&hotkey); - let result_u256 = U256::from(stake); - let mut result = [0_u8; 32]; - U256::to_big_endian(&result_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + Ok(pallet_subtensor::Pallet::::get_total_stake_for_hotkey(&hotkey)) } - fn get_rank(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; - let rank = pallet_subtensor::Pallet::::get_rank_for_uid(netuid, uid); - - let result_u256 = U256::from(rank); - let mut result = [0_u8; 32]; - U256::to_big_endian(&result_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getRank(uint16,uint16)")] + #[precompile::view] + fn get_rank(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + Ok(pallet_subtensor::Pallet::::get_rank_for_uid( + netuid, uid, + )) } - fn get_trust(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; - - let trust = pallet_subtensor::Pallet::::get_trust_for_uid(netuid, uid); - - let result_u256 = U256::from(trust); - let mut result = [0_u8; 32]; - U256::to_big_endian(&result_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getTrust(uint16,uint16)")] + #[precompile::view] + fn get_trust(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + Ok(pallet_subtensor::Pallet::::get_trust_for_uid( + netuid, uid, + )) } - fn get_consensus(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; - - let consensus = pallet_subtensor::Pallet::::get_consensus_for_uid(netuid, uid); - - let result_u256 = U256::from(consensus); - let mut result = [0_u8; 32]; - U256::to_big_endian(&result_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getConsensus(uint16,uint16)")] + #[precompile::view] + fn get_consensus(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + Ok(pallet_subtensor::Pallet::::get_consensus_for_uid( + netuid, uid, + )) } - fn get_incentive(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; - - let incentive = pallet_subtensor::Pallet::::get_incentive_for_uid(netuid, uid); - - let result_u256 = U256::from(incentive); - let mut result = [0_u8; 32]; - U256::to_big_endian(&result_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getIncentive(uint16,uint16)")] + #[precompile::view] + fn get_incentive(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + Ok(pallet_subtensor::Pallet::::get_incentive_for_uid( + netuid, uid, + )) } - fn get_dividends(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; - - let dividends = pallet_subtensor::Pallet::::get_dividends_for_uid(netuid, uid); - - let result_u256 = U256::from(dividends); - let mut result = [0_u8; 32]; - U256::to_big_endian(&result_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getDividends(uint16,uint16)")] + #[precompile::view] + fn get_dividends(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + Ok(pallet_subtensor::Pallet::::get_dividends_for_uid( + netuid, uid, + )) } - fn get_emission(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; - - let emission = pallet_subtensor::Pallet::::get_emission_for_uid(netuid, uid); - - let result_u256 = U256::from(emission); - let mut result = [0_u8; 32]; - U256::to_big_endian(&result_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getEmission(uint16,uint16)")] + #[precompile::view] + fn get_emission(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + Ok(pallet_subtensor::Pallet::::get_emission_for_uid( + netuid, uid, + )) } - fn get_vtrust(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; - - let vtrust = pallet_subtensor::Pallet::::get_validator_trust_for_uid(netuid, uid); - - let result_u256 = U256::from(vtrust); - let mut result = [0_u8; 32]; - U256::to_big_endian(&result_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getVtrust(uint16,uint16)")] + #[precompile::view] + fn get_vtrust(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + Ok(pallet_subtensor::Pallet::::get_validator_trust_for_uid(netuid, uid)) } - fn get_validator_status(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; - - let validator_permit = - pallet_subtensor::Pallet::::get_validator_permit_for_uid(netuid, uid); - - let result_u256 = if validator_permit { - U256::from(1) - } else { - U256::from(0) - }; - let mut result = [0_u8; 32]; - U256::to_big_endian(&result_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getValidatorStatus(uint16,uint16)")] + #[precompile::view] + fn get_validator_status( + handle: &mut impl PrecompileHandle, + netuid: u16, + uid: u16, + ) -> EvmResult { + Ok(pallet_subtensor::Pallet::::get_validator_permit_for_uid(netuid, uid)) } - fn get_last_update(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; - - let last_update = pallet_subtensor::Pallet::::get_last_update_for_uid(netuid, uid); - - let result_u256 = U256::from(last_update); - let mut result = [0_u8; 32]; - U256::to_big_endian(&result_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getLastUpdate(uint16,uint16)")] + #[precompile::view] + fn get_last_update( + handle: &mut impl PrecompileHandle, + netuid: u16, + uid: u16, + ) -> EvmResult { + Ok(pallet_subtensor::Pallet::::get_last_update_for_uid(netuid, uid)) } - fn get_is_active(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; - - let active = pallet_subtensor::Pallet::::get_active_for_uid(netuid, uid); - - let result_u256 = if active { U256::from(1) } else { U256::from(0) }; - let mut result = [0_u8; 32]; - U256::to_big_endian(&result_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getIsActive(uint16,uint16)")] + #[precompile::view] + fn get_is_active(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + Ok(pallet_subtensor::Pallet::::get_active_for_uid( + netuid, uid, + )) } - fn get_axon(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; - + #[precompile::public("getAxon(uint16,uint16)")] + #[precompile::view] + fn get_axon(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { let hotkey = pallet_subtensor::Pallet::::get_hotkey_for_net_and_uid(netuid, uid) .map_err(|_| PrecompileFailure::Error { - exit_status: ExitError::Other(sp_version::Cow::Borrowed(NO_HOTKEY)), + exit_status: ExitError::Other("hotkey not found".into()), })?; - let axon = pallet_subtensor::Pallet::::get_axon_info(netuid, &hotkey); - - let mut block_result = [0_u8; 32]; - U256::to_big_endian(&U256::from(axon.block), &mut block_result); - - let mut version_result = [0_u8; 32]; - U256::to_big_endian(&U256::from(axon.version), &mut version_result); - - let mut ip_result = [0_u8; 32]; - U256::to_big_endian(&U256::from(axon.ip), &mut ip_result); - - let mut port_result = [0_u8; 32]; - U256::to_big_endian(&U256::from(axon.port), &mut port_result); - - let mut ip_type_result = [0_u8; 32]; - U256::to_big_endian(&U256::from(axon.ip_type), &mut ip_type_result); - - let mut protocol_result = [0_u8; 32]; - U256::to_big_endian(&U256::from(axon.protocol), &mut protocol_result); - - let mut result = [0_u8; 192]; - result[..32].copy_from_slice(&block_result); - result[32..64].copy_from_slice(&version_result); - result[64..96].copy_from_slice(&ip_result); - result[96..128].copy_from_slice(&port_result); - result[128..160].copy_from_slice(&ip_type_result); - result[160..].copy_from_slice(&protocol_result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + Ok(pallet_subtensor::Pallet::::get_axon_info(netuid, &hotkey).into()) } - fn get_hotkey(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; - - let hotkey = pallet_subtensor::Pallet::::get_hotkey_for_net_and_uid(netuid, uid) + #[precompile::public("getHotkey(uint16,uint16)")] + #[precompile::view] + fn get_hotkey(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + pallet_subtensor::Pallet::::get_hotkey_for_net_and_uid(netuid, uid) + .map(|acc| H256::from_slice(acc.as_slice())) .map_err(|_| PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - })?; - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: hotkey.as_slice().into(), - }) + exit_status: ExitError::InvalidRange, + }) } - fn get_coldkey(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid = Self::parse_uid(parse_slice(data, 32, 64)?)?; - + #[precompile::public("getColdkey(uint16,uint16)")] + #[precompile::view] + fn get_coldkey(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { let hotkey = pallet_subtensor::Pallet::::get_hotkey_for_net_and_uid(netuid, uid) .map_err(|_| PrecompileFailure::Error { exit_status: ExitError::InvalidRange, })?; - let coldkey = pallet_subtensor::Owner::::get(&hotkey); - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: coldkey.as_slice().into(), - }) - } - - fn parse_netuid(data: &[u8]) -> Result { - if data.len() < 32 { - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - let mut netuid = [0u8; 2]; - netuid.copy_from_slice(parse_slice(data, 30, 32)?); - let result = u16::from_be_bytes(netuid); - Ok(result) - } - - fn parse_uid(data: &[u8]) -> Result { - if data.len() < 32 { - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - let mut uid = [0u8; 2]; - uid.copy_from_slice(parse_slice(data, 30, 32)?); - let result = u16::from_be_bytes(uid); - Ok(result) + Ok(H256::from_slice(coldkey.as_slice())) } } @@ -364,3 +153,26 @@ impl PrecompileExt for MetagraphPrecompile { const INDEX: u64 = 2050; const ADDRESS_SS58: [u8; 32] = [0; 32]; } + +#[derive(Codec)] +struct AxonInfo { + block: u64, + version: u32, + ip: u128, + port: u16, + ip_type: u8, + protocol: u8, +} + +impl From for AxonInfo { + fn from(value: SubtensorModuleAxonInfo) -> Self { + Self { + block: value.block, + version: value.version, + ip: value.ip, + port: value.port, + ip_type: value.ip_type, + protocol: value.protocol, + } + } +} From f1aa660469e86bf271cbbf495ecd3d1468375e84 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 14 Feb 2025 12:47:02 -0500 Subject: [PATCH 08/47] fix try runtime endpoints --- .github/workflows/try-runtime.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/try-runtime.yml b/.github/workflows/try-runtime.yml index 89a28c5c6..69179ef40 100644 --- a/.github/workflows/try-runtime.yml +++ b/.github/workflows/try-runtime.yml @@ -2,8 +2,6 @@ name: Try Runtime on: pull_request: - branches: [main, devnet-ready, devnet, testnet, finney] - types: [labeled, unlabeled, synchronize] env: CARGO_TERM_COLOR: always @@ -35,7 +33,7 @@ jobs: uses: "paritytech/try-runtime-gha@v0.1.0" with: runtime-package: "node-subtensor-runtime" - node-uri: "wss://test.chain.opentensor.ai:443" + node-uri: "wss://wss://archive.test.opentensor.ai:443" checks: "all" extra-args: "--disable-spec-version-check --no-weight-warnings" From d005830c4a76b06c2925b6836ba0fb998df1985f Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 14 Feb 2025 12:49:11 -0500 Subject: [PATCH 09/47] fix --- .github/workflows/try-runtime.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/try-runtime.yml b/.github/workflows/try-runtime.yml index 69179ef40..1375892b0 100644 --- a/.github/workflows/try-runtime.yml +++ b/.github/workflows/try-runtime.yml @@ -33,7 +33,7 @@ jobs: uses: "paritytech/try-runtime-gha@v0.1.0" with: runtime-package: "node-subtensor-runtime" - node-uri: "wss://wss://archive.test.opentensor.ai:443" + node-uri: "wss://wss://test-archive.dev.opentensor.ai:443" checks: "all" extra-args: "--disable-spec-version-check --no-weight-warnings" From 51b3d1c5126db41e566ef128d0be97fce73e3929 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 14 Feb 2025 12:54:57 -0500 Subject: [PATCH 10/47] bump CI From fbe1cbba17708994e13b204ce9814c78dea1c03a Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 14 Feb 2025 12:58:59 -0500 Subject: [PATCH 11/47] only run non-devnet try runtime if we are targeting devnet/testnet/main --- .github/workflows/try-runtime.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/try-runtime.yml b/.github/workflows/try-runtime.yml index 1375892b0..0d740cef0 100644 --- a/.github/workflows/try-runtime.yml +++ b/.github/workflows/try-runtime.yml @@ -24,6 +24,7 @@ jobs: check-testnet: name: check testnet + if: contains(github.base_ref, 'testnet') || contains(github.base_ref, 'devnet') || contains(github.base_ref, 'main') runs-on: SubtensorCI steps: - name: Checkout sources @@ -33,16 +34,18 @@ jobs: uses: "paritytech/try-runtime-gha@v0.1.0" with: runtime-package: "node-subtensor-runtime" - node-uri: "wss://wss://test-archive.dev.opentensor.ai:443" + node-uri: "wss://test-archive.dev.opentensor.ai:443" checks: "all" extra-args: "--disable-spec-version-check --no-weight-warnings" check-finney: name: check finney + if: contains(github.base_ref, 'testnet') || contains(github.base_ref, 'devnet') || contains(github.base_ref, 'main') runs-on: SubtensorCI steps: - name: Checkout sources uses: actions/checkout@v4 + - name: Run Try Runtime Checks uses: "paritytech/try-runtime-gha@v0.1.0" with: From 35a87a6664167caf59f3292a3e8116511c657430 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 14 Feb 2025 13:03:19 -0500 Subject: [PATCH 12/47] tweak --- .github/workflows/try-runtime.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/try-runtime.yml b/.github/workflows/try-runtime.yml index 0d740cef0..9bce50fb5 100644 --- a/.github/workflows/try-runtime.yml +++ b/.github/workflows/try-runtime.yml @@ -24,7 +24,7 @@ jobs: check-testnet: name: check testnet - if: contains(github.base_ref, 'testnet') || contains(github.base_ref, 'devnet') || contains(github.base_ref, 'main') + if: github.base_ref == 'testnet' || github.base_ref == 'devnet' || github.base_ref == 'main' runs-on: SubtensorCI steps: - name: Checkout sources @@ -40,7 +40,7 @@ jobs: check-finney: name: check finney - if: contains(github.base_ref, 'testnet') || contains(github.base_ref, 'devnet') || contains(github.base_ref, 'main') + if: github.base_ref == 'testnet' || github.base_ref == 'devnet' || github.base_ref == 'main' runs-on: SubtensorCI steps: - name: Checkout sources From 85f72d9dc4773f82019016e770238a44a89b8185 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Sun, 16 Feb 2025 21:53:40 -0500 Subject: [PATCH 13/47] mainnet deploy 2/16/2025 (#1310) * upgrade openssl * fix clippy * address freeze_struct * rename commit_reveal_period * apply criticial openssl update to fix RUSTSEC-2025-0004 (openssl) * remove subnet_info_v3 * address lint * update register_network with identity precompile * fix merge commit * bump spec * remove SubnetInfov3 struct * rename emission_values => emission_value * bump spec * safe math * remove duplicated function * use saturating math * add cleaned coinbase * noclaim * remove complexity * non scaled tao emission * bump * fix test * clean coinbase * pre merge * no tao in for non registration * move to moving prices rather than tao reserves * price * moving alpha * bump spec * Fix tests * add moving price tests * add alpha in tests * Fix all tests * Format * Fix unsafe math * alpha tests * set tao weight * reset default staking fee * fix names * add mainnet names * cargo clippy * cargo fmt * add a global min burn and migration * add more tests for root pending etc * alpha divs * fix test for root * new test root tao * fix wrong parse function * fix test * add toggle off for transfers * delete unused workflow file * Fix validation for transfer toggle * remove duplicate tests * fix subnet creation logic * cargo fmt * add new test * bump spec version to 228 * Add test test_drain_alpha_childkey_parentkey * spec bump * fix audit * fix audit * fix contract * commit Cargo.lock * cargo clippy * cargo fmt * fix min lock * fmt * fix migration test * cargo fmt * fix root * cargo fmt * add moving price to metagraph * use correct min burn init (#1265) * use correct min brun init * fmt * no into * no into 2 * bump spec * cargo update to fix cargo audit vulnerabilities * bump spec version * moving price init from emission * cargo fmt * bump spec version * commit Cargo.lock * cargo clippy * cargo fmt * DefaultMinimumPoolLiquidity and tempos in rao migration * update readme of support of M series macs * bump runtime version * add tao_emission to stakeinfo runtime * remove call from coinbase. already in block_step * add negation for pow-reg-allowed * only root can set min pow diff * oops * dont let ck-in-swap-sched move any stake/register * add tests for validation filter * add transfer stake to call nontransfer proxy filter * also add proxy filters for new calls * update staking priority * bump spec * use get_priority_staking for all stake operations * bump spec * clippy * Remove ownership check from transition stake validation * max the price for EMA calc at 1.0 * uncommitted lockfile change * bump spec version * fix merge conflicts * add CI action that requires clean merges between all named branches * fix * fixes * try again * fix again * fix * fix * stop needless wasting of CI hours with on push triggers we don't need * provide an identity for github action to prevent failure * Add serve_axon extrinsic validation * Bump spec version * Check IP validity in serve_axon validation first * make set diff only root * add test for set diff no owner * add migration for min diff * bump spec * only allow top-stake SN owner hk to stay immune * add tests * only allow replace non-top-stake owner hk * bump spec * add tests using SubnetOwnerHotkey * add impl for replace neuron * add swap test * add neuron prune impl * add swap hotkey impl * clippy * clippy * mistake in test * add some tests * add stake ext test * add move_stake tests * cargo lock * bump spec * clpy * use bool return type * clpy * add higher liquidity on mvoe stake tests --------- Co-authored-by: open-junius Co-authored-by: Aliaksandr Tsurko Co-authored-by: JohnReedV <87283488+JohnReedV@users.noreply.github.com> Co-authored-by: Cameron Fairchild Co-authored-by: unconst Co-authored-by: Greg Zaitsev Co-authored-by: Unconst <32490803+unconst@users.noreply.github.com> Co-authored-by: camfairchild Co-authored-by: Prakash Co-authored-by: ibraheem-opentensor --- pallets/subtensor/src/staking/stake_utils.rs | 39 ++- pallets/subtensor/src/tests/staking.rs | 275 ++++++++++++++++++- primitives/share-pool/src/lib.rs | 23 ++ runtime/src/lib.rs | 2 +- 4 files changed, 332 insertions(+), 7 deletions(-) diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index 854fb07cb..07be25171 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -549,6 +549,15 @@ impl Pallet { alpha_share_pool.update_value_for_one(coldkey, amount as i64); } + pub fn try_increase_stake_for_hotkey_and_coldkey_on_subnet( + hotkey: &T::AccountId, + netuid: u16, + amount: u64, + ) -> bool { + let mut alpha_share_pool = Self::get_alpha_share_pool(hotkey.clone(), netuid); + alpha_share_pool.sim_update_value_for_one(amount as i64) + } + /// Sell shares in the hotkey on a given subnet /// /// The function updates share totals given current prices. @@ -877,11 +886,18 @@ impl Pallet { Error::::HotKeyAccountNotExists ); + let expected_alpha = Self::sim_swap_tao_for_alpha(netuid, stake_to_be_added); + // Ensure that we have adequate liquidity - ensure!( - Self::sim_swap_tao_for_alpha(netuid, stake_to_be_added).is_some(), - Error::::InsufficientLiquidity + ensure!(expected_alpha.is_some(), Error::::InsufficientLiquidity); + + // Ensure hotkey pool is precise enough + let try_stake_result = Self::try_increase_stake_for_hotkey_and_coldkey_on_subnet( + hotkey, + netuid, + expected_alpha.unwrap_or(0), ); + ensure!(try_stake_result, Error::::InsufficientLiquidity); Ok(()) } @@ -937,7 +953,7 @@ impl Pallet { origin_coldkey: &T::AccountId, _destination_coldkey: &T::AccountId, origin_hotkey: &T::AccountId, - _destination_hotkey: &T::AccountId, + destination_hotkey: &T::AccountId, origin_netuid: u16, destination_netuid: u16, alpha_amount: u64, @@ -975,7 +991,8 @@ impl Pallet { ); // Ensure that the stake amount to be removed is above the minimum in tao equivalent. - if let Some(tao_equivalent) = Self::sim_swap_alpha_for_tao(origin_netuid, alpha_amount) { + let tao_equivalent_result = Self::sim_swap_alpha_for_tao(origin_netuid, alpha_amount); + if let Some(tao_equivalent) = tao_equivalent_result { ensure!( tao_equivalent > DefaultMinStake::::get(), Error::::AmountTooLow @@ -992,6 +1009,18 @@ impl Pallet { } } + let expected_alpha = + Self::sim_swap_tao_for_alpha(destination_netuid, tao_equivalent_result.unwrap_or(0)) + .unwrap_or(0); + + // Ensure that the amount being staked to the new hotkey is precise enough + let try_stake_result = Self::try_increase_stake_for_hotkey_and_coldkey_on_subnet( + destination_hotkey, + destination_netuid, + expected_alpha, + ); + ensure!(try_stake_result, Error::::InsufficientLiquidity); + if check_transfer_toggle { // Ensure transfer is toggled. ensure!( diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs index 5282c9941..f97373b0b 100644 --- a/pallets/subtensor/src/tests/staking.rs +++ b/pallets/subtensor/src/tests/staking.rs @@ -10,7 +10,7 @@ use approx::assert_abs_diff_eq; use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}; use frame_support::sp_runtime::DispatchError; use sp_core::{Get, H256, U256}; -use substrate_fixed::types::{I96F32, U96F32}; +use substrate_fixed::types::{I96F32, U64F64, U96F32}; /*********************************************************** staking::add_stake() tests @@ -3495,3 +3495,276 @@ fn test_remove_stake_limit_fill_or_kill() { ),); }); } + +// #[test] +// fn test_add_stake_specific() { +// new_test_ext(1).execute_with(|| { +// let sn_owner_coldkey = U256::from(55453); + +// let hotkey_account_id = U256::from(533453); +// let coldkey_account_id = U256::from(55454); +// let hotkey_owner_account_id = U256::from(533454); + +// let existing_shares: U64F64 = +// U64F64::from_num(161_986_254).saturating_div(U64F64::from_num(u64::MAX)); +// let existing_stake = 36_711_495_953; +// let amount_added = 1_274_280_132; + +// //add network +// let netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey); + +// // Register hotkey on netuid +// register_ok_neuron(netuid, hotkey_account_id, hotkey_owner_account_id, 0); +// // Check we have zero staked +// assert_eq!( +// SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), +// 0 +// ); + +// // Set a hotkey pool for the hotkey +// let mut hotkey_pool = SubtensorModule::get_alpha_share_pool(hotkey_account_id, netuid); +// hotkey_pool.update_value_for_one(&hotkey_owner_account_id, 1234); // Doesn't matter, will be overridden + +// // Adjust the total hotkey stake and shares to match the existing values +// TotalHotkeyShares::::insert(hotkey_account_id, netuid, existing_shares); +// TotalHotkeyAlpha::::insert(hotkey_account_id, netuid, existing_stake); + +// // Make the hotkey a delegate +// Delegates::::insert(hotkey_account_id, 0); + +// // Add stake as new hotkey +// SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( +// &hotkey_account_id, +// &coldkey_account_id, +// netuid, +// amount_added, +// ); + +// // Check the stake and shares are correct +// assert!(Alpha::::get((&hotkey_account_id, &coldkey_account_id, netuid)) > 0); +// assert_eq!( +// TotalHotkeyAlpha::::get(hotkey_account_id, netuid), +// amount_added + existing_stake +// ); +// }); +// } + +// #[test] +// // RUST_LOG=info cargo test --package pallet-subtensor --lib -- tests::staking::test_add_stake_specific_stake_into_subnet --exact --show-output +// fn test_add_stake_specific_stake_into_subnet() { +// new_test_ext(1).execute_with(|| { +// let sn_owner_coldkey = U256::from(55453); + +// let hotkey_account_id = U256::from(533453); +// let coldkey_account_id = U256::from(55454); +// let hotkey_owner_account_id = U256::from(533454); + +// let existing_shares: U64F64 = +// U64F64::from_num(161_986_254).saturating_div(U64F64::from_num(u64::MAX)); +// let existing_stake = 36_711_495_953; + +// let tao_in = 2_409_892_148_947; +// let alpha_in = 15_358_708_513_716; + +// let tao_staked = 200_000_000; +// let fee = DefaultStakingFee::::get(); + +// //add network +// let netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey); + +// // Register hotkey on netuid +// register_ok_neuron(netuid, hotkey_account_id, hotkey_owner_account_id, 0); +// // Check we have zero staked +// assert_eq!( +// SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), +// 0 +// ); + +// // Set a hotkey pool for the hotkey +// let mut hotkey_pool = SubtensorModule::get_alpha_share_pool(hotkey_account_id, netuid); +// hotkey_pool.update_value_for_one(&hotkey_owner_account_id, 1234); // Doesn't matter, will be overridden + +// // Adjust the total hotkey stake and shares to match the existing values +// TotalHotkeyShares::::insert(hotkey_account_id, netuid, existing_shares); +// TotalHotkeyAlpha::::insert(hotkey_account_id, netuid, existing_stake); + +// // Make the hotkey a delegate +// Delegates::::insert(hotkey_account_id, 0); + +// // Setup Subnet pool +// SubnetAlphaIn::::insert(netuid, alpha_in); +// SubnetTAO::::insert(netuid, tao_in); + +// // Add stake as new hotkey +// SubtensorModule::stake_into_subnet( +// &hotkey_account_id, +// &coldkey_account_id, +// netuid, +// tao_staked, +// fee, +// ); + +// // Check the stake and shares are correct +// assert!(Alpha::::get((&hotkey_account_id, &coldkey_account_id, netuid)) > 0); +// log::info!( +// "Alpha: {}", +// Alpha::::get((&hotkey_account_id, &coldkey_account_id, netuid)) +// ); +// log::info!( +// "TotalHotkeyAlpha: {}", +// TotalHotkeyAlpha::::get(hotkey_account_id, netuid) +// ); +// }); +// } + +#[test] +// RUST_LOG=info cargo test --package pallet-subtensor --lib -- tests::staking::test_add_stake_specific_stake_into_subnet_fail --exact --show-output +fn test_add_stake_specific_stake_into_subnet_fail() { + new_test_ext(1).execute_with(|| { + let sn_owner_coldkey = U256::from(55453); + + let hotkey_account_id = U256::from(533453); + let coldkey_account_id = U256::from(55454); + let hotkey_owner_account_id = U256::from(533454); + + let existing_shares: U64F64 = + U64F64::from_num(161_986_254).saturating_div(U64F64::from_num(u64::MAX)); + let existing_stake = 36_711_495_953; + + let tao_in = 2_409_892_148_947; + let alpha_in = 15_358_708_513_716; + + let tao_staked = 200_000_000; + + //add network + let netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey); + + // Register hotkey on netuid + register_ok_neuron(netuid, hotkey_account_id, hotkey_owner_account_id, 0); + // Check we have zero staked + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + 0 + ); + + // Set a hotkey pool for the hotkey + let mut hotkey_pool = SubtensorModule::get_alpha_share_pool(hotkey_account_id, netuid); + hotkey_pool.update_value_for_one(&hotkey_owner_account_id, 1234); // Doesn't matter, will be overridden + + // Adjust the total hotkey stake and shares to match the existing values + TotalHotkeyShares::::insert(hotkey_account_id, netuid, existing_shares); + TotalHotkeyAlpha::::insert(hotkey_account_id, netuid, existing_stake); + + // Make the hotkey a delegate + Delegates::::insert(hotkey_account_id, 0); + + // Setup Subnet pool + SubnetAlphaIn::::insert(netuid, alpha_in); + SubnetTAO::::insert(netuid, tao_in); + + // Give TAO balance to coldkey + SubtensorModule::add_balance_to_coldkey_account( + &coldkey_account_id, + tao_staked + 1_000_000_000, + ); + + // Add stake as new hotkey + assert_noop!( + SubtensorModule::add_stake( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + netuid, + tao_staked, + ), + Error::::InsufficientLiquidity + ); + }); +} + +#[test] +// RUST_LOG=info cargo test --package pallet-subtensor --lib -- tests::staking::test_move_stake_specific_stake_into_subnet_fail --exact --show-output +fn test_move_stake_specific_stake_into_subnet_fail() { + new_test_ext(1).execute_with(|| { + let sn_owner_coldkey = U256::from(55453); + + let hotkey_account_id = U256::from(533453); + let coldkey_account_id = U256::from(55454); + let hotkey_owner_account_id = U256::from(533454); + + let existing_shares: U64F64 = + U64F64::from_num(161_986_254).saturating_div(U64F64::from_num(u64::MAX)); + let existing_stake = 36_711_495_953; + + let tao_in = 2_409_892_148_947; + let alpha_in = 15_358_708_513_716; + + let tao_staked = 200_000_000; + + //add network + let netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey); + + let origin_netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey); + + // Register hotkey on netuid + register_ok_neuron(netuid, hotkey_account_id, hotkey_owner_account_id, 0); + // Register hotkey on origin netuid + register_ok_neuron(origin_netuid, hotkey_account_id, hotkey_owner_account_id, 0); + + // Check we have zero staked + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + 0 + ); + + // Set a hotkey pool for the hotkey on destination subnet + let mut hotkey_pool = SubtensorModule::get_alpha_share_pool(hotkey_account_id, netuid); + hotkey_pool.update_value_for_one(&hotkey_owner_account_id, 1234); // Doesn't matter, will be overridden + + // Adjust the total hotkey stake and shares to match the existing values + TotalHotkeyShares::::insert(hotkey_account_id, netuid, existing_shares); + TotalHotkeyAlpha::::insert(hotkey_account_id, netuid, existing_stake); + + // Make the hotkey a delegate + Delegates::::insert(hotkey_account_id, 0); + + // Setup Subnet pool + SubnetAlphaIn::::insert(netuid, alpha_in); + SubnetTAO::::insert(netuid, tao_in); + + // Give TAO balance to coldkey + SubtensorModule::add_balance_to_coldkey_account( + &coldkey_account_id, + tao_staked + 1_000_000_000, + ); + + // Setup Subnet pool for origin netuid + SubnetAlphaIn::::insert(origin_netuid, alpha_in + 10_000_000); + SubnetTAO::::insert(origin_netuid, tao_in + 10_000_000); + + // Add stake as new hotkey + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + origin_netuid, + tao_staked, + ),); + let alpha_to_move = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_account_id, + &coldkey_account_id, + origin_netuid, + ); + + // Move stake to destination subnet + assert_noop!( + SubtensorModule::move_stake( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + hotkey_account_id, + origin_netuid, + netuid, + alpha_to_move, + ), + Error::::InsufficientLiquidity + ); + }); +} diff --git a/primitives/share-pool/src/lib.rs b/primitives/share-pool/src/lib.rs index f3e00fca9..8f963cfd3 100644 --- a/primitives/share-pool/src/lib.rs +++ b/primitives/share-pool/src/lib.rs @@ -75,6 +75,29 @@ where }); } + pub fn sim_update_value_for_one(&mut self, update: i64) -> bool { + let shared_value: U64F64 = self.state_ops.get_shared_value(); + let denominator: U64F64 = self.state_ops.get_denominator(); + + // Then, update this key's share + if denominator == 0 { + true + } else { + // There are already keys in the pool, set or update this key + let value_per_share: I64F64 = I64F64::saturating_from_num( + shared_value + .checked_div(denominator) // denominator is never 0 here + .unwrap_or(U64F64::saturating_from_num(0)), + ); + + let shares_per_update: I64F64 = I64F64::saturating_from_num(update) + .checked_div(value_per_share) + .unwrap_or(I64F64::saturating_from_num(0)); + + shares_per_update != 0 + } + } + /// Update the value associated with an item identified by the Key pub fn update_value_for_one(&mut self, key: &K, update: i64) { let shared_value: U64F64 = self.state_ops.get_shared_value(); diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index bc8d74dd2..8dcce09b1 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: 238, + spec_version: 239, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From c06a4e9ccd9c1826f45fba06bfd5068bc2a34a32 Mon Sep 17 00:00:00 2001 From: Aliaksandr Tsurko Date: Mon, 17 Feb 2025 16:02:35 +0100 Subject: [PATCH 14/47] Refactor subnet precompile --- runtime/src/precompiles/balance_transfer.rs | 18 +- runtime/src/precompiles/ed25519.rs | 10 +- runtime/src/precompiles/metagraph.rs | 10 +- runtime/src/precompiles/neuron.rs | 21 +- runtime/src/precompiles/solidity/subnet.abi | 46 +- runtime/src/precompiles/solidity/subnet.sol | 20 +- runtime/src/precompiles/staking.rs | 18 +- runtime/src/precompiles/subnet.rs | 1911 +++++-------------- 8 files changed, 583 insertions(+), 1471 deletions(-) diff --git a/runtime/src/precompiles/balance_transfer.rs b/runtime/src/precompiles/balance_transfer.rs index 14966867d..68b3edb37 100644 --- a/runtime/src/precompiles/balance_transfer.rs +++ b/runtime/src/precompiles/balance_transfer.rs @@ -17,6 +17,15 @@ use crate::Runtime; pub struct BalanceTransferPrecompile; +impl PrecompileExt for BalanceTransferPrecompile { + const INDEX: u64 = 2048; + const ADDRESS_SS58: [u8; 32] = [ + 0x07, 0xec, 0x71, 0x2a, 0x5d, 0x38, 0x43, 0x4d, 0xdd, 0x03, 0x3f, 0x8f, 0x02, 0x4e, 0xcd, + 0xfc, 0x4b, 0xb5, 0x95, 0x1c, 0x13, 0xc3, 0x08, 0x5c, 0x39, 0x9c, 0x8a, 0x5f, 0x62, 0x93, + 0x70, 0x5d, + ]; +} + #[precompile_utils::precompile] impl BalanceTransferPrecompile { #[precompile::public("transfer(bytes32)")] @@ -38,12 +47,3 @@ impl BalanceTransferPrecompile { handle.try_dispatch_runtime_call(call, contract_to_origin(&Self::ADDRESS_SS58)?) } } - -impl PrecompileExt for BalanceTransferPrecompile { - const INDEX: u64 = 2048; - const ADDRESS_SS58: [u8; 32] = [ - 0x07, 0xec, 0x71, 0x2a, 0x5d, 0x38, 0x43, 0x4d, 0xdd, 0x03, 0x3f, 0x8f, 0x02, 0x4e, 0xcd, - 0xfc, 0x4b, 0xb5, 0x95, 0x1c, 0x13, 0xc3, 0x08, 0x5c, 0x39, 0x9c, 0x8a, 0x5f, 0x62, 0x93, - 0x70, 0x5d, - ]; -} diff --git a/runtime/src/precompiles/ed25519.rs b/runtime/src/precompiles/ed25519.rs index 6ad082029..1a629df52 100644 --- a/runtime/src/precompiles/ed25519.rs +++ b/runtime/src/precompiles/ed25519.rs @@ -9,6 +9,11 @@ use crate::precompiles::{parse_slice, PrecompileExt}; pub struct Ed25519Verify; +impl PrecompileExt for Ed25519Verify { + const INDEX: u64 = 1026; + const ADDRESS_SS58: [u8; 32] = [0; 32]; +} + impl LinearCostPrecompile for Ed25519Verify { const BASE: u64 = 15; const WORD: u64 = 3; @@ -41,8 +46,3 @@ impl LinearCostPrecompile for Ed25519Verify { Ok((ExitSucceed::Returned, buf.to_vec())) } } - -impl PrecompileExt for Ed25519Verify { - const INDEX: u64 = 1026; - const ADDRESS_SS58: [u8; 32] = [0; 32]; -} diff --git a/runtime/src/precompiles/metagraph.rs b/runtime/src/precompiles/metagraph.rs index bf20f05bc..3677ede36 100644 --- a/runtime/src/precompiles/metagraph.rs +++ b/runtime/src/precompiles/metagraph.rs @@ -14,6 +14,11 @@ use crate::Runtime; pub struct MetagraphPrecompile; +impl PrecompileExt for MetagraphPrecompile { + const INDEX: u64 = 2050; + const ADDRESS_SS58: [u8; 32] = [0; 32]; +} + #[precompile_utils::precompile] impl MetagraphPrecompile { #[precompile::public("getUidCount(uint16)")] @@ -149,11 +154,6 @@ impl MetagraphPrecompile { } } -impl PrecompileExt for MetagraphPrecompile { - const INDEX: u64 = 2050; - const ADDRESS_SS58: [u8; 32] = [0; 32]; -} - #[derive(Codec)] struct AxonInfo { block: u64, diff --git a/runtime/src/precompiles/neuron.rs b/runtime/src/precompiles/neuron.rs index cb92a5dfd..4e0c9478c 100644 --- a/runtime/src/precompiles/neuron.rs +++ b/runtime/src/precompiles/neuron.rs @@ -15,11 +15,17 @@ use crate::precompiles::{ }; use crate::{Runtime, RuntimeCall}; -// max paramter lenght 4K -pub const MAX_PARAMETER_SIZE: usize = 4 * 1024; - pub struct NeuronPrecompile; +impl PrecompileExt for NeuronPrecompile { + const INDEX: u64 = 2052; + const ADDRESS_SS58: [u8; 32] = [ + 0xbc, 0x46, 0x35, 0x79, 0xbc, 0x99, 0xf9, 0xee, 0x7c, 0x59, 0xed, 0xee, 0x20, 0x61, 0xa3, + 0x09, 0xd2, 0x1e, 0x68, 0xd5, 0x39, 0xb6, 0x40, 0xec, 0x66, 0x46, 0x90, 0x30, 0xab, 0x74, + 0xc1, 0xdb, + ]; +} + #[precompile_utils::precompile] impl NeuronPrecompile { #[precompile::public("setWeights(uint16,uint16[],uint16[],uint64)")] @@ -91,12 +97,3 @@ impl NeuronPrecompile { handle.try_dispatch_runtime_call(call, RawOrigin::Signed(coldkey)) } } - -impl PrecompileExt for NeuronPrecompile { - const INDEX: u64 = 2052; - const ADDRESS_SS58: [u8; 32] = [ - 0xbc, 0x46, 0x35, 0x79, 0xbc, 0x99, 0xf9, 0xee, 0x7c, 0x59, 0xed, 0xee, 0x20, 0x61, 0xa3, - 0x09, 0xd2, 0x1e, 0x68, 0xd5, 0x39, 0xb6, 0x40, 0xec, 0x66, 0x46, 0x90, 0x30, 0xab, 0x74, - 0xc1, 0xdb, - ]; -} diff --git a/runtime/src/precompiles/solidity/subnet.abi b/runtime/src/precompiles/solidity/subnet.abi index fd81850b7..3cc16d9df 100644 --- a/runtime/src/precompiles/solidity/subnet.abi +++ b/runtime/src/precompiles/solidity/subnet.abi @@ -148,9 +148,9 @@ "name": "getImmunityPeriod", "outputs": [ { - "internalType": "uint64", + "internalType": "uint16", "name": "", - "type": "uint64" + "type": "uint16" } ], "stateMutability": "view", @@ -243,9 +243,9 @@ "name": "getMaxWeightLimit", "outputs": [ { - "internalType": "uint64", + "internalType": "uint16", "name": "", - "type": "uint64" + "type": "uint16" } ], "stateMutability": "view", @@ -443,39 +443,39 @@ "type": "bytes32" }, { - "internalType": "bytes", + "internalType": "string", "name": "subnetName", - "type": "bytes" + "type": "string" }, { - "internalType": "bytes", + "internalType": "string", "name": "githubRepo", - "type": "bytes" + "type": "string" }, { - "internalType": "bytes", + "internalType": "string", "name": "subnetContact", - "type": "bytes" + "type": "string" }, { - "internalType": "bytes", + "internalType": "string", "name": "subnetUrl", - "type": "bytes" + "type": "string" }, { - "internalType": "bytes", + "internalType": "string", "name": "discord", - "type": "bytes" + "type": "string" }, { - "internalType": "bytes", + "internalType": "string", "name": "description", - "type": "bytes" + "type": "string" }, { - "internalType": "bytes", + "internalType": "string", "name": "additional", - "type": "bytes" + "type": "string" } ], "name": "registerNetwork", @@ -622,9 +622,9 @@ "type": "uint16" }, { - "internalType": "uint64", + "internalType": "uint16", "name": "immunityPeriod", - "type": "uint64" + "type": "uint16" } ], "name": "setImmunityPeriod", @@ -712,9 +712,9 @@ "type": "uint16" }, { - "internalType": "uint64", + "internalType": "uint16", "name": "maxWeightLimit", - "type": "uint64" + "type": "uint16" } ], "name": "setMaxWeightLimit", @@ -884,4 +884,4 @@ "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 1afeced49..d5ef0916d 100644 --- a/runtime/src/precompiles/solidity/subnet.sol +++ b/runtime/src/precompiles/solidity/subnet.sol @@ -8,13 +8,13 @@ interface ISubnet { /// Registers a new network with specified subnet name, GitHub repository, and contact information. function registerNetwork( bytes32 hotkey, - bytes memory subnetName, - bytes memory githubRepo, - bytes memory subnetContact, - bytes memory subnetUrl, - bytes memory discord, - bytes memory description, - bytes memory additional + string memory subnetName, + string memory githubRepo, + string memory subnetContact, + string memory subnetUrl, + string memory discord, + string memory description, + string memory additional ) external payable; function getServingRateLimit(uint16 netuid) external view returns (uint64); @@ -61,14 +61,14 @@ interface ISubnet { uint64 adjustmentAlpha ) external payable; - function getMaxWeightLimit(uint16 netuid) external view returns (uint64); + function getMaxWeightLimit(uint16 netuid) external view returns (uint16); function setMaxWeightLimit( uint16 netuid, - uint64 maxWeightLimit + uint16 maxWeightLimit ) external payable; - function getImmunityPeriod(uint16) external view returns (uint64); + function getImmunityPeriod(uint16) external view returns (uint16); function setImmunityPeriod( uint16 netuid, diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs index d99b0199e..29441a21b 100644 --- a/runtime/src/precompiles/staking.rs +++ b/runtime/src/precompiles/staking.rs @@ -44,6 +44,15 @@ use crate::{ProxyType, Runtime, RuntimeCall}; pub struct StakingPrecompile; +impl PrecompileExt for StakingPrecompile { + const INDEX: u64 = 2049; + const ADDRESS_SS58: [u8; 32] = [ + 0x26, 0xf4, 0x10, 0x1e, 0x52, 0xb7, 0x57, 0x34, 0x33, 0x24, 0x5b, 0xc3, 0x0a, 0xe1, 0x8b, + 0x63, 0x99, 0x53, 0xd8, 0x41, 0x79, 0x33, 0x03, 0x61, 0x4d, 0xfa, 0xcf, 0xf0, 0x37, 0xf7, + 0x12, 0x94, + ]; +} + #[precompile_utils::precompile] impl StakingPrecompile { #[precompile::public("addStake(bytes32,uint256)")] @@ -167,12 +176,3 @@ impl StakingPrecompile { Ok(()) } } - -impl PrecompileExt for StakingPrecompile { - const INDEX: u64 = 2049; - const ADDRESS_SS58: [u8; 32] = [ - 0x26, 0xf4, 0x10, 0x1e, 0x52, 0xb7, 0x57, 0x34, 0x33, 0x24, 0x5b, 0xc3, 0x0a, 0xe1, 0x8b, - 0x63, 0x99, 0x53, 0xd8, 0x41, 0x79, 0x33, 0x03, 0x61, 0x4d, 0xfa, 0xcf, 0xf0, 0x37, 0xf7, - 0x12, 0x94, - ]; -} diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs index 8a46cc7dc..88b67527c 100644 --- a/runtime/src/precompiles/subnet.rs +++ b/runtime/src/precompiles/subnet.rs @@ -1,1414 +1,21 @@ +use frame_support::traits::ConstU32; use frame_system::RawOrigin; use pallet_evm::{ AddressMapping, ExitError, ExitSucceed, HashedAddressMapping, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, }; - -use sp_core::U256; -use sp_runtime::{traits::BlakeTwo256, AccountId32, Vec}; +use precompile_utils::{prelude::BoundedString, EvmResult}; +use sp_core::{H256, U256}; +use sp_runtime::{traits::BlakeTwo256, AccountId32}; use sp_std::vec; use crate::precompiles::{ - get_method_id, parse_slice, parse_pubkey, PrecompileExt, PrecompileHandleExt, + get_method_id, parse_pubkey, parse_slice, PrecompileExt, PrecompileHandleExt, }; use crate::{Runtime, RuntimeCall}; -// bytes with max lenght 1K -const MAX_SINGLE_PARAMETER_SIZE: usize = 1024; -// seven bytes with max lenght 1K -const MAX_PARAMETER_SIZE: usize = 7 * MAX_SINGLE_PARAMETER_SIZE; - pub struct SubnetPrecompile; -#[precompile_utils::precompile] -impl SubnetPrecompile { - // pub fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { - // let txdata = handle.input(); - // if txdata.len() > MAX_PARAMETER_SIZE { - // log::error!("the length of subnet call is {} ", txdata.len()); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - // let method_id = get_slice(txdata, 0, 4)?; - // let method_input = txdata - // .get(4..) - // .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,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, - // }), - // } - // } - - // fn register_network(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - // let call = match data.len() { - // 32 => { - // let (hotkey, _) = get_pubkey(data)?; - // RuntimeCall::SubtensorModule( - // pallet_subtensor::Call::::register_network_with_identity { - // hotkey, - // identity: None, - // }, - // ) - // } - // 33.. => { - // let ( - // hotkey, - // subnet_name, - // github_repo, - // subnet_contact, - // subnet_url, - // discord, - // description, - // additional, - // ) = Self::parse_register_network_parameters(data)?; - - // let identity: pallet_subtensor::SubnetIdentityOfV2 = - // pallet_subtensor::SubnetIdentityOfV2 { - // subnet_name, - // github_repo, - // subnet_contact, - // subnet_url, - // discord, - // description, - // additional, - // }; - - // // Create the register_network callcle - // RuntimeCall::SubtensorModule( - // pallet_subtensor::Call::::register_network_with_identity { - // hotkey, - // identity: Some(identity), - // }, - // ) - // } - // _ => { - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - // }; - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: Default::default(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: result.into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - // } - - // 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))?; - // Ok(PrecompileOutput { - // exit_status: ExitSucceed::Returned, - // output: ().into(), - // }) - - // } - - // fn parse_register_network_parameters( - // data: &[u8], - // ) -> Result< - // ( - // AccountId32, - // Vec, - // Vec, - // Vec, - // Vec, - // Vec, - // Vec, - // Vec, - // ), - // PrecompileFailure, - // > { - // let (pubkey, dynamic_params) = get_pubkey(data)?; - // let dynamic_data_len = dynamic_params.len(); - - // let mut buf = [0_u8; 4]; - // // get all start points for the data items: name, repo, contact, url, discord, description, additional - // buf.copy_from_slice(get_slice(data, 60, 64)?); - // let subnet_name_start: usize = u32::from_be_bytes(buf) as usize; - // if subnet_name_start > dynamic_data_len { - // log::error!( - // "the start position of subnet name as {} is too big ", - // subnet_name_start - // ); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - - // buf.copy_from_slice(get_slice(data, 92, 96)?); - // let github_repo_start: usize = u32::from_be_bytes(buf) as usize; - // if github_repo_start > dynamic_data_len { - // log::error!( - // "the start position of github repo as {} is too big ", - // github_repo_start - // ); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - - // buf.copy_from_slice(get_slice(data, 124, 128)?); - // let subnet_contact_start: usize = u32::from_be_bytes(buf) as usize; - // if subnet_contact_start > dynamic_data_len { - // log::error!( - // "the start position of subnet contact as {} is too big ", - // subnet_contact_start - // ); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - - // buf.copy_from_slice(get_slice(data, 156, 160)?); - // let subnet_url_start: usize = u32::from_be_bytes(buf) as usize; - // if subnet_url_start > dynamic_data_len { - // log::error!( - // "the start position of subnet_url as {} is too big ", - // subnet_url_start - // ); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - - // buf.copy_from_slice(get_slice(data, 188, 192)?); - // let discord_start: usize = u32::from_be_bytes(buf) as usize; - // if discord_start > dynamic_data_len { - // log::error!( - // "the start position of discord as {} is too big ", - // discord_start - // ); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - - // buf.copy_from_slice(get_slice(data, 220, 224)?); - // let description_start: usize = u32::from_be_bytes(buf) as usize; - // if description_start > dynamic_data_len { - // log::error!( - // "the start position of description as {} is too big ", - // description_start - // ); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - - // buf.copy_from_slice(get_slice(data, 252, 256)?); - // let additional_start: usize = u32::from_be_bytes(buf) as usize; - // if additional_start > dynamic_data_len { - // log::error!( - // "the start position of additional as {} is too big ", - // additional_start - // ); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - - // // get name - // buf.copy_from_slice(get_slice( - // data, - // subnet_name_start + 28, - // subnet_name_start + 32, - // )?); - // let subnet_name_len: usize = u32::from_be_bytes(buf) as usize; - - // if subnet_name_len > MAX_SINGLE_PARAMETER_SIZE { - // log::error!( - // "the length of subnet name as {} is too big", - // subnet_name_len - // ); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - - // let mut name_vec = vec![0; subnet_name_len]; - // name_vec.copy_from_slice(get_slice( - // data, - // subnet_name_start + 32, - // subnet_name_start + subnet_name_len + 32, - // )?); - - // // get repo data - // buf.copy_from_slice(get_slice( - // data, - // github_repo_start + 28, - // github_repo_start + 32, - // )?); - // let github_repo_len: usize = u32::from_be_bytes(buf) as usize; - // if github_repo_len > MAX_SINGLE_PARAMETER_SIZE { - // log::error!( - // "the length of github repo as {} is too big", - // github_repo_len - // ); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - - // let mut repo_vec = vec![0; github_repo_len]; - // repo_vec.copy_from_slice(get_slice( - // data, - // github_repo_start + 32, - // github_repo_start + github_repo_len + 32, - // )?); - - // // get contact data - // buf.copy_from_slice(get_slice( - // data, - // subnet_contact_start + 28, - // subnet_contact_start + 32, - // )?); - // let subnet_contact_len: usize = u32::from_be_bytes(buf) as usize; - // if subnet_contact_len > MAX_SINGLE_PARAMETER_SIZE { - // log::error!( - // "the length of subnet contact as {} is too big", - // subnet_contact_len - // ); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - - // let mut contact_vec = vec![0; subnet_contact_len]; - // contact_vec.copy_from_slice(get_slice( - // data, - // subnet_contact_start + 32, - // subnet_contact_start + subnet_contact_len + 32, - // )?); - - // // get subnet_url - // buf.copy_from_slice(get_slice( - // data, - // subnet_url_start + 28, - // subnet_url_start + 32, - // )?); - // let subnet_url_len: usize = u32::from_be_bytes(buf) as usize; - // if subnet_url_len > MAX_SINGLE_PARAMETER_SIZE { - // log::error!("the length of subnet_url as {} is too big", subnet_url_len); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - // let mut url_vec = vec![0; subnet_url_len]; - // url_vec.copy_from_slice(get_slice( - // data, - // subnet_url_start + 32, - // subnet_url_start + subnet_url_len + 32, - // )?); - - // // get discord - // buf.copy_from_slice(get_slice(data, discord_start + 28, discord_start + 32)?); - // let discord_len: usize = u32::from_be_bytes(buf) as usize; - // if discord_len > MAX_SINGLE_PARAMETER_SIZE { - // log::error!("the length of discord as {} is too big", discord_len); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - // let mut discord_vec = vec![0; discord_len]; - // discord_vec.copy_from_slice(get_slice( - // data, - // discord_start + 32, - // discord_start + discord_len + 32, - // )?); - - // // get description - // buf.copy_from_slice(get_slice( - // data, - // description_start + 28, - // description_start + 32, - // )?); - // let description_len: usize = u32::from_be_bytes(buf) as usize; - // if description_len > MAX_SINGLE_PARAMETER_SIZE { - // log::error!( - // "the length of description as {} is too big", - // description_len - // ); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - // let mut description_vec = vec![0; description_len]; - // description_vec.copy_from_slice(get_slice( - // data, - // description_start + 32, - // description_start + description_len + 32, - // )?); - - // // get additional - // buf.copy_from_slice(get_slice( - // data, - // additional_start + 28, - // additional_start + 32, - // )?); - // let additional_len: usize = u32::from_be_bytes(buf) as usize; - // if additional_len > MAX_SINGLE_PARAMETER_SIZE { - // log::error!("the length of additional as {} is too big", additional_len); - // return Err(PrecompileFailure::Error { - // exit_status: ExitError::InvalidRange, - // }); - // } - // let mut additional_vec = vec![0; additional_len]; - // additional_vec.copy_from_slice(get_slice( - // data, - // additional_start + 32, - // additional_start + additional_len + 32, - // )?); - - // Ok(( - // pubkey, - // name_vec, - // repo_vec, - // contact_vec, - // url_vec, - // discord_vec, - // description_vec, - // 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)) - // } -} - impl PrecompileExt for SubnetPrecompile { const INDEX: u64 = 2051; const ADDRESS_SS58: [u8; 32] = [ @@ -1417,3 +24,511 @@ impl PrecompileExt for SubnetPrecompile { 0x1c, 0xd3, ]; } + +#[precompile_utils::precompile] +impl SubnetPrecompile { + #[precompile::public("registerNetwork(bytes32)")] + #[precompile::payable] + fn register_network(handle: &mut impl PrecompileHandle, hotkey: H256) -> EvmResult<()> { + let (hotkey, _) = parse_pubkey(hotkey.as_bytes())?; + let call = pallet_subtensor::Call::::register_network_with_identity { + hotkey, + identity: None, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public( + "registerNetwork(bytes32,string,string,string,string,string,string,string)" + )] + #[precompile::payable] + fn register_network_with_identity( + handle: &mut impl PrecompileHandle, + hotkey: H256, + subnet_name: BoundedString>, + github_repo: BoundedString>, + subnet_contact: BoundedString>, + subnet_url: BoundedString>, + discord: BoundedString>, + description: BoundedString>, + additional: BoundedString>, + ) -> EvmResult<()> { + let (hotkey, _) = parse_pubkey(hotkey.as_bytes())?; + let identity = pallet_subtensor::SubnetIdentityOfV2 { + subnet_name: subnet_name.into(), + github_repo: github_repo.into(), + subnet_contact: subnet_contact.into(), + subnet_url: subnet_url.into(), + discord: discord.into(), + description: description.into(), + additional: additional.into(), + }; + + let call = pallet_subtensor::Call::::register_network_with_identity { + hotkey, + identity: Some(identity), + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getServingRateLimit(uint16)")] + #[precompile::view] + fn get_serving_rate_limit(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::ServingRateLimit::::get(netuid)) + } + + #[precompile::public("setServingRateLimit(uint16,uint64)")] + #[precompile::payable] + fn set_serving_rate_limit( + handle: &mut impl PrecompileHandle, + netuid: u16, + serving_rate_limit: u64, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_serving_rate_limit { + netuid, + serving_rate_limit, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getMinDifficulty(uint16)")] + #[precompile::view] + fn get_min_difficulty(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::MinDifficulty::::get(netuid)) + } + + #[precompile::public("setMinDifficulty(uint16,uint64)")] + #[precompile::payable] + fn set_min_difficulty( + handle: &mut impl PrecompileHandle, + netuid: u16, + min_difficulty: u64, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_min_difficulty { + netuid, + min_difficulty, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getMaxDifficulty(uint16)")] + #[precompile::view] + fn get_max_difficulty(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::MaxDifficulty::::get(netuid)) + } + + #[precompile::public("setMaxDifficulty(uint16,uint64)")] + #[precompile::payable] + fn set_max_difficulty( + handle: &mut impl PrecompileHandle, + netuid: u16, + max_difficulty: u64, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_max_difficulty { + netuid, + max_difficulty, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getWeightsVersionKey(uint16)")] + #[precompile::view] + fn get_weights_version_key(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::WeightsVersionKey::::get(netuid)) + } + + #[precompile::public("setWeightsVersionKey(uint16,uint64)")] + #[precompile::payable] + fn set_weights_version_key( + handle: &mut impl PrecompileHandle, + netuid: u16, + weights_version_key: u64, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_weights_version_key { + netuid, + weights_version_key, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getWeightsSetRateLimit(uint16)")] + #[precompile::view] + fn get_weights_set_rate_limit( + handle: &mut impl PrecompileHandle, + netuid: u16, + ) -> EvmResult { + Ok(pallet_subtensor::WeightsSetRateLimit::::get( + netuid, + )) + } + + #[precompile::public("setWeightsSetRateLimit(uint16,uint64)")] + #[precompile::payable] + fn set_weights_set_rate_limit( + handle: &mut impl PrecompileHandle, + netuid: u16, + weights_set_rate_limit: u64, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_weights_set_rate_limit { + netuid, + weights_set_rate_limit, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getAdjustmentAlpha(uint16)")] + #[precompile::view] + fn get_adjustment_alpha(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::AdjustmentAlpha::::get(netuid)) + } + + #[precompile::public("setAdjustmentAlpha(uint16,uint64)")] + #[precompile::payable] + fn set_adjustment_alpha( + handle: &mut impl PrecompileHandle, + netuid: u16, + adjustment_alpha: u64, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_adjustment_alpha { + netuid, + adjustment_alpha, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getMaxWeightLimit(uint16)")] + #[precompile::view] + fn get_max_weight_limit(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::MaxWeightsLimit::::get(netuid)) + } + + #[precompile::public("setMaxWeightLimit(uint16,uint16)")] + #[precompile::payable] + fn set_max_weight_limit( + handle: &mut impl PrecompileHandle, + netuid: u16, + max_weight_limit: u16, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_max_weight_limit { + netuid, + max_weight_limit, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getImmunityPeriod(uint16)")] + #[precompile::view] + fn get_immunity_period(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::ImmunityPeriod::::get(netuid)) + } + + #[precompile::public("setImmunityPeriod(uint16,uint16)")] + #[precompile::payable] + fn set_immunity_period( + handle: &mut impl PrecompileHandle, + netuid: u16, + immunity_period: u16, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_immunity_period { + netuid, + immunity_period, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getMinAllowedWeights(uint16)")] + #[precompile::view] + fn get_min_allowed_weights(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::MinAllowedWeights::::get(netuid)) + } + + #[precompile::public("setMinAllowedWeights(uint16,uint16)")] + #[precompile::payable] + fn set_min_allowed_weights( + handle: &mut impl PrecompileHandle, + netuid: u16, + min_allowed_weights: u16, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_min_allowed_weights { + netuid, + min_allowed_weights, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getKappa(uint16)")] + #[precompile::view] + fn get_kappa(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::Kappa::::get(netuid)) + } + + #[precompile::public("setKappa(uint16,uint16)")] + #[precompile::payable] + fn set_kappa(handle: &mut impl PrecompileHandle, netuid: u16, kappa: u16) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_kappa { netuid, kappa }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getRho(uint16)")] + #[precompile::view] + fn get_rho(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::Rho::::get(netuid)) + } + + #[precompile::public("setRho(uint16,uint16)")] + #[precompile::payable] + fn set_rho(handle: &mut impl PrecompileHandle, netuid: u16, rho: u16) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_rho { netuid, rho }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getActivityCutoff(uint16)")] + #[precompile::view] + fn get_activity_cutoff(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::ActivityCutoff::::get(netuid)) + } + + #[precompile::public("setActivityCutoff(uint16,uint16)")] + #[precompile::payable] + fn set_activity_cutoff( + handle: &mut impl PrecompileHandle, + netuid: u16, + activity_cutoff: u16, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_activity_cutoff { + netuid, + activity_cutoff, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getNetworkRegistrationAllowed(uint16)")] + #[precompile::view] + fn get_network_registration_allowed( + handle: &mut impl PrecompileHandle, + netuid: u16, + ) -> EvmResult { + Ok(pallet_subtensor::NetworkRegistrationAllowed::::get(netuid)) + } + + #[precompile::public("setNetworkRegistrationAllowed(uint16,bool)")] + #[precompile::payable] + fn set_network_registration_allowed( + handle: &mut impl PrecompileHandle, + netuid: u16, + registration_allowed: bool, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_network_registration_allowed { + netuid, + registration_allowed, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getNetworkPowRegistrationAllowed(uint16)")] + #[precompile::view] + fn get_network_pow_registration_allowed( + handle: &mut impl PrecompileHandle, + netuid: u16, + ) -> EvmResult { + Ok(pallet_subtensor::NetworkPowRegistrationAllowed::::get(netuid)) + } + + #[precompile::public("setNetworkPowRegistrationAllowed(uint16,bool)")] + #[precompile::payable] + fn set_network_pow_registration_allowed( + handle: &mut impl PrecompileHandle, + netuid: u16, + registration_allowed: bool, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_network_pow_registration_allowed { + netuid, + registration_allowed, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getMinBurn(uint16)")] + #[precompile::view] + fn get_min_burn(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::MinBurn::::get(netuid)) + } + + #[precompile::public("setMinBurn(uint16,uint64)")] + #[precompile::payable] + fn set_min_burn( + handle: &mut impl PrecompileHandle, + netuid: u16, + min_burn: u64, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_min_burn { netuid, min_burn }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getMaxBurn(uint16)")] + #[precompile::view] + fn get_max_burn(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::MaxBurn::::get(netuid)) + } + + #[precompile::public("setMaxBurn(uint16,uint64)")] + #[precompile::payable] + fn set_max_burn( + handle: &mut impl PrecompileHandle, + netuid: u16, + max_burn: u64, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_max_burn { netuid, max_burn }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getDifficulty(uint16)")] + #[precompile::view] + fn get_difficulty(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::Difficulty::::get(netuid)) + } + + #[precompile::public("setDifficulty(uint16,uint64)")] + #[precompile::payable] + fn set_difficulty( + handle: &mut impl PrecompileHandle, + netuid: u16, + difficulty: u64, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_difficulty { netuid, difficulty }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getBondsMovingAverage(uint16)")] + #[precompile::view] + fn get_bonds_moving_average(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::BondsMovingAverage::::get(netuid)) + } + + #[precompile::public("setBondsMovingAverage(uint16,uint64)")] + #[precompile::payable] + fn set_bonds_moving_average( + handle: &mut impl PrecompileHandle, + netuid: u16, + bonds_moving_average: u64, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_bonds_moving_average { + netuid, + bonds_moving_average, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getCommitRevealWeightsEnabled(uint16)")] + #[precompile::view] + fn get_commit_reveal_weights_enabled( + handle: &mut impl PrecompileHandle, + netuid: u16, + ) -> EvmResult { + Ok(pallet_subtensor::CommitRevealWeightsEnabled::::get(netuid)) + } + + #[precompile::public("setCommitRevealWeightsEnabled(uint16,bool)")] + #[precompile::payable] + fn set_commit_reveal_weights_enabled( + handle: &mut impl PrecompileHandle, + netuid: u16, + enabled: bool, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_commit_reveal_weights_enabled { + netuid, + enabled, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getLiquidAlphaEnabled(uint16)")] + #[precompile::view] + fn get_liquid_alpha_enabled( + handle: &mut impl PrecompileHandle, + netuid: u16, + ) -> EvmResult { + Ok(pallet_subtensor::LiquidAlphaOn::::get(netuid)) + } + + #[precompile::public("setLiquidAlphaEnabled(uint16,bool)")] + #[precompile::payable] + fn set_liquid_alpha_enabled( + handle: &mut impl PrecompileHandle, + netuid: u16, + enabled: bool, + ) -> EvmResult<()> { + let call = + pallet_admin_utils::Call::::sudo_set_liquid_alpha_enabled { netuid, enabled }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getAlphaValues(uint16)")] + #[precompile::view] + fn get_alpha_values(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<(u16, u16)> { + Ok(pallet_subtensor::AlphaValues::::get(netuid)) + } + + #[precompile::public("setAlphaValues(uint16,uint16,uint16)")] + #[precompile::payable] + fn set_alpha_values( + handle: &mut impl PrecompileHandle, + netuid: u16, + alpha_low: u16, + alpha_high: u16, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_alpha_values { + netuid, + alpha_low, + alpha_high, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } + + #[precompile::public("getCommitRevealWeightsInterval(uint16)")] + #[precompile::view] + fn get_commit_reveal_weights_interval( + handle: &mut impl PrecompileHandle, + netuid: u16, + ) -> EvmResult { + Ok(pallet_subtensor::RevealPeriodEpochs::::get(netuid)) + } + + #[precompile::public("setCommitRevealWeightsInterval(uint16,uint64)")] + #[precompile::payable] + fn set_commit_reveal_weights_interval( + handle: &mut impl PrecompileHandle, + netuid: u16, + interval: u64, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_commit_reveal_weights_interval { + netuid, + interval, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } +} From f0310f54c461d9046381672b502b6325e7ac67e1 Mon Sep 17 00:00:00 2001 From: Aliaksandr Tsurko Date: Mon, 17 Feb 2025 16:09:27 +0100 Subject: [PATCH 15/47] Reformat --- runtime/src/precompiles/balance_transfer.rs | 13 +--- runtime/src/precompiles/metagraph.rs | 43 ++++++-------- runtime/src/precompiles/mod.rs | 43 +++----------- runtime/src/precompiles/neuron.rs | 14 +---- runtime/src/precompiles/staking.rs | 13 +--- runtime/src/precompiles/subnet.rs | 66 +++++++++------------ 6 files changed, 62 insertions(+), 130 deletions(-) diff --git a/runtime/src/precompiles/balance_transfer.rs b/runtime/src/precompiles/balance_transfer.rs index 68b3edb37..3b326bca2 100644 --- a/runtime/src/precompiles/balance_transfer.rs +++ b/runtime/src/precompiles/balance_transfer.rs @@ -1,18 +1,9 @@ -use core::marker::PhantomData; - -use pallet_evm::{ - BalanceConverter, ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle, - PrecompileOutput, PrecompileResult, -}; +use pallet_evm::PrecompileHandle; use precompile_utils::EvmResult; use sp_core::H256; use sp_runtime::traits::UniqueSaturatedInto; -use sp_runtime::AccountId32; -use sp_std::vec::Vec; -use crate::precompiles::{ - contract_to_origin, get_method_id, parse_slice, parse_pubkey, PrecompileExt, PrecompileHandleExt, -}; +use crate::precompiles::{contract_to_origin, parse_pubkey, PrecompileExt, PrecompileHandleExt}; use crate::Runtime; pub struct BalanceTransferPrecompile; diff --git a/runtime/src/precompiles/metagraph.rs b/runtime/src/precompiles/metagraph.rs index 3677ede36..f74812cc0 100644 --- a/runtime/src/precompiles/metagraph.rs +++ b/runtime/src/precompiles/metagraph.rs @@ -1,15 +1,12 @@ extern crate alloc; use alloc::string::String; -use fp_evm::{ - ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, -}; +use fp_evm::{ExitError, PrecompileFailure, PrecompileHandle}; use pallet_subtensor::AxonInfo as SubtensorModuleAxonInfo; use precompile_utils::{solidity::Codec, EvmResult}; -use sp_core::{ByteArray, H256, U256}; -use sp_std::vec; +use sp_core::{ByteArray, H256}; -use crate::precompiles::{get_method_id, parse_slice, PrecompileExt, PrecompileHandleExt}; +use crate::precompiles::PrecompileExt; use crate::Runtime; pub struct MetagraphPrecompile; @@ -23,13 +20,13 @@ impl PrecompileExt for MetagraphPrecompile { impl MetagraphPrecompile { #[precompile::public("getUidCount(uint16)")] #[precompile::view] - fn get_uid_count(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_uid_count(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::SubnetworkN::::get(netuid)) } #[precompile::public("getStake(uint16,uint16)")] #[precompile::view] - fn get_stake(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + fn get_stake(_: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { let hotkey = pallet_subtensor::Pallet::::get_hotkey_for_net_and_uid(netuid, uid) .map_err(|_| PrecompileFailure::Error { exit_status: ExitError::InvalidRange, @@ -40,7 +37,7 @@ impl MetagraphPrecompile { #[precompile::public("getRank(uint16,uint16)")] #[precompile::view] - fn get_rank(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + fn get_rank(_: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { Ok(pallet_subtensor::Pallet::::get_rank_for_uid( netuid, uid, )) @@ -48,7 +45,7 @@ impl MetagraphPrecompile { #[precompile::public("getTrust(uint16,uint16)")] #[precompile::view] - fn get_trust(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + fn get_trust(_: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { Ok(pallet_subtensor::Pallet::::get_trust_for_uid( netuid, uid, )) @@ -56,7 +53,7 @@ impl MetagraphPrecompile { #[precompile::public("getConsensus(uint16,uint16)")] #[precompile::view] - fn get_consensus(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + fn get_consensus(_: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { Ok(pallet_subtensor::Pallet::::get_consensus_for_uid( netuid, uid, )) @@ -64,7 +61,7 @@ impl MetagraphPrecompile { #[precompile::public("getIncentive(uint16,uint16)")] #[precompile::view] - fn get_incentive(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + fn get_incentive(_: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { Ok(pallet_subtensor::Pallet::::get_incentive_for_uid( netuid, uid, )) @@ -72,7 +69,7 @@ impl MetagraphPrecompile { #[precompile::public("getDividends(uint16,uint16)")] #[precompile::view] - fn get_dividends(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + fn get_dividends(_: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { Ok(pallet_subtensor::Pallet::::get_dividends_for_uid( netuid, uid, )) @@ -80,7 +77,7 @@ impl MetagraphPrecompile { #[precompile::public("getEmission(uint16,uint16)")] #[precompile::view] - fn get_emission(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + fn get_emission(_: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { Ok(pallet_subtensor::Pallet::::get_emission_for_uid( netuid, uid, )) @@ -88,14 +85,14 @@ impl MetagraphPrecompile { #[precompile::public("getVtrust(uint16,uint16)")] #[precompile::view] - fn get_vtrust(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + fn get_vtrust(_: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { Ok(pallet_subtensor::Pallet::::get_validator_trust_for_uid(netuid, uid)) } #[precompile::public("getValidatorStatus(uint16,uint16)")] #[precompile::view] fn get_validator_status( - handle: &mut impl PrecompileHandle, + _: &mut impl PrecompileHandle, netuid: u16, uid: u16, ) -> EvmResult { @@ -104,17 +101,13 @@ impl MetagraphPrecompile { #[precompile::public("getLastUpdate(uint16,uint16)")] #[precompile::view] - fn get_last_update( - handle: &mut impl PrecompileHandle, - netuid: u16, - uid: u16, - ) -> EvmResult { + fn get_last_update(_: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { Ok(pallet_subtensor::Pallet::::get_last_update_for_uid(netuid, uid)) } #[precompile::public("getIsActive(uint16,uint16)")] #[precompile::view] - fn get_is_active(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + fn get_is_active(_: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { Ok(pallet_subtensor::Pallet::::get_active_for_uid( netuid, uid, )) @@ -122,7 +115,7 @@ impl MetagraphPrecompile { #[precompile::public("getAxon(uint16,uint16)")] #[precompile::view] - fn get_axon(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + fn get_axon(_: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { let hotkey = pallet_subtensor::Pallet::::get_hotkey_for_net_and_uid(netuid, uid) .map_err(|_| PrecompileFailure::Error { exit_status: ExitError::Other("hotkey not found".into()), @@ -133,7 +126,7 @@ impl MetagraphPrecompile { #[precompile::public("getHotkey(uint16,uint16)")] #[precompile::view] - fn get_hotkey(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + fn get_hotkey(_: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { pallet_subtensor::Pallet::::get_hotkey_for_net_and_uid(netuid, uid) .map(|acc| H256::from_slice(acc.as_slice())) .map_err(|_| PrecompileFailure::Error { @@ -143,7 +136,7 @@ impl MetagraphPrecompile { #[precompile::public("getColdkey(uint16,uint16)")] #[precompile::view] - fn get_coldkey(handle: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { + fn get_coldkey(_: &mut impl PrecompileHandle, netuid: u16, uid: u16) -> EvmResult { let hotkey = pallet_subtensor::Pallet::::get_hotkey_for_net_and_uid(netuid, uid) .map_err(|_| PrecompileFailure::Error { exit_status: ExitError::InvalidRange, diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs index 76bf110d8..0e5918e4d 100644 --- a/runtime/src/precompiles/mod.rs +++ b/runtime/src/precompiles/mod.rs @@ -6,15 +6,15 @@ use core::marker::PhantomData; use frame_support::dispatch::{GetDispatchInfo, Pays}; use frame_system::RawOrigin; use pallet_evm::{ - AddressMapping, BalanceConverter, ExitError, ExitSucceed, GasWeightMapping, - HashedAddressMapping, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle, - PrecompileOutput, PrecompileResult, PrecompileSet, + AddressMapping, BalanceConverter, ExitError, GasWeightMapping, HashedAddressMapping, + IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle, PrecompileResult, + PrecompileSet, }; use pallet_evm_precompile_modexp::Modexp; use pallet_evm_precompile_sha3fips::Sha3FIPS256; use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; use precompile_utils::EvmResult; -use sp_core::{hashing::keccak_256, H160, U256}; +use sp_core::{H160, U256}; use sp_runtime::traits::BlakeTwo256; use sp_runtime::{traits::Dispatchable, AccountId32}; use sp_std::vec; @@ -114,19 +114,8 @@ fn hash(a: u64) -> H160 { H160::from_low_u64_be(a) } -/// Returns Ethereum method ID from an str method signature -/// -pub fn get_method_id(method_signature: &str) -> [u8; 4] { - // Calculate the full Keccak-256 hash of the method signature - let hash = keccak_256(method_signature.as_bytes()); - - // Extract the first 4 bytes to get the method ID - [hash[0], hash[1], hash[2], hash[3]] -} - /// Takes a slice from bytes with PrecompileFailure as Error -/// -pub fn parse_slice(data: &[u8], from: usize, to: usize) -> Result<&[u8], PrecompileFailure> { +fn parse_slice(data: &[u8], from: usize, to: usize) -> Result<&[u8], PrecompileFailure> { let maybe_slice = data.get(from..to); if let Some(slice) = maybe_slice { Ok(slice) @@ -143,7 +132,7 @@ pub fn parse_slice(data: &[u8], from: usize, to: usize) -> Result<&[u8], Precomp } } -pub fn parse_pubkey(data: &[u8]) -> Result<(AccountId32, vec::Vec), PrecompileFailure> { +fn parse_pubkey(data: &[u8]) -> Result<(AccountId32, vec::Vec), PrecompileFailure> { let mut pubkey = [0u8; 32]; pubkey.copy_from_slice(parse_slice(data, 0, 32)?); @@ -155,31 +144,17 @@ pub fn parse_pubkey(data: &[u8]) -> Result<(AccountId32, vec::Vec), Precompi } fn try_u16_from_u256(value: U256) -> Result { - u16::try_from(value.as_u32()).map_err(|_| PrecompileFailure::Error { + value.try_into().map_err(|_| PrecompileFailure::Error { exit_status: ExitError::Other("the value is outside of u16 bounds".into()), }) } -fn parse_netuid(data: &[u8], offset: usize) -> Result { - if data.len() < offset + 2 { - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - let mut netuid_bytes = [0u8; 2]; - netuid_bytes.copy_from_slice(parse_slice(data, offset, offset + 2)?); - let netuid: u16 = netuid_bytes[1] as u16 | ((netuid_bytes[0] as u16) << 8u16); - - Ok(netuid) -} - fn contract_to_origin(contract: &[u8; 32]) -> Result, PrecompileFailure> { let (account_id, _) = parse_pubkey(contract)?; Ok(RawOrigin::Signed(account_id)) } -pub(crate) trait PrecompileHandleExt: PrecompileHandle { +trait PrecompileHandleExt: PrecompileHandle { fn caller_account_id(&self) -> AccountId32 { as AddressMapping>::into_account_id( self.context().caller, @@ -266,7 +241,7 @@ pub(crate) trait PrecompileHandleExt: PrecompileHandle { impl PrecompileHandleExt for T where T: PrecompileHandle {} -pub(crate) trait PrecompileExt: Precompile { +trait PrecompileExt: Precompile { const INDEX: u64; // ss58 public key i.e., the contract sends funds it received to the destination address from // the method parameter. diff --git a/runtime/src/precompiles/neuron.rs b/runtime/src/precompiles/neuron.rs index 4e0c9478c..b7dba980c 100644 --- a/runtime/src/precompiles/neuron.rs +++ b/runtime/src/precompiles/neuron.rs @@ -1,19 +1,11 @@ use frame_system::RawOrigin; -use pallet_evm::{ - AddressMapping, ExitError, HashedAddressMapping, PrecompileFailure, PrecompileHandle, - PrecompileResult, -}; +use pallet_evm::PrecompileHandle; use precompile_utils::EvmResult; use sp_core::H256; -use sp_runtime::traits::BlakeTwo256; -use sp_runtime::AccountId32; -use sp_std::vec; use sp_std::vec::Vec; -use crate::precompiles::{ - get_method_id, parse_netuid, parse_pubkey, parse_slice, PrecompileExt, PrecompileHandleExt, -}; -use crate::{Runtime, RuntimeCall}; +use crate::precompiles::{parse_pubkey, PrecompileExt, PrecompileHandleExt}; +use crate::Runtime; pub struct NeuronPrecompile; diff --git a/runtime/src/precompiles/staking.rs b/runtime/src/precompiles/staking.rs index 29441a21b..84b2d8470 100644 --- a/runtime/src/precompiles/staking.rs +++ b/runtime/src/precompiles/staking.rs @@ -26,20 +26,13 @@ // use frame_system::RawOrigin; -use pallet_evm::{ - AddressMapping, BalanceConverter, ExitError, ExitSucceed, HashedAddressMapping, - PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, -}; +use pallet_evm::{BalanceConverter, ExitError, PrecompileFailure, PrecompileHandle}; use precompile_utils::EvmResult; use sp_core::{H256, U256}; -use sp_runtime::traits::{BlakeTwo256, Dispatchable, StaticLookup, UniqueSaturatedInto}; +use sp_runtime::traits::{Dispatchable, StaticLookup, UniqueSaturatedInto}; use sp_runtime::AccountId32; -use sp_std::vec; -use crate::precompiles::{ - get_method_id, parse_slice, parse_netuid, parse_pubkey, try_u16_from_u256, PrecompileExt, - PrecompileHandleExt, -}; +use crate::precompiles::{parse_pubkey, try_u16_from_u256, PrecompileExt, PrecompileHandleExt}; use crate::{ProxyType, Runtime, RuntimeCall}; pub struct StakingPrecompile; diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs index 88b67527c..afda39dd3 100644 --- a/runtime/src/precompiles/subnet.rs +++ b/runtime/src/precompiles/subnet.rs @@ -1,18 +1,11 @@ use frame_support::traits::ConstU32; use frame_system::RawOrigin; -use pallet_evm::{ - AddressMapping, ExitError, ExitSucceed, HashedAddressMapping, PrecompileFailure, - PrecompileHandle, PrecompileOutput, PrecompileResult, -}; +use pallet_evm::PrecompileHandle; use precompile_utils::{prelude::BoundedString, EvmResult}; -use sp_core::{H256, U256}; -use sp_runtime::{traits::BlakeTwo256, AccountId32}; -use sp_std::vec; +use sp_core::H256; -use crate::precompiles::{ - get_method_id, parse_pubkey, parse_slice, PrecompileExt, PrecompileHandleExt, -}; -use crate::{Runtime, RuntimeCall}; +use crate::precompiles::{parse_pubkey, PrecompileExt, PrecompileHandleExt}; +use crate::Runtime; pub struct SubnetPrecompile; @@ -43,6 +36,7 @@ impl SubnetPrecompile { "registerNetwork(bytes32,string,string,string,string,string,string,string)" )] #[precompile::payable] + #[allow(clippy::too_many_arguments)] fn register_network_with_identity( handle: &mut impl PrecompileHandle, hotkey: H256, @@ -75,7 +69,7 @@ impl SubnetPrecompile { #[precompile::public("getServingRateLimit(uint16)")] #[precompile::view] - fn get_serving_rate_limit(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_serving_rate_limit(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::ServingRateLimit::::get(netuid)) } @@ -96,7 +90,7 @@ impl SubnetPrecompile { #[precompile::public("getMinDifficulty(uint16)")] #[precompile::view] - fn get_min_difficulty(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_min_difficulty(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::MinDifficulty::::get(netuid)) } @@ -117,7 +111,7 @@ impl SubnetPrecompile { #[precompile::public("getMaxDifficulty(uint16)")] #[precompile::view] - fn get_max_difficulty(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_max_difficulty(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::MaxDifficulty::::get(netuid)) } @@ -138,7 +132,7 @@ impl SubnetPrecompile { #[precompile::public("getWeightsVersionKey(uint16)")] #[precompile::view] - fn get_weights_version_key(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_weights_version_key(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::WeightsVersionKey::::get(netuid)) } @@ -159,10 +153,7 @@ impl SubnetPrecompile { #[precompile::public("getWeightsSetRateLimit(uint16)")] #[precompile::view] - fn get_weights_set_rate_limit( - handle: &mut impl PrecompileHandle, - netuid: u16, - ) -> EvmResult { + fn get_weights_set_rate_limit(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::WeightsSetRateLimit::::get( netuid, )) @@ -185,7 +176,7 @@ impl SubnetPrecompile { #[precompile::public("getAdjustmentAlpha(uint16)")] #[precompile::view] - fn get_adjustment_alpha(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_adjustment_alpha(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::AdjustmentAlpha::::get(netuid)) } @@ -206,7 +197,7 @@ impl SubnetPrecompile { #[precompile::public("getMaxWeightLimit(uint16)")] #[precompile::view] - fn get_max_weight_limit(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_max_weight_limit(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::MaxWeightsLimit::::get(netuid)) } @@ -227,7 +218,7 @@ impl SubnetPrecompile { #[precompile::public("getImmunityPeriod(uint16)")] #[precompile::view] - fn get_immunity_period(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_immunity_period(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::ImmunityPeriod::::get(netuid)) } @@ -248,7 +239,7 @@ impl SubnetPrecompile { #[precompile::public("getMinAllowedWeights(uint16)")] #[precompile::view] - fn get_min_allowed_weights(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_min_allowed_weights(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::MinAllowedWeights::::get(netuid)) } @@ -269,7 +260,7 @@ impl SubnetPrecompile { #[precompile::public("getKappa(uint16)")] #[precompile::view] - fn get_kappa(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_kappa(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::Kappa::::get(netuid)) } @@ -283,7 +274,7 @@ impl SubnetPrecompile { #[precompile::public("getRho(uint16)")] #[precompile::view] - fn get_rho(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_rho(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::Rho::::get(netuid)) } @@ -297,7 +288,7 @@ impl SubnetPrecompile { #[precompile::public("getActivityCutoff(uint16)")] #[precompile::view] - fn get_activity_cutoff(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_activity_cutoff(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::ActivityCutoff::::get(netuid)) } @@ -319,7 +310,7 @@ impl SubnetPrecompile { #[precompile::public("getNetworkRegistrationAllowed(uint16)")] #[precompile::view] fn get_network_registration_allowed( - handle: &mut impl PrecompileHandle, + _: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { Ok(pallet_subtensor::NetworkRegistrationAllowed::::get(netuid)) @@ -343,7 +334,7 @@ impl SubnetPrecompile { #[precompile::public("getNetworkPowRegistrationAllowed(uint16)")] #[precompile::view] fn get_network_pow_registration_allowed( - handle: &mut impl PrecompileHandle, + _: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { Ok(pallet_subtensor::NetworkPowRegistrationAllowed::::get(netuid)) @@ -366,7 +357,7 @@ impl SubnetPrecompile { #[precompile::public("getMinBurn(uint16)")] #[precompile::view] - fn get_min_burn(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_min_burn(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::MinBurn::::get(netuid)) } @@ -384,7 +375,7 @@ impl SubnetPrecompile { #[precompile::public("getMaxBurn(uint16)")] #[precompile::view] - fn get_max_burn(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_max_burn(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::MaxBurn::::get(netuid)) } @@ -402,7 +393,7 @@ impl SubnetPrecompile { #[precompile::public("getDifficulty(uint16)")] #[precompile::view] - fn get_difficulty(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_difficulty(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::Difficulty::::get(netuid)) } @@ -420,7 +411,7 @@ impl SubnetPrecompile { #[precompile::public("getBondsMovingAverage(uint16)")] #[precompile::view] - fn get_bonds_moving_average(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + fn get_bonds_moving_average(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::BondsMovingAverage::::get(netuid)) } @@ -442,7 +433,7 @@ impl SubnetPrecompile { #[precompile::public("getCommitRevealWeightsEnabled(uint16)")] #[precompile::view] fn get_commit_reveal_weights_enabled( - handle: &mut impl PrecompileHandle, + _: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { Ok(pallet_subtensor::CommitRevealWeightsEnabled::::get(netuid)) @@ -465,10 +456,7 @@ impl SubnetPrecompile { #[precompile::public("getLiquidAlphaEnabled(uint16)")] #[precompile::view] - fn get_liquid_alpha_enabled( - handle: &mut impl PrecompileHandle, - netuid: u16, - ) -> EvmResult { + fn get_liquid_alpha_enabled(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::LiquidAlphaOn::::get(netuid)) } @@ -487,7 +475,7 @@ impl SubnetPrecompile { #[precompile::public("getAlphaValues(uint16)")] #[precompile::view] - fn get_alpha_values(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<(u16, u16)> { + fn get_alpha_values(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<(u16, u16)> { Ok(pallet_subtensor::AlphaValues::::get(netuid)) } @@ -511,7 +499,7 @@ impl SubnetPrecompile { #[precompile::public("getCommitRevealWeightsInterval(uint16)")] #[precompile::view] fn get_commit_reveal_weights_interval( - handle: &mut impl PrecompileHandle, + _: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { Ok(pallet_subtensor::RevealPeriodEpochs::::get(netuid)) From b24b181b06503a4b208dbeaf95f612157976dbb2 Mon Sep 17 00:00:00 2001 From: Aliaksandr Tsurko Date: Mon, 17 Feb 2025 17:39:00 +0100 Subject: [PATCH 16/47] Update spec version --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 8dcce09b1..0320e8998 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: 239, + spec_version: 240, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 9139bf78094178f15072d1c85bc65ce1b4c6e362 Mon Sep 17 00:00:00 2001 From: Aliaksandr Tsurko Date: Mon, 17 Feb 2025 18:36:28 +0100 Subject: [PATCH 17/47] Fix commit_hash type in Neuron::commit_weights precompile --- runtime/src/precompiles/neuron.rs | 2 +- runtime/src/precompiles/solidity/neuron.abi | 6 +++--- runtime/src/precompiles/solidity/neuron.sol | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/runtime/src/precompiles/neuron.rs b/runtime/src/precompiles/neuron.rs index 771bf0bc3..f8fd1f158 100644 --- a/runtime/src/precompiles/neuron.rs +++ b/runtime/src/precompiles/neuron.rs @@ -39,7 +39,7 @@ impl NeuronPrecompile { handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - #[precompile::public("commitWeights(uint16,uint256)")] + #[precompile::public("commitWeights(uint16,bytes32)")] #[precompile::payable] pub fn commit_weights( handle: &mut impl PrecompileHandle, diff --git a/runtime/src/precompiles/solidity/neuron.abi b/runtime/src/precompiles/solidity/neuron.abi index e12685f99..e4ffb6fa1 100644 --- a/runtime/src/precompiles/solidity/neuron.abi +++ b/runtime/src/precompiles/solidity/neuron.abi @@ -25,9 +25,9 @@ "type": "uint16" }, { - "internalType": "uint256", + "internalType": "bytes32", "name": "commitHash", - "type": "uint256" + "type": "bytes32" } ], "name": "commitWeights", @@ -230,4 +230,4 @@ "stateMutability": "payable", "type": "function" } -] \ No newline at end of file +] diff --git a/runtime/src/precompiles/solidity/neuron.sol b/runtime/src/precompiles/solidity/neuron.sol index 772f29063..204bc3f60 100644 --- a/runtime/src/precompiles/solidity/neuron.sol +++ b/runtime/src/precompiles/solidity/neuron.sol @@ -99,9 +99,9 @@ interface INeuron { * @dev Commits the weights for a neuron. * * @param netuid The subnet to commit the weights for (uint16). - * @param commitHash The commit hash for the weights (uint256). + * @param commitHash The commit hash for the weights (bytes32). */ - function commitWeights(uint16 netuid, uint256 commitHash) external payable; + function commitWeights(uint16 netuid, bytes32 commitHash) external payable; /** * @dev Reveals the weights for a neuron. From 7b0d84f4b5af08813c1b9ba877f31e620272186d Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 17 Feb 2025 16:15:59 -0500 Subject: [PATCH 18/47] Prevent precision errors in share pool --- pallets/subtensor/src/staking/stake_utils.rs | 32 ++-- pallets/subtensor/src/tests/staking.rs | 64 ++++++-- pallets/subtensor/src/tests/staking2.rs | 17 +- primitives/share-pool/src/lib.rs | 156 +++++++++++++++---- 4 files changed, 202 insertions(+), 67 deletions(-) diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index 07be25171..039287052 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -544,9 +544,10 @@ impl Pallet { coldkey: &T::AccountId, netuid: u16, amount: u64, - ) { + ) -> u64 { let mut alpha_share_pool = Self::get_alpha_share_pool(hotkey.clone(), netuid); - alpha_share_pool.update_value_for_one(coldkey, amount as i64); + let actual_alpha = alpha_share_pool.update_value_for_one(coldkey, amount as i64); + actual_alpha.unsigned_abs() } pub fn try_increase_stake_for_hotkey_and_coldkey_on_subnet( @@ -573,13 +574,16 @@ impl Pallet { coldkey: &T::AccountId, netuid: u16, amount: u64, - ) { + ) -> u64 { let mut alpha_share_pool = Self::get_alpha_share_pool(hotkey.clone(), netuid); + let mut actual_alpha = 0; if let Ok(value) = alpha_share_pool.try_get_value(coldkey) { if value >= amount { - alpha_share_pool.update_value_for_one(coldkey, (amount as i64).neg()); + actual_alpha = + alpha_share_pool.update_value_for_one(coldkey, (amount as i64).neg()); } } + actual_alpha.unsigned_abs() } /// Calculates Some(Alpha) returned from pool by staking operation @@ -735,11 +739,12 @@ impl Pallet { alpha: u64, fee: u64, ) -> u64 { - // Step 1: Swap the alpha for TAO. - let tao: u64 = Self::swap_alpha_for_tao(netuid, alpha); + // Step 1: Decrease alpha on subneet + let actual_alpha_decrease = + Self::decrease_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid, alpha); - // Step 2: Decrease alpha on subneet - Self::decrease_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid, alpha); + // Step 2: Swap the alpha for TAO. + let tao: u64 = Self::swap_alpha_for_tao(netuid, actual_alpha_decrease); // Step 3: Update StakingHotkeys if the hotkey's total alpha, across all subnets, is zero // TODO const: fix. @@ -799,9 +804,12 @@ impl Pallet { // Step 2. Swap the tao to alpha. let alpha: u64 = Self::swap_tao_for_alpha(netuid, tao_staked); + let mut actual_alpha = 0; if (tao_staked > 0) && (alpha > 0) { // Step 3: Increase the alpha on the hotkey account. - Self::increase_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid, alpha); + actual_alpha = Self::increase_stake_for_hotkey_and_coldkey_on_subnet( + hotkey, coldkey, netuid, alpha, + ); // Step 4: Update the list of hotkeys staking for this coldkey let mut staking_hotkeys = StakingHotkeys::::get(coldkey); @@ -825,7 +833,7 @@ impl Pallet { coldkey.clone(), hotkey.clone(), tao_staked, - alpha, + actual_alpha, netuid, )); log::info!( @@ -833,12 +841,12 @@ impl Pallet { coldkey.clone(), hotkey.clone(), tao_staked, - alpha, + actual_alpha, netuid ); // Step 7: Return the amount of alpha staked - alpha + actual_alpha } pub fn get_alpha_share_pool( diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs index f97373b0b..794617d77 100644 --- a/pallets/subtensor/src/tests/staking.rs +++ b/pallets/subtensor/src/tests/staking.rs @@ -3669,14 +3669,25 @@ fn test_add_stake_specific_stake_into_subnet_fail() { ); // Add stake as new hotkey - assert_noop!( - SubtensorModule::add_stake( - RuntimeOrigin::signed(coldkey_account_id), - hotkey_account_id, - netuid, - tao_staked, + let expected_alpha = + SubtensorModule::sim_swap_tao_for_alpha(netuid, tao_staked).unwrap_or(0); + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + netuid, + tao_staked, + )); + + // Check we have non-zero staked + assert!(expected_alpha > 0); + assert_abs_diff_eq!( + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_account_id, + &coldkey_account_id, + netuid ), - Error::::InsufficientLiquidity + expected_alpha, + epsilon = expected_alpha / 1000 ); }); } @@ -3755,16 +3766,37 @@ fn test_move_stake_specific_stake_into_subnet_fail() { ); // Move stake to destination subnet - assert_noop!( - SubtensorModule::move_stake( - RuntimeOrigin::signed(coldkey_account_id), - hotkey_account_id, - hotkey_account_id, - origin_netuid, - netuid, - alpha_to_move, + assert_ok!(SubtensorModule::move_stake( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + hotkey_account_id, + origin_netuid, + netuid, + alpha_to_move, + )); + + // Check that the stake has been moved + assert_eq!( + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_account_id, + &coldkey_account_id, + origin_netuid ), - Error::::InsufficientLiquidity + 0 + ); + let fee = DefaultStakingFee::::get(); + let alpha_fee: I96F32 = I96F32::from_num(fee) / SubtensorModule::get_alpha_price(netuid); + let expected_value = I96F32::from_num(alpha_to_move) + * SubtensorModule::get_alpha_price(origin_netuid) + / SubtensorModule::get_alpha_price(netuid); + assert_abs_diff_eq!( + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_account_id, + &coldkey_account_id, + netuid + ), + (expected_value - alpha_fee).to_num::(), + epsilon = (expected_value / 1000).to_num::() ); }); } diff --git a/pallets/subtensor/src/tests/staking2.rs b/pallets/subtensor/src/tests/staking2.rs index 2abff8faf..471d67025 100644 --- a/pallets/subtensor/src/tests/staking2.rs +++ b/pallets/subtensor/src/tests/staking2.rs @@ -424,23 +424,30 @@ fn test_share_based_staking_denominator_precision() { let stake1 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( &hotkey1, &coldkey1, netuid, ); - assert_eq!(stake1, stake_amount - unstake_amount); + let expected_remaining_stake = + if (stake_amount as f64 - unstake_amount as f64) / (stake_amount as f64) <= 0.00001 + { + 0 + } else { + stake_amount - unstake_amount + }; + assert_eq!(stake1, expected_remaining_stake); }); }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::staking2::test_share_based_staking_denominator_precision_2 --exact --show-output --nocapture +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::staking2::test_share_based_staking_stake_unstake_inject --exact --show-output --nocapture #[test] fn test_share_based_staking_stake_unstake_inject() { // Test case amounts: stake, unstake, inject, tolerance [ (1_000, 999, 1_000_000, 0), - (1_000_000, 999_999, 100_000_000, 0), + (1_000_000, 999_000, 100_000_000, 0), (1_000_000, 900_000, 100_000_000, 0), (100_000_000_000, 1_000_000_000, 1_000_000_000_000, 1), (100_000_000_000, 99_000_000_000, 1_000_000_000_000, 1), - (100_000_000_000, 99_999_999_500, 1_000_000_000_000, 1), - (100_000_000_000, 99_999_999_500, 1_234_567_890, 1), + (100_000_000_000, 99_990_000_000, 1_000_000_000_000, 1), + (100_000_000_000, 99_990_000_000, 1_234_567_890, 1), ] .iter() .for_each(|test_case| { diff --git a/primitives/share-pool/src/lib.rs b/primitives/share-pool/src/lib.rs index 8f963cfd3..27006ad96 100644 --- a/primitives/share-pool/src/lib.rs +++ b/primitives/share-pool/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::result_unit_err)] +use safe_math::*; use sp_std::marker; use sp_std::ops::Neg; use substrate_fixed::types::{I64F64, U64F64}; @@ -50,11 +51,16 @@ where let current_share: U64F64 = self.state_ops.get_share(key); let denominator: U64F64 = self.state_ops.get_denominator(); - shared_value - .checked_div(denominator) - .unwrap_or(U64F64::saturating_from_num(0)) - .saturating_mul(current_share) - .saturating_to_num::() + let maybe_value_per_share = shared_value.checked_div(denominator); + (if let Some(value_per_share) = maybe_value_per_share { + value_per_share.saturating_mul(current_share) + } else { + shared_value + .saturating_mul(current_share) + .checked_div(denominator) + .unwrap_or(U64F64::saturating_from_num(0)) + }) + .saturating_to_num::() } pub fn try_get_value(&self, key: &K) -> Result { @@ -84,25 +90,40 @@ where true } else { // There are already keys in the pool, set or update this key - let value_per_share: I64F64 = I64F64::saturating_from_num( - shared_value - .checked_div(denominator) // denominator is never 0 here - .unwrap_or(U64F64::saturating_from_num(0)), - ); - - let shares_per_update: I64F64 = I64F64::saturating_from_num(update) - .checked_div(value_per_share) - .unwrap_or(I64F64::saturating_from_num(0)); + let shares_per_update: I64F64 = + self.get_shares_per_update(update, &shared_value, &denominator); shares_per_update != 0 } } + fn get_shares_per_update( + &self, + update: i64, + shared_value: &U64F64, + denominator: &U64F64, + ) -> I64F64 { + let maybe_value_per_share = shared_value.checked_div(*denominator); + if let Some(value_per_share) = maybe_value_per_share { + I64F64::saturating_from_num(update) + .checked_div(I64F64::saturating_from_num(value_per_share)) + .unwrap_or(I64F64::saturating_from_num(0)) + } else { + I64F64::saturating_from_num(update) + .checked_div(I64F64::saturating_from_num(*shared_value)) + .unwrap_or(I64F64::saturating_from_num(0)) + .saturating_mul(I64F64::saturating_from_num(*denominator)) + } + } + /// Update the value associated with an item identified by the Key - pub fn update_value_for_one(&mut self, key: &K, update: i64) { + /// Returns actual update + /// + pub fn update_value_for_one(&mut self, key: &K, update: i64) -> i64 { let shared_value: U64F64 = self.state_ops.get_shared_value(); let current_share: U64F64 = self.state_ops.get_share(key); let denominator: U64F64 = self.state_ops.get_denominator(); + let initial_value: i64 = self.get_value(key) as i64; // First, update shared value self.update_value_for_all(update); @@ -114,16 +135,8 @@ where self.state_ops.set_denominator(new_shared_value); self.state_ops.set_share(key, new_shared_value); } else { - // There are already keys in the pool, set or update this key - let value_per_share: I64F64 = I64F64::saturating_from_num( - shared_value - .checked_div(denominator) // denominator is never 0 here - .unwrap_or(U64F64::saturating_from_num(0)), - ); - - let shares_per_update: I64F64 = I64F64::saturating_from_num(update) - .checked_div(value_per_share) - .unwrap_or(I64F64::saturating_from_num(0)); + let shares_per_update: I64F64 = + self.get_shares_per_update(update, &shared_value, &denominator); if shares_per_update >= 0 { self.state_ops.set_denominator( @@ -134,17 +147,36 @@ where current_share.saturating_add(U64F64::saturating_from_num(shares_per_update)), ); } else { - self.state_ops.set_denominator( - denominator - .saturating_sub(U64F64::saturating_from_num(shares_per_update.neg())), - ); - self.state_ops.set_share( - key, - current_share - .saturating_sub(U64F64::saturating_from_num(shares_per_update.neg())), - ); + // Check if this entry is about to break precision + let mut new_denominator = denominator + .saturating_sub(U64F64::saturating_from_num(shares_per_update.neg())); + let mut new_share = current_share + .saturating_sub(U64F64::saturating_from_num(shares_per_update.neg())); + let shares_per_update_u64f64 = U64F64::saturating_from_num(shares_per_update.neg()); + + // The condition here is either the share remainder is too little OR + // the new_denominator is too low compared to what shared_value + year worth of emissions would be + if (current_share + .saturating_sub(shares_per_update_u64f64) + .safe_div(current_share) + < U64F64::saturating_from_num(0.00001)) + || shared_value + .saturating_add(U64F64::saturating_from_num(2_628_000_000_000_000_u64)) + .checked_div(new_denominator) + .is_none() + { + // yes, precision is low, just remove all + new_share = U64F64::saturating_from_num(0); + new_denominator = denominator.saturating_sub(current_share); + } + + self.state_ops.set_denominator(new_denominator); + self.state_ops.set_share(key, new_share); } } + + let final_value: i64 = self.get_value(key) as i64; + final_value.saturating_sub(initial_value) } } @@ -279,6 +311,62 @@ mod tests { assert_eq!(value2, 10); } + // cargo test --package share-pool --lib -- tests::test_denom_high_precision --exact --show-output + #[test] + fn test_denom_high_precision() { + let mock_ops = MockSharePoolDataOperations::new(); + let mut pool = SharePool::::new(mock_ops); + + pool.update_value_for_one(&1, 1); + pool.update_value_for_one(&2, 1); + + pool.update_value_for_all(999_999_999_999_998); + + pool.update_value_for_one(&1, -499_999_999_999_990); + pool.update_value_for_one(&2, -499_999_999_999_990); + + pool.update_value_for_all(999_999_999_999_980); + + pool.update_value_for_one(&1, 1_000_000_000_000); + pool.update_value_for_one(&2, 1_000_000_000_000); + + let value1 = pool.get_value(&1) as i128; + let value2 = pool.get_value(&2) as i128; + + // First to stake gets all accumulated emission if there are no other stakers + // (which is artificial situation because there will be no emissions if there is no stake) + assert!((value1 - 1_001_000_000_000_000).abs() < 10); + assert!((value2 - 1_000_000_000_000).abs() < 10); + } + + // cargo test --package share-pool --lib -- tests::test_denom_high_precision_many_small_unstakes --exact --show-output + #[test] + fn test_denom_high_precision_many_small_unstakes() { + let mock_ops = MockSharePoolDataOperations::new(); + let mut pool = SharePool::::new(mock_ops); + + pool.update_value_for_one(&1, 1); + pool.update_value_for_one(&2, 1); + + pool.update_value_for_all(1_000_000_000_000_000); + + for _ in 0..1_000_000 { + pool.update_value_for_one(&1, -500_000_000); + pool.update_value_for_one(&2, -500_000_000); + } + + pool.update_value_for_all(1_000_000_000_000_000); + + pool.update_value_for_one(&1, 1_000_000_000_000); + pool.update_value_for_one(&2, 1_000_000_000_000); + + let value1 = pool.get_value(&1) as i128; + let value2 = pool.get_value(&2) as i128; + + assert!((value1 - 1_001_000_000_000_000).abs() < 10); + assert!((value2 - 1_000_000_000_000).abs() < 10); + } + #[test] fn test_update_value_for_one() { let mock_ops = MockSharePoolDataOperations::new(); From 621523a240120129519b25cda7d07c7316a77709 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 17 Feb 2025 17:24:40 -0500 Subject: [PATCH 19/47] Fix unstaking 99.999% and add tests --- pallets/subtensor/src/tests/move_stake.rs | 111 ++++++++++++++- pallets/subtensor/src/tests/staking.rs | 166 ++++++++++++---------- primitives/share-pool/src/lib.rs | 22 +-- 3 files changed, 210 insertions(+), 89 deletions(-) diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs index 15832b93f..5409ad589 100644 --- a/pallets/subtensor/src/tests/move_stake.rs +++ b/pallets/subtensor/src/tests/move_stake.rs @@ -3,7 +3,7 @@ use crate::*; use approx::assert_abs_diff_eq; use frame_support::{assert_err, assert_noop, assert_ok}; use sp_core::{Get, U256}; -use substrate_fixed::types::I96F32; +use substrate_fixed::types::{I96F32, U64F64}; // 1. test_do_move_success // Description: Test a successful move of stake between two hotkeys in the same subnet @@ -1641,3 +1641,112 @@ fn test_stake_transfers_disabled_validate() { assert_ok!(result3); }); } + +#[test] +// RUST_LOG=info cargo test --package pallet-subtensor --lib -- tests::staking::test_move_stake_specific_stake_into_subnet_fail --exact --show-output +fn test_move_stake_specific_stake_into_subnet_fail() { + new_test_ext(1).execute_with(|| { + let sn_owner_coldkey = U256::from(55453); + + let hotkey_account_id = U256::from(533453); + let coldkey_account_id = U256::from(55454); + let hotkey_owner_account_id = U256::from(533454); + + let existing_shares: U64F64 = + U64F64::from_num(161_986_254).saturating_div(U64F64::from_num(u64::MAX)); + let existing_stake = 36_711_495_953; + + let tao_in = 2_409_892_148_947; + let alpha_in = 15_358_708_513_716; + + let tao_staked = 200_000_000; + + //add network + let netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey); + + let origin_netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey); + + // Register hotkey on netuid + register_ok_neuron(netuid, hotkey_account_id, hotkey_owner_account_id, 0); + // Register hotkey on origin netuid + register_ok_neuron(origin_netuid, hotkey_account_id, hotkey_owner_account_id, 0); + + // Check we have zero staked + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + 0 + ); + + // Set a hotkey pool for the hotkey on destination subnet + let mut hotkey_pool = SubtensorModule::get_alpha_share_pool(hotkey_account_id, netuid); + hotkey_pool.update_value_for_one(&hotkey_owner_account_id, 1234); // Doesn't matter, will be overridden + + // Adjust the total hotkey stake and shares to match the existing values + TotalHotkeyShares::::insert(hotkey_account_id, netuid, existing_shares); + TotalHotkeyAlpha::::insert(hotkey_account_id, netuid, existing_stake); + + // Make the hotkey a delegate + Delegates::::insert(hotkey_account_id, 0); + + // Setup Subnet pool + SubnetAlphaIn::::insert(netuid, alpha_in); + SubnetTAO::::insert(netuid, tao_in); + + // Give TAO balance to coldkey + SubtensorModule::add_balance_to_coldkey_account( + &coldkey_account_id, + tao_staked + 1_000_000_000, + ); + + // Setup Subnet pool for origin netuid + SubnetAlphaIn::::insert(origin_netuid, alpha_in + 10_000_000); + SubnetTAO::::insert(origin_netuid, tao_in + 10_000_000); + + // Add stake as new hotkey + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + origin_netuid, + tao_staked, + ),); + let alpha_to_move = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_account_id, + &coldkey_account_id, + origin_netuid, + ); + + // Move stake to destination subnet + assert_ok!(SubtensorModule::move_stake( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + hotkey_account_id, + origin_netuid, + netuid, + alpha_to_move, + )); + + // Check that the stake has been moved + assert_eq!( + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_account_id, + &coldkey_account_id, + origin_netuid + ), + 0 + ); + let fee = DefaultStakingFee::::get(); + let alpha_fee: I96F32 = I96F32::from_num(fee) / SubtensorModule::get_alpha_price(netuid); + let expected_value = I96F32::from_num(alpha_to_move) + * SubtensorModule::get_alpha_price(origin_netuid) + / SubtensorModule::get_alpha_price(netuid); + assert_abs_diff_eq!( + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_account_id, + &coldkey_account_id, + netuid + ), + (expected_value - alpha_fee).to_num::(), + epsilon = (expected_value / 1000).to_num::() + ); + }); +} diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs index 794617d77..80fd4db65 100644 --- a/pallets/subtensor/src/tests/staking.rs +++ b/pallets/subtensor/src/tests/staking.rs @@ -3692,111 +3692,121 @@ fn test_add_stake_specific_stake_into_subnet_fail() { }); } +// cargo test --package pallet-subtensor --lib -- tests::staking::test_remove_99_999_per_cent_stake_removes_all --exact --show-output #[test] -// RUST_LOG=info cargo test --package pallet-subtensor --lib -- tests::staking::test_move_stake_specific_stake_into_subnet_fail --exact --show-output -fn test_move_stake_specific_stake_into_subnet_fail() { +fn test_remove_99_9991_per_cent_stake_removes_all() { + // When we remove stake, the total issuance of the balances pallet should not change + // this is because the stake should be part of the coldkey account balance (reserved/locked) + // then the removed stake just becomes free balance new_test_ext(1).execute_with(|| { - let sn_owner_coldkey = U256::from(55453); - - let hotkey_account_id = U256::from(533453); - let coldkey_account_id = U256::from(55454); - let hotkey_owner_account_id = U256::from(533454); - - let existing_shares: U64F64 = - U64F64::from_num(161_986_254).saturating_div(U64F64::from_num(u64::MAX)); - let existing_stake = 36_711_495_953; - - let tao_in = 2_409_892_148_947; - let alpha_in = 15_358_708_513_716; - - let tao_staked = 200_000_000; + let subnet_owner_coldkey = U256::from(1); + let subnet_owner_hotkey = U256::from(2); + let hotkey_account_id = U256::from(581337); + let coldkey_account_id = U256::from(81337); + let amount = 10_000_000_000; + let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + let fee = DefaultStakingFee::::get(); + register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, 192213123); - //add network - let netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey); + // Give it some $$$ in his coldkey balance + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, amount); - let origin_netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey); + // Stake to hotkey account, and check if the result is ok + assert_ok!(SubtensorModule::add_stake( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + netuid, + amount + )); - // Register hotkey on netuid - register_ok_neuron(netuid, hotkey_account_id, hotkey_owner_account_id, 0); - // Register hotkey on origin netuid - register_ok_neuron(origin_netuid, hotkey_account_id, hotkey_owner_account_id, 0); + // Remove 99.9991% stake + let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_account_id, + &coldkey_account_id, + netuid, + ); + assert_ok!(SubtensorModule::remove_stake( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + netuid, + (U64F64::from_num(alpha) * U64F64::from_num(0.999991)).to_num::() + )); - // Check we have zero staked + // Check that all alpha was unstaked and all TAO balance was returned (less fees) + assert_abs_diff_eq!( + SubtensorModule::get_coldkey_balance(&coldkey_account_id), + amount - fee * 2, + epsilon = 10000, + ); assert_eq!( SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), 0 ); - - // Set a hotkey pool for the hotkey on destination subnet - let mut hotkey_pool = SubtensorModule::get_alpha_share_pool(hotkey_account_id, netuid); - hotkey_pool.update_value_for_one(&hotkey_owner_account_id, 1234); // Doesn't matter, will be overridden - - // Adjust the total hotkey stake and shares to match the existing values - TotalHotkeyShares::::insert(hotkey_account_id, netuid, existing_shares); - TotalHotkeyAlpha::::insert(hotkey_account_id, netuid, existing_stake); - - // Make the hotkey a delegate - Delegates::::insert(hotkey_account_id, 0); - - // Setup Subnet pool - SubnetAlphaIn::::insert(netuid, alpha_in); - SubnetTAO::::insert(netuid, tao_in); - - // Give TAO balance to coldkey - SubtensorModule::add_balance_to_coldkey_account( + let new_alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_account_id, &coldkey_account_id, - tao_staked + 1_000_000_000, + netuid, ); + assert_eq!(new_alpha, 0); + }); +} + +// cargo test --package pallet-subtensor --lib -- tests::staking::test_remove_99_9989_per_cent_stake_leaves_a_little --exact --show-output +#[test] +fn test_remove_99_9989_per_cent_stake_leaves_a_little() { + // When we remove stake, the total issuance of the balances pallet should not change + // this is because the stake should be part of the coldkey account balance (reserved/locked) + // then the removed stake just becomes free balance + new_test_ext(1).execute_with(|| { + let subnet_owner_coldkey = U256::from(1); + let subnet_owner_hotkey = U256::from(2); + let hotkey_account_id = U256::from(581337); + let coldkey_account_id = U256::from(81337); + let amount = 10_000_000_000; + let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + let fee = DefaultStakingFee::::get(); + register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, 192213123); - // Setup Subnet pool for origin netuid - SubnetAlphaIn::::insert(origin_netuid, alpha_in + 10_000_000); - SubnetTAO::::insert(origin_netuid, tao_in + 10_000_000); + // Give it some $$$ in his coldkey balance + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, amount); - // Add stake as new hotkey + // Stake to hotkey account, and check if the result is ok assert_ok!(SubtensorModule::add_stake( RuntimeOrigin::signed(coldkey_account_id), hotkey_account_id, - origin_netuid, - tao_staked, - ),); - let alpha_to_move = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + netuid, + amount + )); + + // Remove 99.9989% stake + let alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( &hotkey_account_id, &coldkey_account_id, - origin_netuid, + netuid, ); - - // Move stake to destination subnet - assert_ok!(SubtensorModule::move_stake( + assert_ok!(SubtensorModule::remove_stake( RuntimeOrigin::signed(coldkey_account_id), hotkey_account_id, - hotkey_account_id, - origin_netuid, netuid, - alpha_to_move, + (U64F64::from_num(alpha) * U64F64::from_num(0.99)).to_num::() )); - // Check that the stake has been moved - assert_eq!( - SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( - &hotkey_account_id, - &coldkey_account_id, - origin_netuid - ), - 0 + // Check that all alpha was unstaked and 99% TAO balance was returned (less fees) + assert_abs_diff_eq!( + SubtensorModule::get_coldkey_balance(&coldkey_account_id), + (amount as f64 * 0.99) as u64 - fee * 2, + epsilon = amount / 1000, ); - let fee = DefaultStakingFee::::get(); - let alpha_fee: I96F32 = I96F32::from_num(fee) / SubtensorModule::get_alpha_price(netuid); - let expected_value = I96F32::from_num(alpha_to_move) - * SubtensorModule::get_alpha_price(origin_netuid) - / SubtensorModule::get_alpha_price(netuid); assert_abs_diff_eq!( - SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( - &hotkey_account_id, - &coldkey_account_id, - netuid - ), - (expected_value - alpha_fee).to_num::(), - epsilon = (expected_value / 1000).to_num::() + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + (amount as f64 * 0.01) as u64, + epsilon = amount / 1000, + ); + let new_alpha = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_account_id, + &coldkey_account_id, + netuid, ); + assert_abs_diff_eq!(new_alpha, (alpha as f64 * 0.01) as u64, epsilon = 10); }); } diff --git a/primitives/share-pool/src/lib.rs b/primitives/share-pool/src/lib.rs index 27006ad96..6251401dc 100644 --- a/primitives/share-pool/src/lib.rs +++ b/primitives/share-pool/src/lib.rs @@ -124,16 +124,14 @@ where let current_share: U64F64 = self.state_ops.get_share(key); let denominator: U64F64 = self.state_ops.get_denominator(); let initial_value: i64 = self.get_value(key) as i64; - - // First, update shared value - self.update_value_for_all(update); - let new_shared_value: U64F64 = self.state_ops.get_shared_value(); + let mut actual_update: i64 = update; // Then, update this key's share if denominator == 0 { // Initialize the pool. The first key gets all. - self.state_ops.set_denominator(new_shared_value); - self.state_ops.set_share(key, new_shared_value); + let update_fixed: U64F64 = U64F64::saturating_from_num(update); + self.state_ops.set_denominator(update_fixed); + self.state_ops.set_share(key, update_fixed); } else { let shares_per_update: I64F64 = self.get_shares_per_update(update, &shared_value, &denominator); @@ -168,6 +166,7 @@ where // yes, precision is low, just remove all new_share = U64F64::saturating_from_num(0); new_denominator = denominator.saturating_sub(current_share); + actual_update = initial_value.neg(); } self.state_ops.set_denominator(new_denominator); @@ -175,8 +174,11 @@ where } } - let final_value: i64 = self.get_value(key) as i64; - final_value.saturating_sub(initial_value) + // Update shared value + self.update_value_for_all(actual_update); + + // Return actual udate + actual_update } } @@ -335,8 +337,8 @@ mod tests { // First to stake gets all accumulated emission if there are no other stakers // (which is artificial situation because there will be no emissions if there is no stake) - assert!((value1 - 1_001_000_000_000_000).abs() < 10); - assert!((value2 - 1_000_000_000_000).abs() < 10); + assert!((value1 - 1_001_000_000_000_000).abs() < 100); + assert!((value2 - 1_000_000_000_000).abs() < 100); } // cargo test --package share-pool --lib -- tests::test_denom_high_precision_many_small_unstakes --exact --show-output From f06e95e7632d4fec672e0aeda5798d3a1ca67ade Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 17 Feb 2025 17:35:29 -0500 Subject: [PATCH 20/47] Fix event and logging in unstake_from_subnet --- pallets/subtensor/src/staking/stake_utils.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index 039287052..20497ae96 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -770,7 +770,7 @@ impl Pallet { coldkey.clone(), hotkey.clone(), tao_unstaked, - alpha, + actual_alpha_decrease, netuid, )); log::info!( @@ -778,7 +778,7 @@ impl Pallet { coldkey.clone(), hotkey.clone(), tao_unstaked, - alpha, + actual_alpha_decrease, netuid ); From f30517a80047f28819b214a256948c8db08b3db4 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 17 Feb 2025 17:43:22 -0500 Subject: [PATCH 21/47] Fix build --- pallets/subtensor/src/staking/stake_utils.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index 800a75348..20497ae96 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -559,15 +559,6 @@ impl Pallet { alpha_share_pool.sim_update_value_for_one(amount as i64) } - pub fn try_increase_stake_for_hotkey_and_coldkey_on_subnet( - hotkey: &T::AccountId, - netuid: u16, - amount: u64, - ) -> bool { - let mut alpha_share_pool = Self::get_alpha_share_pool(hotkey.clone(), netuid); - alpha_share_pool.sim_update_value_for_one(amount as i64) - } - /// Sell shares in the hotkey on a given subnet /// /// The function updates share totals given current prices. From 5c5d232cd6f6dc0d9740c6aea16155f7d05cd850 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 17 Feb 2025 17:58:46 -0500 Subject: [PATCH 22/47] Bump spec version --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 8dcce09b1..0320e8998 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: 239, + spec_version: 240, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 8742aa70dfc9bcd41171fe55c5087f2321389a16 Mon Sep 17 00:00:00 2001 From: gztensor <166415444+gztensor@users.noreply.github.com> Date: Mon, 17 Feb 2025 15:46:27 -0800 Subject: [PATCH 23/47] Update primitives/share-pool/src/lib.rs Co-authored-by: Cameron Fairchild --- primitives/share-pool/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/primitives/share-pool/src/lib.rs b/primitives/share-pool/src/lib.rs index 6251401dc..5dff32efd 100644 --- a/primitives/share-pool/src/lib.rs +++ b/primitives/share-pool/src/lib.rs @@ -154,8 +154,7 @@ where // The condition here is either the share remainder is too little OR // the new_denominator is too low compared to what shared_value + year worth of emissions would be - if (current_share - .saturating_sub(shares_per_update_u64f64) + if (new_share .safe_div(current_share) < U64F64::saturating_from_num(0.00001)) || shared_value From a0e4165b5b3ede5cf7f009127aa37630208c8ca4 Mon Sep 17 00:00:00 2001 From: gztensor <166415444+gztensor@users.noreply.github.com> Date: Mon, 17 Feb 2025 15:46:51 -0800 Subject: [PATCH 24/47] Update pallets/subtensor/src/tests/staking.rs Co-authored-by: Cameron Fairchild --- pallets/subtensor/src/tests/staking.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs index 80fd4db65..74ffe5629 100644 --- a/pallets/subtensor/src/tests/staking.rs +++ b/pallets/subtensor/src/tests/staking.rs @@ -3695,9 +3695,6 @@ fn test_add_stake_specific_stake_into_subnet_fail() { // cargo test --package pallet-subtensor --lib -- tests::staking::test_remove_99_999_per_cent_stake_removes_all --exact --show-output #[test] fn test_remove_99_9991_per_cent_stake_removes_all() { - // When we remove stake, the total issuance of the balances pallet should not change - // this is because the stake should be part of the coldkey account balance (reserved/locked) - // then the removed stake just becomes free balance new_test_ext(1).execute_with(|| { let subnet_owner_coldkey = U256::from(1); let subnet_owner_hotkey = U256::from(2); From b57130f861adb32f2a53ee976375da82f247ed21 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 17 Feb 2025 18:48:11 -0500 Subject: [PATCH 25/47] Remove unused variable --- primitives/share-pool/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/primitives/share-pool/src/lib.rs b/primitives/share-pool/src/lib.rs index 5dff32efd..0056f391f 100644 --- a/primitives/share-pool/src/lib.rs +++ b/primitives/share-pool/src/lib.rs @@ -150,13 +150,10 @@ where .saturating_sub(U64F64::saturating_from_num(shares_per_update.neg())); let mut new_share = current_share .saturating_sub(U64F64::saturating_from_num(shares_per_update.neg())); - let shares_per_update_u64f64 = U64F64::saturating_from_num(shares_per_update.neg()); // The condition here is either the share remainder is too little OR // the new_denominator is too low compared to what shared_value + year worth of emissions would be - if (new_share - .safe_div(current_share) - < U64F64::saturating_from_num(0.00001)) + if (new_share.safe_div(current_share) < U64F64::saturating_from_num(0.00001)) || shared_value .saturating_add(U64F64::saturating_from_num(2_628_000_000_000_000_u64)) .checked_div(new_denominator) From 41d50fd68a936965655477e386061207b1d0d8a5 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 17 Feb 2025 19:22:07 -0500 Subject: [PATCH 26/47] Add test_get_shares_per_update --- primitives/share-pool/src/lib.rs | 46 ++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/primitives/share-pool/src/lib.rs b/primitives/share-pool/src/lib.rs index 0056f391f..a49187ae0 100644 --- a/primitives/share-pool/src/lib.rs +++ b/primitives/share-pool/src/lib.rs @@ -387,4 +387,50 @@ mod tests { U64F64::saturating_from_num(1000) ); } + + // cargo test --package share-pool --lib -- tests::test_get_shares_per_update --exact --show-output + #[test] + fn test_get_shares_per_update() { + [ + (1_i64, 1_u64, 1.0, 1.0), + ( + 1_000, + 21_000_000_000_000_000, + 0.00001, + 0.00000000000000000043, + ), + ( + 21_000_000_000_000_000, + 21_000_000_000_000_000, + 0.00001, + 0.00001, + ), + ( + 210_000_000_000_000_000, + 21_000_000_000_000_000, + 0.00001, + 0.0001, + ), + ( + 1_000, + 1_000, + 21_000_000_000_000_000_f64, + 21_000_000_000_000_000_f64, + ), + ] + .iter() + .for_each(|(update, shared_value, denominator, expected)| { + let mock_ops = MockSharePoolDataOperations::new(); + let pool = SharePool::::new(mock_ops); + + let shared_fixed = U64F64::from_num(*shared_value); + let denominator_fixed = U64F64::from_num(*denominator); + let expected_fixed = I64F64::from_num(*expected); + + let spu: I64F64 = + pool.get_shares_per_update(*update, &shared_fixed, &denominator_fixed); + let precision: I64F64 = I64F64::from_num(1000.); + assert!((spu - expected_fixed).abs() <= expected_fixed / precision,); + }); + } } From a27b99613047fd33d93407c3e1504826cff0e37e Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 18 Feb 2025 10:46:20 -0500 Subject: [PATCH 27/47] try it again --- .github/workflows/try-runtime.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/try-runtime.yml b/.github/workflows/try-runtime.yml index 9bce50fb5..de43efa9a 100644 --- a/.github/workflows/try-runtime.yml +++ b/.github/workflows/try-runtime.yml @@ -24,7 +24,7 @@ jobs: check-testnet: name: check testnet - if: github.base_ref == 'testnet' || github.base_ref == 'devnet' || github.base_ref == 'main' + # if: github.base_ref == 'testnet' || github.base_ref == 'devnet' || github.base_ref == 'main' runs-on: SubtensorCI steps: - name: Checkout sources From a5df0857a1525367709cbd494fadf86949d88ada Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 18 Feb 2025 10:50:29 -0500 Subject: [PATCH 28/47] use latest rust-cache version --- .github/workflows/check-rust.yml | 10 +++++----- .github/workflows/update-chainspec.yml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/check-rust.yml b/.github/workflows/check-rust.yml index cdee05bfa..722940166 100644 --- a/.github/workflows/check-rust.yml +++ b/.github/workflows/check-rust.yml @@ -93,7 +93,7 @@ jobs: sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - name: Utilize Shared Rust Cache - uses: Swatinem/rust-cache@v2.2.1 + uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.os }}-${{ env.RUST_BIN_DIR }} @@ -137,7 +137,7 @@ jobs: profile: minimal - name: Utilize Shared Rust Cache - uses: Swatinem/rust-cache@v2.2.1 + uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.os }}-${{ env.RUST_BIN_DIR }} @@ -178,7 +178,7 @@ jobs: sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - name: Utilize Shared Rust Cache - uses: Swatinem/rust-cache@v2.2.1 + uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.os }}-${{ env.RUST_BIN_DIR }} @@ -217,7 +217,7 @@ jobs: sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - name: Utilize Rust shared cached - uses: Swatinem/rust-cache@v2.2.1 + uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.os }}-${{ env.RUST_BIN_DIR }} @@ -258,7 +258,7 @@ jobs: sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - name: Utilize Rust shared cached - uses: Swatinem/rust-cache@v2.2.1 + uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.os }}-${{ env.RUST_BIN_DIR }} diff --git a/.github/workflows/update-chainspec.yml b/.github/workflows/update-chainspec.yml index bf7cc5588..be50108bf 100644 --- a/.github/workflows/update-chainspec.yml +++ b/.github/workflows/update-chainspec.yml @@ -49,7 +49,7 @@ jobs: sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - name: Utilize Shared Rust Cache - uses: Swatinem/rust-cache@v2.2.1 + uses: Swatinem/rust-cache@v2 with: key: ubuntu-latest-target/x86_64-unknown-linux-gnu From 1c236003596338ffbf7aaafa553e50d1d47ecb30 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 18 Feb 2025 11:03:22 -0500 Subject: [PATCH 29/47] improve spec version check cache performance --- .github/workflows/check-devnet.yml | 11 ++++++++--- .github/workflows/check-finney.yml | 11 ++++++++--- .github/workflows/check-testnet.yml | 11 ++++++++--- Cargo.lock | 2 +- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/.github/workflows/check-devnet.yml b/.github/workflows/check-devnet.yml index 13ebf89cc..b6c20beee 100644 --- a/.github/workflows/check-devnet.yml +++ b/.github/workflows/check-devnet.yml @@ -20,12 +20,17 @@ jobs: sudo apt-get install -y curl clang curl libssl-dev llvm \ libudev-dev protobuf-compiler - - name: Install substrate-spec-version - run: cargo install substrate-spec-version - - name: Check-out repository under $GITHUB_WORKSPACE uses: actions/checkout@v4 + - name: Utilize Shared Rust Cache + uses: Swatinem/rust-cache@v2 + with: + key: "spec-version" + + - name: Install substrate-spec-version + run: cargo install substrate-spec-version + - name: Check that spec_version has been bumped run: | spec_version=$(PATH=$PATH:$HOME/.cargo/.bin substrate-spec-version wss://dev.chain.opentensor.ai:443 | tr -d '\n') diff --git a/.github/workflows/check-finney.yml b/.github/workflows/check-finney.yml index 98f90fc8e..448e53ee1 100644 --- a/.github/workflows/check-finney.yml +++ b/.github/workflows/check-finney.yml @@ -20,12 +20,17 @@ jobs: sudo apt-get install -y curl clang curl libssl-dev llvm \ libudev-dev protobuf-compiler - - name: Install substrate-spec-version - run: cargo install substrate-spec-version - - name: Check-out repository under $GITHUB_WORKSPACE uses: actions/checkout@v4 + - name: Utilize Shared Rust Cache + uses: Swatinem/rust-cache@v2 + with: + key: "spec-version" + + - name: Install substrate-spec-version + run: cargo install substrate-spec-version + - name: Check that spec_version has been bumped run: | spec_version=$(PATH=$PATH:$HOME/.cargo/.bin substrate-spec-version wss://entrypoint-finney.opentensor.ai:443 | tr -d '\n') diff --git a/.github/workflows/check-testnet.yml b/.github/workflows/check-testnet.yml index 7c8532ec5..8a59036d9 100644 --- a/.github/workflows/check-testnet.yml +++ b/.github/workflows/check-testnet.yml @@ -20,12 +20,17 @@ jobs: sudo apt-get install -y curl clang curl libssl-dev llvm \ libudev-dev protobuf-compiler - - name: Install substrate-spec-version - run: cargo install substrate-spec-version - - name: Check-out repository under $GITHUB_WORKSPACE uses: actions/checkout@v4 + - name: Utilize Shared Rust Cache + uses: Swatinem/rust-cache@v2 + with: + key: "spec-version" + + - name: Install substrate-spec-version + run: cargo install substrate-spec-version + - name: Check that spec_version has been bumped run: | spec_version=$(PATH=$PATH:$HOME/.cargo/.bin substrate-spec-version wss://test.finney.opentensor.ai:443 | tr -d '\n') diff --git a/Cargo.lock b/Cargo.lock index bf63b9aea..0d7618801 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1785,7 +1785,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1145d32e826a7748b69ee8fc62d3e6355ff7f1051df53141e7048162fc90481b" dependencies = [ "data-encoding", - "syn 1.0.109", + "syn 2.0.96", ] [[package]] From 68c119699ec96d555a6f45e65b40625098aec9b3 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 18 Feb 2025 11:19:46 -0500 Subject: [PATCH 30/47] try busting cache --- .github/workflows/check-devnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-devnet.yml b/.github/workflows/check-devnet.yml index b6c20beee..f835b61c3 100644 --- a/.github/workflows/check-devnet.yml +++ b/.github/workflows/check-devnet.yml @@ -22,7 +22,7 @@ jobs: - name: Check-out repository under $GITHUB_WORKSPACE uses: actions/checkout@v4 - + # file change to break cache - name: Utilize Shared Rust Cache uses: Swatinem/rust-cache@v2 with: From 45ae5e725b2b2a2585332bbbfbcd9e43d6aecfd5 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 18 Feb 2025 11:24:29 -0500 Subject: [PATCH 31/47] it worked :fire: --- .github/workflows/check-devnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-devnet.yml b/.github/workflows/check-devnet.yml index f835b61c3..b6c20beee 100644 --- a/.github/workflows/check-devnet.yml +++ b/.github/workflows/check-devnet.yml @@ -22,7 +22,7 @@ jobs: - name: Check-out repository under $GITHUB_WORKSPACE uses: actions/checkout@v4 - # file change to break cache + - name: Utilize Shared Rust Cache uses: Swatinem/rust-cache@v2 with: From 676114ee5a83874e8067f0ebd7cb5a1750c55a51 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 18 Feb 2025 12:23:50 -0500 Subject: [PATCH 32/47] use better rust cache throughout CI + clean up CI --- .github/workflows/cargo-audit.yml | 5 + .github/workflows/check-rust.yml | 148 +++------------------- .github/workflows/e2e-bittensor-tests.yml | 29 +---- .github/workflows/try-runtime.yml | 16 +++ .github/workflows/update-chainspec.yml | 12 +- 5 files changed, 44 insertions(+), 166 deletions(-) diff --git a/.github/workflows/cargo-audit.yml b/.github/workflows/cargo-audit.yml index 14e2d9449..aa8fb7c9f 100644 --- a/.github/workflows/cargo-audit.yml +++ b/.github/workflows/cargo-audit.yml @@ -24,6 +24,11 @@ jobs: sudo apt-get update && sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler + - name: Utilize Shared Rust Cache + uses: Swatinem/rust-cache@v2 + with: + key: "cargo-audit" + - name: Install cargo-audit run: cargo install --force cargo-audit diff --git a/.github/workflows/check-rust.yml b/.github/workflows/check-rust.yml index cdee05bfa..25f544f36 100644 --- a/.github/workflows/check-rust.yml +++ b/.github/workflows/check-rust.yml @@ -24,25 +24,8 @@ jobs: cargo-fmt: name: cargo fmt runs-on: SubtensorCI - strategy: - matrix: - rust-branch: - - nightly-2024-03-05 - rust-target: - - x86_64-unknown-linux-gnu - # - x86_64-apple-darwin - os: - - ubuntu-latest - # - macos-latest - include: - - os: ubuntu-latest - # - os: macos-latest env: - RELEASE_NAME: development - # RUSTFLAGS: -A warnings RUST_BACKTRACE: full - SKIP_WASM_BUILD: 1 - TARGET: ${{ matrix.rust-target }} steps: - name: Check-out repository under $GITHUB_WORKSPACE uses: actions/checkout@v4 @@ -50,39 +33,18 @@ jobs: - name: Install dependencies run: sudo apt-get update && sudo apt-get install -y build-essential - - name: Install Rust Nightly - uses: actions-rs/toolchain@v1.0.6 - with: - toolchain: nightly - components: rustfmt - profile: minimal + - name: Utilize Shared Rust Cache + uses: Swatinem/rust-cache@v2 - name: cargo fmt - run: cargo fmt --check --all + run: cargo +nightly fmt --check --all cargo-clippy-default-features: name: cargo clippy runs-on: SubtensorCI - strategy: - matrix: - rust-branch: - - stable - rust-target: - - x86_64-unknown-linux-gnu - # - x86_64-apple-darwin - os: - - ubuntu-latest - # - macos-latest - include: - - os: ubuntu-latest - # - os: macos-latest env: - RELEASE_NAME: development - # RUSTFLAGS: -A warnings RUST_BACKTRACE: full SKIP_WASM_BUILD: 1 - TARGET: ${{ matrix.rust-target }} - RUST_BIN_DIR: target/${{ matrix.rust-target }} steps: - name: Check-out repository under $GITHUB_WORKSPACE uses: actions/checkout@v4 @@ -93,9 +55,7 @@ jobs: sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - name: Utilize Shared Rust Cache - uses: Swatinem/rust-cache@v2.2.1 - with: - key: ${{ matrix.os }}-${{ env.RUST_BIN_DIR }} + uses: Swatinem/rust-cache@v2 - name: cargo clippy --workspace --all-targets -- -D warnings run: cargo clippy --workspace --all-targets -- -D warnings @@ -103,23 +63,10 @@ jobs: cargo-check-lints: name: check custom lints runs-on: SubtensorCI - strategy: - matrix: - rust-branch: - - stable - rust-target: - - x86_64-unknown-linux-gnu - # - x86_64-apple-darwin - os: - - ubuntu-latest - # - macos-latest env: - RELEASE_NAME: development RUSTFLAGS: -D warnings RUST_BACKTRACE: full SKIP_WASM_BUILD: 1 - TARGET: ${{ matrix.rust-target }} - RUST_BIN_DIR: target/${{ matrix.rust-target }} steps: - name: Check-out repository under $GITHUB_WORKSPACE uses: actions/checkout@v4 @@ -129,17 +76,8 @@ jobs: sudo apt-get update && sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - - name: Install Rust ${{ matrix.rust-branch }} - uses: actions-rs/toolchain@v1.0.6 - with: - toolchain: ${{ matrix.rust-branch }} - components: rustfmt, clippy - profile: minimal - - name: Utilize Shared Rust Cache - uses: Swatinem/rust-cache@v2.2.1 - with: - key: ${{ matrix.os }}-${{ env.RUST_BIN_DIR }} + uses: Swatinem/rust-cache@v2 - name: check lints run: | @@ -150,27 +88,12 @@ jobs: cargo-clippy-all-features: name: cargo clippy --all-features runs-on: SubtensorCI - strategy: - matrix: - rust-target: - - x86_64-unknown-linux-gnu - # - x86_64-apple-darwin - os: - - ubuntu-latest - # - macos-latest - include: - - os: ubuntu-latest - # - os: macos-latest env: - RELEASE_NAME: development - # RUSTFLAGS: -A warnings RUST_BACKTRACE: full - RUST_BIN_DIR: target/${{ matrix.rust-target }} SKIP_WASM_BUILD: 1 - TARGET: ${{ matrix.rust-target }} steps: - name: Check-out repository under $GITHUB_WORKSPACE - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install dependencies run: | @@ -178,35 +101,18 @@ jobs: sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - name: Utilize Shared Rust Cache - uses: Swatinem/rust-cache@v2.2.1 - with: - key: ${{ matrix.os }}-${{ env.RUST_BIN_DIR }} + uses: Swatinem/rust-cache@v2 - name: cargo clippy --workspace --all-targets --all-features -- -D warnings run: cargo clippy --workspace --all-targets --all-features -- -D warnings - # runs cargo test --workspace + # runs cargo test --workspace --all-features cargo-test: name: cargo test runs-on: SubtensorCI - strategy: - matrix: - rust-target: - - x86_64-unknown-linux-gnu - # - x86_64-apple-darwin - os: - - ubuntu-latest - # - macos-latest - include: - - os: ubuntu-latest - # - os: macos-latest env: - RELEASE_NAME: development - # RUSTFLAGS: -A warnings RUST_BACKTRACE: full - RUST_BIN_DIR: target/${{ matrix.rust-target }} SKIP_WASM_BUILD: 1 - TARGET: ${{ matrix.rust-target }} steps: - name: Check-out repository under $GITHUB_WORKSPACE uses: actions/checkout@v4 @@ -216,10 +122,8 @@ jobs: sudo apt-get update && sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - - name: Utilize Rust shared cached - uses: Swatinem/rust-cache@v2.2.1 - with: - key: ${{ matrix.os }}-${{ env.RUST_BIN_DIR }} + - name: Utilize Shared Rust Cache + uses: Swatinem/rust-cache@v2 - name: cargo test --workspace --all-features run: cargo test --workspace --all-features @@ -228,26 +132,9 @@ jobs: cargo-fix: name: cargo fix runs-on: SubtensorCI - strategy: - matrix: - rust-branch: - - stable - rust-target: - - x86_64-unknown-linux-gnu - # - x86_64-apple-darwin - os: - - ubuntu-latest - # - macos-latest - include: - - os: ubuntu-latest - # - os: macos-latest env: - RELEASE_NAME: development - # RUSTFLAGS: -A warnings RUST_BACKTRACE: full - RUST_BIN_DIR: target/${{ matrix.rust-target }} SKIP_WASM_BUILD: 1 - TARGET: ${{ matrix.rust-target }} steps: - name: Check-out repository under $GITHUB_WORKSPACE uses: actions/checkout@v4 @@ -257,10 +144,8 @@ jobs: sudo apt-get update && sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - - name: Utilize Rust shared cached - uses: Swatinem/rust-cache@v2.2.1 - with: - key: ${{ matrix.os }}-${{ env.RUST_BIN_DIR }} + - name: Utilize Shared Rust Cache + uses: Swatinem/rust-cache@v2 - name: cargo fix --workspace run: | @@ -280,13 +165,16 @@ jobs: runs-on: SubtensorCI steps: - - name: Install Zepter - run: cargo install --locked -q zepter && zepter --version - - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 # Dont clone historic commits. + - name: Utilize Shared Rust Cache + uses: Swatinem/rust-cache@v2 + + - name: Install Zepter + run: cargo install --locked -q zepter && zepter --version + - name: Check features run: zepter run check diff --git a/.github/workflows/e2e-bittensor-tests.yml b/.github/workflows/e2e-bittensor-tests.yml index 851c30a6d..5be78c2ec 100644 --- a/.github/workflows/e2e-bittensor-tests.yml +++ b/.github/workflows/e2e-bittensor-tests.yml @@ -22,41 +22,20 @@ env: jobs: run: runs-on: SubtensorCI - strategy: - matrix: - rust-branch: - - nightly-2024-03-05 - rust-target: - - x86_64-unknown-linux-gnu - # - x86_64-apple-darwin - os: - - ubuntu-latest - # - macos-latest - include: - - os: ubuntu-latest - # - os: macos-latest env: - RELEASE_NAME: development - RUSTV: ${{ matrix.rust-branch }} RUST_BACKTRACE: full - RUST_BIN_DIR: target/${{ matrix.rust-target }} - TARGET: ${{ matrix.rust-target }} steps: - name: Check-out repository under $GITHUB_WORKSPACE - uses: actions/checkout@v2 + uses: actions/checkout@v4 + + - name: Utilize Shared Rust Cache + uses: Swatinem/rust-cache@v2 - name: Install dependencies run: | sudo apt-get update && sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - - name: Install Rust ${{ matrix.rust-branch }} - uses: actions-rs/toolchain@v1.0.6 - with: - toolchain: ${{ matrix.rust-branch }} - components: rustfmt - profile: minimal - - name: Clone bittensor repo run: git clone https://github.com/opentensor/bittensor.git diff --git a/.github/workflows/try-runtime.yml b/.github/workflows/try-runtime.yml index 89a28c5c6..2e09f3201 100644 --- a/.github/workflows/try-runtime.yml +++ b/.github/workflows/try-runtime.yml @@ -16,6 +16,11 @@ jobs: - name: Checkout sources uses: actions/checkout@v4 + - name: Utilize Shared Rust Cache + uses: Swatinem/rust-cache@v2 + with: + key: "try-runtime" + - name: Run Try Runtime Checks uses: "paritytech/try-runtime-gha@v0.1.0" with: @@ -31,6 +36,11 @@ jobs: - name: Checkout sources uses: actions/checkout@v4 + - name: Utilize Shared Rust Cache + uses: Swatinem/rust-cache@v2 + with: + key: "try-runtime" + - name: Run Try Runtime Checks uses: "paritytech/try-runtime-gha@v0.1.0" with: @@ -45,6 +55,12 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v4 + + - name: Utilize Shared Rust Cache + uses: Swatinem/rust-cache@v2 + with: + key: "try-runtime" + - name: Run Try Runtime Checks uses: "paritytech/try-runtime-gha@v0.1.0" with: diff --git a/.github/workflows/update-chainspec.yml b/.github/workflows/update-chainspec.yml index bf7cc5588..1aedfeaa4 100644 --- a/.github/workflows/update-chainspec.yml +++ b/.github/workflows/update-chainspec.yml @@ -29,14 +29,6 @@ jobs: github.event.pull_request.head.ref != 'testnet' && github.event.pull_request.head.ref != 'main' - strategy: - matrix: - rust-target: - - x86_64-unknown-linux-gnu - os: - - ubuntu-latest - include: - - os: ubuntu-latest env: RUST_BACKTRACE: full steps: @@ -49,9 +41,7 @@ jobs: sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - name: Utilize Shared Rust Cache - uses: Swatinem/rust-cache@v2.2.1 - with: - key: ubuntu-latest-target/x86_64-unknown-linux-gnu + uses: Swatinem/rust-cache@v2 - name: Build chainspecs run: ./scripts/build_all_chainspecs.sh From 0b0a55f5bfff7946776ab518c9724c20b7c0d3a4 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 18 Feb 2025 12:35:50 -0500 Subject: [PATCH 33/47] install rust nightly for cargo fmt --- .github/workflows/check-rust.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/check-rust.yml b/.github/workflows/check-rust.yml index 25f544f36..f481cc614 100644 --- a/.github/workflows/check-rust.yml +++ b/.github/workflows/check-rust.yml @@ -54,6 +54,9 @@ jobs: sudo apt-get update && sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler + - name: Install Rust Nightly + run: rustup install nightly + - name: Utilize Shared Rust Cache uses: Swatinem/rust-cache@v2 From a3e9c66c2c77bd82887812dc4b4b7cfc5237b55f Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 18 Feb 2025 12:42:00 -0500 Subject: [PATCH 34/47] whoops --- .github/workflows/check-rust.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check-rust.yml b/.github/workflows/check-rust.yml index f481cc614..a030173c5 100644 --- a/.github/workflows/check-rust.yml +++ b/.github/workflows/check-rust.yml @@ -33,6 +33,9 @@ jobs: - name: Install dependencies run: sudo apt-get update && sudo apt-get install -y build-essential + - name: Install Rust Nightly + run: rustup install nightly + - name: Utilize Shared Rust Cache uses: Swatinem/rust-cache@v2 @@ -54,9 +57,6 @@ jobs: sudo apt-get update && sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - - name: Install Rust Nightly - run: rustup install nightly - - name: Utilize Shared Rust Cache uses: Swatinem/rust-cache@v2 From 249cd1a3e13cdb1d28d8c973ceec28fae1cddcf2 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 18 Feb 2025 12:52:37 -0500 Subject: [PATCH 35/47] fix --- .github/workflows/check-rust.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check-rust.yml b/.github/workflows/check-rust.yml index a030173c5..0fae77fa3 100644 --- a/.github/workflows/check-rust.yml +++ b/.github/workflows/check-rust.yml @@ -34,7 +34,9 @@ jobs: run: sudo apt-get update && sudo apt-get install -y build-essential - name: Install Rust Nightly - run: rustup install nightly + run: | + rustup install nightly + rustup component add --toolchain nightly-x86_64-unknown-linux-gnu rustfmt - name: Utilize Shared Rust Cache uses: Swatinem/rust-cache@v2 From 900e4c74ca9651f68a405a09fc2ab4ce99b71a68 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 18 Feb 2025 13:02:12 -0500 Subject: [PATCH 36/47] try re-enabling finney try truntime --- .github/workflows/try-runtime.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/try-runtime.yml b/.github/workflows/try-runtime.yml index c3b54a351..1241ca94d 100644 --- a/.github/workflows/try-runtime.yml +++ b/.github/workflows/try-runtime.yml @@ -50,7 +50,7 @@ jobs: check-finney: name: check finney - if: github.base_ref == 'testnet' || github.base_ref == 'devnet' || github.base_ref == 'main' + # if: github.base_ref == 'testnet' || github.base_ref == 'devnet' || github.base_ref == 'main' runs-on: SubtensorCI steps: - name: Checkout sources From b4ebb4e6090998478ca40bb6d85ff002048d4f27 Mon Sep 17 00:00:00 2001 From: gztensor <166415444+gztensor@users.noreply.github.com> Date: Tue, 18 Feb 2025 10:37:58 -0800 Subject: [PATCH 37/47] Update pallets/subtensor/src/tests/staking.rs Co-authored-by: Cameron Fairchild --- pallets/subtensor/src/tests/staking.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs index 74ffe5629..f651d6b2b 100644 --- a/pallets/subtensor/src/tests/staking.rs +++ b/pallets/subtensor/src/tests/staking.rs @@ -3751,9 +3751,6 @@ fn test_remove_99_9991_per_cent_stake_removes_all() { // cargo test --package pallet-subtensor --lib -- tests::staking::test_remove_99_9989_per_cent_stake_leaves_a_little --exact --show-output #[test] fn test_remove_99_9989_per_cent_stake_leaves_a_little() { - // When we remove stake, the total issuance of the balances pallet should not change - // this is because the stake should be part of the coldkey account balance (reserved/locked) - // then the removed stake just becomes free balance new_test_ext(1).execute_with(|| { let subnet_owner_coldkey = U256::from(1); let subnet_owner_hotkey = U256::from(2); From 178130c9c6b38fbe655645bac09b45e130014c4c Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 18 Feb 2025 14:42:59 -0500 Subject: [PATCH 38/47] fix --- .github/workflows/try-runtime.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/try-runtime.yml b/.github/workflows/try-runtime.yml index 1241ca94d..c3b54a351 100644 --- a/.github/workflows/try-runtime.yml +++ b/.github/workflows/try-runtime.yml @@ -50,7 +50,7 @@ jobs: check-finney: name: check finney - # if: github.base_ref == 'testnet' || github.base_ref == 'devnet' || github.base_ref == 'main' + if: github.base_ref == 'testnet' || github.base_ref == 'devnet' || github.base_ref == 'main' runs-on: SubtensorCI steps: - name: Checkout sources From 2a229a915787d0f704b303d2af6f68ad3bed2019 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 19 Feb 2025 09:07:04 -0500 Subject: [PATCH 39/47] add get value using current_shares arg --- primitives/share-pool/src/lib.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/primitives/share-pool/src/lib.rs b/primitives/share-pool/src/lib.rs index a49187ae0..d43f36259 100644 --- a/primitives/share-pool/src/lib.rs +++ b/primitives/share-pool/src/lib.rs @@ -63,6 +63,22 @@ where .saturating_to_num::() } + pub fn get_value_from_shares(&self, current_share: U64F64) -> u64 { + let shared_value: U64F64 = self.state_ops.get_shared_value(); + let denominator: U64F64 = self.state_ops.get_denominator(); + + let maybe_value_per_share = shared_value.checked_div(denominator); + (if let Some(value_per_share) = maybe_value_per_share { + value_per_share.saturating_mul(current_share) + } else { + shared_value + .saturating_mul(current_share) + .checked_div(denominator) + .unwrap_or(U64F64::saturating_from_num(0)) + }) + .saturating_to_num::() + } + pub fn try_get_value(&self, key: &K) -> Result { match self.state_ops.try_get_share(key) { Ok(_) => Ok(self.get_value(key)), From 4aad85260f517b2272e0d5d29105e2714fa22b85 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 19 Feb 2025 09:11:53 -0500 Subject: [PATCH 40/47] make delegate info useful again --- .../subtensor/src/rpc_info/delegate_info.rs | 71 ++++++++++++------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/pallets/subtensor/src/rpc_info/delegate_info.rs b/pallets/subtensor/src/rpc_info/delegate_info.rs index acfe28b43..fc1c4aa55 100644 --- a/pallets/subtensor/src/rpc_info/delegate_info.rs +++ b/pallets/subtensor/src/rpc_info/delegate_info.rs @@ -1,18 +1,18 @@ use super::*; use frame_support::pallet_prelude::{Decode, Encode}; -use frame_support::storage::IterableStorageMap; -use frame_support::IterableStorageDoubleMap; +use frame_support::IterableStorageMap; use safe_math::*; use substrate_fixed::types::U64F64; extern crate alloc; +use alloc::collections::BTreeMap; use codec::Compact; -#[freeze_struct("66105c2cfec0608d")] +#[freeze_struct("f729f2481d94a1de")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, TypeInfo)] pub struct DelegateInfo { delegate_ss58: AccountId, take: Compact, - nominators: Vec<(AccountId, Compact)>, // map of nominator_ss58 to stake amount + nominators: Vec<(AccountId, Vec<(Compact, Compact)>)>, // map of nominator_ss58 to netuid and stake amount owner_ss58: AccountId, registrations: Vec>, // Vec of netuid this delegate is registered on validator_permits: Vec>, // Vec of netuid this delegate has validator permit on @@ -49,19 +49,38 @@ impl Pallet { Self::return_per_1000_tao(take, total_stake, emissions_per_day) } - fn get_delegate_by_existing_account(delegate: AccountIdOf) -> DelegateInfo { - let mut nominators = Vec::<(T::AccountId, Compact)>::new(); + fn get_delegate_by_existing_account( + delegate: AccountIdOf, + skip_nominators: bool, + ) -> DelegateInfo { + let mut nominators = Vec::<(T::AccountId, Vec<(Compact, Compact)>)>::new(); + let mut nominator_map = BTreeMap::, Compact)>>::new(); + + if !skip_nominators { + let mut alpha_share_pools = vec![]; + for netuid in Self::get_all_subnet_netuids() { + let alpha_share_pool = Self::get_alpha_share_pool(delegate.clone(), netuid); + alpha_share_pools.push(alpha_share_pool); + } + + for ((nominator, netuid), alpha_stake) in Alpha::::iter_prefix((delegate.clone(),)) { + if alpha_stake == 0 { + continue; + } + + if let Some(alpha_share_pool) = alpha_share_pools.get(netuid as usize) { + let coldkey_stake = alpha_share_pool.get_value_from_shares(alpha_stake); - for (nominator, stake) in - as IterableStorageDoubleMap>::iter_prefix( - delegate.clone(), - ) - { - if stake == 0 { - continue; + nominator_map + .entry(nominator.clone()) + .or_insert(Vec::new()) + .push((netuid.into(), coldkey_stake.into())); + } + } + + for (nominator, stakes) in nominator_map { + nominators.push((nominator, stakes)); } - // Only add nominators with stake - nominators.push((nominator.clone(), stake.into())); } let registrations = Self::get_registered_networks_for_hotkey(&delegate.clone()); @@ -112,7 +131,7 @@ impl Pallet { return None; } - let delegate_info = Self::get_delegate_by_existing_account(delegate.clone()); + let delegate_info = Self::get_delegate_by_existing_account(delegate.clone(), false); Some(delegate_info) } @@ -121,7 +140,7 @@ impl Pallet { pub fn get_delegates() -> Vec> { let mut delegates = Vec::>::new(); for delegate in as IterableStorageMap>::iter_keys() { - let delegate_info = Self::get_delegate_by_existing_account(delegate.clone()); + let delegate_info = Self::get_delegate_by_existing_account(delegate.clone(), false); delegates.push(delegate_info); } @@ -136,16 +155,14 @@ impl Pallet { let mut delegates: Vec<(DelegateInfo, Compact)> = Vec::new(); for delegate in as IterableStorageMap>::iter_keys() { // Staked to this delegate, so add to list - let delegate_info = Self::get_delegate_by_existing_account(delegate.clone()); - delegates.push(( - delegate_info, - Self::get_stake_for_hotkey_and_coldkey_on_subnet( - &delegatee, - &delegate, - Self::get_root_netuid(), - ) - .into(), - )); + for (netuid, _) in Alpha::::iter_prefix((delegate.clone(), delegatee.clone())) { + let delegate_info = Self::get_delegate_by_existing_account(delegate.clone(), true); + delegates.push(( + delegate_info, + Self::get_stake_for_hotkey_and_coldkey_on_subnet(&delegate, &delegatee, netuid) + .into(), + )); + } } delegates From cf00f3098f64ed19373be2bbb0a88473c014bab0 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 19 Feb 2025 09:31:00 -0500 Subject: [PATCH 41/47] return different format for get delegated --- pallets/subtensor/runtime-api/src/lib.rs | 2 +- pallets/subtensor/src/rpc_info/delegate_info.rs | 12 +++++++++--- runtime/src/lib.rs | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/pallets/subtensor/runtime-api/src/lib.rs b/pallets/subtensor/runtime-api/src/lib.rs index 9f6d96040..c6665bcd9 100644 --- a/pallets/subtensor/runtime-api/src/lib.rs +++ b/pallets/subtensor/runtime-api/src/lib.rs @@ -19,7 +19,7 @@ sp_api::decl_runtime_apis! { pub trait DelegateInfoRuntimeApi { fn get_delegates() -> Vec>; fn get_delegate( delegate_account: AccountId32 ) -> Option>; - fn get_delegated( delegatee_account: AccountId32 ) -> Vec<(DelegateInfo, Compact)>; + fn get_delegated( delegatee_account: AccountId32 ) -> Vec<(DelegateInfo, (Compact, Compact))>; } pub trait NeuronInfoRuntimeApi { diff --git a/pallets/subtensor/src/rpc_info/delegate_info.rs b/pallets/subtensor/src/rpc_info/delegate_info.rs index fc1c4aa55..8c437efc7 100644 --- a/pallets/subtensor/src/rpc_info/delegate_info.rs +++ b/pallets/subtensor/src/rpc_info/delegate_info.rs @@ -151,16 +151,22 @@ impl Pallet { /// pub fn get_delegated( delegatee: T::AccountId, - ) -> Vec<(DelegateInfo, Compact)> { - let mut delegates: Vec<(DelegateInfo, Compact)> = Vec::new(); + ) -> Vec<(DelegateInfo, (Compact, Compact))> { + let mut delegates: Vec<(DelegateInfo, (Compact, Compact))> = + Vec::new(); for delegate in as IterableStorageMap>::iter_keys() { // Staked to this delegate, so add to list for (netuid, _) in Alpha::::iter_prefix((delegate.clone(), delegatee.clone())) { let delegate_info = Self::get_delegate_by_existing_account(delegate.clone(), true); delegates.push(( delegate_info, - Self::get_stake_for_hotkey_and_coldkey_on_subnet(&delegate, &delegatee, netuid) + ( + netuid.into(), + Self::get_stake_for_hotkey_and_coldkey_on_subnet( + &delegate, &delegatee, netuid, + ) .into(), + ), )); } } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 0320e8998..c796296da 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -2062,7 +2062,7 @@ impl_runtime_apis! { SubtensorModule::get_delegate(delegate_account) } - fn get_delegated(delegatee_account: AccountId32) -> Vec<(DelegateInfo, Compact)> { + fn get_delegated(delegatee_account: AccountId32) -> Vec<(DelegateInfo, (Compact, Compact))> { SubtensorModule::get_delegated(delegatee_account) } } From e4ae0d30a67666670b9224d34c75312848a4573d Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 19 Feb 2025 10:49:57 -0500 Subject: [PATCH 42/47] remove CODEOWNERS file so we can do green merges --- CODEOWNERS | 1 - 1 file changed, 1 deletion(-) delete mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index ffc01511b..000000000 --- a/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @unconst From 85d9abf70ea2b126efd5c72ea828766cfd8664fd Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 19 Feb 2025 10:53:26 -0500 Subject: [PATCH 43/47] bump CI From 956263fbb8994386bf209d307b062955ce42d83a Mon Sep 17 00:00:00 2001 From: camfairchild Date: Wed, 19 Feb 2025 14:24:01 -0500 Subject: [PATCH 44/47] sub out root divs to get alpha divs --- pallets/subtensor/src/coinbase/run_coinbase.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 9b119f178..04976adc6 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -318,12 +318,14 @@ impl Pallet { let root_prop: I96F32 = root_alpha.checked_div(total_alpha).unwrap_or(zero); // Compute root dividends let root_divs: I96F32 = dividend.saturating_mul(root_prop); - // Record the root dividends. + // Compute alpha dividends + let alpha_divs: I96F32 = dividend.saturating_sub(root_divs); + // Record the alpha dividends. alpha_dividends .entry(hotkey.clone()) - .and_modify(|e| *e = e.saturating_add(dividend)) - .or_insert(dividend); - // Record the alpha_dividends. + .and_modify(|e| *e = e.saturating_add(alpha_divs)) + .or_insert(alpha_divs); + // Record the root dividends. root_dividends .entry(hotkey.clone()) .and_modify(|e| *e = e.saturating_add(root_divs)) From c6e53360f3cd27b054080c47c133a6798892de71 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 19 Feb 2025 14:30:25 -0500 Subject: [PATCH 45/47] bump spec version to 241 --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index c796296da..af3720c36 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: 240, + spec_version: 241, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From d092dbdcca2c647f16f181ec7230df3d43254f84 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 19 Feb 2025 15:00:02 -0500 Subject: [PATCH 46/47] const fixes --- pallets/subtensor/src/tests/coinbase.rs | 62 +++++++++++++++++++------ 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 66332654a..8fe4f417e 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -19,6 +19,23 @@ fn close(value: u64, target: u64, eps: u64) { ) } +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_hotkey_take --exact --show-output --nocapture +#[test] +fn test_hotkey_take() { + new_test_ext(1).execute_with(|| { + let hotkey = U256::from(1); + Delegates::::insert(hotkey, u16::MAX / 2); + log::info!( + "expected: {:?}", + SubtensorModule::get_hotkey_take_float(&hotkey) + ); + log::info!( + "expected: {:?}", + SubtensorModule::get_hotkey_take_float(&&hotkey) + ); + }); +} + // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_dynamic_function_various_values --exact --show-output --nocapture #[test] fn test_dynamic_function_various_values() { @@ -476,6 +493,7 @@ fn test_drain_base_with_subnet_with_single_staker_registered_root_weight() { let stake_before: u64 = 1_000_000_000; // register_ok_neuron(root, hotkey, coldkey, 0); register_ok_neuron(netuid, hotkey, coldkey, 0); + Delegates::::insert(hotkey, 0); SubtensorModule::set_tao_weight(u64::MAX); // Set TAO weight to 1.0 SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( &hotkey, @@ -496,7 +514,7 @@ fn test_drain_base_with_subnet_with_single_staker_registered_root_weight() { SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid); let root_after = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, root); - close(stake_before + pending_alpha, stake_after, 10); // Registered gets all alpha emission. + close(stake_before + pending_alpha / 2, stake_after, 10); // Registered gets all alpha emission. close(stake_before + pending_tao, root_after, 10); // Registered gets all tao emission }); } @@ -549,6 +567,8 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root() { let stake_before: u64 = 1_000_000_000; register_ok_neuron(netuid, hotkey1, coldkey, 0); register_ok_neuron(netuid, hotkey2, coldkey, 0); + Delegates::::insert(hotkey1, 0); + Delegates::::insert(hotkey2, 0); SubtensorModule::set_tao_weight(u64::MAX); // Set TAO weight to 1.0 SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( &hotkey1, @@ -585,8 +605,8 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root() { SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey2, &coldkey, netuid); let root_after2 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey2, &coldkey, root); - close(stake_before + pending_alpha / 2, stake_after1, 10); // Registered gets 1/2 emission - close(stake_before + pending_alpha / 2, stake_after2, 10); // Registered gets 1/2 emission. + close(stake_before + pending_alpha / 4, stake_after1, 10); // Registered gets 1/2 emission + close(stake_before + pending_alpha / 4, stake_after2, 10); // Registered gets 1/2 emission. close(stake_before + pending_tao / 2, root_after1, 10); // Registered gets 1/2 tao emission close(stake_before + pending_tao / 2, root_after2, 10); // Registered gets 1/2 tao emission }); @@ -603,6 +623,8 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am let hotkey2 = U256::from(2); let coldkey = U256::from(3); let stake_before: u64 = 1_000_000_000; + Delegates::::insert(hotkey1, 0); + Delegates::::insert(hotkey2, 0); register_ok_neuron(netuid, hotkey1, coldkey, 0); register_ok_neuron(netuid, hotkey2, coldkey, 0); SubtensorModule::set_tao_weight(u64::MAX); // Set TAO weight to 1.0 @@ -642,10 +664,14 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am let root_after2 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey2, &coldkey, root); let expected_stake = I96F32::from_num(stake_before) - + I96F32::from_num(pending_alpha) * I96F32::from_num(3.0 / 5.0); + + (I96F32::from_num(pending_alpha) + * I96F32::from_num(3.0 / 5.0) + * I96F32::from_num(1.0 / 3.0)); close(expected_stake.to_num::(), stake_after1, 10); // Registered gets 60% of emission let expected_stake2 = I96F32::from_num(stake_before) - + I96F32::from_num(pending_alpha) * I96F32::from_num(2.0 / 5.0); + + I96F32::from_num(pending_alpha) + * I96F32::from_num(2.0 / 5.0) + * I96F32::from_num(1.0 / 2.0); close(expected_stake2.to_num::(), stake_after2, 10); // Registered gets 40% emission let expected_root1 = I96F32::from_num(2 * stake_before) + I96F32::from_num(pending_tao) * I96F32::from_num(2.0 / 3.0); @@ -668,6 +694,8 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am let hotkey2 = U256::from(2); let coldkey = U256::from(3); let stake_before: u64 = 1_000_000_000; + Delegates::::insert(hotkey1, 0); + Delegates::::insert(hotkey2, 0); register_ok_neuron(netuid, hotkey1, coldkey, 0); register_ok_neuron(netuid, hotkey2, coldkey, 0); SubtensorModule::set_tao_weight(u64::MAX / 2); // Set TAO weight to 0.5 @@ -708,11 +736,15 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey2, &coldkey, root); // hotkey 1 has (1 + (2 * 0.5))/( 1 + 1*0.5 + 1 + (2 * 0.5)) = 0.5714285714 of the hotkey emission. let expected_stake = I96F32::from_num(stake_before) - + I96F32::from_num(pending_alpha) * I96F32::from_num(0.5714285714); + + I96F32::from_num(pending_alpha) + * I96F32::from_num(0.5714285714) + * I96F32::from_num(1.0 / 2.0); close(expected_stake.to_num::(), stake_after1, 10); // hotkey 2 has (1 + 1*0.5)/( 1 + 1*0.5 + 1 + (2 * 0.5)) = 0.4285714286 of the hotkey emission. let expected_stake2 = I96F32::from_num(stake_before) - + I96F32::from_num(pending_alpha) * I96F32::from_num(0.4285714286); + + I96F32::from_num(pending_alpha) + * I96F32::from_num(0.4285714286) + * I96F32::from_num(2.0 / 3.0); close(expected_stake2.to_num::(), stake_after2, 10); // hotkey 1 has 2 / 3 root tao let expected_root1 = I96F32::from_num(2 * stake_before) @@ -970,11 +1002,11 @@ fn test_get_root_children_drain() { // Alice and Bob both made half of the dividends. assert_eq!( SubtensorModule::get_stake_for_hotkey_on_subnet(&alice, alpha), - alice_alpha_stake + pending_alpha / 2 + alice_alpha_stake + pending_alpha / 4 ); assert_eq!( SubtensorModule::get_stake_for_hotkey_on_subnet(&bob, alpha), - bob_alpha_stake + pending_alpha / 2 + bob_alpha_stake + pending_alpha / 4 ); // Lets drain @@ -1006,7 +1038,7 @@ fn test_get_root_children_drain() { // Bob makes it all. assert_eq!( AlphaDividendsPerSubnet::::get(alpha, bob), - pending_alpha + (I96F32::from_num(pending_alpha) * I96F32::from_num(1.0 - 0.495412844)).to_num::() ); assert_eq!(TaoDividendsPerSubnet::::get(alpha, bob), pending_root); }); @@ -1083,12 +1115,12 @@ fn test_get_root_children_drain_half_proportion() { // Alice and Bob make the same amount. close( AlphaDividendsPerSubnet::::get(alpha, alice), - pending_alpha / 2, + pending_alpha / 4, 10, ); close( AlphaDividendsPerSubnet::::get(alpha, bob), - pending_alpha / 2, + pending_alpha / 4, 10, ); }); @@ -1165,7 +1197,7 @@ fn test_get_root_children_drain_with_take() { close(AlphaDividendsPerSubnet::::get(alpha, alice), 0, 10); close( AlphaDividendsPerSubnet::::get(alpha, bob), - pending_alpha, + pending_alpha / 2, 10, ); }); @@ -1241,12 +1273,12 @@ fn test_get_root_children_drain_with_half_take() { // Alice and Bob make the same amount. close( AlphaDividendsPerSubnet::::get(alpha, alice), - pending_alpha / 4, + pending_alpha / 8, 10000, ); close( AlphaDividendsPerSubnet::::get(alpha, bob), - 3 * (pending_alpha / 4), + 3 * (pending_alpha / 8), 10000, ); }); From 9396ec0a04782074e170aeffe1d2fad5ccf21a51 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 19 Feb 2025 15:33:33 -0500 Subject: [PATCH 47/47] cargo clippy --- pallets/subtensor/src/tests/coinbase.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 8fe4f417e..d8ecdebd3 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -31,7 +31,7 @@ fn test_hotkey_take() { ); log::info!( "expected: {:?}", - SubtensorModule::get_hotkey_take_float(&&hotkey) + SubtensorModule::get_hotkey_take_float(&hotkey) ); }); }