Skip to content

Commit 0a41ca6

Browse files
authored
Merge pull request #2079 from opentensor/evm-associate-key-rate-limit
Evm associate key rate limit
2 parents 3a266cb + af9aafc commit 0a41ca6

File tree

12 files changed

+227
-85
lines changed

12 files changed

+227
-85
lines changed

evm-tests/test/evm-uid.precompile.lookup.test.ts

Lines changed: 60 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -14,77 +14,76 @@ import { keccak256 } from 'ethers';
1414
import { addNewSubnetwork, forceSetBalanceToSs58Address, startCall } from "../src/subtensor";
1515

1616
describe("Test the UID Lookup precompile", () => {
17-
const hotkey = getRandomSubstrateKeypair();
18-
const coldkey = getRandomSubstrateKeypair();
19-
const evmWallet = generateRandomEthersWallet();
20-
let publicClient: PublicClient;
17+
const hotkey = getRandomSubstrateKeypair();
18+
const coldkey = getRandomSubstrateKeypair();
19+
const evmWallet = generateRandomEthersWallet();
20+
let publicClient: PublicClient;
2121

22-
let api: TypedApi<typeof devnet>
22+
let api: TypedApi<typeof devnet>
2323

24-
let alice: PolkadotSigner;
24+
let alice: PolkadotSigner;
2525

26-
let uid: number;
27-
let blockNumber: number;
28-
let netuid: number;
29-
let blockNumberAssociated: bigint;
26+
let uid: number;
27+
let blockNumber: number;
28+
let netuid: number;
29+
let blockNumberAssociated: bigint;
3030

31-
before(async () => {
32-
publicClient = await getPublicClient(ETH_LOCAL_URL)
33-
api = await getDevnetApi()
34-
alice = await getAliceSigner();
31+
before(async () => {
32+
publicClient = await getPublicClient(ETH_LOCAL_URL)
33+
api = await getDevnetApi()
34+
alice = await getAliceSigner();
3535

36-
await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(alice.publicKey))
37-
await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(hotkey.publicKey))
38-
await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(coldkey.publicKey))
36+
await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(alice.publicKey))
37+
await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(hotkey.publicKey))
38+
await forceSetBalanceToSs58Address(api, convertPublicKeyToSs58(coldkey.publicKey))
3939

40-
netuid = await addNewSubnetwork(api, hotkey, coldkey)
41-
await startCall(api, netuid, coldkey)
40+
netuid = await addNewSubnetwork(api, hotkey, coldkey)
41+
await startCall(api, netuid, coldkey)
4242

43-
const maybeUid = await api.query.SubtensorModule.Uids.getValue(netuid, convertPublicKeyToSs58(hotkey.publicKey))
43+
const maybeUid = await api.query.SubtensorModule.Uids.getValue(netuid, convertPublicKeyToSs58(hotkey.publicKey))
4444

45-
if (maybeUid === undefined) {
46-
throw new Error("UID should be defined")
47-
}
48-
uid = maybeUid
45+
if (maybeUid === undefined) {
46+
throw new Error("UID should be defined")
47+
}
48+
uid = maybeUid
4949

50-
// Associate EVM key
51-
blockNumber = await api.query.System.Number.getValue();
52-
const blockNumberBytes = u64.enc(BigInt(blockNumber));
53-
const blockNumberHash = hexToU8a(keccak256(blockNumberBytes));
54-
const concatenatedArray = new Uint8Array([...hotkey.publicKey, ...blockNumberHash]);
55-
const signature = await evmWallet.signMessage(concatenatedArray);
56-
const associateEvmKeyTx = api.tx.SubtensorModule.associate_evm_key({
57-
netuid: netuid,
58-
hotkey: convertPublicKeyToSs58(hotkey.publicKey),
59-
evm_key: convertToFixedSizeBinary(evmWallet.address, 20),
60-
block_number: BigInt(blockNumber),
61-
signature: convertToFixedSizeBinary(signature, 65)
62-
});
63-
const signer = getSignerFromKeypair(coldkey);
64-
await waitForTransactionCompletion(api, associateEvmKeyTx, signer)
65-
.then(() => { })
66-
.catch((error) => { console.log(`transaction error ${error}`) });
50+
// Associate EVM key
51+
blockNumber = await api.query.System.Number.getValue();
52+
const blockNumberBytes = u64.enc(BigInt(blockNumber));
53+
const blockNumberHash = hexToU8a(keccak256(blockNumberBytes));
54+
const concatenatedArray = new Uint8Array([...hotkey.publicKey, ...blockNumberHash]);
55+
const signature = await evmWallet.signMessage(concatenatedArray);
56+
const associateEvmKeyTx = api.tx.SubtensorModule.associate_evm_key({
57+
netuid: netuid,
58+
evm_key: convertToFixedSizeBinary(evmWallet.address, 20),
59+
block_number: BigInt(blockNumber),
60+
signature: convertToFixedSizeBinary(signature, 65)
61+
});
62+
const signer = getSignerFromKeypair(hotkey);
63+
await waitForTransactionCompletion(api, associateEvmKeyTx, signer)
64+
.then(() => { })
65+
.catch((error) => { console.log(`transaction error ${error}`) });
6766

68-
const storedEvmKey = await api.query.SubtensorModule.AssociatedEvmAddress.getValue(netuid, uid)
69-
assert.notEqual(storedEvmKey, undefined, "storedEvmKey should be defined")
70-
if (storedEvmKey !== undefined) {
71-
assert.equal(storedEvmKey[0].asHex(), convertToFixedSizeBinary(evmWallet.address, 20).asHex())
72-
blockNumberAssociated = storedEvmKey[1]
73-
}
74-
})
75-
76-
it("UID lookup via precompile contract works correctly", async () => {
77-
// Get UID for the EVM address
78-
const uidArray = await publicClient.readContract({
79-
abi: IUIDLookupABI,
80-
address: toViemAddress(IUID_LOOKUP_ADDRESS),
81-
functionName: "uidLookup",
82-
args: [netuid, evmWallet.address, 1024]
83-
})
67+
const storedEvmKey = await api.query.SubtensorModule.AssociatedEvmAddress.getValue(netuid, uid)
68+
assert.notEqual(storedEvmKey, undefined, "storedEvmKey should be defined")
69+
if (storedEvmKey !== undefined) {
70+
assert.equal(storedEvmKey[0].asHex(), convertToFixedSizeBinary(evmWallet.address, 20).asHex())
71+
blockNumberAssociated = storedEvmKey[1]
72+
}
73+
})
8474

85-
assert.notEqual(uidArray, undefined, "UID should be defined")
86-
assert.ok(Array.isArray(uidArray), `UID should be an array, got ${typeof uidArray}`)
87-
assert.ok(uidArray.length > 0, "UID array should not be empty")
88-
assert.deepStrictEqual(uidArray[0], { uid: uid, block_associated: blockNumberAssociated })
75+
it("UID lookup via precompile contract works correctly", async () => {
76+
// Get UID for the EVM address
77+
const uidArray = await publicClient.readContract({
78+
abi: IUIDLookupABI,
79+
address: toViemAddress(IUID_LOOKUP_ADDRESS),
80+
functionName: "uidLookup",
81+
args: [netuid, evmWallet.address, 1024]
8982
})
83+
84+
assert.notEqual(uidArray, undefined, "UID should be defined")
85+
assert.ok(Array.isArray(uidArray), `UID should be an array, got ${typeof uidArray}`)
86+
assert.ok(uidArray.length > 0, "UID array should not be empty")
87+
assert.deepStrictEqual(uidArray[0], { uid: uid, block_associated: blockNumberAssociated })
88+
})
9089
});

pallets/admin-utils/src/tests/mock.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ parameter_types! {
152152
pub const HotkeySwapOnSubnetInterval: u64 = 7 * 24 * 60 * 60 / 12; // 7 days
153153
pub const LeaseDividendsDistributionInterval: u32 = 100; // 100 blocks
154154
pub const MaxImmuneUidsPercentage: Percent = Percent::from_percent(80);
155+
pub const EvmKeyAssociateRateLimit: u64 = 0;
155156
}
156157

157158
impl pallet_subtensor::Config for Test {
@@ -231,6 +232,7 @@ impl pallet_subtensor::Config for Test {
231232
type GetCommitments = ();
232233
type MaxImmuneUidsPercentage = MaxImmuneUidsPercentage;
233234
type CommitmentsInterface = CommitmentsI;
235+
type EvmKeyAssociateRateLimit = EvmKeyAssociateRateLimit;
234236
}
235237

236238
parameter_types! {

pallets/subtensor/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2002,6 +2002,8 @@ pub enum CustomTransactionError {
20022002
CommitNotFound,
20032003
CommitBlockNotInRevealRange,
20042004
InputLengthsUnequal,
2005+
UidNotFound,
2006+
EvmKeyAssociateRateLimitExceeded,
20052007
}
20062008

20072009
impl From<CustomTransactionError> for u8 {
@@ -2027,6 +2029,8 @@ impl From<CustomTransactionError> for u8 {
20272029
CustomTransactionError::CommitNotFound => 16,
20282030
CustomTransactionError::CommitBlockNotInRevealRange => 17,
20292031
CustomTransactionError::InputLengthsUnequal => 18,
2032+
CustomTransactionError::UidNotFound => 19,
2033+
CustomTransactionError::EvmKeyAssociateRateLimitExceeded => 20,
20302034
}
20312035
}
20322036
}

pallets/subtensor/src/macros/config.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ mod config {
6666
/// Interface to clean commitments on network dissolution.
6767
type CommitmentsInterface: CommitmentsInterface;
6868

69+
/// Rate limit for associating an EVM key.
70+
type EvmKeyAssociateRateLimit: Get<u64>;
71+
6972
/// =================================
7073
/// ==== Initial Value Constants ====
7174
/// =================================

pallets/subtensor/src/macros/dispatches.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,17 +2037,15 @@ mod dispatches {
20372037
/// ```
20382038
///
20392039
/// # Arguments
2040-
/// * `origin` - The origin of the transaction, which must be signed by the coldkey that owns the `hotkey`.
2040+
/// * `origin` - The origin of the transaction, which must be signed by the `hotkey`.
20412041
/// * `netuid` - The netuid that the `hotkey` belongs to.
2042-
/// * `hotkey` - The hotkey associated with the `origin`.
20432042
/// * `evm_key` - The EVM key to associate with the `hotkey`.
20442043
/// * `block_number` - The block number used in the `signature`.
20452044
/// * `signature` - A signed message by the `evm_key` containing the `hotkey` and the hashed `block_number`.
20462045
///
20472046
/// # Errors
20482047
/// Returns an error if:
20492048
/// * The transaction is not signed.
2050-
/// * The hotkey is not owned by the origin coldkey.
20512049
/// * The hotkey does not belong to the subnet identified by the netuid.
20522050
/// * The EVM key cannot be recovered from the signature.
20532051
/// * The EVM key recovered from the signature does not match the given EVM key.
@@ -2058,17 +2056,16 @@ mod dispatches {
20582056
#[pallet::weight((
20592057
Weight::from_parts(3_000_000, 0).saturating_add(T::DbWeight::get().reads_writes(2, 1)),
20602058
DispatchClass::Normal,
2061-
Pays::Yes
2059+
Pays::No
20622060
))]
20632061
pub fn associate_evm_key(
20642062
origin: T::RuntimeOrigin,
20652063
netuid: NetUid,
2066-
hotkey: T::AccountId,
20672064
evm_key: H160,
20682065
block_number: u64,
20692066
signature: Signature,
20702067
) -> DispatchResult {
2071-
Self::do_associate_evm_key(origin, netuid, hotkey, evm_key, block_number, signature)
2068+
Self::do_associate_evm_key(origin, netuid, evm_key, block_number, signature)
20722069
}
20732070

20742071
/// Recycles alpha from a cold/hot key pair, reducing AlphaOut on a subnet

pallets/subtensor/src/macros/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,5 +254,7 @@ mod errors {
254254
SubnetLimitReached,
255255
/// Insufficient funds to meet the subnet lock cost
256256
CannotAffordLockCost,
257+
/// exceeded the rate limit for associating an EVM key.
258+
EvmKeyAssociateRateLimitExceeded,
257259
}
258260
}

0 commit comments

Comments
 (0)