diff --git a/Cargo.lock b/Cargo.lock index a9b72f109e..795fa936e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18236,6 +18236,7 @@ dependencies = [ "pallet-crowdloan", "pallet-drand", "pallet-evm", + "pallet-evm-chain-id", "pallet-evm-precompile-bn128", "pallet-evm-precompile-dispatch", "pallet-evm-precompile-modexp", diff --git a/contract-tests/test/subnet.precompile.hyperparameter.test.ts b/contract-tests/test/subnet.precompile.hyperparameter.test.ts deleted file mode 100644 index 347a9639eb..0000000000 --- a/contract-tests/test/subnet.precompile.hyperparameter.test.ts +++ /dev/null @@ -1,583 +0,0 @@ -import * as assert from "assert"; - -import { getAliceSigner, getDevnetApi, getRandomSubstrateKeypair, waitForTransactionWithRetry } from "../src/substrate" -import { devnet } from "@polkadot-api/descriptors" -import { Binary, FixedSizeBinary, TypedApi, getTypedCodecs } from "polkadot-api"; -import { convertH160ToSS58, convertPublicKeyToSs58 } from "../src/address-utils" -import { generateRandomEthersWallet } from "../src/utils"; -import { ISubnetABI, ISUBNET_ADDRESS } from "../src/contracts/subnet" -import { ethers } from "ethers" -import { disableAdminFreezeWindowAndOwnerHyperparamRateLimit, forceSetBalanceToEthAddress, forceSetBalanceToSs58Address } from "../src/subtensor" -import { blake2AsU8a } from "@polkadot/util-crypto" - -describe("Test the Subnet precompile contract", () => { - // init eth part - const wallet = generateRandomEthersWallet(); - // init substrate part - - const hotkey1 = getRandomSubstrateKeypair(); - const hotkey2 = getRandomSubstrateKeypair(); - let api: TypedApi - - before(async () => { - // init variables got from await and async - api = await getDevnetApi() - - await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(hotkey1.publicKey)) - await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(hotkey2.publicKey)) - await forceSetBalanceToEthAddress(api, wallet.address) - - await disableAdminFreezeWindowAndOwnerHyperparamRateLimit(api) - }) - - it("Can register network without identity info", async () => { - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const tx = await contract.registerNetwork(hotkey1.publicKey); - await tx.wait(); - - const totalNetworkAfterAdd = await api.query.SubtensorModule.TotalNetworks.getValue() - assert.ok(totalNetwork + 1 === totalNetworkAfterAdd) - }); - - it("Can register network with identity info", async () => { - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const tx = await contract.registerNetwork(hotkey2.publicKey, - "name", - "repo", - "contact", - "subnetUrl", - "discord", - "description", - "additional" - ); - await tx.wait(); - - const totalNetworkAfterAdd = await api.query.SubtensorModule.TotalNetworks.getValue() - assert.ok(totalNetwork + 1 === totalNetworkAfterAdd) - }); - - // it.only("Can register network with identity info and logo url", async () => { - // const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - - // const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - - // const tx = await contract["registerNetwork(bytes32,string,string,string,string,string,string,string,string)"]( - // hotkey2.publicKey, - // "name", - // "repo", - // "contact", - // "subnetUrl", - // "discord", - // "description", - // "logoUrl", - // "additional" - // ); - // await tx.wait(); - - // const totalNetworkAfterAdd = await api.query.SubtensorModule.TotalNetworks.getValue() - // assert.ok(totalNetwork + 1 === totalNetworkAfterAdd) - // }); - - it("Can set servingRateLimit parameter", async () => { - - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const newValue = 100; - const tx = await contract.setServingRateLimit(netuid, newValue); - await tx.wait(); - - let onchainValue = await api.query.SubtensorModule.ServingRateLimit.getValue(netuid) - - - let valueFromContract = Number( - await contract.getServingRateLimit(netuid) - ); - - assert.equal(valueFromContract, newValue) - assert.equal(valueFromContract, onchainValue); - }) - - - // minDifficulty hyperparameter - // - // disabled: only by sudo - // - // newValue = 101; - // tx = await contract.setMinDifficulty(netuid, newValue); - // await tx.wait(); - - // await usingApi(async (api) => { - // onchainValue = Number( - // await api.query.subtensorModule.minDifficulty(netuid) - // ); - // }); - - // valueFromContract = Number(await contract.getMinDifficulty(netuid)); - - // expect(valueFromContract).to.eq(newValue); - // expect(valueFromContract).to.eq(onchainValue); - - it("Can set maxDifficulty parameter", async () => { - - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const newValue = 102; - const tx = await contract.setMaxDifficulty(netuid, newValue); - await tx.wait(); - - let onchainValue = await api.query.SubtensorModule.MaxDifficulty.getValue(netuid) - - - let valueFromContract = Number( - await contract.getMaxDifficulty(netuid) - ); - - assert.equal(valueFromContract, newValue) - assert.equal(valueFromContract, onchainValue); - }) - - - it("Can set weightsVersionKey parameter", async () => { - - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const newValue = 103; - const tx = await contract.setWeightsVersionKey(netuid, newValue); - await tx.wait(); - - let onchainValue = await api.query.SubtensorModule.WeightsVersionKey.getValue(netuid) - - - let valueFromContract = Number( - await contract.getWeightsVersionKey(netuid) - ); - - assert.equal(valueFromContract, newValue) - assert.equal(valueFromContract, onchainValue); - }) - - // need sudo as origin now - // it("Can set weightsSetRateLimit parameter", async () => { - - // const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - // const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - // const netuid = totalNetwork - 1; - - // const newValue = 104; - // const tx = await contract.setWeightsSetRateLimit(netuid, newValue); - // await tx.wait(); - - // let onchainValue = await api.query.SubtensorModule.WeightsSetRateLimit.getValue(netuid) - - - // let valueFromContract = Number( - // await contract.getWeightsSetRateLimit(netuid) - // ); - - // assert.equal(valueFromContract, newValue) - // assert.equal(valueFromContract, onchainValue); - // }) - - it("Can set adjustmentAlpha parameter", async () => { - - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const newValue = 105; - const tx = await contract.setAdjustmentAlpha(netuid, newValue); - await tx.wait(); - - let onchainValue = await api.query.SubtensorModule.AdjustmentAlpha.getValue(netuid) - - - let valueFromContract = Number( - await contract.getAdjustmentAlpha(netuid) - ); - - assert.equal(valueFromContract, newValue) - assert.equal(valueFromContract, onchainValue); - }) - - it("Returns constant maxWeightLimit", async () => { - - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const valueFromContract = Number( - await contract.getMaxWeightLimit(netuid) - ); - - assert.equal(valueFromContract, 0xFFFF) - }) - - it("Can set immunityPeriod parameter", async () => { - - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const newValue = 107; - const tx = await contract.setImmunityPeriod(netuid, newValue); - await tx.wait(); - - let onchainValue = await api.query.SubtensorModule.ImmunityPeriod.getValue(netuid) - - - let valueFromContract = Number( - await contract.getImmunityPeriod(netuid) - ); - - assert.equal(valueFromContract, newValue) - assert.equal(valueFromContract, onchainValue); - }) - - it("Can set minAllowedWeights parameter", async () => { - - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const newValue = 108; - const tx = await contract.setMinAllowedWeights(netuid, newValue); - await tx.wait(); - - let onchainValue = await api.query.SubtensorModule.MinAllowedWeights.getValue(netuid) - - - let valueFromContract = Number( - await contract.getMinAllowedWeights(netuid) - ); - - assert.equal(valueFromContract, newValue) - assert.equal(valueFromContract, onchainValue); - }) - - // disable the set kappa parameter test, because it is only callable by sudo now - // it("Can set kappa parameter", async () => { - - // const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - // const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - // const netuid = totalNetwork - 1; - - // const newValue = 109; - // const tx = await contract.setKappa(netuid, newValue); - // await tx.wait(); - - // let onchainValue = await api.query.SubtensorModule.Kappa.getValue(netuid) - - - // let valueFromContract = Number( - // await contract.getKappa(netuid) - // ); - - // assert.equal(valueFromContract, newValue) - // assert.equal(valueFromContract, onchainValue); - // }) - - it("Can set rho parameter", async () => { - - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const newValue = 110; - const tx = await contract.setRho(netuid, newValue); - await tx.wait(); - - let onchainValue = await api.query.SubtensorModule.Rho.getValue(netuid) - - - let valueFromContract = Number( - await contract.getRho(netuid) - ); - - assert.equal(valueFromContract, newValue) - assert.equal(valueFromContract, onchainValue); - }) - - it("Can set activityCutoff parameter", async () => { - - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - const newValue = await api.query.SubtensorModule.MinActivityCutoff.getValue() + 1; - const tx = await contract.setActivityCutoff(netuid, newValue); - await tx.wait(); - - let onchainValue = await api.query.SubtensorModule.ActivityCutoff.getValue(netuid) - - - let valueFromContract = Number( - await contract.getActivityCutoff(netuid) - ); - - assert.equal(valueFromContract, newValue) - assert.equal(valueFromContract, onchainValue); - }) - - // it("Can set networkRegistrationAllowed parameter", async () => { - - // const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - // const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - // const netuid = totalNetwork - 1; - - // const newValue = true; - // const tx = await contract.setNetworkRegistrationAllowed(netuid, newValue); - // await tx.wait(); - - // let onchainValue = await api.query.SubtensorModule.NetworkRegistrationAllowed.getValue(netuid) - - - // let valueFromContract = Boolean( - // await contract.getNetworkRegistrationAllowed(netuid) - // ); - - // assert.equal(valueFromContract, newValue) - // assert.equal(valueFromContract, onchainValue); - // }) - - // it("Can set networkPowRegistrationAllowed parameter", async () => { - - // const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - // const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - // const netuid = totalNetwork - 1; - - // const newValue = true; - // const tx = await contract.setNetworkPowRegistrationAllowed(netuid, newValue); - // await tx.wait(); - - // let onchainValue = await api.query.SubtensorModule.NetworkPowRegistrationAllowed.getValue(netuid) - - - // let valueFromContract = Boolean( - // await contract.getNetworkPowRegistrationAllowed(netuid) - // ); - - // assert.equal(valueFromContract, newValue) - // assert.equal(valueFromContract, onchainValue); - // }) - - // minBurn hyperparameter. only sudo can set it now - // newValue = 112; - - // tx = await contract.setMinBurn(netuid, newValue); - // await tx.wait(); - - // await usingApi(async (api) => { - // onchainValue = Number( - // await api.query.subtensorModule.minBurn(netuid) - // ); - // }); - - // valueFromContract = Number(await contract.getMinBurn(netuid)); - - // expect(valueFromContract).to.eq(newValue); - // expect(valueFromContract).to.eq(onchainValue); - - // maxBurn hyperparameter. only sudo can set it now - // it("Can set maxBurn parameter", async () => { - - // const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - // const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - // const netuid = totalNetwork - 1; - - // const newValue = 113; - // const tx = await contract.setMaxBurn(netuid, newValue); - // await tx.wait(); - - // let onchainValue = await api.query.SubtensorModule.MaxBurn.getValue(netuid) - - - // let valueFromContract = Number( - // await contract.getMaxBurn(netuid) - // ); - - // assert.equal(valueFromContract, newValue) - // assert.equal(valueFromContract, onchainValue); - // }) - - - // difficulty hyperparameter (disabled: sudo only) - // newValue = 114; - - // tx = await contract.setDifficulty(netuid, newValue); - // await tx.wait(); - - // await usingApi(async (api) => { - // onchainValue = Number( - // await api.query.subtensorModule.difficulty(netuid) - // ); - // }); - - // valueFromContract = Number(await contract.getDifficulty(netuid)); - - // expect(valueFromContract).to.eq(newValue); - // expect(valueFromContract).to.eq(onchainValue); - - it("Can set bondsMovingAverage parameter", async () => { - - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const newValue = 115; - const tx = await contract.setBondsMovingAverage(netuid, newValue); - await tx.wait(); - - let onchainValue = await api.query.SubtensorModule.BondsMovingAverage.getValue(netuid) - - - let valueFromContract = Number( - await contract.getBondsMovingAverage(netuid) - ); - - assert.equal(valueFromContract, newValue) - assert.equal(valueFromContract, onchainValue); - }) - - it("Can set commitRevealWeightsEnabled parameter", async () => { - - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const newValue = true; - const tx = await contract.setCommitRevealWeightsEnabled(netuid, newValue); - await tx.wait(); - - let onchainValue = await api.query.SubtensorModule.CommitRevealWeightsEnabled.getValue(netuid) - - - let valueFromContract = Boolean( - await contract.getCommitRevealWeightsEnabled(netuid) - ); - - assert.equal(valueFromContract, newValue) - assert.equal(valueFromContract, onchainValue); - }) - - it("Can set liquidAlphaEnabled parameter", async () => { - - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const newValue = true; - const tx = await contract.setLiquidAlphaEnabled(netuid, newValue); - await tx.wait(); - - let onchainValue = await api.query.SubtensorModule.LiquidAlphaOn.getValue(netuid) - - - let valueFromContract = Boolean( - await contract.getLiquidAlphaEnabled(netuid) - ); - - assert.equal(valueFromContract, newValue) - assert.equal(valueFromContract, onchainValue); - }) - - it("Can set yuma3Enabled hyperparameter", async () => { - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const newValue = true; - const tx = await contract.setYuma3Enabled(netuid, newValue); - await tx.wait(); - - let onchainValue = await api.query.SubtensorModule.Yuma3On.getValue(netuid) - - let valueFromContract = Boolean( - await contract.getYuma3Enabled(netuid) - ); - assert.equal(valueFromContract, newValue) - assert.equal(valueFromContract, onchainValue); - }) - - - // it("Can set alphaValues parameter", async () => { - // const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - // const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - // const netuid = totalNetwork - 1; - - // const newValue = [118, 52429]; - // const tx = await contract.setAlphaValues(netuid, newValue[0], newValue[1]); - // await tx.wait(); - - // let onchainValue = await api.query.SubtensorModule.AlphaV2Values.getValue(netuid) - - // let value = await contract.getAlphaValues(netuid) - // let valueFromContract = [Number(value[0]), Number(value[1])] - - // assert.equal(valueFromContract[0], newValue[0]) - // assert.equal(valueFromContract[1], newValue[1]) - // assert.equal(valueFromContract[0], onchainValue[0]); - // assert.equal(valueFromContract[1], onchainValue[1]); - // }) - - it("Can set commitRevealWeightsInterval parameter", async () => { - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const newValue = 99; - const tx = await contract.setCommitRevealWeightsInterval(netuid, newValue); - await tx.wait(); - - let onchainValue = await api.query.SubtensorModule.RevealPeriodEpochs.getValue(netuid) - - let valueFromContract = Number( - await contract.getCommitRevealWeightsInterval(netuid) - ); - - assert.equal(valueFromContract, newValue) - assert.equal(valueFromContract, onchainValue); - }) - - it("Rejects subnet precompile calls when coldkey swap is scheduled (tx extension)", async () => { - const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() - const contract = new ethers.Contract(ISUBNET_ADDRESS, ISubnetABI, wallet); - const netuid = totalNetwork - 1; - - const coldkeySs58 = convertH160ToSS58(wallet.address) - const newColdkeyHash = FixedSizeBinary.fromBytes(blake2AsU8a(hotkey1.publicKey)) - const currentBlock = await api.query.System.Number.getValue() - const executionBlock = currentBlock + 10 - - const codec = await getTypedCodecs(devnet); - const valueBytes = codec.query.SubtensorModule.ColdkeySwapAnnouncements.value.enc([ - executionBlock, - newColdkeyHash - ]) - const key = await api.query.SubtensorModule.ColdkeySwapAnnouncements.getKey(coldkeySs58); - - // Use sudo + set_storage since the swap-scheduled check only exists in the tx extension. - const setStorageCall = api.tx.System.set_storage({ - items: [[Binary.fromHex(key), Binary.fromBytes(valueBytes)]], - }) - const sudoTx = api.tx.Sudo.sudo({ call: setStorageCall.decodedCall }) - await waitForTransactionWithRetry(api, sudoTx, getAliceSigner()) - - const storedValue = await api.query.SubtensorModule.ColdkeySwapAnnouncements.getValue(coldkeySs58) - assert.equal(storedValue?.[0], executionBlock) - assert.equal(storedValue?.[1].asHex(), newColdkeyHash.asHex()) - - await assert.rejects(async () => { - const tx = await contract.setServingRateLimit(netuid, 100); - await tx.wait(); - }) - }) -}) diff --git a/contract-tests/test/votingPower.precompile.test.ts b/contract-tests/test/votingPower.precompile.test.ts deleted file mode 100644 index f98edd5fc1..0000000000 --- a/contract-tests/test/votingPower.precompile.test.ts +++ /dev/null @@ -1,226 +0,0 @@ -import * as assert from "assert"; - -import { getDevnetApi, getRandomSubstrateKeypair, getAliceSigner, getSignerFromKeypair, waitForTransactionWithRetry } from "../src/substrate" -import { getPublicClient } from "../src/utils"; -import { ETH_LOCAL_URL } from "../src/config"; -import { devnet } from "@polkadot-api/descriptors" -import { PublicClient } from "viem"; -import { PolkadotSigner, TypedApi } from "polkadot-api"; -import { toViemAddress, convertPublicKeyToSs58 } from "../src/address-utils" -import { IVotingPowerABI, IVOTING_POWER_ADDRESS } from "../src/contracts/votingPower" -import { forceSetBalanceToSs58Address, addNewSubnetwork, startCall } from "../src/subtensor"; - -describe("Test VotingPower Precompile", () => { - // init substrate part - const hotkey = getRandomSubstrateKeypair(); - const coldkey = getRandomSubstrateKeypair(); - let publicClient: PublicClient; - - let api: TypedApi; - - // sudo account alice as signer - let alice: PolkadotSigner; - - // init other variable - let subnetId = 0; - - before(async () => { - // init variables got from await and async - publicClient = await getPublicClient(ETH_LOCAL_URL) - api = await getDevnetApi() - alice = await getAliceSigner(); - - await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(hotkey.publicKey)) - await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(coldkey.publicKey)) - - let netuid = await addNewSubnetwork(api, hotkey, coldkey) - await startCall(api, netuid, coldkey) - subnetId = netuid - }) - - describe("VotingPower Tracking Status Functions", () => { - it("isVotingPowerTrackingEnabled returns false by default", async () => { - const isEnabled = await publicClient.readContract({ - abi: IVotingPowerABI, - address: toViemAddress(IVOTING_POWER_ADDRESS), - functionName: "isVotingPowerTrackingEnabled", - args: [subnetId] - }) - - assert.ok(isEnabled !== undefined, "isVotingPowerTrackingEnabled should return a value"); - assert.strictEqual(typeof isEnabled, 'boolean', "isVotingPowerTrackingEnabled should return a boolean"); - // By default, voting power tracking is disabled - assert.strictEqual(isEnabled, false, "Voting power tracking should be disabled by default"); - }); - - it("getVotingPowerDisableAtBlock returns 0 when not scheduled", async () => { - const disableAtBlock = await publicClient.readContract({ - abi: IVotingPowerABI, - address: toViemAddress(IVOTING_POWER_ADDRESS), - functionName: "getVotingPowerDisableAtBlock", - args: [subnetId] - }) - - assert.ok(disableAtBlock !== undefined, "getVotingPowerDisableAtBlock should return a value"); - assert.strictEqual(typeof disableAtBlock, 'bigint', "getVotingPowerDisableAtBlock should return a bigint"); - assert.strictEqual(disableAtBlock, BigInt(0), "Disable at block should be 0 when not scheduled"); - }); - - it("getVotingPowerEmaAlpha returns default alpha value", async () => { - const alpha = await publicClient.readContract({ - abi: IVotingPowerABI, - address: toViemAddress(IVOTING_POWER_ADDRESS), - functionName: "getVotingPowerEmaAlpha", - args: [subnetId] - }) - - assert.ok(alpha !== undefined, "getVotingPowerEmaAlpha should return a value"); - assert.strictEqual(typeof alpha, 'bigint', "getVotingPowerEmaAlpha should return a bigint"); - // Default alpha is 0_003_570_000_000_000_000 // 0.00357 * 10^18 = 2 weeks e-folding (time-constant) @ 361 - assert.strictEqual(alpha, BigInt("3570000000000000"), "Default alpha should be 0.00357 * 10^18 (3570000000000000)"); - }); - }); - - describe("VotingPower Query Functions", () => { - it("getVotingPower returns 0 for hotkey without voting power", async () => { - // Convert hotkey public key to bytes32 format (0x prefixed hex string) - const hotkeyBytes32 = '0x' + Buffer.from(hotkey.publicKey).toString('hex'); - - const votingPower = await publicClient.readContract({ - abi: IVotingPowerABI, - address: toViemAddress(IVOTING_POWER_ADDRESS), - functionName: "getVotingPower", - args: [subnetId, hotkeyBytes32 as `0x${string}`] - }) - - assert.ok(votingPower !== undefined, "getVotingPower should return a value"); - assert.strictEqual(typeof votingPower, 'bigint', "getVotingPower should return a bigint"); - // Without voting power tracking enabled, voting power should be 0 - assert.strictEqual(votingPower, BigInt(0), "Voting power should be 0 when tracking is disabled"); - }); - - it("getVotingPower returns 0 for unknown hotkey", async () => { - // Generate a random hotkey that doesn't exist - const randomHotkey = getRandomSubstrateKeypair(); - const randomHotkeyBytes32 = '0x' + Buffer.from(randomHotkey.publicKey).toString('hex'); - - const votingPower = await publicClient.readContract({ - abi: IVotingPowerABI, - address: toViemAddress(IVOTING_POWER_ADDRESS), - functionName: "getVotingPower", - args: [subnetId, randomHotkeyBytes32 as `0x${string}`] - }) - - assert.ok(votingPower !== undefined, "getVotingPower should return a value"); - assert.strictEqual(votingPower, BigInt(0), "Voting power should be 0 for unknown hotkey"); - }); - - it("getTotalVotingPower returns 0 when no voting power exists", async () => { - const totalVotingPower = await publicClient.readContract({ - abi: IVotingPowerABI, - address: toViemAddress(IVOTING_POWER_ADDRESS), - functionName: "getTotalVotingPower", - args: [subnetId] - }) - - assert.ok(totalVotingPower !== undefined, "getTotalVotingPower should return a value"); - assert.strictEqual(typeof totalVotingPower, 'bigint', "getTotalVotingPower should return a bigint"); - assert.strictEqual(totalVotingPower, BigInt(0), "Total voting power should be 0 when tracking is disabled"); - }); - }); - - describe("VotingPower with Tracking Enabled", () => { - let enabledSubnetId: number; - - before(async () => { - // Create a new subnet for this test - const hotkey2 = getRandomSubstrateKeypair(); - const coldkey2 = getRandomSubstrateKeypair(); - - await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(hotkey2.publicKey)) - await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(coldkey2.publicKey)) - - enabledSubnetId = await addNewSubnetwork(api, hotkey2, coldkey2) - await startCall(api, enabledSubnetId, coldkey2) - - // Enable voting power tracking via sudo - const internalCall = api.tx.SubtensorModule.enable_voting_power_tracking({ netuid: enabledSubnetId }) - const tx = api.tx.Sudo.sudo({ call: internalCall.decodedCall }) - await waitForTransactionWithRetry(api, tx, alice) - }); - - it("isVotingPowerTrackingEnabled returns true after enabling", async () => { - const isEnabled = await publicClient.readContract({ - abi: IVotingPowerABI, - address: toViemAddress(IVOTING_POWER_ADDRESS), - functionName: "isVotingPowerTrackingEnabled", - args: [enabledSubnetId] - }) - - assert.strictEqual(isEnabled, true, "Voting power tracking should be enabled"); - }); - - it("getVotingPowerDisableAtBlock still returns 0 when enabled but not scheduled for disable", async () => { - const disableAtBlock = await publicClient.readContract({ - abi: IVotingPowerABI, - address: toViemAddress(IVOTING_POWER_ADDRESS), - functionName: "getVotingPowerDisableAtBlock", - args: [enabledSubnetId] - }) - - assert.strictEqual(disableAtBlock, BigInt(0), "Disable at block should still be 0"); - }); - }); - - describe("All precompile functions are accessible", () => { - it("All VotingPower precompile functions can be called", async () => { - const hotkeyBytes32 = '0x' + Buffer.from(hotkey.publicKey).toString('hex'); - - // Test all five functions - const results = await Promise.all([ - publicClient.readContract({ - abi: IVotingPowerABI, - address: toViemAddress(IVOTING_POWER_ADDRESS), - functionName: "getVotingPower", - args: [subnetId, hotkeyBytes32 as `0x${string}`] - }), - publicClient.readContract({ - abi: IVotingPowerABI, - address: toViemAddress(IVOTING_POWER_ADDRESS), - functionName: "isVotingPowerTrackingEnabled", - args: [subnetId] - }), - publicClient.readContract({ - abi: IVotingPowerABI, - address: toViemAddress(IVOTING_POWER_ADDRESS), - functionName: "getVotingPowerDisableAtBlock", - args: [subnetId] - }), - publicClient.readContract({ - abi: IVotingPowerABI, - address: toViemAddress(IVOTING_POWER_ADDRESS), - functionName: "getVotingPowerEmaAlpha", - args: [subnetId] - }), - publicClient.readContract({ - abi: IVotingPowerABI, - address: toViemAddress(IVOTING_POWER_ADDRESS), - functionName: "getTotalVotingPower", - args: [subnetId] - }) - ]); - - // All functions should return defined values - results.forEach((result: unknown, index: number) => { - assert.ok(result !== undefined, `Function ${index} should return a value`); - }); - - // Verify types - assert.strictEqual(typeof results[0], 'bigint', "getVotingPower should return bigint"); - assert.strictEqual(typeof results[1], 'boolean', "isVotingPowerTrackingEnabled should return boolean"); - assert.strictEqual(typeof results[2], 'bigint', "getVotingPowerDisableAtBlock should return bigint"); - assert.strictEqual(typeof results[3], 'bigint', "getVotingPowerEmaAlpha should return bigint"); - assert.strictEqual(typeof results[4], 'bigint', "getTotalVotingPower should return bigint"); - }); - }); -}); diff --git a/precompiles/Cargo.toml b/precompiles/Cargo.toml index 68f617176d..7a33d9e4c1 100644 --- a/precompiles/Cargo.toml +++ b/precompiles/Cargo.toml @@ -57,6 +57,7 @@ std = [ "pallet-crowdloan/std", "pallet-drand/std", "pallet-evm-precompile-bn128/std", + "pallet-evm-chain-id/std", "pallet-evm-precompile-dispatch/std", "pallet-evm-precompile-modexp/std", "pallet-evm-precompile-sha3fips/std", @@ -100,6 +101,7 @@ runtime-benchmarks = [ [dev-dependencies] pallet-drand = { workspace = true, features = ["std"] } +pallet-evm-chain-id = { workspace = true, features = ["std"] } pallet-preimage = { workspace = true, features = ["std"] } pallet-scheduler = { workspace = true, features = ["std"] } pallet-timestamp = { workspace = true, features = ["std"] } diff --git a/precompiles/src/mock.rs b/precompiles/src/mock.rs index f1482b5262..272e0a01e0 100644 --- a/precompiles/src/mock.rs +++ b/precompiles/src/mock.rs @@ -45,6 +45,8 @@ frame_support::construct_runtime!( Crowdloan: pallet_crowdloan::{Pallet, Call, Storage, Event} = 10, Proxy: pallet_subtensor_proxy = 11, Evm: pallet_evm = 12, + AdminUtils: pallet_admin_utils = 13, + EVMChainId: pallet_evm_chain_id = 14, } ); @@ -338,6 +340,17 @@ mod test_crypto { } } +impl pallet_evm_chain_id::Config for Runtime {} + +impl pallet_admin_utils::Config for Runtime { + type Aura = (); + type Grandpa = (); + type AuthorityId = test_crypto::Public; + type MaxAuthorities = MaxAuthorities; + type Balance = TaoBalance; + type WeightInfo = (); +} + impl pallet_drand::Config for Runtime { type AuthorityId = test_crypto::TestAuthId; type Verifier = pallet_drand::verifier::QuicknetVerifier; diff --git a/precompiles/src/subnet.rs b/precompiles/src/subnet.rs index 79c08c2625..b3114b6454 100644 --- a/precompiles/src/subnet.rs +++ b/precompiles/src/subnet.rs @@ -782,3 +782,445 @@ where ) } } + +#[cfg(test)] +mod tests { + #![allow(clippy::expect_used, clippy::arithmetic_side_effects)] + + use super::*; + use crate::PrecompileExt; + use crate::mock::{ + AccountId, Runtime, addr_from_index, assert_static_call, new_test_ext, precompiles, + selector_u32, + }; + use pallet_evm::AddressMapping; + use precompile_utils::solidity::encode_with_selector; + use precompile_utils::testing::PrecompileTesterExt; + use sp_core::{H160, H256, U256}; + + const TEST_NETUID_U16: u16 = 1; + const TEST_TEMPO: u16 = 100; + + fn mapped_account(address: H160) -> AccountId { + ::AddressMapping::into_account_id(address) + } + + fn setup_owner_subnet(caller: H160) -> NetUid { + let netuid = NetUid::from(TEST_NETUID_U16); + let owner = mapped_account(caller); + let owner_hotkey = AccountId::from([0x55; 32]); + + pallet_subtensor::Pallet::::init_new_network(netuid, TEST_TEMPO); + pallet_subtensor::SubnetOwner::::insert(netuid, owner); + pallet_subtensor::SubnetOwnerHotkey::::insert(netuid, owner_hotkey); + pallet_subtensor::AdminFreezeWindow::::set(0); + pallet_subtensor::OwnerHyperparamRateLimit::::set(0); + + netuid + } + + #[test] + fn subnet_precompile_registers_network_without_identity() { + new_test_ext().execute_with(|| { + let caller = addr_from_index(0x5000); + let caller_account = mapped_account(caller); + let hotkey = AccountId::from([0x44; 32]); + let precompiles = precompiles::>(); + let precompile_addr = addr_from_index(SubnetPrecompile::::INDEX); + + pallet_subtensor::Pallet::::add_balance_to_coldkey_account( + &caller_account, + 1_000_000_000_000_u64.into(), + ); + + let total_before = pallet_subtensor::TotalNetworks::::get(); + let netuid = pallet_subtensor::Pallet::::get_next_netuid(); + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("registerNetwork(bytes32)"), + (H256::from_slice(hotkey.as_ref()),), + ), + ) + .execute_returns(()); + + let total_after = pallet_subtensor::TotalNetworks::::get(); + assert_eq!(total_after, total_before + 1); + assert_eq!( + pallet_subtensor::SubnetOwner::::get(netuid), + caller_account + ); + assert!(!pallet_subtensor::SubnetIdentitiesV3::::contains_key(netuid)); + }); + } + + #[test] + fn subnet_precompile_registers_network_with_identity() { + new_test_ext().execute_with(|| { + let caller = addr_from_index(0x5002); + let caller_account = mapped_account(caller); + let hotkey = AccountId::from([0x45; 32]); + let precompiles = precompiles::>(); + let precompile_addr = addr_from_index(SubnetPrecompile::::INDEX); + + pallet_subtensor::Pallet::::add_balance_to_coldkey_account( + &caller_account, + 1_000_000_000_000_u64.into(), + ); + + let total_before = pallet_subtensor::TotalNetworks::::get(); + let netuid = pallet_subtensor::Pallet::::get_next_netuid(); + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32( + "registerNetwork(bytes32,string,string,string,string,string,string,string)", + ), + ( + H256::from_slice(hotkey.as_ref()), + precompile_utils::solidity::codec::UnboundedString::from("name"), + precompile_utils::solidity::codec::UnboundedString::from("repo"), + precompile_utils::solidity::codec::UnboundedString::from("contact"), + precompile_utils::solidity::codec::UnboundedString::from("subnetUrl"), + precompile_utils::solidity::codec::UnboundedString::from("discord"), + precompile_utils::solidity::codec::UnboundedString::from("description"), + precompile_utils::solidity::codec::UnboundedString::from("additional"), + ), + ), + ) + .execute_returns(()); + + let total_after = pallet_subtensor::TotalNetworks::::get(); + assert_eq!(total_after, total_before + 1); + assert_eq!(pallet_subtensor::SubnetOwner::::get(netuid), caller_account); + assert!(pallet_subtensor::SubnetIdentitiesV3::::contains_key(netuid)); + }); + } + + #[test] + fn subnet_precompile_sets_and_gets_owner_hyperparameters() { + new_test_ext().execute_with(|| { + let caller = addr_from_index(0x5001); + let netuid = setup_owner_subnet(caller); + let precompiles = precompiles::>(); + let precompile_addr = addr_from_index(SubnetPrecompile::::INDEX); + + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("setServingRateLimit(uint16,uint64)"), + (TEST_NETUID_U16, 100_u64), + ), + ) + .execute_returns(()); + assert_eq!( + pallet_subtensor::ServingRateLimit::::get(netuid), + 100 + ); + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector( + selector_u32("getServingRateLimit(uint16)"), + (TEST_NETUID_U16,), + ), + U256::from(100_u64), + ); + + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("setMaxDifficulty(uint16,uint64)"), + (TEST_NETUID_U16, 102_u64), + ), + ) + .execute_returns(()); + assert_eq!(pallet_subtensor::MaxDifficulty::::get(netuid), 102); + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector(selector_u32("getMaxDifficulty(uint16)"), (TEST_NETUID_U16,)), + U256::from(102_u64), + ); + + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("setWeightsVersionKey(uint16,uint64)"), + (TEST_NETUID_U16, 103_u64), + ), + ) + .execute_returns(()); + assert_eq!( + pallet_subtensor::WeightsVersionKey::::get(netuid), + 103 + ); + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector( + selector_u32("getWeightsVersionKey(uint16)"), + (TEST_NETUID_U16,), + ), + U256::from(103_u64), + ); + + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("setAdjustmentAlpha(uint16,uint64)"), + (TEST_NETUID_U16, 105_u64), + ), + ) + .execute_returns(()); + assert_eq!( + pallet_subtensor::AdjustmentAlpha::::get(netuid), + 105 + ); + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector( + selector_u32("getAdjustmentAlpha(uint16)"), + (TEST_NETUID_U16,), + ), + U256::from(105_u64), + ); + + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector( + selector_u32("getMaxWeightLimit(uint16)"), + (TEST_NETUID_U16,), + ), + U256::from(0xFFFF_u64), + ); + + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("setImmunityPeriod(uint16,uint16)"), + (TEST_NETUID_U16, 107_u16), + ), + ) + .execute_returns(()); + assert_eq!( + pallet_subtensor::ImmunityPeriod::::get(netuid), + 107 + ); + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector( + selector_u32("getImmunityPeriod(uint16)"), + (TEST_NETUID_U16,), + ), + U256::from(107_u64), + ); + + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("setMinAllowedWeights(uint16,uint16)"), + (TEST_NETUID_U16, 108_u16), + ), + ) + .execute_returns(()); + assert_eq!( + pallet_subtensor::MinAllowedWeights::::get(netuid), + 108 + ); + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector( + selector_u32("getMinAllowedWeights(uint16)"), + (TEST_NETUID_U16,), + ), + U256::from(108_u64), + ); + + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("setRho(uint16,uint16)"), + (TEST_NETUID_U16, 110_u16), + ), + ) + .execute_returns(()); + assert_eq!(pallet_subtensor::Rho::::get(netuid), 110); + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector(selector_u32("getRho(uint16)"), (TEST_NETUID_U16,)), + U256::from(110_u64), + ); + + let activity_cutoff = pallet_subtensor::MinActivityCutoff::::get() + 1; + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("setActivityCutoff(uint16,uint16)"), + (TEST_NETUID_U16, activity_cutoff), + ), + ) + .execute_returns(()); + assert_eq!( + pallet_subtensor::ActivityCutoff::::get(netuid), + activity_cutoff + ); + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector( + selector_u32("getActivityCutoff(uint16)"), + (TEST_NETUID_U16,), + ), + U256::from(activity_cutoff), + ); + + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("setBondsMovingAverage(uint16,uint64)"), + (TEST_NETUID_U16, 115_u64), + ), + ) + .execute_returns(()); + assert_eq!( + pallet_subtensor::BondsMovingAverage::::get(netuid), + 115 + ); + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector( + selector_u32("getBondsMovingAverage(uint16)"), + (TEST_NETUID_U16,), + ), + U256::from(115_u64), + ); + + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("setCommitRevealWeightsEnabled(uint16,bool)"), + (TEST_NETUID_U16, true), + ), + ) + .execute_returns(()); + assert!(pallet_subtensor::CommitRevealWeightsEnabled::::get(netuid)); + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector( + selector_u32("getCommitRevealWeightsEnabled(uint16)"), + (TEST_NETUID_U16,), + ), + U256::one(), + ); + + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("setLiquidAlphaEnabled(uint16,bool)"), + (TEST_NETUID_U16, true), + ), + ) + .execute_returns(()); + assert!(pallet_subtensor::LiquidAlphaOn::::get(netuid)); + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector( + selector_u32("getLiquidAlphaEnabled(uint16)"), + (TEST_NETUID_U16,), + ), + U256::one(), + ); + + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("setYuma3Enabled(uint16,bool)"), + (TEST_NETUID_U16, true), + ), + ) + .execute_returns(()); + assert!(pallet_subtensor::Yuma3On::::get(netuid)); + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector(selector_u32("getYuma3Enabled(uint16)"), (TEST_NETUID_U16,)), + U256::one(), + ); + + precompiles + .prepare_test( + caller, + precompile_addr, + encode_with_selector( + selector_u32("setCommitRevealWeightsInterval(uint16,uint64)"), + (TEST_NETUID_U16, 99_u64), + ), + ) + .execute_returns(()); + assert_eq!( + pallet_subtensor::RevealPeriodEpochs::::get(netuid), + 99 + ); + assert_static_call( + &precompiles, + caller, + precompile_addr, + encode_with_selector( + selector_u32("getCommitRevealWeightsInterval(uint16)"), + (TEST_NETUID_U16,), + ), + U256::from(99_u64), + ); + }); + } +} diff --git a/precompiles/src/voting_power.rs b/precompiles/src/voting_power.rs index 74e1731b6e..af7896dac1 100644 --- a/precompiles/src/voting_power.rs +++ b/precompiles/src/voting_power.rs @@ -129,3 +129,136 @@ where Ok(U256::from(total)) } } + +#[cfg(test)] +mod tests { + #![allow(clippy::arithmetic_side_effects)] + + use super::*; + use crate::PrecompileExt; + use crate::mock::{ + AccountId, Runtime, addr_from_index, assert_static_call, new_test_ext, precompiles, + selector_u32, + }; + use precompile_utils::solidity::encode_with_selector; + use sp_core::{H160, H256, U256}; + + const TEST_NETUID_U16: u16 = 1; + const TEST_TEMPO: u16 = 100; + const DEFAULT_ALPHA: u64 = 3_570_000_000_000_000; + + fn setup_subnet() -> NetUid { + let netuid = NetUid::from(TEST_NETUID_U16); + pallet_subtensor::Pallet::::init_new_network(netuid, TEST_TEMPO); + netuid + } + + fn hotkey(byte: u8) -> AccountId { + AccountId::from([byte; 32]) + } + + fn assert_voting_power_call( + caller: H160, + signature: &str, + args: impl precompile_utils::solidity::Codec, + expected: U256, + ) { + assert_static_call( + &precompiles::>(), + caller, + addr_from_index(VotingPowerPrecompile::::INDEX), + encode_with_selector(selector_u32(signature), args), + expected, + ); + } + + #[test] + fn voting_power_precompile_returns_default_zero_values() { + new_test_ext().execute_with(|| { + let netuid = setup_subnet(); + let caller = addr_from_index(0x6001); + let existing_hotkey = hotkey(0x11); + let unknown_hotkey = hotkey(0x22); + + assert!(!pallet_subtensor::VotingPowerTrackingEnabled::::get(netuid)); + assert_voting_power_call( + caller, + "isVotingPowerTrackingEnabled(uint16)", + (TEST_NETUID_U16,), + U256::zero(), + ); + assert_voting_power_call( + caller, + "getVotingPowerDisableAtBlock(uint16)", + (TEST_NETUID_U16,), + U256::zero(), + ); + assert_voting_power_call( + caller, + "getVotingPowerEmaAlpha(uint16)", + (TEST_NETUID_U16,), + U256::from(DEFAULT_ALPHA), + ); + assert_voting_power_call( + caller, + "getVotingPower(uint16,bytes32)", + ( + TEST_NETUID_U16, + H256::from_slice(existing_hotkey.as_slice()), + ), + U256::zero(), + ); + assert_voting_power_call( + caller, + "getVotingPower(uint16,bytes32)", + (TEST_NETUID_U16, H256::from_slice(unknown_hotkey.as_slice())), + U256::zero(), + ); + assert_voting_power_call( + caller, + "getTotalVotingPower(uint16)", + (TEST_NETUID_U16,), + U256::zero(), + ); + }); + } + + #[test] + fn voting_power_precompile_reads_enabled_tracking_and_stored_power() { + new_test_ext().execute_with(|| { + let netuid = setup_subnet(); + let caller = addr_from_index(0x6002); + let first_hotkey = hotkey(0x33); + let second_hotkey = hotkey(0x44); + + pallet_subtensor::VotingPowerTrackingEnabled::::insert(netuid, true); + pallet_subtensor::VotingPower::::insert(netuid, &first_hotkey, 123_u64); + pallet_subtensor::VotingPower::::insert(netuid, &second_hotkey, 456_u64); + + assert_voting_power_call( + caller, + "isVotingPowerTrackingEnabled(uint16)", + (TEST_NETUID_U16,), + U256::one(), + ); + assert_voting_power_call( + caller, + "getVotingPowerDisableAtBlock(uint16)", + (TEST_NETUID_U16,), + U256::zero(), + ); + assert_voting_power_call( + caller, + "getVotingPower(uint16,bytes32)", + (TEST_NETUID_U16, H256::from_slice(first_hotkey.as_slice())), + U256::from(123_u64), + ); + assert_voting_power_call( + caller, + "getTotalVotingPower(uint16)", + (TEST_NETUID_U16,), + U256::from(579_u64), + ); + }); + } +}