diff --git a/.github/workflows/cargo-audit.yml b/.github/workflows/cargo-audit.yml index 14e2d94491..aa8fb7c9f3 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-devnet.yml b/.github/workflows/check-devnet.yml index 13ebf89cc9..b6c20beee0 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 98f90fc8e0..448e53ee1f 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-rust.yml b/.github/workflows/check-rust.yml index cdee05bfaf..0fae77fa33 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 @@ -51,38 +34,22 @@ jobs: 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 + 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 - 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 +60,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 +68,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 +81,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 +93,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 +106,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 +127,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 +137,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 +149,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 +170,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/check-testnet.yml b/.github/workflows/check-testnet.yml index 7c8532ec5a..8a59036d98 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/.github/workflows/e2e-bittensor-tests.yml b/.github/workflows/e2e-bittensor-tests.yml index 851c30a6db..5be78c2ec2 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 89a28c5c68..c3b54a3514 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 @@ -16,6 +14,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: @@ -26,25 +29,38 @@ jobs: check-testnet: name: check testnet + # if: github.base_ref == 'testnet' || github.base_ref == 'devnet' || github.base_ref == 'main' runs-on: SubtensorCI 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: runtime-package: "node-subtensor-runtime" - node-uri: "wss://test.chain.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: github.base_ref == 'testnet' || github.base_ref == 'devnet' || github.base_ref == 'main' runs-on: SubtensorCI 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 bf7cc5588b..1aedfeaa4a 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 diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index ffc01511bb..0000000000 --- a/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @unconst diff --git a/Cargo.lock b/Cargo.lock index ed3b5ae451..0d76188012 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" @@ -1779,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]] @@ -5854,6 +5860,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pallet-utility", "parity-scale-codec", + "precompile-utils", "rand_chacha", "scale-info", "serde_json", @@ -7226,6 +7233,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/pallets/subtensor/runtime-api/src/lib.rs b/pallets/subtensor/runtime-api/src/lib.rs index 9f6d960407..c6665bcd97 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/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 9b119f1786..04976adc67 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)) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 7242575ef8..59f43fddea 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>; diff --git a/pallets/subtensor/src/rpc_info/delegate_info.rs b/pallets/subtensor/src/rpc_info/delegate_info.rs index acfe28b43d..8c437efc70 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); } @@ -132,20 +151,24 @@ 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 - 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, + ( + netuid.into(), + Self::get_stake_for_hotkey_and_coldkey_on_subnet( + &delegate, &delegatee, netuid, + ) + .into(), + ), + )); + } } delegates diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index 07be25171a..20497ae96a 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. @@ -765,7 +770,7 @@ impl Pallet { coldkey.clone(), hotkey.clone(), tao_unstaked, - alpha, + actual_alpha_decrease, netuid, )); log::info!( @@ -773,7 +778,7 @@ impl Pallet { coldkey.clone(), hotkey.clone(), tao_unstaked, - alpha, + actual_alpha_decrease, netuid ); @@ -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/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 66332654a0..d8ecdebd38 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, ); }); diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs index 15832b93fe..5409ad5891 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 f97373b0b3..f651d6b2b3 100644 --- a/pallets/subtensor/src/tests/staking.rs +++ b/pallets/subtensor/src/tests/staking.rs @@ -3669,102 +3669,138 @@ 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 ); }); } +// 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() { 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); + }); +} - // Setup Subnet pool for origin netuid - SubnetAlphaIn::::insert(origin_netuid, alpha_in + 10_000_000); - SubnetTAO::::insert(origin_netuid, tao_in + 10_000_000); +// 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() { + 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); - // Add stake as new hotkey + // Give it some $$$ in his coldkey balance + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, amount); + + // 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, ); + assert_ok!(SubtensorModule::remove_stake( + RuntimeOrigin::signed(coldkey_account_id), + hotkey_account_id, + netuid, + (U64F64::from_num(alpha) * U64F64::from_num(0.99)).to_num::() + )); - // 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 + // 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, + ); + assert_abs_diff_eq!( + 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/pallets/subtensor/src/tests/staking2.rs b/pallets/subtensor/src/tests/staking2.rs index 2abff8faf7..471d670254 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 8f963cfd36..d43f36259c 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,32 @@ 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 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 { @@ -84,46 +106,51 @@ 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(); - - // First, update shared value - self.update_value_for_all(update); - let new_shared_value: U64F64 = self.state_ops.get_shared_value(); + let initial_value: i64 = self.get_value(key) as i64; + 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 { - // 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 +161,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())); + + // 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)) + || 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); + actual_update = initial_value.neg(); + } + + self.state_ops.set_denominator(new_denominator); + self.state_ops.set_share(key, new_share); } } + + // Update shared value + self.update_value_for_all(actual_update); + + // Return actual udate + actual_update } } @@ -279,6 +325,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() < 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 + #[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(); @@ -301,4 +403,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,); + }); + } } diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 2e6eda522c..831debfa6b 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 } @@ -163,6 +164,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/lib.rs b/runtime/src/lib.rs index 8dcce09b1e..af3720c369 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: 241, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -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) } } diff --git a/runtime/src/precompiles/balance_transfer.rs b/runtime/src/precompiles/balance_transfer.rs index 6154cf8a52..3b326bca28 100644 --- a/runtime/src/precompiles/balance_transfer.rs +++ b/runtime/src/precompiles/balance_transfer.rs @@ -1,60 +1,40 @@ -use pallet_evm::{ - BalanceConverter, ExitError, ExitSucceed, PrecompileHandle, PrecompileOutput, PrecompileResult, -}; +use pallet_evm::PrecompileHandle; +use precompile_utils::EvmResult; +use sp_core::H256; use sp_runtime::traits::UniqueSaturatedInto; -use sp_std::vec; -use crate::precompiles::{ - contract_to_origin, get_method_id, get_pubkey, get_slice, try_dispatch_runtime_call, -}; +use crate::precompiles::{contract_to_origin, 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; -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 - let amount = handle.context().apparent_value; +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, + ]; +} - // Use BalanceConverter to convert EVM amount to Substrate balance - let amount_sub = - ::BalanceConverter::into_substrate_balance(amount) - .ok_or(ExitError::OutOfFund)?; +#[precompile_utils::precompile] +impl BalanceTransferPrecompile { + #[precompile::public("transfer(bytes32)")] + #[precompile::payable] + fn transfer(handle: &mut impl PrecompileHandle, address: H256) -> EvmResult<()> { + let amount_sub = handle.try_convert_apparent_value()?; 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 = parse_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)?) + handle.try_dispatch_runtime_call(call, contract_to_origin(&Self::ADDRESS_SS58)?) } } diff --git a/runtime/src/precompiles/ed25519.rs b/runtime/src/precompiles/ed25519.rs index 83be4ca774..1a629df523 100644 --- a/runtime/src/precompiles/ed25519.rs +++ b/runtime/src/precompiles/ed25519.rs @@ -2,14 +2,18 @@ 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; +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; @@ -23,13 +27,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()), } diff --git a/runtime/src/precompiles/metagraph.rs b/runtime/src/precompiles/metagraph.rs index ffc4cbed79..f74812cc09 100644 --- a/runtime/src/precompiles/metagraph.rs +++ b/runtime/src/precompiles/metagraph.rs @@ -1,360 +1,171 @@ 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; -pub struct MetagraphPrecompile; - -const NO_HOTKEY: &str = "no hotkey"; - -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 +use alloc::string::String; - 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) - } +use fp_evm::{ExitError, PrecompileFailure, PrecompileHandle}; +use pallet_subtensor::AxonInfo as SubtensorModuleAxonInfo; +use precompile_utils::{solidity::Codec, EvmResult}; +use sp_core::{ByteArray, H256}; - _ => Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }), - } - } +use crate::precompiles::PrecompileExt; +use crate::Runtime; - fn get_uid_count(data: &[u8]) -> PrecompileResult { - let netuid = Self::parse_netuid(data)?; - let uid_count = pallet_subtensor::SubnetworkN::::get(netuid); +pub struct MetagraphPrecompile; - let uid_count_u256 = U256::from(uid_count); - let mut result = [0_u8; 32]; - U256::to_big_endian(&uid_count_u256, &mut result); +impl PrecompileExt for MetagraphPrecompile { + const INDEX: u64 = 2050; + const ADDRESS_SS58: [u8; 32] = [0; 32]; +} - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) +#[precompile_utils::precompile] +impl MetagraphPrecompile { + #[precompile::public("getUidCount(uint16)")] + #[precompile::view] + fn get_uid_count(_: &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(get_slice(data, 32, 64)?)?; + #[precompile::public("getStake(uint16,uint16)")] + #[precompile::view] + 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, })?; - 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(get_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(_: &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(get_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(_: &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(get_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(_: &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(get_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(_: &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(get_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(_: &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(get_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(_: &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(get_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(_: &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(get_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( + _: &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(get_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(_: &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(get_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(_: &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(get_slice(data, 32, 64)?)?; - + #[precompile::public("getAxon(uint16,uint16)")] + #[precompile::view] + 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(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(get_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(_: &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(get_slice(data, 32, 64)?)?; - + #[precompile::public("getColdkey(uint16,uint16)")] + #[precompile::view] + 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, })?; - let coldkey = pallet_subtensor::Owner::::get(&hotkey); - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: coldkey.as_slice().into(), - }) + Ok(H256::from_slice(coldkey.as_slice())) } +} - 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(get_slice(data, 30, 32)?); - let result = u16::from_be_bytes(netuid); - Ok(result) - } +#[derive(Codec)] +struct AxonInfo { + block: u64, + version: u32, + ip: u128, + port: u16, + ip_type: u8, + protocol: u8, +} - fn parse_uid(data: &[u8]) -> Result { - if data.len() < 32 { - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); +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, } - let mut uid = [0u8; 2]; - uid.copy_from_slice(get_slice(data, 30, 32)?); - let result = u16::from_be_bytes(uid); - Ok(result) } } diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs index 6bed2913cd..349d1ce455 100644 --- a/runtime/src/precompiles/mod.rs +++ b/runtime/src/precompiles/mod.rs @@ -3,24 +3,26 @@ extern crate alloc; use alloc::format; use core::marker::PhantomData; -use crate::{Runtime, RuntimeCall}; - +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, 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 frame_support::dispatch::{GetDispatchInfo, Pays}; -use frame_system::RawOrigin; -use sp_core::{hashing::keccak_256, H160}; +use precompile_utils::EvmResult; +use sp_core::{H160, U256}; +use sp_runtime::traits::BlakeTwo256; use sp_runtime::{traits::Dispatchable, AccountId32}; use pallet_admin_utils::{PrecompileEnable, PrecompileEnum}; use sp_std::vec; +use crate::{Runtime, RuntimeCall}; + // Include custom precompiles mod balance_transfer; mod ed25519; @@ -35,6 +37,7 @@ use metagraph::*; use neuron::*; use staking::*; use subnet::*; + pub struct FrontierPrecompiles(PhantomData); impl Default for FrontierPrecompiles where @@ -61,12 +64,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), ] } } @@ -85,10 +88,9 @@ 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) => { if PrecompileEnable::::get(PrecompileEnum::BalanceTransfer) { Some(BalanceTransferPrecompile::execute(handle)) } else { @@ -99,7 +101,7 @@ where })) } } - a if a == hash(STAKING_PRECOMPILE_INDEX) => { + a if a == hash(StakingPrecompile::INDEX) => { if PrecompileEnable::::get(PrecompileEnum::Staking) { Some(StakingPrecompile::execute(handle)) } else { @@ -111,7 +113,7 @@ where } } - a if a == hash(SUBNET_PRECOMPILE_INDEX) => { + a if a == hash(SubnetPrecompile::INDEX) => { if PrecompileEnable::::get(PrecompileEnum::Subnet) { Some(SubnetPrecompile::execute(handle)) } else { @@ -120,7 +122,7 @@ where })) } } - a if a == hash(METAGRAPH_PRECOMPILE_INDEX) => { + a if a == hash(MetagraphPrecompile::INDEX) => { if PrecompileEnable::::get(PrecompileEnum::Metagraph) { Some(MetagraphPrecompile::execute(handle)) } else { @@ -129,7 +131,7 @@ where })) } } - a if a == hash(NEURON_PRECOMPILE_INDEX) => { + a if a == hash(NeuronPrecompile::INDEX) => { if PrecompileEnable::::get(PrecompileEnum::Neuron) { Some(NeuronPrecompile::execute(handle)) } else { @@ -155,19 +157,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 get_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) @@ -184,9 +175,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> { +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(), @@ -195,107 +186,107 @@ pub fn get_pubkey(data: &[u8]) -> Result<(AccountId32, vec::Vec), Precompile )) } -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(get_slice(data, offset, offset + 2)?); - let netuid: u16 = netuid_bytes[1] as u16 | ((netuid_bytes[0] as u16) << 8u16); - - Ok(netuid) +fn try_u16_from_u256(value: U256) -> Result { + value.try_into().map_err(|_| PrecompileFailure::Error { + exit_status: ExitError::Other("the value is outside of u16 bounds".into()), + }) } 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, -) -> PrecompileResult { - 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, - }); - } +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, - )?; + 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(), + ), + }, + ) + } - 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)?; + /// 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(); - 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()), - ), - ); + 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, + }); } + } - log::info!("Dispatch succeeded. Post info: {:?}", post_info); + self.record_external_cost( + Some(info.weight.ref_time()), + Some(info.weight.proof_size()), + None, + )?; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: Default::default(), - }) - } - 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(), - ), - }) + 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(), + ), + }) + } } } } -/// Retrieves a single u8 value from the given data slice at the specified index. -/// -/// # Args -/// * `data`: The slice of bytes from which to retrieve the u8 value. -/// * `index`: The index within the `data` slice where the u8 value is located. -/// -/// # Returns -/// A `Result` containing the u8 value at the specified index if successful, or a `PrecompileFailure` if the index is out of range. -pub fn get_single_u8(data: &[u8], index: usize) -> Result { - if let Some(result) = data.get(index) { - Ok(*result) - } else { - log::error!("fail to get data from data, {:?}, at {}", &data, index); - Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }) - } +impl PrecompileHandleExt for T where T: PrecompileHandle {} + +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 38fb701fbe..f8fd1f1586 100644 --- a/runtime/src/precompiles/neuron.rs +++ b/runtime/src/precompiles/neuron.rs @@ -1,157 +1,109 @@ -use pallet_evm::{ - AddressMapping, ExitError, HashedAddressMapping, PrecompileFailure, PrecompileHandle, - PrecompileResult, -}; - -use crate::precompiles::{ - get_method_id, get_pubkey, get_single_u8, get_slice, parse_netuid, try_dispatch_runtime_call, -}; -use crate::{Runtime, RuntimeCall}; use frame_system::RawOrigin; +use pallet_evm::PrecompileHandle; +use precompile_utils::{prelude::UnboundedBytes, EvmResult}; use sp_core::H256; -use sp_runtime::traits::BlakeTwo256; -use sp_runtime::AccountId32; -use sp_std::vec; use sp_std::vec::Vec; -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; - -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) - } +use crate::precompiles::{parse_pubkey, PrecompileExt, PrecompileHandleExt}; +use crate::Runtime; - id if id == get_method_id("burnedRegister(uint16,bytes32)") => { - Self::burned_register(handle, &method_input) - } - id if id - == get_method_id( - "serveAxon(uint16,uint32,uint128,uint16,uint8,uint8,uint8,uint8)", - ) => - { - Self::serve_axon(handle, &method_input) - } - id if id - == get_method_id( - "serveAxonTls(uint16,uint32,uint128,uint16,uint8,uint8,uint8,uint8,bytes)", - ) => - { - Self::serve_axon_tls(handle, &method_input) - } - id if id == get_method_id("servePrometheus(uint16,uint32,uint128,uint16,uint8)") => { - Self::serve_prometheus(handle, &method_input) - } +pub struct NeuronPrecompile; - _ => Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }), - } - } +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, + ]; +} - 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 { +#[precompile_utils::precompile] +impl NeuronPrecompile { + #[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, - }); - 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 commit_weights(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - let (netuid, commit_hash) = Self::parse_netuid_commit_hash(data)?; + #[precompile::public("commitWeights(uint16,bytes32)")] + #[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, + }; - pub fn burned_register(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - let (netuid, hotkey) = Self::parse_netuid_hotkey_parameter(data)?; - let call = - RuntimeCall::SubtensorModule(pallet_subtensor::Call::::burned_register { - netuid, - hotkey, - }); - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + #[precompile::public("burnedRegister(uint16,bytes32)")] + #[precompile::payable] + fn burned_register( + handle: &mut impl PrecompileHandle, + netuid: u16, + hotkey: H256, + ) -> EvmResult<()> { + let coldkey = handle.caller_account_id(); + let (hotkey, _) = parse_pubkey(hotkey.as_bytes())?; + let call = pallet_subtensor::Call::::burned_register { netuid, hotkey }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(coldkey)) } - pub fn serve_axon(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - let (netuid, version, ip, port, ip_type, protocol, placeholder1, placeholder2) = - Self::parse_serve_axon_parameters(data)?; - let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::::serve_axon { + #[precompile::public("serveAxon(uint16,uint32,uint128,uint16,uint8,uint8,uint8,uint8)")] + #[precompile::payable] + #[allow(clippy::too_many_arguments)] + fn serve_axon( + handle: &mut impl PrecompileHandle, + netuid: u16, + version: u32, + ip: u128, + port: u16, + ip_type: u8, + protocol: u8, + placeholder1: u8, + placeholder2: u8, + ) -> EvmResult<()> { + let call = pallet_subtensor::Call::::serve_axon { netuid, version, ip, @@ -160,367 +112,29 @@ impl NeuronPrecompile { protocol, placeholder1, placeholder2, - }); - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - } - - pub fn serve_axon_tls(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - let (netuid, version, ip, port, ip_type, protocol, placeholder1, placeholder2, certificate) = - Self::parse_serve_axon_tls_parameters(data)?; - let call = - RuntimeCall::SubtensorModule(pallet_subtensor::Call::::serve_axon_tls { - netuid, - version, - ip, - port, - ip_type, - protocol, - placeholder1, - placeholder2, - certificate, - }); - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); + }; - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - pub fn serve_prometheus(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - let (netuid, version, ip, port, ip_type) = Self::parse_serve_prometheus_parameters(data)?; - let call = - RuntimeCall::SubtensorModule(pallet_subtensor::Call::::serve_prometheus { - netuid, - version, - ip, - port, - ip_type, - }); - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - - // Dispatch the register_network call - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - } - - 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)?)?; - - Ok((netuid, hotkey)) - } - - 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 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)) - } - - 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)) - } - - fn parse_serve_axon_parameters( - data: &[u8], - ) -> Result<(u16, u32, u128, u16, u8, u8, u8, u8), PrecompileFailure> { - if data.len() < 256 { - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - let netuid = parse_netuid(data, 30)?; - - let mut version_vec = [0u8; 4]; - version_vec.copy_from_slice(get_slice(data, 60, 64)?); - let version = u32::from_be_bytes(version_vec); - - let mut ip_vec = [0u8; 16]; - ip_vec.copy_from_slice(get_slice(data, 80, 96)?); - let ip = u128::from_be_bytes(ip_vec); - - let mut port_vec = [0u8; 2]; - port_vec.copy_from_slice(get_slice(data, 126, 128)?); - let port = u16::from_be_bytes(port_vec); - - let ip_type = get_single_u8(data, 159)?; - let protocol = get_single_u8(data, 191)?; - let placeholder1 = get_single_u8(data, 223)?; - let placeholder2 = get_single_u8(data, 255)?; - Ok(( + #[precompile::public( + "serveAxonTls(uint16,uint32,uint128,uint16,uint8,uint8,uint8,uint8,bytes)" + )] + #[precompile::payable] + #[allow(clippy::too_many_arguments)] + fn serve_axon_tls( + handle: &mut impl PrecompileHandle, + netuid: u16, + version: u32, + ip: u128, + port: u16, + ip_type: u8, + protocol: u8, + placeholder1: u8, + placeholder2: u8, + certificate: UnboundedBytes, + ) -> EvmResult<()> { + let call = pallet_subtensor::Call::::serve_axon_tls { netuid, version, ip, @@ -529,101 +143,31 @@ impl NeuronPrecompile { protocol, placeholder1, placeholder2, - )) - } - - fn parse_serve_axon_tls_parameters( - data: &[u8], - ) -> Result<(u16, u32, u128, u16, u8, u8, u8, u8, vec::Vec), PrecompileFailure> { - let data_len = data.len(); - if data_len < 288 { - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - let netuid = parse_netuid(data, 30)?; - - let mut version_vec = [0u8; 4]; - version_vec.copy_from_slice(get_slice(data, 60, 64)?); - let version = u32::from_be_bytes(version_vec); - - let mut ip_vec = [0u8; 16]; - ip_vec.copy_from_slice(get_slice(data, 80, 96)?); - let ip = u128::from_be_bytes(ip_vec); - - let mut port_vec = [0u8; 2]; - port_vec.copy_from_slice(get_slice(data, 126, 128)?); - let port = u16::from_be_bytes(port_vec); - - let ip_type = get_single_u8(data, 159)?; - let protocol = get_single_u8(data, 191)?; - let placeholder1 = get_single_u8(data, 223)?; - let placeholder2 = get_single_u8(data, 255)?; - - let mut len_position_vec = [0u8; 2]; - len_position_vec.copy_from_slice(get_slice(data, 286, 288)?); - let len_position = u16::from_be_bytes(len_position_vec) as usize; - - if len_position > data_len { - log::error!( - "the start position of certificate as {} is bigger than whole data len {}", - len_position, - data_len - ); - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } + certificate: certificate.into(), + }; - let mut len_vec = [0u8; 2]; - len_vec.copy_from_slice(get_slice(data, len_position + 30, len_position + 32)?); - let vec_len = u16::from_be_bytes(len_vec) as usize; - - let vec_result = get_slice( - data, - len_position + 32, - len_position.saturating_add(32).saturating_add(vec_len), - )? - .to_vec(); + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } - Ok(( + #[precompile::public("servePrometheus(uint16,uint32,uint128,uint16,uint8)")] + #[precompile::payable] + #[allow(clippy::too_many_arguments)] + fn serve_prometheus( + handle: &mut impl PrecompileHandle, + netuid: u16, + version: u32, + ip: u128, + port: u16, + ip_type: u8, + ) -> EvmResult<()> { + let call = pallet_subtensor::Call::::serve_prometheus { netuid, version, ip, port, ip_type, - protocol, - placeholder1, - placeholder2, - vec_result, - )) - } - - fn parse_serve_prometheus_parameters( - data: &[u8], - ) -> Result<(u16, u32, u128, u16, u8), PrecompileFailure> { - if data.len() < 160 { - return Err(PrecompileFailure::Error { - exit_status: ExitError::InvalidRange, - }); - } - - let netuid = parse_netuid(data, 30)?; - - let mut version_vec = [0u8; 4]; - version_vec.copy_from_slice(get_slice(data, 60, 64)?); - let version = u32::from_be_bytes(version_vec); - - let mut ip_vec = [0u8; 16]; - ip_vec.copy_from_slice(get_slice(data, 80, 96)?); - let ip = u128::from_be_bytes(ip_vec); - - let mut port_vec = [0u8; 2]; - port_vec.copy_from_slice(get_slice(data, 126, 128)?); - let port = u16::from_be_bytes(port_vec); + }; - let ip_type = get_single_u8(data, 159)?; - Ok((netuid, version, ip, port, ip_type)) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } } diff --git a/runtime/src/precompiles/solidity/neuron.abi b/runtime/src/precompiles/solidity/neuron.abi index e12685f99f..e4ffb6fa18 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 772f290638..204bc3f600 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. diff --git a/runtime/src/precompiles/solidity/subnet.abi b/runtime/src/precompiles/solidity/subnet.abi index fd81850b74..3cc16d9df7 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 1afeced493..d5ef0916d9 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 8cc1c879af..84b2d84700 100644 --- a/runtime/src/precompiles/staking.rs +++ b/runtime/src/precompiles/staking.rs @@ -25,173 +25,122 @@ // - 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 sp_runtime::traits::{BlakeTwo256, Dispatchable, StaticLookup, UniqueSaturatedInto}; +use pallet_evm::{BalanceConverter, ExitError, PrecompileFailure, PrecompileHandle}; +use precompile_utils::EvmResult; +use sp_core::{H256, U256}; +use sp_runtime::traits::{Dispatchable, StaticLookup, UniqueSaturatedInto}; use sp_runtime::AccountId32; -use sp_std::vec; - -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, -]; +use crate::precompiles::{parse_pubkey, try_u16_from_u256, PrecompileExt, PrecompileHandleExt}; +use crate::{ProxyType, Runtime, RuntimeCall}; pub struct StakingPrecompile; -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 { - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); +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, + ]; +} - let (hotkey, _) = get_pubkey(data)?; - let amount: U256 = handle.context().apparent_value; - let netuid = parse_netuid(data, 0x3E)?; +#[precompile_utils::precompile] +impl StakingPrecompile { + #[precompile::public("addStake(bytes32,uint256)")] + #[precompile::payable] + fn add_stake(handle: &mut impl PrecompileHandle, address: H256, netuid: U256) -> EvmResult<()> { + 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(ExitError::OutOfFund)?; - - let call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::::add_stake { + let amount_sub = handle.try_convert_apparent_value()?; + let (hotkey, _) = parse_pubkey(address.as_bytes())?; + let netuid = try_u16_from_u256(netuid)?; + 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)) } - fn remove_stake(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - 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 call = RuntimeCall::SubtensorModule(pallet_subtensor::Call::::remove_stake { + #[precompile::public("removeStake(bytes32,uint256,uint256)")] + fn remove_stake( + handle: &mut impl PrecompileHandle, + address: H256, + amount: U256, + netuid: U256, + ) -> EvmResult<()> { + 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 = pallet_subtensor::Call::::remove_stake { hotkey, netuid, - amount_unstaked: amount_sub.unique_saturated_into(), - }); - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + amount_unstaked, + }; + + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(account_id)) } - fn add_proxy(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - let (delegate, _) = get_pubkey(data)?; + #[precompile::public("addProxy(bytes32)")] + fn add_proxy(handle: &mut impl PrecompileHandle, delegate: H256) -> EvmResult<()> { + 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)) } - fn remove_proxy(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - let (delegate, _) = get_pubkey(data)?; + #[precompile::public("removeProxy(bytes32)")] + fn remove_proxy(handle: &mut impl PrecompileHandle, delegate: H256) -> EvmResult<()> { + 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)) } - 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, _) = 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, ); - // 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(), - }) + Ok(stake.into()) } fn transfer_back_to_caller( 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)?; diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs index ee85a3f864..afda39dd30 100644 --- a/runtime/src/precompiles/subnet.rs +++ b/runtime/src/precompiles/subnet.rs @@ -1,1319 +1,522 @@ -use crate::precompiles::{ - get_method_id, get_pubkey, get_slice, parse_netuid, try_dispatch_runtime_call, -}; -use crate::{Runtime, RuntimeCall}; +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 sp_std::vec; - -pub const SUBNET_PRECOMPILE_INDEX: u64 = 2051; -// bytes with max lenght 1K -pub 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, -]; +use pallet_evm::PrecompileHandle; +use precompile_utils::{prelude::BoundedString, EvmResult}; +use sp_core::H256; + +use crate::precompiles::{parse_pubkey, PrecompileExt, PrecompileHandleExt}; +use crate::Runtime; + pub struct SubnetPrecompile; -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, - }), - } - } +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, + ]; +} - 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, - }); - } +#[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, }; - 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())) } - fn get_serving_rate_limit(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::ServingRateLimit::::get(netuid); + #[precompile::public( + "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, + 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 value_u256 = U256::from(value); - let mut result = [0_u8; 32]; - U256::to_big_endian(&value_u256, &mut result); + let call = pallet_subtensor::Call::::register_network_with_identity { + hotkey, + identity: Some(identity), + }; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - 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)) + #[precompile::public("getServingRateLimit(uint16)")] + #[precompile::view] + fn get_serving_rate_limit(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::ServingRateLimit::::get(netuid)) } - 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); + #[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, + }; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - 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)) + #[precompile::public("getMinDifficulty(uint16)")] + #[precompile::view] + fn get_min_difficulty(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::MinDifficulty::::get(netuid)) } - 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); + #[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, + }; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - 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)) + #[precompile::public("getMaxDifficulty(uint16)")] + #[precompile::view] + fn get_max_difficulty(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::MaxDifficulty::::get(netuid)) } - fn get_weights_version_key(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::WeightsVersionKey::::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, + }; - let value_u256 = U256::from(value); - let mut result = [0_u8; 32]; - U256::to_big_endian(&value_u256, &mut result); + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getWeightsVersionKey(uint16)")] + #[precompile::view] + fn get_weights_version_key(_: &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, - data: &[u8], - ) -> PrecompileResult { - let (netuid, weights_version_key) = Self::parse_netuid_u64_parameter(data)?; - let call = RuntimeCall::AdminUtils( - pallet_admin_utils::Call::::sudo_set_weights_version_key { - netuid, - weights_version_key, - }, - ); - - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - } - - fn get_weights_set_rate_limit(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::WeightsSetRateLimit::::get(netuid); + netuid: u16, + weights_version_key: u64, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_weights_version_key { + netuid, + weights_version_key, + }; - let value_u256 = U256::from(value); - let mut result = [0_u8; 32]; - U256::to_big_endian(&value_u256, &mut result); + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getWeightsSetRateLimit(uint16)")] + #[precompile::view] + fn get_weights_set_rate_limit(_: &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, - data: &[u8], - ) -> PrecompileResult { - let (netuid, weights_set_rate_limit) = Self::parse_netuid_u64_parameter(data)?; - - let call = RuntimeCall::AdminUtils( - pallet_admin_utils::Call::::sudo_set_weights_set_rate_limit { - netuid, - weights_set_rate_limit, - }, - ); - - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - } - - fn get_adjustment_alpha(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::AdjustmentAlpha::::get(netuid); - - let value_u256 = U256::from(value); - let mut result = [0_u8; 32]; - U256::to_big_endian(&value_u256, &mut result); + 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, + }; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - 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)) + #[precompile::public("getAdjustmentAlpha(uint16)")] + #[precompile::view] + fn get_adjustment_alpha(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::AdjustmentAlpha::::get(netuid)) } - 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); + #[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, + }; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - 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)) + #[precompile::public("getMaxWeightLimit(uint16)")] + #[precompile::view] + fn get_max_weight_limit(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::MaxWeightsLimit::::get(netuid)) } - 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); + #[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, + }; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - 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)) + #[precompile::public("getImmunityPeriod(uint16)")] + #[precompile::view] + fn get_immunity_period(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::ImmunityPeriod::::get(netuid)) } - fn get_min_allowed_weights(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::MinAllowedWeights::::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, + }; - let value_u256 = U256::from(value); - let mut result = [0_u8; 32]; - U256::to_big_endian(&value_u256, &mut result); + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getMinAllowedWeights(uint16)")] + #[precompile::view] + fn get_min_allowed_weights(_: &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, - data: &[u8], - ) -> PrecompileResult { - let (netuid, min_allowed_weights) = Self::parse_netuid_u16_parameter(data)?; - let call = RuntimeCall::AdminUtils( - pallet_admin_utils::Call::::sudo_set_min_allowed_weights { - netuid, - min_allowed_weights, - }, - ); - - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - } - - fn get_kappa(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::Kappa::::get(netuid); - - let value_u256 = U256::from(value); - let mut result = [0_u8; 32]; - U256::to_big_endian(&value_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) - } - - fn set_kappa(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - let (netuid, kappa) = Self::parse_netuid_u16_parameter(data)?; - let call = RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_kappa { + netuid: u16, + min_allowed_weights: u16, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_min_allowed_weights { netuid, - kappa, - }); - - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); + min_allowed_weights, + }; - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - fn get_rho(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::Rho::::get(netuid); - - let value_u256 = U256::from(value); - let mut result = [0_u8; 32]; - U256::to_big_endian(&value_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getKappa(uint16)")] + #[precompile::view] + fn get_kappa(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::Kappa::::get(netuid)) } - 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, - ); + #[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 }; - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - fn get_activity_cutoff(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::ActivityCutoff::::get(netuid); + #[precompile::public("getRho(uint16)")] + #[precompile::view] + fn get_rho(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(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); + #[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 }; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - 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)) + #[precompile::public("getActivityCutoff(uint16)")] + #[precompile::view] + fn get_activity_cutoff(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::ActivityCutoff::::get(netuid)) } - fn get_network_registration_allowed(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::NetworkRegistrationAllowed::::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, + }; - 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); + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getNetworkRegistrationAllowed(uint16)")] + #[precompile::view] + fn get_network_registration_allowed( + _: &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, - data: &[u8], - ) -> PrecompileResult { - let (netuid, registration_allowed) = Self::parse_netuid_bool_parameter(data)?; - let call = RuntimeCall::AdminUtils( - pallet_admin_utils::Call::::sudo_set_network_registration_allowed { - netuid, - registration_allowed, - }, - ); - - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - } - - fn get_network_pow_registration_allowed(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::NetworkPowRegistrationAllowed::::get(netuid); + netuid: u16, + registration_allowed: bool, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_network_registration_allowed { + netuid, + registration_allowed, + }; - 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); + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getNetworkPowRegistrationAllowed(uint16)")] + #[precompile::view] + fn get_network_pow_registration_allowed( + _: &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, - data: &[u8], - ) -> PrecompileResult { - let (netuid, registration_allowed) = Self::parse_netuid_bool_parameter(data)?; - let call = RuntimeCall::AdminUtils( - pallet_admin_utils::Call::::sudo_set_network_pow_registration_allowed { - netuid, - registration_allowed, - }, - ); - - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - } - - fn get_min_burn(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::MinBurn::::get(netuid); - - let value_u256 = U256::from(value); - let mut result = [0_u8; 32]; - U256::to_big_endian(&value_u256, &mut result); + netuid: u16, + registration_allowed: bool, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_network_pow_registration_allowed { + netuid, + registration_allowed, + }; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - 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)) + #[precompile::public("getMinBurn(uint16)")] + #[precompile::view] + fn get_min_burn(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::MinBurn::::get(netuid)) } - 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); + #[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 }; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - 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)) + #[precompile::public("getMaxBurn(uint16)")] + #[precompile::view] + fn get_max_burn(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::MaxBurn::::get(netuid)) } - 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); + #[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 }; - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - 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)) + #[precompile::public("getDifficulty(uint16)")] + #[precompile::view] + fn get_difficulty(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { + Ok(pallet_subtensor::Difficulty::::get(netuid)) } - fn get_bonds_moving_average(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::BondsMovingAverage::::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 }; - let value_u256 = U256::from(value); - let mut result = [0_u8; 32]; - U256::to_big_endian(&value_u256, &mut result); + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getBondsMovingAverage(uint16)")] + #[precompile::view] + fn get_bonds_moving_average(_: &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, - data: &[u8], - ) -> PrecompileResult { - let (netuid, bonds_moving_average) = Self::parse_netuid_u64_parameter(data)?; - let call = RuntimeCall::AdminUtils( - pallet_admin_utils::Call::::sudo_set_bonds_moving_average { - netuid, - bonds_moving_average, - }, - ); - - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - } - - fn get_commit_reveal_weights_enabled(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::CommitRevealWeightsEnabled::::get(netuid); + netuid: u16, + bonds_moving_average: u64, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_bonds_moving_average { + netuid, + bonds_moving_average, + }; - 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); + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getCommitRevealWeightsEnabled(uint16)")] + #[precompile::view] + fn get_commit_reveal_weights_enabled( + _: &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, - data: &[u8], - ) -> PrecompileResult { - let (netuid, enabled) = Self::parse_netuid_bool_parameter(data)?; - let call = RuntimeCall::AdminUtils( - pallet_admin_utils::Call::::sudo_set_commit_reveal_weights_enabled { - netuid, - enabled, - }, - ); - - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - } - - fn get_liquid_alpha_enabled(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::LiquidAlphaOn::::get(netuid); + netuid: u16, + enabled: bool, + ) -> EvmResult<()> { + let call = pallet_admin_utils::Call::::sudo_set_commit_reveal_weights_enabled { + netuid, + enabled, + }; - 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); + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) + } - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) + #[precompile::public("getLiquidAlphaEnabled(uint16)")] + #[precompile::view] + fn get_liquid_alpha_enabled(_: &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, - data: &[u8], - ) -> PrecompileResult { - let (netuid, enabled) = Self::parse_netuid_bool_parameter(data)?; - let call = RuntimeCall::AdminUtils( - pallet_admin_utils::Call::::sudo_set_liquid_alpha_enabled { netuid, enabled }, - ); - - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - } - - fn get_alpha_values(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let (alpha_low, alpha_high) = pallet_subtensor::AlphaValues::::get(netuid); - - let mut value_u256 = U256::from(alpha_low); - let mut result = [0_u8; 64]; - U256::to_big_endian(&value_u256, &mut result[0..]); - - value_u256 = U256::from(alpha_high); - U256::to_big_endian(&value_u256, &mut result[32..]); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) - } - - fn set_alpha_values(handle: &mut impl PrecompileHandle, data: &[u8]) -> PrecompileResult { - let (netuid, alpha_low, alpha_high) = Self::parse_netuid_u16_u16_parameter(data)?; + netuid: u16, + enabled: bool, + ) -> EvmResult<()> { let call = - RuntimeCall::AdminUtils(pallet_admin_utils::Call::::sudo_set_alpha_values { - netuid, - alpha_low, - alpha_high, - }); - - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - } - - fn get_commit_reveal_weights_interval(data: &[u8]) -> PrecompileResult { - let netuid = parse_netuid(data, 30)?; - - let value = pallet_subtensor::RevealPeriodEpochs::::get(netuid); - - let value_u256 = U256::from(value); - let mut result = [0_u8; 32]; - U256::to_big_endian(&value_u256, &mut result); - - Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: result.into(), - }) - } - - fn set_commit_reveal_weights_interval( - handle: &mut impl PrecompileHandle, - data: &[u8], - ) -> PrecompileResult { - let (netuid, interval) = Self::parse_netuid_u64_parameter(data)?; - let call = RuntimeCall::AdminUtils( - pallet_admin_utils::Call::::sudo_set_commit_reveal_weights_interval { - netuid, - interval, - }, - ); - - let account_id = - as AddressMapping>::into_account_id( - handle.context().caller, - ); - - try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id)) - } + pallet_admin_utils::Call::::sudo_set_liquid_alpha_enabled { netuid, enabled }; - 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, - )) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - 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)) + #[precompile::public("getAlphaValues(uint16)")] + #[precompile::view] + fn get_alpha_values(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<(u16, u16)> { + Ok(pallet_subtensor::AlphaValues::::get(netuid)) } - 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); + #[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, + }; - Ok((netuid, parameter)) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } - 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)) + #[precompile::public("getCommitRevealWeightsInterval(uint16)")] + #[precompile::view] + fn get_commit_reveal_weights_interval( + _: &mut impl PrecompileHandle, + netuid: u16, + ) -> EvmResult { + Ok(pallet_subtensor::RevealPeriodEpochs::::get(netuid)) } - 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; + #[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, + }; - Ok((netuid, parameter)) + handle.try_dispatch_runtime_call(call, RawOrigin::Signed(handle.caller_account_id())) } }