diff --git a/evm-tests/test/evm-uid.precompile.lookup.test.ts b/evm-tests/test/evm-uid.precompile.lookup.test.ts index f6e22ce032..6e702d612e 100644 --- a/evm-tests/test/evm-uid.precompile.lookup.test.ts +++ b/evm-tests/test/evm-uid.precompile.lookup.test.ts @@ -55,11 +55,12 @@ describe("Test the UID Lookup precompile", () => { const signature = await evmWallet.signMessage(concatenatedArray); const associateEvmKeyTx = api.tx.SubtensorModule.associate_evm_key({ netuid: netuid, + hotkey: convertPublicKeyToSs58(hotkey.publicKey), evm_key: convertToFixedSizeBinary(evmWallet.address, 20), block_number: BigInt(blockNumber), signature: convertToFixedSizeBinary(signature, 65) }); - const signer = getSignerFromKeypair(hotkey); + const signer = getSignerFromKeypair(coldkey); await waitForTransactionCompletion(api, associateEvmKeyTx, signer) .then(() => { }) .catch((error) => { console.log(`transaction error ${error}`) }); diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 28f7ff384d..1325a6258c 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -2048,11 +2048,12 @@ mod dispatches { pub fn associate_evm_key( origin: T::RuntimeOrigin, netuid: NetUid, + hotkey: T::AccountId, evm_key: H160, block_number: u64, signature: Signature, ) -> DispatchResult { - Self::do_associate_evm_key(origin, netuid, evm_key, block_number, signature) + Self::do_associate_evm_key(origin, netuid, hotkey, evm_key, block_number, signature) } /// Recycles alpha from a cold/hot key pair, reducing AlphaOut on a subnet diff --git a/pallets/subtensor/src/tests/evm.rs b/pallets/subtensor/src/tests/evm.rs index a65e69c207..95d0c4e6db 100644 --- a/pallets/subtensor/src/tests/evm.rs +++ b/pallets/subtensor/src/tests/evm.rs @@ -58,8 +58,9 @@ fn test_associate_evm_key_success() { let signature = sign_evm_message(&pair, message); assert_ok!(SubtensorModule::associate_evm_key( - RuntimeOrigin::signed(hotkey), + RuntimeOrigin::signed(coldkey), netuid, + hotkey, evm_key, block_number, signature, @@ -104,8 +105,9 @@ fn test_associate_evm_key_different_block_number_success() { let signature = sign_evm_message(&pair, message); assert_ok!(SubtensorModule::associate_evm_key( - RuntimeOrigin::signed(hotkey), + RuntimeOrigin::signed(coldkey), netuid, + hotkey, evm_key, block_number, signature, @@ -123,6 +125,43 @@ fn test_associate_evm_key_different_block_number_success() { }); } +#[test] +fn test_associate_evm_key_coldkey_does_not_own_hotkey() { + new_test_ext(1).execute_with(|| { + let netuid = NetUid::from(1); + + let tempo: u16 = 2; + let modality: u16 = 2; + + add_network(netuid, tempo, modality); + + let coldkey = U256::from(1); + let hotkey = U256::from(2); + + let pair = ecdsa::Pair::generate().0; + let public = pair.public(); + let evm_key = public_to_evm_key(&public); + let block_number = frame_system::Pallet::::block_number(); + let hashed_block_number = keccak_256(block_number.encode().as_ref()); + let hotkey_bytes = hotkey.encode(); + + let message = [hotkey_bytes.as_ref(), hashed_block_number.as_ref()].concat(); + let signature = sign_evm_message(&pair, message); + + assert_err!( + SubtensorModule::associate_evm_key( + RuntimeOrigin::signed(coldkey), + netuid, + hotkey, + evm_key, + block_number, + signature, + ), + Error::::NonAssociatedColdKey + ); + }); +} + #[test] fn test_associate_evm_key_hotkey_not_registered_in_subnet() { new_test_ext(1).execute_with(|| { @@ -149,8 +188,9 @@ fn test_associate_evm_key_hotkey_not_registered_in_subnet() { assert_err!( SubtensorModule::associate_evm_key( - RuntimeOrigin::signed(hotkey), + RuntimeOrigin::signed(coldkey), netuid, + hotkey, evm_key, block_number, signature, @@ -189,8 +229,9 @@ fn test_associate_evm_key_using_wrong_hash_function() { assert_err!( SubtensorModule::associate_evm_key( - RuntimeOrigin::signed(hotkey), + RuntimeOrigin::signed(coldkey), netuid, + hotkey, evm_key, block_number, signature, diff --git a/pallets/subtensor/src/utils/evm.rs b/pallets/subtensor/src/utils/evm.rs index 652fb8ea27..757c2ef91e 100644 --- a/pallets/subtensor/src/utils/evm.rs +++ b/pallets/subtensor/src/utils/evm.rs @@ -24,11 +24,12 @@ impl Pallet { /// Associate an EVM key with a hotkey. /// - /// This function accepts a Signature, which is a signed message containing the hotkey concatenated with - /// the hashed block number. It will then attempt to recover the EVM key from the signature and compare it - /// with the `evm_key` parameter, and ensures that they match. + /// This function accepts a Signature, which is a signed message containing the hotkey + /// concatenated with the hashed block number. It will then attempt to recover the EVM key from + /// the signature and compare it with the `evm_key` parameter, and ensures that they match. /// - /// The EVM key is expected to sign the message according to this formula to produce the signature: + /// The EVM key is expected to sign the message according to this formula to produce the + /// signature: /// ```text /// keccak_256(hotkey ++ keccak_256(block_number)) /// ``` @@ -40,15 +41,22 @@ impl Pallet { /// * `hotkey` - The hotkey associated with the `origin` coldkey. /// * `evm_key` - The EVM address to associate with the `hotkey`. /// * `block_number` - The block number used in the `signature`. - /// * `signature` - A signed message by the `evm_key` containing the `hotkey` and the hashed `block_number`. + /// * `signature` - A signed message by the `evm_key` containing the `hotkey` and the hashed + /// `block_number`. pub fn do_associate_evm_key( origin: T::RuntimeOrigin, netuid: NetUid, + hotkey: T::AccountId, evm_key: H160, block_number: u64, mut signature: Signature, ) -> dispatch::DispatchResult { - let hotkey = ensure_signed(origin)?; + let coldkey = ensure_signed(origin)?; + + ensure!( + Self::get_owning_coldkey_for_hotkey(&hotkey) == coldkey, + Error::::NonAssociatedColdKey + ); // Normalize the v value to 0 or 1 if signature.0[64] >= 27 {