|
1 | 1 | import * as assert from "assert"; |
2 | | -import { getAliceSigner, getDevnetApi } from "../src/substrate" |
| 2 | +import { getAliceSigner, getDevnetApi, getRandomSubstrateKeypair } from "../src/substrate" |
3 | 3 | import { generateRandomEthersWallet, getPublicClient } from "../src/utils"; |
4 | 4 | import { IDISPATCH_ADDRESS, ISTORAGE_QUERY_ADDRESS, ETH_LOCAL_URL } from "../src/config"; |
5 | 5 | import { devnet, MultiAddress } from "@polkadot-api/descriptors" |
6 | | -import { hexToNumber, PublicClient } from "viem"; |
7 | | -import { PolkadotSigner, TypedApi } from "polkadot-api"; |
| 6 | +import { PublicClient } from "viem"; |
| 7 | +import { PolkadotSigner, TypedApi, getTypedCodecs } from "polkadot-api"; |
8 | 8 | import { convertPublicKeyToSs58 } from "../src/address-utils" |
9 | | -import { forceSetBalanceToEthAddress, setMaxChildkeyTake } from "../src/subtensor"; |
10 | | -import { xxhashAsU8a } from '@polkadot/util-crypto'; |
11 | | -import { u8aToHex } from '@polkadot/util'; |
| 9 | +import { forceSetBalanceToEthAddress, setMaxChildkeyTake, burnedRegister, forceSetBalanceToSs58Address, addStake, setTxRateLimit, addNewSubnetwork, startCall, setTempo } from "../src/subtensor"; |
12 | 10 |
|
13 | 11 | describe("Test the dispatch precompile", () => { |
14 | 12 | let publicClient: PublicClient; |
15 | 13 | const wallet1 = generateRandomEthersWallet(); |
16 | 14 | let api: TypedApi<typeof devnet> |
17 | 15 | let alice: PolkadotSigner; |
| 16 | + const hotkey = getRandomSubstrateKeypair(); |
| 17 | + const coldkey = getRandomSubstrateKeypair(); |
| 18 | + let netuid: number; |
18 | 19 |
|
19 | 20 | before(async () => { |
20 | 21 | publicClient = await getPublicClient(ETH_LOCAL_URL) |
21 | 22 | api = await getDevnetApi() |
22 | 23 | alice = await getAliceSigner() |
23 | 24 | await forceSetBalanceToEthAddress(api, wallet1.address) |
| 25 | + |
| 26 | + await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(hotkey.publicKey)) |
| 27 | + await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(coldkey.publicKey)) |
| 28 | + |
| 29 | + |
| 30 | + netuid = await addNewSubnetwork(api, hotkey, coldkey) |
| 31 | + // set tempo big enough to avoid stake value updated with fast block feature |
| 32 | + await setTempo(api, netuid, 10000) |
| 33 | + await startCall(api, netuid, coldkey) |
| 34 | + await setTxRateLimit(api, BigInt(0)) |
| 35 | + |
| 36 | + await burnedRegister(api, netuid, convertPublicKeyToSs58(hotkey.publicKey), coldkey) |
| 37 | + await addStake(api, netuid, convertPublicKeyToSs58(hotkey.publicKey), BigInt(1_000_000_000), coldkey) |
24 | 38 | }) |
25 | 39 |
|
26 | 40 | it("Dispatch transfer call via precompile contract works correctly", async () => { |
@@ -49,27 +63,73 @@ describe("Test the dispatch precompile", () => { |
49 | 63 | }) |
50 | 64 |
|
51 | 65 |
|
52 | | - it("Storage query call via precompile contract works correctly", async () => { |
53 | | - const palletPrefixBytes = xxhashAsU8a("SubtensorModule", 128); |
54 | | - const storageItemPrefixBytes = xxhashAsU8a("MaxChildkeyTake", 128); |
55 | | - const fullStorageKeyBytes = new Uint8Array([...palletPrefixBytes, ...storageItemPrefixBytes]); |
56 | | - // 0x658faa385070e074c85bf6b568cf0555dba018859cab7e989f77669457b394be |
57 | | - // key for max child key take |
58 | | - const fullStorageKeyHex = u8aToHex(fullStorageKeyBytes); |
| 66 | + it("Value type storage query call via precompile contract works correctly", async () => { |
| 67 | + const key = await api.query.SubtensorModule.MaxChildkeyTake.getKey(); |
59 | 68 |
|
60 | 69 | let maxChildkeyTake = 257; |
61 | 70 | await setMaxChildkeyTake(api, maxChildkeyTake) |
62 | 71 |
|
63 | 72 | api.query.SubtensorModule.MaxChildkeyTake.getValue(); |
64 | 73 | const rawCallResponse = await publicClient.call({ |
65 | 74 | to: ISTORAGE_QUERY_ADDRESS, |
66 | | - data: fullStorageKeyHex, |
| 75 | + data: key.toString() as `0x${string}`, |
| 76 | + }) |
| 77 | + const rawResultData = rawCallResponse.data ?? ""; |
| 78 | + |
| 79 | + const codec = await getTypedCodecs(devnet); |
| 80 | + const maxChildkeyTakeCodec = codec.query.SubtensorModule.MaxChildkeyTake.value; |
| 81 | + const maxChildkeyTakeFromContract = maxChildkeyTakeCodec.dec(rawResultData); |
| 82 | + assert.equal(maxChildkeyTakeFromContract, maxChildkeyTake, "value should be 257") |
| 83 | + }) |
| 84 | + |
| 85 | + it("Map type storage query call via precompile contract works correctly", async () => { |
| 86 | + |
| 87 | + const key = await api.query.SubtensorModule.Tempo.getKey(netuid); |
| 88 | + |
| 89 | + const tempoOnChain = await api.query.SubtensorModule.Tempo.getValue(netuid); |
| 90 | + const rawCallResponse = await publicClient.call({ |
| 91 | + to: ISTORAGE_QUERY_ADDRESS, |
| 92 | + data: key.toString() as `0x${string}`, |
67 | 93 | }) |
68 | | - const rawResultData = rawCallResponse.data; |
69 | | - if (rawResultData === undefined) { |
70 | | - throw new Error("rawResultData is undefined"); |
71 | | - } |
72 | | - let value = hexToNumber(rawResultData); |
73 | | - assert.equal(value, maxChildkeyTake, "value should be 257") |
| 94 | + const rawResultData = rawCallResponse.data ?? ""; |
| 95 | + |
| 96 | + const codec = await getTypedCodecs(devnet); |
| 97 | + const maxChildkeyTakeValueCodec = codec.query.SubtensorModule.Tempo.value; |
| 98 | + const decodedValue = maxChildkeyTakeValueCodec.dec(rawResultData); |
| 99 | + assert.equal(tempoOnChain, decodedValue, "value should be the same as on chain") |
| 100 | + }) |
| 101 | + |
| 102 | + it("Double map type storage query call via precompile contract works correctly", async () => { |
| 103 | + const key = await api.query.SubtensorModule.TotalHotkeyAlpha.getKey(convertPublicKeyToSs58(hotkey.publicKey), netuid); |
| 104 | + const totalHotkeyAlphaOnChain = await api.query.SubtensorModule.TotalHotkeyAlpha.getValue(convertPublicKeyToSs58(hotkey.publicKey), netuid); |
| 105 | + |
| 106 | + const rawCallResponse = await publicClient.call({ |
| 107 | + to: ISTORAGE_QUERY_ADDRESS, |
| 108 | + data: key.toString() as `0x${string}`, |
| 109 | + }) |
| 110 | + const rawResultData = rawCallResponse.data ?? ""; |
| 111 | + const codec = await getTypedCodecs(devnet); |
| 112 | + const totalHotkeyAlphaValueCodec = codec.query.SubtensorModule.TotalHotkeyAlpha.value; |
| 113 | + const decodedValue = totalHotkeyAlphaValueCodec.dec(rawResultData); |
| 114 | + assert.equal(totalHotkeyAlphaOnChain, decodedValue, "value should be the same as on chain") |
| 115 | + |
74 | 116 | }) |
| 117 | + |
| 118 | + // Polkadot api can't decode the boolean type for now. |
| 119 | + // it("Double map type storage query call via precompile contract works correctly", async () => { |
| 120 | + // const key = await api.query.SubtensorModule.IsNetworkMember.getKey(convertPublicKeyToSs58(alice.publicKey), netuid); |
| 121 | + |
| 122 | + // const isNetworkMemberOnChain = await api.query.SubtensorModule.IsNetworkMember.getValue(convertPublicKeyToSs58(alice.publicKey), netuid); |
| 123 | + // const rawCallResponse = await publicClient.call({ |
| 124 | + // to: ISTORAGE_QUERY_ADDRESS, |
| 125 | + // data: key.toString() as `0x${string}`, |
| 126 | + // }) |
| 127 | + |
| 128 | + // const rawResultData = rawCallResponse.data ?? ""; |
| 129 | + // const codec = await getTypedCodecs(devnet); |
| 130 | + // const isNetworkMemberValueCodec = codec.query.SubtensorModule.IsNetworkMember.value; |
| 131 | + // const decodedValue = isNetworkMemberValueCodec.dec(rawResultData); |
| 132 | + // assert.equal(isNetworkMemberOnChain, decodedValue, "value should be the same as on chain") |
| 133 | + // }) |
| 134 | + |
75 | 135 | }); |
0 commit comments