Skip to content

Commit 3bf3ab6

Browse files
committed
Merge branch 'devnet-ready' into fix/clear-small-noms-if-new-min-nom-stake-less
2 parents e115d9b + 8f1d998 commit 3bf3ab6

File tree

9 files changed

+219
-9
lines changed

9 files changed

+219
-9
lines changed

.github/workflows/docker.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ on:
99
description: "Branch or tag to use for the Docker image tag and ref to checkout (optional)"
1010
required: false
1111
default: ""
12-
1312
push:
1413
branches:
1514
- devnet-ready
@@ -35,6 +34,13 @@ jobs:
3534
echo "tag=$branch_or_tag" >> $GITHUB_ENV
3635
echo "ref=$branch_or_tag" >> $GITHUB_ENV
3736
37+
# Check if this is a tagged release (not devnet-ready/devnet/testnet)
38+
if [[ "${{ github.event_name }}" == "release" && "$branch_or_tag" != "devnet-ready" && "$branch_or_tag" != "devnet" && "$branch_or_tag" != "testnet" ]]; then
39+
echo "latest_tag=true" >> $GITHUB_ENV
40+
else
41+
echo "latest_tag=false" >> $GITHUB_ENV
42+
fi
43+
3844
- name: Checkout code
3945
uses: actions/checkout@v4
4046
with:
@@ -60,3 +66,4 @@ jobs:
6066
push: true
6167
tags: |
6268
ghcr.io/${{ github.repository }}:${{ env.tag }}
69+
${{ env.latest_tag == 'true' && format('ghcr.io/{0}:latest', github.repository) || '' }}

pallets/admin-utils/src/lib.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,36 @@ pub mod pallet {
13991399
log::debug!("SubnetMovingAlphaSet( alpha: {:?} )", alpha);
14001400
Ok(())
14011401
}
1402+
1403+
/// Change the SubnetOwnerHotkey for a given subnet.
1404+
///
1405+
/// # Arguments
1406+
/// * `origin` - The origin of the call, which must be the subnet owner.
1407+
/// * `netuid` - The unique identifier for the subnet.
1408+
/// * `hotkey` - The new hotkey for the subnet owner.
1409+
///
1410+
/// # Errors
1411+
/// * `BadOrigin` - If the caller is not the subnet owner or root account.
1412+
///
1413+
/// # Weight
1414+
/// Weight is handled by the `#[pallet::weight]` attribute.
1415+
#[pallet::call_index(64)]
1416+
#[pallet::weight((0, DispatchClass::Operational, Pays::No))]
1417+
pub fn sudo_set_subnet_owner_hotkey(
1418+
origin: OriginFor<T>,
1419+
netuid: u16,
1420+
hotkey: T::AccountId,
1421+
) -> DispatchResult {
1422+
pallet_subtensor::Pallet::<T>::ensure_subnet_owner(origin.clone(), netuid)?;
1423+
pallet_subtensor::Pallet::<T>::set_subnet_owner_hotkey(netuid, &hotkey);
1424+
1425+
log::debug!(
1426+
"SubnetOwnerHotkeySet( netuid: {:?}, hotkey: {:?} )",
1427+
netuid,
1428+
hotkey
1429+
);
1430+
Ok(())
1431+
}
14021432
}
14031433
}
14041434

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,3 +1549,46 @@ fn test_sets_a_lower_value_clears_small_nominations() {
15491549
);
15501550
});
15511551
}
1552+
1553+
#[test]
1554+
fn test_sudo_set_subnet_owner_hotkey() {
1555+
new_test_ext().execute_with(|| {
1556+
let netuid: u16 = 1;
1557+
1558+
let coldkey: U256 = U256::from(1);
1559+
let hotkey: U256 = U256::from(2);
1560+
let new_hotkey: U256 = U256::from(3);
1561+
1562+
let coldkey_origin = <<Test as Config>::RuntimeOrigin>::signed(coldkey);
1563+
let root = RuntimeOrigin::root();
1564+
let random_account = RuntimeOrigin::signed(U256::from(123456));
1565+
1566+
pallet_subtensor::SubnetOwner::<Test>::insert(netuid, coldkey);
1567+
pallet_subtensor::SubnetOwnerHotkey::<Test>::insert(netuid, hotkey);
1568+
assert_eq!(
1569+
pallet_subtensor::SubnetOwnerHotkey::<Test>::get(netuid),
1570+
hotkey
1571+
);
1572+
1573+
assert_ok!(AdminUtils::sudo_set_subnet_owner_hotkey(
1574+
coldkey_origin,
1575+
netuid,
1576+
new_hotkey
1577+
));
1578+
1579+
assert_eq!(
1580+
pallet_subtensor::SubnetOwnerHotkey::<Test>::get(netuid),
1581+
new_hotkey
1582+
);
1583+
1584+
assert_noop!(
1585+
AdminUtils::sudo_set_subnet_owner_hotkey(random_account, netuid, new_hotkey),
1586+
DispatchError::BadOrigin
1587+
);
1588+
1589+
assert_noop!(
1590+
AdminUtils::sudo_set_subnet_owner_hotkey(root, netuid, new_hotkey),
1591+
DispatchError::BadOrigin
1592+
);
1593+
});
1594+
}

pallets/subtensor/src/macros/events.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,5 +271,11 @@ mod events {
271271
/// Parameters:
272272
/// (netuid, bool)
273273
TransferToggle(u16, bool),
274+
275+
/// The owner hotkey for a subnet has been set.
276+
///
277+
/// Parameters:
278+
/// (netuid, new_hotkey)
279+
SubnetOwnerHotkeySet(u16, T::AccountId),
274280
}
275281
}

pallets/subtensor/src/utils/misc.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::*;
22
use crate::{
33
Error,
4-
system::{ensure_root, ensure_signed_or_root, pallet_prelude::BlockNumberFor},
4+
system::{ensure_root, ensure_signed, ensure_signed_or_root, pallet_prelude::BlockNumberFor},
55
};
66
use safe_math::*;
77
use sp_core::Get;
@@ -23,6 +23,15 @@ impl<T: Config> Pallet<T> {
2323
}
2424
}
2525

26+
pub fn ensure_subnet_owner(o: T::RuntimeOrigin, netuid: u16) -> Result<(), DispatchError> {
27+
let coldkey = ensure_signed(o);
28+
match coldkey {
29+
Ok(who) if SubnetOwner::<T>::get(netuid) == who => Ok(()),
30+
Ok(_) => Err(DispatchError::BadOrigin),
31+
Err(x) => Err(x.into()),
32+
}
33+
}
34+
2635
// ========================
2736
// ==== Global Setters ====
2837
// ========================
@@ -743,4 +752,20 @@ impl<T: Config> Pallet<T> {
743752
DissolveNetworkScheduleDuration::<T>::set(duration);
744753
Self::deposit_event(Event::DissolveNetworkScheduleDurationSet(duration));
745754
}
755+
756+
/// Set the owner hotkey for a subnet.
757+
///
758+
/// # Arguments
759+
///
760+
/// * `netuid` - The unique identifier for the subnet.
761+
/// * `hotkey` - The new hotkey for the subnet owner.
762+
///
763+
/// # Effects
764+
///
765+
/// * Update the SubnetOwnerHotkey storage.
766+
/// * Emits a SubnetOwnerHotkeySet event.
767+
pub fn set_subnet_owner_hotkey(netuid: u16, hotkey: &T::AccountId) {
768+
SubnetOwnerHotkey::<T>::insert(netuid, hotkey.clone());
769+
Self::deposit_event(Event::SubnetOwnerHotkeySet(netuid, hotkey.clone()));
770+
}
746771
}

runtime/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
228228
// `spec_version`, and `authoring_version` are the same between Wasm and native.
229229
// This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
230230
// the compatible custom types.
231-
spec_version: 244,
231+
spec_version: 245,
232232
impl_version: 1,
233233
apis: RUNTIME_API_VERSIONS,
234234
transaction_version: 1,

runtime/src/precompiles/solidity/staking.abi

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,43 @@
9494
"outputs": [],
9595
"stateMutability": "nonpayable",
9696
"type": "function"
97+
},
98+
{
99+
"inputs": [
100+
{
101+
"internalType": "bytes32",
102+
"name": "coldkey",
103+
"type": "bytes32"
104+
}
105+
],
106+
"name": "getTotalColdkeyStake",
107+
"outputs": [
108+
{
109+
"internalType": "uint256",
110+
"name": "",
111+
"type": "uint256"
112+
}
113+
],
114+
"stateMutability": "view",
115+
"type": "function"
116+
},
117+
{
118+
"inputs": [
119+
{
120+
"internalType": "bytes32",
121+
"name": "hotkey",
122+
"type": "bytes32"
123+
}
124+
],
125+
"name": "getTotalHotkeyStake",
126+
"outputs": [
127+
{
128+
"internalType": "uint256",
129+
"name": "",
130+
"type": "uint256"
131+
}
132+
],
133+
"stateMutability": "view",
134+
"type": "function"
97135
}
98136
]

runtime/src/precompiles/solidity/staking.sol

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,36 @@ interface IStaking {
4646
uint256 netuid
4747
) external;
4848

49-
/**
50-
* @dev Delegates staking to a proxy account.
51-
*
52-
* @param delegate The public key (32 bytes) of the delegate.
53-
*/
54-
function addProxy(bytes32 delegate) external;
49+
/**
50+
* @dev Returns the amount of RAO staked by the coldkey.
51+
*
52+
* This function allows external accounts and contracts to query the amount of RAO staked by the coldkey
53+
* which effectively calls `get_total_coldkey_stake` on the subtensor pallet with
54+
* specified coldkey as a parameter.
55+
*
56+
* @param coldkey The coldkey public key (32 bytes).
57+
* @return The amount of RAO staked by the coldkey.
58+
*/
59+
function getTotalColdkeyStake(bytes32 coldkey) external view returns (uint256);
60+
61+
/**
62+
* @dev Returns the total amount of stake under a hotkey (delegative or otherwise)
63+
*
64+
* This function allows external accounts and contracts to query the total amount of RAO staked under a hotkey
65+
* which effectively calls `get_total_hotkey_stake` on the subtensor pallet with
66+
* specified hotkey as a parameter.
67+
*
68+
* @param hotkey The hotkey public key (32 bytes).
69+
* @return The total amount of RAO staked under the hotkey.
70+
*/
71+
function getTotalHotkeyStake(bytes32 hotkey) external view returns (uint256);
72+
73+
/**
74+
* @dev Delegates staking to a proxy account.
75+
*
76+
* @param delegate The public key (32 bytes) of the delegate.
77+
*/
78+
function addProxy(bytes32 delegate) external;
5579

5680
/**
5781
* @dev Removes staking proxy account.

runtime/src/precompiles/staking.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,43 @@ impl StakingPrecompile {
9090
handle.try_dispatch_runtime_call(call, RawOrigin::Signed(account_id))
9191
}
9292

93+
#[precompile::public("getTotalColdkeyStake(bytes32)")]
94+
fn get_total_coldkey_stake(
95+
_handle: &mut impl PrecompileHandle,
96+
coldkey_h256: H256,
97+
) -> EvmResult<U256> {
98+
let (coldkey, _) = parse_pubkey(coldkey_h256.as_bytes())?;
99+
100+
// get total stake of coldkey
101+
let total_stake =
102+
pallet_subtensor::Pallet::<Runtime>::get_total_stake_for_coldkey(&coldkey);
103+
// Convert to EVM decimals
104+
let stake_u256 = U256::from(total_stake);
105+
let stake_eth =
106+
<Runtime as pallet_evm::Config>::BalanceConverter::into_evm_balance(stake_u256)
107+
.ok_or(ExitError::InvalidRange)?;
108+
109+
Ok(stake_eth)
110+
}
111+
112+
#[precompile::public("getTotalHotkeyStake(bytes32)")]
113+
fn get_total_hotkey_stake(
114+
_handle: &mut impl PrecompileHandle,
115+
hotkey_h256: H256,
116+
) -> EvmResult<U256> {
117+
let (hotkey, _) = parse_pubkey(hotkey_h256.as_bytes())?;
118+
119+
// get total stake of hotkey
120+
let total_stake = pallet_subtensor::Pallet::<Runtime>::get_total_stake_for_hotkey(&hotkey);
121+
// Convert to EVM decimals
122+
let stake_u256 = U256::from(total_stake);
123+
let stake_eth =
124+
<Runtime as pallet_evm::Config>::BalanceConverter::into_evm_balance(stake_u256)
125+
.ok_or(ExitError::InvalidRange)?;
126+
127+
Ok(stake_eth)
128+
}
129+
93130
#[precompile::public("addProxy(bytes32)")]
94131
fn add_proxy(handle: &mut impl PrecompileHandle, delegate: H256) -> EvmResult<()> {
95132
let account_id = handle.caller_account_id();

0 commit comments

Comments
 (0)