From b04169101ee205c182d0b25c27b6d66c61159e25 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 15 May 2025 10:25:50 +0800 Subject: [PATCH 01/17] init solution --- Cargo.lock | 13 ++++ Cargo.toml | 1 + precompiles/Cargo.toml | 1 + precompiles/src/extensions.rs | 3 + precompiles/src/lib.rs | 68 ++++++++++++++++++- precompiles/src/runtime_call_query.rs | 53 +++++++++++++++ precompiles/src/solidity/runtimeCallQuery.abi | 34 ++++++++++ precompiles/src/solidity/runtimeCallQuery.sol | 14 ++++ precompiles/src/uid_lookup.rs | 4 +- 9 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 precompiles/src/runtime_call_query.rs create mode 100644 precompiles/src/solidity/runtimeCallQuery.abi create mode 100644 precompiles/src/solidity/runtimeCallQuery.sol diff --git a/Cargo.lock b/Cargo.lock index b0c56ffb2e..42dc2f1b20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6235,6 +6235,18 @@ dependencies = [ "scale-info", ] +[[package]] +name = "pallet-evm-precompile-dispatch" +version = "2.0.0-dev" +source = "git+https://github.com/opentensor/frontier?rev=cd6bca14a3#cd6bca14a366cc7cb1c3b1b1d7bc8213667e4126" +dependencies = [ + "fp-evm", + "frame-support", + "pallet-evm", + "parity-scale-codec", + "sp-runtime", +] + [[package]] name = "pallet-evm-precompile-modexp" version = "2.0.0-dev" @@ -11070,6 +11082,7 @@ dependencies = [ "pallet-admin-utils", "pallet-balances", "pallet-evm", + "pallet-evm-precompile-dispatch", "pallet-evm-precompile-modexp", "pallet-evm-precompile-sha3fips", "pallet-evm-precompile-simple", diff --git a/Cargo.toml b/Cargo.toml index 548bc5af63..4599d36c23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -207,6 +207,7 @@ pallet-base-fee = { git = "https://github.com/opentensor/frontier", rev = "cd6bc pallet-dynamic-fee = { git = "https://github.com/opentensor/frontier", rev = "cd6bca14a3", default-features = false } pallet-ethereum = { git = "https://github.com/opentensor/frontier", rev = "cd6bca14a3", default-features = false } pallet-evm = { git = "https://github.com/opentensor/frontier", rev = "cd6bca14a3", default-features = false } +pallet-evm-precompile-dispatch = { git = "https://github.com/opentensor/frontier", rev = "cd6bca14a3", default-features = false } pallet-evm-chain-id = { git = "https://github.com/opentensor/frontier", rev = "cd6bca14a3", default-features = false } pallet-evm-precompile-modexp = { git = "https://github.com/opentensor/frontier", rev = "cd6bca14a3", default-features = false } pallet-evm-precompile-sha3fips = { git = "https://github.com/opentensor/frontier", rev = "cd6bca14a3", default-features = false } diff --git a/precompiles/Cargo.toml b/precompiles/Cargo.toml index ec46e6aee2..b3d318da14 100644 --- a/precompiles/Cargo.toml +++ b/precompiles/Cargo.toml @@ -18,6 +18,7 @@ frame-system = { workspace = true } log = { workspace = true } pallet-balances = { workspace = true } pallet-evm = { workspace = true } +pallet-evm-precompile-dispatch = { workspace = true } pallet-evm-precompile-modexp = { workspace = true } pallet-evm-precompile-sha3fips = { workspace = true } pallet-evm-precompile-simple = { workspace = true } diff --git a/precompiles/src/extensions.rs b/precompiles/src/extensions.rs index 1c90922c57..0e1a8490c3 100644 --- a/precompiles/src/extensions.rs +++ b/precompiles/src/extensions.rs @@ -9,6 +9,7 @@ use pallet_evm::{ AddressMapping, BalanceConverter, EvmBalance, ExitError, GasWeightMapping, Precompile, PrecompileFailure, PrecompileHandle, PrecompileResult, }; +use pallet_evm_precompile_dispatch::Dispatch; use precompile_utils::EvmResult; use sp_core::{H160, U256, blake2_256}; use sp_runtime::traits::Dispatchable; @@ -137,6 +138,8 @@ pub(crate) trait PrecompileExt>: Precompile { R: frame_system::Config + pallet_admin_utils::Config, { if PrecompileEnable::::get(&precompile_enum) { + // Some(Dispatch::::execute(handle)) + Some(Self::execute(handle)) } else { Some(Err(PrecompileFailure::Error { diff --git a/precompiles/src/lib.rs b/precompiles/src/lib.rs index ca52831323..3ea8bb49dc 100644 --- a/precompiles/src/lib.rs +++ b/precompiles/src/lib.rs @@ -4,11 +4,15 @@ extern crate alloc; use core::marker::PhantomData; -use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; +use frame_support::{ + dispatch::{GetDispatchInfo, PostDispatchInfo}, + traits::ConstU32, +}; use pallet_evm::{ AddressMapping, IsPrecompileResult, Precompile, PrecompileHandle, PrecompileResult, PrecompileSet, }; +use pallet_evm_precompile_dispatch::Dispatch; use pallet_evm_precompile_modexp::Modexp; use pallet_evm_precompile_sha3fips::Sha3FIPS256; use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; @@ -39,6 +43,8 @@ mod uid_lookup; pub struct Precompiles(PhantomData); +type DecodeLimit = ConstU32<8>; + impl Default for Precompiles where R: frame_system::Config @@ -132,6 +138,7 @@ where a if a == hash(3) => Some(Ripemd160::execute(handle)), a if a == hash(4) => Some(Identity::execute(handle)), a if a == hash(5) => Some(Modexp::execute(handle)), + // a if a == hash(6) => Some(Dispatch::::execute(handle)), // Non-Frontier specific nor Ethereum precompiles : a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)), a if a == hash(1025) => Some(ECRecoverPublicKey::execute(handle)), @@ -178,3 +185,62 @@ where fn hash(a: u64) -> H160 { H160::from_low_u64_be(a) } + +#[cfg(test)] +mod tests { + use super::*; + struct A; + impl PrecompileHandle for A { + fn gas_limit(&self) -> Option { + Some(1000000) + } + + fn code_address(&self) -> H160 { + hash(1) + } + + fn input(&self) -> &[u8] { + &[0] + } + + fn context(&self) -> &fp_evm::Context { + unimplemented!() + } + + fn is_static(&self) -> bool { + false + } + + fn remaining_gas(&self) -> u64 { + 1000000 + } + fn call( + &mut self, + to: H160, + transfer: Option, + input: Vec, + gas_limit: Option, + is_static: bool, + context: &fp_evm::Context, + ) -> (fp_evm::ExitReason, Vec) { + unimplemented!() + } + fn record_cost(&mut self, cost: u64) -> Result<(), fp_evm::ExitError> { + unimplemented!() + } + } + + #[test] + fn test_hash() { + let a = A {}; + let compiles = Precompiles::default(); + let hash = compiles.execute(&mut a); + // assert_eq!(hash, H160::from_low_u64_be(1)); + } + + #[test] + fn test_hash_2() { + let hash = hash(2); + assert_eq!(hash, H160::from_low_u64_be(2)); + } +} diff --git a/precompiles/src/runtime_call_query.rs b/precompiles/src/runtime_call_query.rs new file mode 100644 index 0000000000..61fb9d6d7f --- /dev/null +++ b/precompiles/src/runtime_call_query.rs @@ -0,0 +1,53 @@ +use core::marker::PhantomData; + +use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; +use pallet_evm::PrecompileHandle; +use precompile_utils::{EvmResult, prelude::Address}; +use sp_runtime::traits::{Dispatchable, StaticLookup}; +use sp_std::vec::Vec; + +use crate::PrecompileExt; + +pub(crate) struct UidLookupPrecompile(PhantomData); + +impl PrecompileExt for UidLookupPrecompile +where + R: frame_system::Config + pallet_subtensor::Config + pallet_evm::Config, + R::AccountId: From<[u8; 32]>, + ::RuntimeCall: + GetDispatchInfo + Dispatchable, + ::RuntimeCall: From> + + GetDispatchInfo + + Dispatchable, + <::Lookup as StaticLookup>::Source: From, +{ + const INDEX: u64 = 2054; +} + +#[precompile_utils::precompile] +impl UidLookupPrecompile +where + R: frame_system::Config + pallet_subtensor::Config + pallet_evm::Config, + R::AccountId: From<[u8; 32]>, + ::RuntimeCall: + GetDispatchInfo + Dispatchable, + ::RuntimeCall: From> + + GetDispatchInfo + + Dispatchable, + <::Lookup as StaticLookup>::Source: From, +{ + #[precompile::public("uidLookup(uint16,address,uint16)")] + #[precompile::view] + fn uid_lookup( + _handle: &mut impl PrecompileHandle, + netuid: u16, + evm_address: Address, + limit: u16, + ) -> EvmResult> { + Ok(pallet_subtensor::Pallet::::uid_lookup( + netuid, + evm_address.0, + limit, + )) + } +} diff --git a/precompiles/src/solidity/runtimeCallQuery.abi b/precompiles/src/solidity/runtimeCallQuery.abi new file mode 100644 index 0000000000..ad33075ffc --- /dev/null +++ b/precompiles/src/solidity/runtimeCallQuery.abi @@ -0,0 +1,34 @@ +[ + { + "inputs": [ + { + "internalType": "bytes", + "name": "call", + "type": "bytes" + } + ], + "name": "call", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "key", + "type": "bytes" + } + ], + "name": "query", + "outputs": [ + { + "internalType": "bytes", + "name": "result", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/precompiles/src/solidity/runtimeCallQuery.sol b/precompiles/src/solidity/runtimeCallQuery.sol new file mode 100644 index 0000000000..8ae03d1e17 --- /dev/null +++ b/precompiles/src/solidity/runtimeCallQuery.sol @@ -0,0 +1,14 @@ +pragma solidity ^0.8.0; + +address constant IUID_LOOKUP_ADDRESS = 0x0000000000000000000000000000000000000807; + +interface IRuntimeCallQuery { + function call( + bytes memory call, + ) external payable; + + function query( + bytes memory key, + ) external view returns (bytes memory result); +} + diff --git a/precompiles/src/uid_lookup.rs b/precompiles/src/uid_lookup.rs index 61fb9d6d7f..3c14e9438f 100644 --- a/precompiles/src/uid_lookup.rs +++ b/precompiles/src/uid_lookup.rs @@ -1,13 +1,13 @@ use core::marker::PhantomData; +use crate::PrecompileExt; use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; use pallet_evm::PrecompileHandle; + use precompile_utils::{EvmResult, prelude::Address}; use sp_runtime::traits::{Dispatchable, StaticLookup}; use sp_std::vec::Vec; -use crate::PrecompileExt; - pub(crate) struct UidLookupPrecompile(PhantomData); impl PrecompileExt for UidLookupPrecompile From 4a6d525c3b9324cf1b4366b509cd74f91b5ae3ee Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 15 May 2025 10:30:23 +0800 Subject: [PATCH 02/17] call dispatch --- precompiles/src/extensions.rs | 3 -- precompiles/src/lib.rs | 61 +-------------------------- precompiles/src/runtime_call_query.rs | 34 ++------------- 3 files changed, 4 insertions(+), 94 deletions(-) diff --git a/precompiles/src/extensions.rs b/precompiles/src/extensions.rs index 0e1a8490c3..1c90922c57 100644 --- a/precompiles/src/extensions.rs +++ b/precompiles/src/extensions.rs @@ -9,7 +9,6 @@ use pallet_evm::{ AddressMapping, BalanceConverter, EvmBalance, ExitError, GasWeightMapping, Precompile, PrecompileFailure, PrecompileHandle, PrecompileResult, }; -use pallet_evm_precompile_dispatch::Dispatch; use precompile_utils::EvmResult; use sp_core::{H160, U256, blake2_256}; use sp_runtime::traits::Dispatchable; @@ -138,8 +137,6 @@ pub(crate) trait PrecompileExt>: Precompile { R: frame_system::Config + pallet_admin_utils::Config, { if PrecompileEnable::::get(&precompile_enum) { - // Some(Dispatch::::execute(handle)) - Some(Self::execute(handle)) } else { Some(Err(PrecompileFailure::Error { diff --git a/precompiles/src/lib.rs b/precompiles/src/lib.rs index 3ea8bb49dc..a9f238310a 100644 --- a/precompiles/src/lib.rs +++ b/precompiles/src/lib.rs @@ -138,7 +138,7 @@ where a if a == hash(3) => Some(Ripemd160::execute(handle)), a if a == hash(4) => Some(Identity::execute(handle)), a if a == hash(5) => Some(Modexp::execute(handle)), - // a if a == hash(6) => Some(Dispatch::::execute(handle)), + a if a == hash(6) => Some(Dispatch::::execute(handle)), // Non-Frontier specific nor Ethereum precompiles : a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)), a if a == hash(1025) => Some(ECRecoverPublicKey::execute(handle)), @@ -185,62 +185,3 @@ where fn hash(a: u64) -> H160 { H160::from_low_u64_be(a) } - -#[cfg(test)] -mod tests { - use super::*; - struct A; - impl PrecompileHandle for A { - fn gas_limit(&self) -> Option { - Some(1000000) - } - - fn code_address(&self) -> H160 { - hash(1) - } - - fn input(&self) -> &[u8] { - &[0] - } - - fn context(&self) -> &fp_evm::Context { - unimplemented!() - } - - fn is_static(&self) -> bool { - false - } - - fn remaining_gas(&self) -> u64 { - 1000000 - } - fn call( - &mut self, - to: H160, - transfer: Option, - input: Vec, - gas_limit: Option, - is_static: bool, - context: &fp_evm::Context, - ) -> (fp_evm::ExitReason, Vec) { - unimplemented!() - } - fn record_cost(&mut self, cost: u64) -> Result<(), fp_evm::ExitError> { - unimplemented!() - } - } - - #[test] - fn test_hash() { - let a = A {}; - let compiles = Precompiles::default(); - let hash = compiles.execute(&mut a); - // assert_eq!(hash, H160::from_low_u64_be(1)); - } - - #[test] - fn test_hash_2() { - let hash = hash(2); - assert_eq!(hash, H160::from_low_u64_be(2)); - } -} diff --git a/precompiles/src/runtime_call_query.rs b/precompiles/src/runtime_call_query.rs index 61fb9d6d7f..ecc1e2693c 100644 --- a/precompiles/src/runtime_call_query.rs +++ b/precompiles/src/runtime_call_query.rs @@ -8,9 +8,9 @@ use sp_std::vec::Vec; use crate::PrecompileExt; -pub(crate) struct UidLookupPrecompile(PhantomData); +pub(crate) struct RuntimeCallQueryPrecompile(PhantomData); -impl PrecompileExt for UidLookupPrecompile +impl PrecompileExt for RuntimeCallQueryPrecompile where R: frame_system::Config + pallet_subtensor::Config + pallet_evm::Config, R::AccountId: From<[u8; 32]>, @@ -21,33 +21,5 @@ where + Dispatchable, <::Lookup as StaticLookup>::Source: From, { - const INDEX: u64 = 2054; -} - -#[precompile_utils::precompile] -impl UidLookupPrecompile -where - R: frame_system::Config + pallet_subtensor::Config + pallet_evm::Config, - R::AccountId: From<[u8; 32]>, - ::RuntimeCall: - GetDispatchInfo + Dispatchable, - ::RuntimeCall: From> - + GetDispatchInfo - + Dispatchable, - <::Lookup as StaticLookup>::Source: From, -{ - #[precompile::public("uidLookup(uint16,address,uint16)")] - #[precompile::view] - fn uid_lookup( - _handle: &mut impl PrecompileHandle, - netuid: u16, - evm_address: Address, - limit: u16, - ) -> EvmResult> { - Ok(pallet_subtensor::Pallet::::uid_lookup( - netuid, - evm_address.0, - limit, - )) - } + const INDEX: u64 = 2055; } From ae8591320a19de3132930daae44f7f34eef052b3 Mon Sep 17 00:00:00 2001 From: Keith Date: Fri, 16 May 2025 00:11:57 +0800 Subject: [PATCH 03/17] Add missing trait bounds --- precompiles/src/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/precompiles/src/lib.rs b/precompiles/src/lib.rs index a9f238310a..9968596f32 100644 --- a/precompiles/src/lib.rs +++ b/precompiles/src/lib.rs @@ -6,6 +6,7 @@ use core::marker::PhantomData; use frame_support::{ dispatch::{GetDispatchInfo, PostDispatchInfo}, + pallet_prelude::Decode, traits::ConstU32, }; use pallet_evm::{ @@ -43,8 +44,6 @@ mod uid_lookup; pub struct Precompiles(PhantomData); -type DecodeLimit = ConstU32<8>; - impl Default for Precompiles where R: frame_system::Config @@ -125,7 +124,10 @@ where + From> + From> + GetDispatchInfo - + Dispatchable, + + Dispatchable + + Decode, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: + From>, ::AddressMapping: AddressMapping, ::Balance: TryFrom, <::Lookup as StaticLookup>::Source: From, From fb9ca431a2619cbf891c2e16f912d69fae1e2b1e Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 16 May 2025 13:06:27 +0800 Subject: [PATCH 04/17] evm test part --- Cargo.lock | 1 + evm-tests/package-lock.json | 6 +- evm-tests/package.json | 3 +- evm-tests/src/config.ts | 6 +- .../test/runtime.call.precompile.test.ts | 69 +++++++++++++++++++ precompiles/Cargo.toml | 2 + precompiles/src/lib.rs | 11 ++- precompiles/src/runtime_call_query.rs | 25 ------- precompiles/src/storage_query.rs | 54 +++++++++++++++ 9 files changed, 146 insertions(+), 31 deletions(-) create mode 100644 evm-tests/test/runtime.call.precompile.test.ts delete mode 100644 precompiles/src/runtime_call_query.rs create mode 100644 precompiles/src/storage_query.rs diff --git a/Cargo.lock b/Cargo.lock index 42dc2f1b20..1ec256be62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11090,6 +11090,7 @@ dependencies = [ "pallet-subtensor", "precompile-utils", "sp-core", + "sp-io", "sp-runtime", "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2409-7)", "subtensor-runtime-common", diff --git a/evm-tests/package-lock.json b/evm-tests/package-lock.json index ce2766fb4e..68fae940bf 100644 --- a/evm-tests/package-lock.json +++ b/evm-tests/package-lock.json @@ -6,6 +6,7 @@ "": { "license": "ISC", "dependencies": { + "@polkadot-api/descriptors": "file:.papi/descriptors", "@polkadot-labs/hdkd": "^0.0.10", "@polkadot-labs/hdkd-helpers": "^0.0.11", "@polkadot/api": "15.1.1", @@ -32,7 +33,6 @@ ".papi/descriptors": { "name": "@polkadot-api/descriptors", "version": "0.1.0-autogenerated.7914363913476982777", - "extraneous": true, "peerDependencies": { "polkadot-api": "*" } @@ -731,6 +731,10 @@ "@polkadot-api/utils": "0.1.2" } }, + "node_modules/@polkadot-api/descriptors": { + "resolved": ".papi/descriptors", + "link": true + }, "node_modules/@polkadot-api/ink-contracts": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/@polkadot-api/ink-contracts/-/ink-contracts-0.2.6.tgz", diff --git a/evm-tests/package.json b/evm-tests/package.json index 0e90cdb976..b3ab563ef5 100644 --- a/evm-tests/package.json +++ b/evm-tests/package.json @@ -1,11 +1,12 @@ { "scripts": { - "test": "mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register test/*test.ts" + "test": "mocha --timeout 999999 --file src/setup.ts --require ts-node/register test/runtime*test.ts" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { + "@polkadot-api/descriptors": "file:.papi/descriptors", "@polkadot-labs/hdkd": "^0.0.10", "@polkadot-labs/hdkd-helpers": "^0.0.11", "@polkadot/api": "15.1.1", diff --git a/evm-tests/src/config.ts b/evm-tests/src/config.ts index 00b942f802..7fb40e67cb 100644 --- a/evm-tests/src/config.ts +++ b/evm-tests/src/config.ts @@ -35,4 +35,8 @@ export const IBalanceTransferABI = [ stateMutability: "payable", type: "function", }, -]; \ No newline at end of file +]; + +export const IDISPATCH_ADDRESS = "0x0000000000000000000000000000000000000006"; + +export const ISTORAGE_QUERY_ADDRESS = "0x0000000000000000000000000000000000000807"; \ No newline at end of file diff --git a/evm-tests/test/runtime.call.precompile.test.ts b/evm-tests/test/runtime.call.precompile.test.ts new file mode 100644 index 0000000000..8876dbdad8 --- /dev/null +++ b/evm-tests/test/runtime.call.precompile.test.ts @@ -0,0 +1,69 @@ + + + +import * as assert from "assert"; + +import { getAliceSigner, getDevnetApi } from "../src/substrate" +import { generateRandomEthersWallet, getPublicClient } from "../src/utils"; +import { IDISPATCH_ADDRESS, ISTORAGE_QUERY_ADDRESS, ETH_LOCAL_URL } from "../src/config"; +import { devnet } from "@polkadot-api/descriptors" +import { PublicClient } from "viem"; +import { PolkadotSigner, TypedApi } from "polkadot-api"; +import { convertPublicKeyToSs58 } from "../src/address-utils" +import { forceSetBalanceToEthAddress } from "../src/subtensor"; + +describe("Test the dispatch precompile", () => { + let publicClient: PublicClient; + // init eth part + const wallet1 = generateRandomEthersWallet(); + + let api: TypedApi + let alice: PolkadotSigner; + + before(async () => { + publicClient = await getPublicClient(ETH_LOCAL_URL) + api = await getDevnetApi() + alice = await getAliceSigner() + await forceSetBalanceToEthAddress(api, wallet1.address) + console.log("wallet1 address: ", wallet1.address) + }) + + // it("Dispatch transfer call via precompile contract works correctly", async () => { + // // 0x050300d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d02286bee + // // call for transfer 1 token to alice + // const transferAmount = BigInt(1000000000); + // const transferCall = "0x050300d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d02286bee" + // const aliceBalance = (await api.query.System.Account.getValue( convertPublicKeyToSs58(alice.publicKey))).data.free + + // console.log("alice balance before transfer: ", aliceBalance.toString()) + // const txResponse = await wallet1.sendTransaction({ + // to: IDISPATCH_ADDRESS, + // data: transferCall, + // }) + // await txResponse.wait() + + // const aliceBalanceAfterTransfer = (await api.query.System.Account.getValue( convertPublicKeyToSs58(alice.publicKey))).data.free + + // assert.equal(aliceBalance + transferAmount, aliceBalanceAfterTransfer) + + // console.log("alice balance after transfer: ", aliceBalanceAfterTransfer.toString()) + // }) + + + + it("Storage query call via precompile contract works correctly", async () => { + // 0x658faa385070e074c85bf6b568cf0555f14f14d903e9994045ff1902b3e513dc + // key for min child key take + const storageQuery = "0x658faa385070e074c85bf6b568cf0555f14f14d903e9994045ff1902b3e513dc" + + const rawCallResponse = await publicClient.call({ + to: ISTORAGE_QUERY_ADDRESS, + data: storageQuery, + }) + const rawResultData = rawCallResponse.data; + console.log("Raw result data:", rawResultData); + + + + }) +}); diff --git a/precompiles/Cargo.toml b/precompiles/Cargo.toml index b3d318da14..91f3955a8d 100644 --- a/precompiles/Cargo.toml +++ b/precompiles/Cargo.toml @@ -25,6 +25,7 @@ pallet-evm-precompile-simple = { workspace = true } pallet-proxy = { workspace = true } precompile-utils = { workspace = true } sp-core = { workspace = true } +sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } subtensor-runtime-common = { workspace = true } @@ -53,6 +54,7 @@ std = [ "pallet-subtensor/std", "precompile-utils/std", "sp-core/std", + "sp-io/std", "sp-runtime/std", "sp-std/std", "subtensor-runtime-common/std", diff --git a/precompiles/src/lib.rs b/precompiles/src/lib.rs index 9968596f32..3bdf417d8d 100644 --- a/precompiles/src/lib.rs +++ b/precompiles/src/lib.rs @@ -7,7 +7,6 @@ use core::marker::PhantomData; use frame_support::{ dispatch::{GetDispatchInfo, PostDispatchInfo}, pallet_prelude::Decode, - traits::ConstU32, }; use pallet_evm::{ AddressMapping, IsPrecompileResult, Precompile, PrecompileHandle, PrecompileResult, @@ -30,6 +29,7 @@ use crate::extensions::*; use crate::metagraph::*; use crate::neuron::*; use crate::staking::*; +use crate::storage_query::*; use crate::subnet::*; use crate::uid_lookup::*; @@ -39,9 +39,9 @@ mod extensions; mod metagraph; mod neuron; mod staking; +mod storage_query; mod subnet; mod uid_lookup; - pub struct Precompiles(PhantomData); impl Default for Precompiles @@ -91,13 +91,14 @@ where Self(Default::default()) } - pub fn used_addresses() -> [H160; 14] { + pub fn used_addresses() -> [H160; 16] { [ hash(1), hash(2), hash(3), hash(4), hash(5), + hash(6), hash(1024), hash(1025), hash(Ed25519Verify::::INDEX), @@ -107,6 +108,7 @@ where hash(MetagraphPrecompile::::INDEX), hash(NeuronPrecompile::::INDEX), hash(StakingPrecompileV2::::INDEX), + hash(StorageQueryPrecompile::::INDEX), ] } } @@ -172,6 +174,9 @@ where a if a == hash(UidLookupPrecompile::::INDEX) => { UidLookupPrecompile::::try_execute::(handle, PrecompileEnum::UidLookup) } + a if a == hash(StorageQueryPrecompile::::INDEX) => { + Some(StorageQueryPrecompile::::execute(handle)) + } _ => None, } } diff --git a/precompiles/src/runtime_call_query.rs b/precompiles/src/runtime_call_query.rs deleted file mode 100644 index ecc1e2693c..0000000000 --- a/precompiles/src/runtime_call_query.rs +++ /dev/null @@ -1,25 +0,0 @@ -use core::marker::PhantomData; - -use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; -use pallet_evm::PrecompileHandle; -use precompile_utils::{EvmResult, prelude::Address}; -use sp_runtime::traits::{Dispatchable, StaticLookup}; -use sp_std::vec::Vec; - -use crate::PrecompileExt; - -pub(crate) struct RuntimeCallQueryPrecompile(PhantomData); - -impl PrecompileExt for RuntimeCallQueryPrecompile -where - R: frame_system::Config + pallet_subtensor::Config + pallet_evm::Config, - R::AccountId: From<[u8; 32]>, - ::RuntimeCall: - GetDispatchInfo + Dispatchable, - ::RuntimeCall: From> - + GetDispatchInfo - + Dispatchable, - <::Lookup as StaticLookup>::Source: From, -{ - const INDEX: u64 = 2055; -} diff --git a/precompiles/src/storage_query.rs b/precompiles/src/storage_query.rs new file mode 100644 index 0000000000..1062e78e95 --- /dev/null +++ b/precompiles/src/storage_query.rs @@ -0,0 +1,54 @@ +use core::marker::PhantomData; + +use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; +use pallet_evm::{ExitSucceed, Precompile, PrecompileHandle, PrecompileOutput}; +use sp_runtime::traits::{Dispatchable, StaticLookup}; +use sp_std::vec::Vec; + +use crate::PrecompileExt; + +pub(crate) struct StorageQueryPrecompile(PhantomData); + +impl PrecompileExt for StorageQueryPrecompile +where + R: frame_system::Config + pallet_subtensor::Config + pallet_evm::Config, + R::AccountId: From<[u8; 32]>, + ::RuntimeCall: + GetDispatchInfo + Dispatchable, + ::RuntimeCall: From> + + GetDispatchInfo + + Dispatchable, + <::Lookup as StaticLookup>::Source: From, +{ + const INDEX: u64 = 2055; +} + +impl Precompile for StorageQueryPrecompile +where + R: frame_system::Config + pallet_subtensor::Config + pallet_evm::Config, + R::AccountId: From<[u8; 32]>, + ::RuntimeCall: + GetDispatchInfo + Dispatchable, + ::RuntimeCall: From> + + GetDispatchInfo + + Dispatchable, + <::Lookup as StaticLookup>::Source: From, +{ + fn execute(handle: &mut impl PrecompileHandle) -> fp_evm::PrecompileResult { + let input = handle.input(); + let data = sp_io::storage::get(&input[..]); + match data { + Some(value) => { + let result = value.to_vec(); + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: result, + }) + } + None => Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: Vec::new(), + }), + } + } +} From da050d83c1ae703ea65b612fd0543afae2932e05 Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 17 May 2025 21:03:30 +0800 Subject: [PATCH 05/17] test is done --- evm-tests/src/subtensor.ts | 10 ++++ .../test/runtime.call.precompile.test.ts | 55 +++++++++++-------- pallets/subtensor/src/tests/batch_tx.rs | 45 ++++++++++++++- precompiles/src/lib.rs | 1 + precompiles/src/storage_query.rs | 15 +++++ 5 files changed, 102 insertions(+), 24 deletions(-) diff --git a/evm-tests/src/subtensor.ts b/evm-tests/src/subtensor.ts index 3111d90544..dd5161933a 100644 --- a/evm-tests/src/subtensor.ts +++ b/evm-tests/src/subtensor.ts @@ -343,4 +343,14 @@ export async function startCall(api: TypedApi, netuid: number, ke const callStarted = await api.query.SubtensorModule.FirstEmissionBlockNumber .getValue(netuid); assert.notEqual(callStarted, undefined); +} + +// sudo_set_max_childkey_take + +export async function setMaxChildkeyTake(api: TypedApi, take: number) { + const alice = getAliceSigner() + const internalCall = api.tx.SubtensorModule.sudo_set_max_childkey_take({ take }) + const tx = api.tx.Sudo.sudo({ call: internalCall.decodedCall }) + + await waitForTransactionWithRetry(api, tx, alice) } \ No newline at end of file diff --git a/evm-tests/test/runtime.call.precompile.test.ts b/evm-tests/test/runtime.call.precompile.test.ts index 8876dbdad8..8bd1eb1702 100644 --- a/evm-tests/test/runtime.call.precompile.test.ts +++ b/evm-tests/test/runtime.call.precompile.test.ts @@ -7,10 +7,10 @@ import { getAliceSigner, getDevnetApi } from "../src/substrate" import { generateRandomEthersWallet, getPublicClient } from "../src/utils"; import { IDISPATCH_ADDRESS, ISTORAGE_QUERY_ADDRESS, ETH_LOCAL_URL } from "../src/config"; import { devnet } from "@polkadot-api/descriptors" -import { PublicClient } from "viem"; +import { hexToBigInt, hexToNumber, PublicClient } from "viem"; import { PolkadotSigner, TypedApi } from "polkadot-api"; import { convertPublicKeyToSs58 } from "../src/address-utils" -import { forceSetBalanceToEthAddress } from "../src/subtensor"; +import { forceSetBalanceToEthAddress, setMaxChildkeyTake } from "../src/subtensor"; describe("Test the dispatch precompile", () => { let publicClient: PublicClient; @@ -25,43 +25,54 @@ describe("Test the dispatch precompile", () => { api = await getDevnetApi() alice = await getAliceSigner() await forceSetBalanceToEthAddress(api, wallet1.address) + console.log("wallet1 address: ", wallet1.address) }) - // it("Dispatch transfer call via precompile contract works correctly", async () => { - // // 0x050300d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d02286bee - // // call for transfer 1 token to alice - // const transferAmount = BigInt(1000000000); - // const transferCall = "0x050300d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d02286bee" - // const aliceBalance = (await api.query.System.Account.getValue( convertPublicKeyToSs58(alice.publicKey))).data.free - - // console.log("alice balance before transfer: ", aliceBalance.toString()) - // const txResponse = await wallet1.sendTransaction({ - // to: IDISPATCH_ADDRESS, - // data: transferCall, - // }) - // await txResponse.wait() - - // const aliceBalanceAfterTransfer = (await api.query.System.Account.getValue( convertPublicKeyToSs58(alice.publicKey))).data.free + it("Dispatch transfer call via precompile contract works correctly", async () => { + // 0x050300d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d02286bee + // call for transfer 1 token to alice + const transferAmount = BigInt(1000000000); + const transferCall = "0x050300d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d02286bee" + const aliceBalance = (await api.query.System.Account.getValue( convertPublicKeyToSs58(alice.publicKey))).data.free + + console.log("alice balance before transfer: ", aliceBalance.toString()) + const txResponse = await wallet1.sendTransaction({ + to: IDISPATCH_ADDRESS, + data: transferCall, + }) + await txResponse.wait() - // assert.equal(aliceBalance + transferAmount, aliceBalanceAfterTransfer) + const aliceBalanceAfterTransfer = (await api.query.System.Account.getValue( convertPublicKeyToSs58(alice.publicKey))).data.free - // console.log("alice balance after transfer: ", aliceBalanceAfterTransfer.toString()) - // }) + assert.equal(aliceBalance + transferAmount, aliceBalanceAfterTransfer) + }) it("Storage query call via precompile contract works correctly", async () => { + let maxChildkeyTake = 257; + await setMaxChildkeyTake(api, maxChildkeyTake) + // sudo_set_max_childkey_take // 0x658faa385070e074c85bf6b568cf0555f14f14d903e9994045ff1902b3e513dc // key for min child key take - const storageQuery = "0x658faa385070e074c85bf6b568cf0555f14f14d903e9994045ff1902b3e513dc" + + const storageQuery = "0x658faa385070e074c85bf6b568cf0555dba018859cab7e989f77669457b394be" + + api.query.SubtensorModule.MaxChildkeyTake.getValue(); + + // api.apis. const rawCallResponse = await publicClient.call({ to: ISTORAGE_QUERY_ADDRESS, data: storageQuery, }) const rawResultData = rawCallResponse.data; - console.log("Raw result data:", rawResultData); + if (rawResultData === undefined) { + throw new Error("rawResultData is undefined"); + } + let value = hexToNumber(rawResultData); + assert.equal(value, maxChildkeyTake, "value should be 257") diff --git a/pallets/subtensor/src/tests/batch_tx.rs b/pallets/subtensor/src/tests/batch_tx.rs index 512fa9b368..9147d9f39a 100644 --- a/pallets/subtensor/src/tests/batch_tx.rs +++ b/pallets/subtensor/src/tests/batch_tx.rs @@ -1,8 +1,10 @@ +use crate::MaxChildkeyTake; + use super::mock::*; -use frame_support::{assert_ok, traits::Currency}; +use frame_support::{StorageHasher, Twox128, assert_ok, traits::Currency}; use frame_system::Config; use sp_core::U256; - +use sp_io::hashing::twox_128; // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::batch_tx::test_batch_txs --exact --show-output --nocapture #[test] fn test_batch_txs() { @@ -33,3 +35,42 @@ fn test_batch_txs() { assert_eq!(Balances::total_balance(&charlie), 2_000_000_000); }); } + +// [101, 143, 170, 56, 80, 112, 224, 116, 200, 91, 246, 181, 104, 207, 5, 85, 219, 160, 24, 133, 156, 171, 126, 152, 159, 119, 102, 148, 87, 179, 148, 190] +#[test] +fn test_batch_txs2() { + let alice = U256::from(0); + let bob = U256::from(1); + let charlie = U256::from(2); + let initial_balances = vec![ + (alice, 8_000_000_000), + (bob, 1_000_000_000), + (charlie, 1_000_000_000), + ]; + test_ext_with_balances(initial_balances).execute_with(|| { + let init_value = SubtensorModule::get_max_childkey_take(); + log::error!("Storage value: {:?}", init_value); + + SubtensorModule::set_max_childkey_take(1000); + + // let mut final_key = [0u8; 32]; + // final_key[16..].copy_from_slice(twox_128(b"Subtensor")); + // final_key[..16].copy_from_slice(twox_128(b"MaxChildkeyTake")); + let final_key = [twox_128(b"SubtensorModule"), twox_128(b"MaxChildkeyTake")].concat(); + log::error!("Storage value: {:?}", final_key); + + let hash_key = MaxChildkeyTake::::hashed_key(); + log::error!("Storage value: {:?}", hash_key); + // let key = [ + // 101, 143, 170, 56, 80, 112, 224, 116, 200, 91, 246, 181, 104, 207, 5, 85, 219, 160, 24, + // 133, 156, 171, 126, 152, 159, 119, 102, 148, 87, 179, 148, 190, + // ]; + let value = sp_io::storage::get(&final_key[..]); + log::error!("Storage value: {:?}", value); + assert_eq!(value, None); + + sp_io::storage::set(&final_key[..], &[0u8; 32][..]); + let init_value = SubtensorModule::get_max_childkey_take(); + log::error!("Storage value: {:?}", init_value); + }); +} diff --git a/precompiles/src/lib.rs b/precompiles/src/lib.rs index 3bdf417d8d..2b7e720f08 100644 --- a/precompiles/src/lib.rs +++ b/precompiles/src/lib.rs @@ -175,6 +175,7 @@ where UidLookupPrecompile::::try_execute::(handle, PrecompileEnum::UidLookup) } a if a == hash(StorageQueryPrecompile::::INDEX) => { + log::error!("StorageQueryPrecompile::execute {} {}", file!(), line!()); Some(StorageQueryPrecompile::::execute(handle)) } _ => None, diff --git a/precompiles/src/storage_query.rs b/precompiles/src/storage_query.rs index 1062e78e95..3534b2b739 100644 --- a/precompiles/src/storage_query.rs +++ b/precompiles/src/storage_query.rs @@ -35,11 +35,26 @@ where <::Lookup as StaticLookup>::Source: From, { fn execute(handle: &mut impl PrecompileHandle) -> fp_evm::PrecompileResult { + log::error!("StorageQueryPrecompile::execute {} {}", file!(), line!()); + let input = handle.input(); let data = sp_io::storage::get(&input[..]); + log::error!( + "============================= StorageQueryPrecompile::execute {:?} {:?}", + input, + data + ); + + log::error!("StorageQueryPrecompile::execute {} {}", file!(), line!()); + match data { Some(value) => { let result = value.to_vec(); + log::error!( + "============================= StorageQueryPrecompile::execute {:?}", + result + ); + Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, output: result, From 8270040007f7d5af6a8342935ffb85dd75c1baae Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 17 May 2025 21:25:19 +0800 Subject: [PATCH 06/17] clean up code --- evm-tests/package.json | 2 +- .../test/runtime.call.precompile.test.ts | 21 +-------- pallets/subtensor/src/tests/batch_tx.rs | 44 +------------------ precompiles/src/storage_query.rs | 13 ------ 4 files changed, 4 insertions(+), 76 deletions(-) diff --git a/evm-tests/package.json b/evm-tests/package.json index b3ab563ef5..ca35fe2d1b 100644 --- a/evm-tests/package.json +++ b/evm-tests/package.json @@ -1,6 +1,6 @@ { "scripts": { - "test": "mocha --timeout 999999 --file src/setup.ts --require ts-node/register test/runtime*test.ts" + "test": "mocha --timeout 999999 --retries 3 --file src/setup.ts --require ts-node/register test/*test.ts" }, "keywords": [], "author": "", diff --git a/evm-tests/test/runtime.call.precompile.test.ts b/evm-tests/test/runtime.call.precompile.test.ts index 8bd1eb1702..e1da4a0b57 100644 --- a/evm-tests/test/runtime.call.precompile.test.ts +++ b/evm-tests/test/runtime.call.precompile.test.ts @@ -1,22 +1,16 @@ - - - import * as assert from "assert"; - import { getAliceSigner, getDevnetApi } from "../src/substrate" import { generateRandomEthersWallet, getPublicClient } from "../src/utils"; import { IDISPATCH_ADDRESS, ISTORAGE_QUERY_ADDRESS, ETH_LOCAL_URL } from "../src/config"; import { devnet } from "@polkadot-api/descriptors" -import { hexToBigInt, hexToNumber, PublicClient } from "viem"; +import { hexToNumber, PublicClient } from "viem"; import { PolkadotSigner, TypedApi } from "polkadot-api"; import { convertPublicKeyToSs58 } from "../src/address-utils" import { forceSetBalanceToEthAddress, setMaxChildkeyTake } from "../src/subtensor"; describe("Test the dispatch precompile", () => { let publicClient: PublicClient; - // init eth part const wallet1 = generateRandomEthersWallet(); - let api: TypedApi let alice: PolkadotSigner; @@ -25,8 +19,6 @@ describe("Test the dispatch precompile", () => { api = await getDevnetApi() alice = await getAliceSigner() await forceSetBalanceToEthAddress(api, wallet1.address) - - console.log("wallet1 address: ", wallet1.address) }) it("Dispatch transfer call via precompile contract works correctly", async () => { @@ -35,8 +27,6 @@ describe("Test the dispatch precompile", () => { const transferAmount = BigInt(1000000000); const transferCall = "0x050300d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d02286bee" const aliceBalance = (await api.query.System.Account.getValue( convertPublicKeyToSs58(alice.publicKey))).data.free - - console.log("alice balance before transfer: ", aliceBalance.toString()) const txResponse = await wallet1.sendTransaction({ to: IDISPATCH_ADDRESS, data: transferCall, @@ -53,16 +43,12 @@ describe("Test the dispatch precompile", () => { it("Storage query call via precompile contract works correctly", async () => { let maxChildkeyTake = 257; await setMaxChildkeyTake(api, maxChildkeyTake) - // sudo_set_max_childkey_take // 0x658faa385070e074c85bf6b568cf0555f14f14d903e9994045ff1902b3e513dc - // key for min child key take + // key for min child key take const storageQuery = "0x658faa385070e074c85bf6b568cf0555dba018859cab7e989f77669457b394be" api.query.SubtensorModule.MaxChildkeyTake.getValue(); - - // api.apis. - const rawCallResponse = await publicClient.call({ to: ISTORAGE_QUERY_ADDRESS, data: storageQuery, @@ -73,8 +59,5 @@ describe("Test the dispatch precompile", () => { } let value = hexToNumber(rawResultData); assert.equal(value, maxChildkeyTake, "value should be 257") - - - }) }); diff --git a/pallets/subtensor/src/tests/batch_tx.rs b/pallets/subtensor/src/tests/batch_tx.rs index 9147d9f39a..8c2e3a42ad 100644 --- a/pallets/subtensor/src/tests/batch_tx.rs +++ b/pallets/subtensor/src/tests/batch_tx.rs @@ -1,10 +1,7 @@ -use crate::MaxChildkeyTake; - use super::mock::*; -use frame_support::{StorageHasher, Twox128, assert_ok, traits::Currency}; +use frame_support::{assert_ok, traits::Currency}; use frame_system::Config; use sp_core::U256; -use sp_io::hashing::twox_128; // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::batch_tx::test_batch_txs --exact --show-output --nocapture #[test] fn test_batch_txs() { @@ -35,42 +32,3 @@ fn test_batch_txs() { assert_eq!(Balances::total_balance(&charlie), 2_000_000_000); }); } - -// [101, 143, 170, 56, 80, 112, 224, 116, 200, 91, 246, 181, 104, 207, 5, 85, 219, 160, 24, 133, 156, 171, 126, 152, 159, 119, 102, 148, 87, 179, 148, 190] -#[test] -fn test_batch_txs2() { - let alice = U256::from(0); - let bob = U256::from(1); - let charlie = U256::from(2); - let initial_balances = vec![ - (alice, 8_000_000_000), - (bob, 1_000_000_000), - (charlie, 1_000_000_000), - ]; - test_ext_with_balances(initial_balances).execute_with(|| { - let init_value = SubtensorModule::get_max_childkey_take(); - log::error!("Storage value: {:?}", init_value); - - SubtensorModule::set_max_childkey_take(1000); - - // let mut final_key = [0u8; 32]; - // final_key[16..].copy_from_slice(twox_128(b"Subtensor")); - // final_key[..16].copy_from_slice(twox_128(b"MaxChildkeyTake")); - let final_key = [twox_128(b"SubtensorModule"), twox_128(b"MaxChildkeyTake")].concat(); - log::error!("Storage value: {:?}", final_key); - - let hash_key = MaxChildkeyTake::::hashed_key(); - log::error!("Storage value: {:?}", hash_key); - // let key = [ - // 101, 143, 170, 56, 80, 112, 224, 116, 200, 91, 246, 181, 104, 207, 5, 85, 219, 160, 24, - // 133, 156, 171, 126, 152, 159, 119, 102, 148, 87, 179, 148, 190, - // ]; - let value = sp_io::storage::get(&final_key[..]); - log::error!("Storage value: {:?}", value); - assert_eq!(value, None); - - sp_io::storage::set(&final_key[..], &[0u8; 32][..]); - let init_value = SubtensorModule::get_max_childkey_take(); - log::error!("Storage value: {:?}", init_value); - }); -} diff --git a/precompiles/src/storage_query.rs b/precompiles/src/storage_query.rs index 3534b2b739..b29219b033 100644 --- a/precompiles/src/storage_query.rs +++ b/precompiles/src/storage_query.rs @@ -35,25 +35,12 @@ where <::Lookup as StaticLookup>::Source: From, { fn execute(handle: &mut impl PrecompileHandle) -> fp_evm::PrecompileResult { - log::error!("StorageQueryPrecompile::execute {} {}", file!(), line!()); - let input = handle.input(); let data = sp_io::storage::get(&input[..]); - log::error!( - "============================= StorageQueryPrecompile::execute {:?} {:?}", - input, - data - ); - - log::error!("StorageQueryPrecompile::execute {} {}", file!(), line!()); match data { Some(value) => { let result = value.to_vec(); - log::error!( - "============================= StorageQueryPrecompile::execute {:?}", - result - ); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, From 1f9fbb1d322b0a30fece3e2883136669fd7a8a2b Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 17 May 2025 21:27:43 +0800 Subject: [PATCH 07/17] clean up code --- evm-tests/src/subtensor.ts | 2 -- precompiles/src/lib.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/evm-tests/src/subtensor.ts b/evm-tests/src/subtensor.ts index dd5161933a..e3d5526268 100644 --- a/evm-tests/src/subtensor.ts +++ b/evm-tests/src/subtensor.ts @@ -345,8 +345,6 @@ export async function startCall(api: TypedApi, netuid: number, ke assert.notEqual(callStarted, undefined); } -// sudo_set_max_childkey_take - export async function setMaxChildkeyTake(api: TypedApi, take: number) { const alice = getAliceSigner() const internalCall = api.tx.SubtensorModule.sudo_set_max_childkey_take({ take }) diff --git a/precompiles/src/lib.rs b/precompiles/src/lib.rs index 2b7e720f08..3bdf417d8d 100644 --- a/precompiles/src/lib.rs +++ b/precompiles/src/lib.rs @@ -175,7 +175,6 @@ where UidLookupPrecompile::::try_execute::(handle, PrecompileEnum::UidLookup) } a if a == hash(StorageQueryPrecompile::::INDEX) => { - log::error!("StorageQueryPrecompile::execute {} {}", file!(), line!()); Some(StorageQueryPrecompile::::execute(handle)) } _ => None, From 919c9e03273482b3ec7f39ec9420faa67146531b Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 17 May 2025 21:29:58 +0800 Subject: [PATCH 08/17] remove contract definition --- precompiles/src/solidity/runtimeCallQuery.abi | 34 ------------------- precompiles/src/solidity/runtimeCallQuery.sol | 14 -------- 2 files changed, 48 deletions(-) delete mode 100644 precompiles/src/solidity/runtimeCallQuery.abi delete mode 100644 precompiles/src/solidity/runtimeCallQuery.sol diff --git a/precompiles/src/solidity/runtimeCallQuery.abi b/precompiles/src/solidity/runtimeCallQuery.abi deleted file mode 100644 index ad33075ffc..0000000000 --- a/precompiles/src/solidity/runtimeCallQuery.abi +++ /dev/null @@ -1,34 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "bytes", - "name": "call", - "type": "bytes" - } - ], - "name": "call", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "key", - "type": "bytes" - } - ], - "name": "query", - "outputs": [ - { - "internalType": "bytes", - "name": "result", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - } -] \ No newline at end of file diff --git a/precompiles/src/solidity/runtimeCallQuery.sol b/precompiles/src/solidity/runtimeCallQuery.sol deleted file mode 100644 index 8ae03d1e17..0000000000 --- a/precompiles/src/solidity/runtimeCallQuery.sol +++ /dev/null @@ -1,14 +0,0 @@ -pragma solidity ^0.8.0; - -address constant IUID_LOOKUP_ADDRESS = 0x0000000000000000000000000000000000000807; - -interface IRuntimeCallQuery { - function call( - bytes memory call, - ) external payable; - - function query( - bytes memory key, - ) external view returns (bytes memory result); -} - From b855e7de4fd0fd2209b77c39c567a8404ad68ff1 Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 17 May 2025 21:31:57 +0800 Subject: [PATCH 09/17] format code --- precompiles/src/uid_lookup.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/precompiles/src/uid_lookup.rs b/precompiles/src/uid_lookup.rs index 3c14e9438f..0a330566d8 100644 --- a/precompiles/src/uid_lookup.rs +++ b/precompiles/src/uid_lookup.rs @@ -1,13 +1,10 @@ -use core::marker::PhantomData; - use crate::PrecompileExt; +use core::marker::PhantomData; use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; use pallet_evm::PrecompileHandle; - use precompile_utils::{EvmResult, prelude::Address}; use sp_runtime::traits::{Dispatchable, StaticLookup}; use sp_std::vec::Vec; - pub(crate) struct UidLookupPrecompile(PhantomData); impl PrecompileExt for UidLookupPrecompile From 00d7ca7b327923f7ee8c75f4bef10d0bd31fc916 Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 17 May 2025 21:33:19 +0800 Subject: [PATCH 10/17] cargo clippy --- precompiles/src/storage_query.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/precompiles/src/storage_query.rs b/precompiles/src/storage_query.rs index b29219b033..b9455ae708 100644 --- a/precompiles/src/storage_query.rs +++ b/precompiles/src/storage_query.rs @@ -36,7 +36,7 @@ where { fn execute(handle: &mut impl PrecompileHandle) -> fp_evm::PrecompileResult { let input = handle.input(); - let data = sp_io::storage::get(&input[..]); + let data = sp_io::storage::get(input); match data { Some(value) => { From 7094c4f35d03692e56c762b8701949339703402e Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 17 May 2025 22:01:50 +0800 Subject: [PATCH 11/17] not include the descriptos --- evm-tests/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/evm-tests/package.json b/evm-tests/package.json index ca35fe2d1b..0e90cdb976 100644 --- a/evm-tests/package.json +++ b/evm-tests/package.json @@ -6,7 +6,6 @@ "author": "", "license": "ISC", "dependencies": { - "@polkadot-api/descriptors": "file:.papi/descriptors", "@polkadot-labs/hdkd": "^0.0.10", "@polkadot-labs/hdkd-helpers": "^0.0.11", "@polkadot/api": "15.1.1", From 6b53c5fba63fe471a9cf6030ce10e69012dd2785 Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 17 May 2025 22:03:13 +0800 Subject: [PATCH 12/17] revert lock file --- evm-tests/package-lock.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/evm-tests/package-lock.json b/evm-tests/package-lock.json index 68fae940bf..ce2766fb4e 100644 --- a/evm-tests/package-lock.json +++ b/evm-tests/package-lock.json @@ -6,7 +6,6 @@ "": { "license": "ISC", "dependencies": { - "@polkadot-api/descriptors": "file:.papi/descriptors", "@polkadot-labs/hdkd": "^0.0.10", "@polkadot-labs/hdkd-helpers": "^0.0.11", "@polkadot/api": "15.1.1", @@ -33,6 +32,7 @@ ".papi/descriptors": { "name": "@polkadot-api/descriptors", "version": "0.1.0-autogenerated.7914363913476982777", + "extraneous": true, "peerDependencies": { "polkadot-api": "*" } @@ -731,10 +731,6 @@ "@polkadot-api/utils": "0.1.2" } }, - "node_modules/@polkadot-api/descriptors": { - "resolved": ".papi/descriptors", - "link": true - }, "node_modules/@polkadot-api/ink-contracts": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/@polkadot-api/ink-contracts/-/ink-contracts-0.2.6.tgz", From 227220b8f7c7688798ef782ee1f40e57f56c45c7 Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 17 May 2025 22:14:22 +0800 Subject: [PATCH 13/17] revert unnecessary change --- pallets/subtensor/src/tests/batch_tx.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pallets/subtensor/src/tests/batch_tx.rs b/pallets/subtensor/src/tests/batch_tx.rs index 8c2e3a42ad..512fa9b368 100644 --- a/pallets/subtensor/src/tests/batch_tx.rs +++ b/pallets/subtensor/src/tests/batch_tx.rs @@ -2,6 +2,7 @@ use super::mock::*; use frame_support::{assert_ok, traits::Currency}; use frame_system::Config; use sp_core::U256; + // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::batch_tx::test_batch_txs --exact --show-output --nocapture #[test] fn test_batch_txs() { From a6154824f46adfd9c9ed0c777feeef76f405f789 Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 17 May 2025 22:15:36 +0800 Subject: [PATCH 14/17] revert unnecessary change --- precompiles/src/uid_lookup.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/precompiles/src/uid_lookup.rs b/precompiles/src/uid_lookup.rs index 0a330566d8..61fb9d6d7f 100644 --- a/precompiles/src/uid_lookup.rs +++ b/precompiles/src/uid_lookup.rs @@ -1,10 +1,13 @@ -use crate::PrecompileExt; use core::marker::PhantomData; + use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; use pallet_evm::PrecompileHandle; use precompile_utils::{EvmResult, prelude::Address}; use sp_runtime::traits::{Dispatchable, StaticLookup}; use sp_std::vec::Vec; + +use crate::PrecompileExt; + pub(crate) struct UidLookupPrecompile(PhantomData); impl PrecompileExt for UidLookupPrecompile From dd8d8ab340e87d6ba3445bd35a86e95b40ca0f0a Mon Sep 17 00:00:00 2001 From: open-junius Date: Sat, 17 May 2025 22:26:17 +0800 Subject: [PATCH 15/17] cargo fix --- precompiles/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/precompiles/Cargo.toml b/precompiles/Cargo.toml index 91f3955a8d..f19e8f2d1e 100644 --- a/precompiles/Cargo.toml +++ b/precompiles/Cargo.toml @@ -46,6 +46,7 @@ std = [ "log/std", "pallet-admin-utils/std", "pallet-balances/std", + "pallet-evm-precompile-dispatch/std", "pallet-evm-precompile-modexp/std", "pallet-evm-precompile-sha3fips/std", "pallet-evm-precompile-simple/std", From cf56ee2f8118b8ceb1ef50344b76e68199e5dd79 Mon Sep 17 00:00:00 2001 From: open-junius Date: Sun, 18 May 2025 21:08:06 +0800 Subject: [PATCH 16/17] use hash function to get the key --- evm-tests/test/runtime.call.precompile.test.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/evm-tests/test/runtime.call.precompile.test.ts b/evm-tests/test/runtime.call.precompile.test.ts index e1da4a0b57..135900808b 100644 --- a/evm-tests/test/runtime.call.precompile.test.ts +++ b/evm-tests/test/runtime.call.precompile.test.ts @@ -7,6 +7,8 @@ import { hexToNumber, PublicClient } from "viem"; import { PolkadotSigner, TypedApi } from "polkadot-api"; import { convertPublicKeyToSs58 } from "../src/address-utils" import { forceSetBalanceToEthAddress, setMaxChildkeyTake } from "../src/subtensor"; +import { xxhashAsU8a } from '@polkadot/util-crypto'; +import { u8aToHex } from '@polkadot/util'; describe("Test the dispatch precompile", () => { let publicClient: PublicClient; @@ -38,20 +40,22 @@ describe("Test the dispatch precompile", () => { assert.equal(aliceBalance + transferAmount, aliceBalanceAfterTransfer) }) - it("Storage query call via precompile contract works correctly", async () => { + const palletPrefixBytes = xxhashAsU8a("SubtensorModule", 128); + const storageItemPrefixBytes = xxhashAsU8a("MaxChildkeyTake", 128); + const fullStorageKeyBytes = new Uint8Array([...palletPrefixBytes, ...storageItemPrefixBytes]); + // 0x658faa385070e074c85bf6b568cf0555dba018859cab7e989f77669457b394be + // key for max child key take + const fullStorageKeyHex = u8aToHex(fullStorageKeyBytes); + let maxChildkeyTake = 257; await setMaxChildkeyTake(api, maxChildkeyTake) - // 0x658faa385070e074c85bf6b568cf0555f14f14d903e9994045ff1902b3e513dc - // key for min child key take - - const storageQuery = "0x658faa385070e074c85bf6b568cf0555dba018859cab7e989f77669457b394be" api.query.SubtensorModule.MaxChildkeyTake.getValue(); const rawCallResponse = await publicClient.call({ to: ISTORAGE_QUERY_ADDRESS, - data: storageQuery, + data: fullStorageKeyHex, }) const rawResultData = rawCallResponse.data; if (rawResultData === undefined) { From 7904b1014218439a1749554ee994d257e1814f42 Mon Sep 17 00:00:00 2001 From: open-junius Date: Sun, 18 May 2025 21:43:44 +0800 Subject: [PATCH 17/17] add generate call data process --- evm-tests/test/runtime.call.precompile.test.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/evm-tests/test/runtime.call.precompile.test.ts b/evm-tests/test/runtime.call.precompile.test.ts index 135900808b..4cd7690724 100644 --- a/evm-tests/test/runtime.call.precompile.test.ts +++ b/evm-tests/test/runtime.call.precompile.test.ts @@ -2,7 +2,7 @@ import * as assert from "assert"; import { getAliceSigner, getDevnetApi } from "../src/substrate" import { generateRandomEthersWallet, getPublicClient } from "../src/utils"; import { IDISPATCH_ADDRESS, ISTORAGE_QUERY_ADDRESS, ETH_LOCAL_URL } from "../src/config"; -import { devnet } from "@polkadot-api/descriptors" +import { devnet, MultiAddress } from "@polkadot-api/descriptors" import { hexToNumber, PublicClient } from "viem"; import { PolkadotSigner, TypedApi } from "polkadot-api"; import { convertPublicKeyToSs58 } from "../src/address-utils" @@ -24,10 +24,18 @@ describe("Test the dispatch precompile", () => { }) it("Dispatch transfer call via precompile contract works correctly", async () => { - // 0x050300d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d02286bee // call for transfer 1 token to alice const transferAmount = BigInt(1000000000); - const transferCall = "0x050300d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d02286bee" + + const unsignedTx = api.tx.Balances.transfer_keep_alive({ + dest: MultiAddress.Id(convertPublicKeyToSs58(alice.publicKey)), + value: transferAmount, + }); + const encodedCallDataBytes = await unsignedTx.getEncodedData(); + + // encoded call should be 0x050300d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d02286bee + const transferCall = encodedCallDataBytes.asHex() + const aliceBalance = (await api.query.System.Account.getValue( convertPublicKeyToSs58(alice.publicKey))).data.free const txResponse = await wallet1.sendTransaction({ to: IDISPATCH_ADDRESS,