Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Schedule Coldkey Swap #620

Merged
merged 57 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
c66aeb9
initial
Jul 5, 2024
4a39895
merge
Jul 5, 2024
bfea68a
push changes
Jul 5, 2024
462ed12
Fix build and straighten up the logic for draining coldkeys
gztensor Jul 5, 2024
7149b5b
Make tests build for draining coldkeys
gztensor Jul 5, 2024
b76408a
merge
Jul 6, 2024
b6bdb30
Merge branch 'arbitrage_coldkeys' of github.com:opentensor/subtensor …
Jul 6, 2024
a499116
Fix coldkey drain
gztensor Jul 6, 2024
3f3201c
Merge branch 'arbitrage_coldkeys' of github.com:opentensor/subtensor …
Jul 6, 2024
c5aef40
check
Jul 6, 2024
8851879
passing here
Jul 6, 2024
e7337af
fxi tests on arbitrated coldkey swap
Jul 6, 2024
cf4c8d5
add more test
Jul 6, 2024
c5b78f8
chore: update comments, lints
Jul 7, 2024
dad3925
fix: tests , feat: benchmarks
Jul 7, 2024
9a3f725
fix: benchmarks
Jul 7, 2024
f32c546
chore: whitelist schedule_arbitrated_coldkey_swap and set_weights, se…
Jul 7, 2024
68df4e1
feat: signed extension arbitration , swap cold key min amount
Jul 7, 2024
507e8cf
chore: lints
Jul 7, 2024
0bcdd26
feat: signed extensions , reduce arbitration time
Jul 7, 2024
cc9c094
feat: pow coldkey swaps ,todo fix tests , dont clear map during abrit…
Jul 7, 2024
60f3713
fix unit tests
open-junius Jul 8, 2024
c210904
fix conflict
open-junius Jul 8, 2024
be043ac
update runtime version
open-junius Jul 8, 2024
25744e4
fix benchmark function
open-junius Jul 8, 2024
8f8b92c
add arithmetic side effects
open-junius Jul 8, 2024
6daad1e
fix clippy in test file
open-junius Jul 8, 2024
fd980b1
chore: add event
Jul 8, 2024
fbe1924
feat: unlimited arb time
Jul 8, 2024
2e2b51d
fix: broken test
Jul 8, 2024
82be091
use on_idle for swap_coldkeys logic
orriin Jul 8, 2024
01c1529
Merge branch 'arbitrage_coldkeys' into arbitrate_coldkeys_on_idle
orriin Jul 8, 2024
247c861
Increase base difficulty to 10M for PoW swaps
gztensor Jul 8, 2024
219413c
Merge pull request #621 from opentensor/arbitrate_coldkeys_on_idle
orriin Jul 8, 2024
c6dab93
add the unit test back
open-junius Jul 8, 2024
e271f37
fix broken tests
Jul 8, 2024
54a1466
chore: fix tests
Jul 8, 2024
7bf6524
chore: fix test_arbitrated_coldkey_swap_multiple_arbitrations
Jul 8, 2024
2891d62
chore: fix tests
Jul 8, 2024
d1ee744
add swap test
Jul 8, 2024
9b4d63f
Merge branch 'arbitrage_coldkeys' of github.com:opentensor/subtensor …
Jul 8, 2024
4a97e79
working
Jul 8, 2024
ba00c23
add stake balance as equal
Jul 8, 2024
41feafc
chore: bump spec version
Jul 8, 2024
b1feb3c
feat: reduce arb period to 18 hours for testnet
Jul 8, 2024
e4c9ef2
feat: allow subnet owners to swap without funds , todo: fix test_comp…
Jul 8, 2024
af555d7
chore: introduce difficulty var to make tests shorter , fix test_comp…
Jul 9, 2024
a14337b
make it easier
open-junius Jul 9, 2024
83819ff
fix fmt
open-junius Jul 9, 2024
4563e78
feat: get total delegated stake
Jul 9, 2024
4eefcf9
fix: delegated stake tests, whitelist serve_axon, lints
Jul 9, 2024
e30c8f4
feat: coldkey swap info
Jul 9, 2024
7aaeb09
feat: move back to on_initialise, lints
Jul 9, 2024
3817b76
chore: bump arb delay back to 3 days
Jul 9, 2024
380aa65
chore: reduce min tao req to 0.1
Jul 9, 2024
fec59cb
feat: whitelist set_commitment
Jul 9, 2024
9de2afb
spec verion , lints
Jul 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions pallets/subtensor/src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,4 +428,29 @@ reveal_weights {
let _ = Subtensor::<T>::commit_weights(<T as frame_system::Config>::RuntimeOrigin::from(RawOrigin::Signed(hotkey.clone())), netuid, commit_hash);

}: reveal_weights(RawOrigin::Signed(hotkey.clone()), netuid, uids, weight_values, salt, version_key)

schedule_coldkey_swap {
distributedstatemachine marked this conversation as resolved.
Show resolved Hide resolved
let seed: u32 = 1;
let old_coldkey: T::AccountId = account("OldColdkey", 0, seed);
let new_coldkey: T::AccountId = account("NewColdkey", 0, seed + 1);
let hotkey: T::AccountId = account("Hotkey", 0, seed);

let netuid = 1u16;
let tempo = 1u16;

// Initialize the network
Subtensor::<T>::init_new_network(netuid, tempo);
Subtensor::<T>::set_network_registration_allowed(netuid, true);

// Add balance to the old coldkey account
let amount_to_be_staked: u64 = 1000000u32.into();
Subtensor::<T>::add_balance_to_coldkey_account(&old_coldkey.clone(), amount_to_be_staked+1000000000);
// Burned register the hotkey with the old coldkey
assert_ok!(Subtensor::<T>::burned_register(
RawOrigin::Signed(old_coldkey.clone()).into(),
netuid,
hotkey.clone()
));

}: schedule_coldkey_swap(RawOrigin::Signed(old_coldkey.clone()), new_coldkey)
}
8 changes: 8 additions & 0 deletions pallets/subtensor/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,13 @@ mod errors {
NoBalanceToTransfer,
/// Same coldkey
SameColdkey,
/// The coldkey is in arbitration
ColdkeyIsInArbitration,
/// The new coldkey is already registered for the drain
DuplicateColdkey,
/// Error thrown on a coldkey swap.
SwapError,
distributedstatemachine marked this conversation as resolved.
Show resolved Hide resolved
/// Insufficient Balance to Schedule coldkey swap
InsufficientBalanceToPerformColdkeySwap,
}
}
98 changes: 89 additions & 9 deletions pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use frame_support::{
use codec::{Decode, Encode};
use frame_support::sp_runtime::transaction_validity::InvalidTransaction;
use frame_support::sp_runtime::transaction_validity::ValidTransaction;
use pallet_balances::Call as BalancesCall;
use scale_info::TypeInfo;
use sp_runtime::{
traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension},
Expand Down Expand Up @@ -366,6 +367,9 @@ pub mod pallet {
#[pallet::storage] // --- MAP ( cold ) --> Vec<hot> | Returns the vector of hotkeys controlled by this coldkey.
pub type OwnedHotkeys<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, Vec<T::AccountId>, ValueQuery>;
#[pallet::storage] // --- DMAP ( cold ) --> Vec<hot> | Maps coldkey to hotkeys that stake to it
pub type StakingHotkeys<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, Vec<T::AccountId>, ValueQuery>;
#[pallet::storage] // --- MAP ( hot ) --> take | Returns the hotkey delegation take. And signals that this key is open for delegation.
pub type Delegates<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, u16, ValueQuery, DefaultDefaultTake<T>>;
Expand All @@ -380,6 +384,36 @@ pub mod pallet {
ValueQuery,
DefaultAccountTake<T>,
>;

#[pallet::type_value]
/// Default value for hotkeys.
pub fn EmptyAccounts<T: Config>() -> Vec<T::AccountId> {
vec![]
}
#[pallet::type_value]
/// Default stake interval.
pub fn DefaultArbitrationPeriod<T: Config>() -> u64 {
7200 * 3
}
#[pallet::storage] // ---- StorageItem Global Used Work.
pub type ArbitrationPeriod<T: Config> =
StorageValue<_, u64, ValueQuery, DefaultArbitrationPeriod<T>>;
#[pallet::storage] // --- MAP ( cold ) --> Vec<wallet_to_drain_to> | Returns a list of keys to drain to, if there are two, we extend the period.
pub type ColdkeySwapDestinations<T: Config> = StorageMap<
_,
Blake2_128Concat,
T::AccountId,
Vec<T::AccountId>,
ValueQuery,
EmptyAccounts<T>,
>;
#[pallet::storage] // --- MAP ( cold ) --> u64 | Block when the coldkey will be arbitrated.
pub type ColdkeyArbitrationBlock<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, u64, ValueQuery>;
#[pallet::storage] // --- MAP ( u64 ) --> Vec<coldkeys_to_drain> | Coldkeys to drain on the specific block.
pub type ColdkeysToSwapAtBlock<T: Config> =
StorageMap<_, Identity, u64, Vec<T::AccountId>, ValueQuery, EmptyAccounts<T>>;

/// -- ITEM (switches liquid alpha on)
#[pallet::type_value]
pub fn DefaultLiquidAlpha<T: Config>() -> bool {
Expand Down Expand Up @@ -1225,6 +1259,13 @@ pub mod pallet {

Stake::<T>::insert(hotkey.clone(), coldkey.clone(), stake);

// Update StakingHotkeys map
let mut staking_hotkeys = StakingHotkeys::<T>::get(coldkey);
if !staking_hotkeys.contains(hotkey) {
staking_hotkeys.push(hotkey.clone());
StakingHotkeys::<T>::insert(coldkey, staking_hotkeys);
}

next_uid = next_uid.checked_add(1).expect(
"should not have total number of hotkey accounts larger than u16::MAX",
);
Expand Down Expand Up @@ -1291,21 +1332,29 @@ pub mod pallet {
// * 'n': (BlockNumberFor<T>):
// - The number of the block we are initializing.
fn on_initialize(_block_number: BlockNumberFor<T>) -> Weight {
// Unstake all and transfer pending coldkeys
let swap_weight = match Self::swap_coldkeys_this_block() {
distributedstatemachine marked this conversation as resolved.
Show resolved Hide resolved
Ok(weight) => weight,
Err(_) => Weight::from_parts(0, 0),
};

let block_step_result = Self::block_step();
match block_step_result {
Ok(_) => {
// --- If the block step was successful, return the weight.
log::info!("Successfully ran block step.");
log::debug!("Successfully ran block step.");
Weight::from_parts(110_634_229_000_u64, 0)
.saturating_add(T::DbWeight::get().reads(8304_u64))
.saturating_add(T::DbWeight::get().writes(110_u64))
.saturating_add(swap_weight)
}
Err(e) => {
// --- If the block step was unsuccessful, return the weight anyway.
log::error!("Error while stepping block: {:?}", e);
Weight::from_parts(110_634_229_000_u64, 0)
.saturating_add(T::DbWeight::get().reads(8304_u64))
.saturating_add(T::DbWeight::get().writes(110_u64))
.saturating_add(swap_weight)
}
}
}
Expand Down Expand Up @@ -1337,7 +1386,9 @@ pub mod pallet {
// Doesn't check storage version. TODO: Remove after upgrade
.saturating_add(migration::migration5_total_issuance::<T>(false))
// Populate OwnedHotkeys map for coldkey swap. Doesn't update storage vesion.
.saturating_add(migration::migrate_populate_owned::<T>());
.saturating_add(migration::migrate_populate_owned::<T>())
// Populate StakingHotkeys map for coldkey swap. Doesn't update storage vesion.
.saturating_add(migration::migrate_populate_staking_hotkeys::<T>());

weight
}
Expand Down Expand Up @@ -2025,15 +2076,19 @@ pub mod pallet {
///
/// Weight is calculated based on the number of database reads and writes.
#[pallet::call_index(72)]
#[pallet::weight((Weight::from_parts(1_940_000_000, 0)
.saturating_add(T::DbWeight::get().reads(272))
.saturating_add(T::DbWeight::get().writes(527)), DispatchClass::Operational, Pays::No))]
pub fn unstake_all_and_transfer_to_new_coldkey(
#[pallet::weight((Weight::from_parts(21_000_000, 0)
.saturating_add(T::DbWeight::get().reads(3))
.saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Operational, Pays::No))]
pub fn schedule_coldkey_swap(
origin: OriginFor<T>,
new_coldkey: T::AccountId,
work: Vec<u8>,
block_number: u64,
nonce: u64,
) -> DispatchResult {
let current_coldkey = ensure_signed(origin)?;
Self::do_unstake_all_and_transfer_to_new_coldkey(current_coldkey, new_coldkey)
// Attain the calling coldkey from the origin.
let old_coldkey: T::AccountId = ensure_signed(origin)?;
Self::do_schedule_coldkey_swap(&old_coldkey, &new_coldkey, work, block_number, nonce)
}

// ---- SUDO ONLY FUNCTIONS ------------------------------------------------------------
Expand Down Expand Up @@ -2266,10 +2321,12 @@ impl<T: Config + Send + Sync + TypeInfo> sp_std::fmt::Debug for SubtensorSignedE
}
}

impl<T: Config + Send + Sync + TypeInfo> SignedExtension for SubtensorSignedExtension<T>
impl<T: Config + Send + Sync + TypeInfo + pallet_balances::Config> SignedExtension
for SubtensorSignedExtension<T>
where
T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
<T as frame_system::Config>::RuntimeCall: IsSubType<Call<T>>,
<T as frame_system::Config>::RuntimeCall: IsSubType<BalancesCall<T>>,
{
const IDENTIFIER: &'static str = "SubtensorSignedExtension";

Expand All @@ -2289,6 +2346,19 @@ where
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> TransactionValidity {
// Check if the call is one of the balance transfer types we want to reject
if let Some(balances_call) = call.is_sub_type() {
match balances_call {
BalancesCall::transfer_allow_death { .. }
| BalancesCall::transfer_keep_alive { .. }
| BalancesCall::transfer_all { .. } => {
if Pallet::<T>::coldkey_in_arbitration(who) {
return Err(TransactionValidityError::Invalid(InvalidTransaction::Call));
}
}
_ => {} // Other Balances calls are allowed
}
}
match call.is_sub_type() {
Some(Call::commit_weights { netuid, .. }) => {
if Self::check_weights_min_stake(who) {
Expand Down Expand Up @@ -2365,6 +2435,16 @@ where
priority: Self::get_priority_vanilla(),
..Default::default()
}),
Some(Call::dissolve_network { .. }) => {
if Pallet::<T>::coldkey_in_arbitration(who) {
Err(TransactionValidityError::Invalid(InvalidTransaction::Call))
} else {
Ok(ValidTransaction {
priority: Self::get_priority_vanilla(),
..Default::default()
})
}
}
_ => Ok(ValidTransaction {
priority: Self::get_priority_vanilla(),
..Default::default()
Expand Down
64 changes: 64 additions & 0 deletions pallets/subtensor/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,3 +539,67 @@ pub fn migrate_populate_owned<T: Config>() -> Weight {
Weight::zero()
}
}

/// Populate the StakingHotkeys map from Stake map
pub fn migrate_populate_staking_hotkeys<T: Config>() -> Weight {
// Setup migration weight
let mut weight = T::DbWeight::get().reads(1);
let migration_name = "Populate StakingHotkeys map";

// Check if this migration is needed (if StakingHotkeys map is empty)
let migrate = StakingHotkeys::<T>::iter().next().is_none();

// Only runs if the migration is needed
if migrate {
info!(target: LOG_TARGET_1, ">>> Starting Migration: {}", migration_name);

let mut longest_hotkey_vector: usize = 0;
let mut longest_coldkey: Option<T::AccountId> = None;
let mut keys_touched: u64 = 0;
let mut storage_reads: u64 = 0;
let mut storage_writes: u64 = 0;

// Iterate through all Owner entries
Stake::<T>::iter().for_each(|(hotkey, coldkey, stake)| {
storage_reads = storage_reads.saturating_add(1); // Read from Owner storage
if stake > 0 {
let mut hotkeys = StakingHotkeys::<T>::get(&coldkey);
storage_reads = storage_reads.saturating_add(1); // Read from StakingHotkeys storage

// Add the hotkey if it's not already in the vector
if !hotkeys.contains(&hotkey) {
hotkeys.push(hotkey);
keys_touched = keys_touched.saturating_add(1);

// Update longest hotkey vector info
if longest_hotkey_vector < hotkeys.len() {
longest_hotkey_vector = hotkeys.len();
longest_coldkey = Some(coldkey.clone());
}

// Update the StakingHotkeys storage
StakingHotkeys::<T>::insert(&coldkey, hotkeys);
storage_writes = storage_writes.saturating_add(1); // Write to StakingHotkeys storage
}

// Accrue weight for reads and writes
weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 1));
}
});

// Log migration results
info!(
target: LOG_TARGET_1,
"Migration {} finished. Keys touched: {}, Longest hotkey vector: {}, Storage reads: {}, Storage writes: {}",
migration_name, keys_touched, longest_hotkey_vector, storage_reads, storage_writes
);
if let Some(c) = longest_coldkey {
info!(target: LOG_TARGET_1, "Longest hotkey vector is controlled by: {:?}", c);
}

weight
} else {
info!(target: LOG_TARGET_1, "Migration {} already done!", migration_name);
Weight::zero()
}
}
4 changes: 4 additions & 0 deletions pallets/subtensor/src/registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ impl<T: Config> Pallet<T> {
) -> DispatchResult {
// --- 1. Check that the caller has signed the transaction. (the coldkey of the pairing)
let coldkey = ensure_signed(origin)?;
ensure!(
!Self::coldkey_in_arbitration(&coldkey),
Error::<T>::ColdkeyIsInArbitration
);
log::info!(
"do_registration( coldkey:{:?} netuid:{:?} hotkey:{:?} )",
coldkey,
Expand Down
20 changes: 20 additions & 0 deletions pallets/subtensor/src/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,10 @@ impl<T: Config> Pallet<T> {

// --- 1. Ensure that the call originates from a signed source and retrieve the caller's account ID (coldkey).
let coldkey = ensure_signed(origin)?;
ensure!(
!Self::coldkey_in_arbitration(&coldkey),
Error::<T>::ColdkeyIsInArbitration
);
log::info!(
"do_root_register( coldkey: {:?}, hotkey: {:?} )",
coldkey,
Expand Down Expand Up @@ -623,6 +627,10 @@ impl<T: Config> Pallet<T> {
) -> dispatch::DispatchResult {
// Check the caller's signature. This is the coldkey of a registered account.
let coldkey = ensure_signed(origin)?;
ensure!(
!Self::coldkey_in_arbitration(&coldkey),
Error::<T>::ColdkeyIsInArbitration
);
log::info!(
"do_set_root_weights( origin:{:?} netuid:{:?}, uids:{:?}, values:{:?})",
coldkey,
Expand Down Expand Up @@ -744,6 +752,10 @@ impl<T: Config> Pallet<T> {
) -> DispatchResultWithPostInfo {
// --- 1. Ensure that the caller has signed with their coldkey.
let coldkey = ensure_signed(origin.clone())?;
ensure!(
!Self::coldkey_in_arbitration(&coldkey),
Error::<T>::ColdkeyIsInArbitration
);

// --- 2. Ensure that the calling coldkey owns the associated hotkey.
ensure!(
Expand Down Expand Up @@ -797,6 +809,10 @@ impl<T: Config> Pallet<T> {
pub fn user_add_network(origin: T::RuntimeOrigin) -> dispatch::DispatchResult {
// --- 0. Ensure the caller is a signed user.
let coldkey = ensure_signed(origin)?;
ensure!(
!Self::coldkey_in_arbitration(&coldkey),
Error::<T>::ColdkeyIsInArbitration
);

// --- 1. Rate limit for network registrations.
let current_block = Self::get_current_block_as_u64();
Expand Down Expand Up @@ -885,6 +901,10 @@ impl<T: Config> Pallet<T> {
pub fn user_remove_network(origin: T::RuntimeOrigin, netuid: u16) -> dispatch::DispatchResult {
// --- 1. Ensure the function caller is a signed user.
let coldkey = ensure_signed(origin)?;
ensure!(
!Self::coldkey_in_arbitration(&coldkey),
Error::<T>::ColdkeyIsInArbitration
);

// --- 2. Ensure this subnet exists.
ensure!(
Expand Down
Loading