Skip to content

Commit bed9db1

Browse files
committed
Migrate allocator role to sudo key
1 parent 60f1069 commit bed9db1

5 files changed

Lines changed: 150 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# Changelog
22

3+
## Spec 29
4+
5+
This release migrates the allocator role to the current sudo key.
6+
7+
### Allocator Migration
8+
9+
- Runtime `spec_version` is bumped from `28` to `29`.
10+
- Governance storage version is bumped from `5` to `6`.
11+
- The migration reads the current sudo key and makes it the only governance allocator.
12+
- The sudo allocator is whitelisted, funded with the current registration burn from the DAO treasury, and registered through the normal `torus0` registration path.
13+
- Existing stake to prior allocators is transferred to the sudo allocator through the `torus0` staking path before prior allocator agents are deregistered.
14+
- Prior allocator agents are deregistered through the `torus0` deregistration path after their inbound stake has moved.
15+
316
## Spec 27
417

518
This release introduces an explicit admin-controlled authority rotation path for the solo-chain runtime, replacing ad hoc emergency storage mutation workflows with a dedicated runtime extrinsic.

docs/changes/spec-29.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Spec 29 Changelog
2+
3+
This release migrates the allocator role to the current sudo key.
4+
5+
## 1. Extrinsics
6+
7+
No extrinsics were added, changed, or removed.
8+
9+
## 2. Events
10+
11+
No events were added, changed, or removed.
12+
13+
## 3. Storage Items
14+
15+
No storage items were added, changed, or removed.
16+
17+
## 4. Runtime Migration
18+
19+
- Runtime `spec_version` is bumped from `28` to `29`.
20+
- `governance` storage version is bumped from `5` to `6`.
21+
- The migration reads the current sudo key and makes it the only governance allocator.
22+
- The governance allocator set is replaced with the sudo key.
23+
- The sudo allocator is whitelisted, funded with the current registration burn from the DAO treasury, and registered through the normal torus0 registration path.
24+
- Stake to prior allocators is transferred to the sudo allocator through the torus0 staking path before prior allocator agents are deregistered.
25+
- Prior allocator agents are deregistered through the torus0 deregistration path after their inbound stake has moved.

pallets/governance/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use crate::{
4141
pub mod pallet {
4242
#![allow(clippy::too_many_arguments)]
4343

44-
const STORAGE_VERSION: StorageVersion = StorageVersion::new(5);
44+
const STORAGE_VERSION: StorageVersion = StorageVersion::new(6);
4545

4646
use pallet_permission0_api::{CuratorPermissions, Permission0Api, Permission0CuratorApi};
4747
use polkadot_sdk::sp_core::ConstBool;

runtime/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use sp_version::RuntimeVersion;
2222
pub mod apis;
2323
pub mod benchmarks;
2424
pub mod configs;
25+
pub mod migrations;
2526
pub mod precompiles;
2627

2728
impl_opaque_keys! {
@@ -37,7 +38,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
3738
spec_name: create_runtime_str!("torus-runtime"),
3839
impl_name: create_runtime_str!("torus-runtime"),
3940
authoring_version: 1,
40-
spec_version: 28,
41+
spec_version: 29,
4142
impl_version: 1,
4243
apis: apis::RUNTIME_API_VERSIONS,
4344
transaction_version: 1,
@@ -82,7 +83,7 @@ pub type SignedPayload = sp_runtime::generic::SignedPayload<RuntimeCall, SignedE
8283
/// All migrations of the runtime, aside from the ones declared in the pallets.
8384
///
8485
/// This can be a tuple of types, each implementing `OnRuntimeUpgrade`.
85-
type Migrations = ();
86+
type Migrations = (migrations::MigrateAllocator,);
8687

8788
/// Executive: handles dispatch to the various modules.
8889
pub type RuntimeExecutive = frame_executive::Executive<

runtime/src/migrations.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
use alloc::vec::Vec;
2+
3+
use polkadot_sdk::{
4+
frame_support::{
5+
pallet_prelude::*,
6+
storage_alias,
7+
traits::{Currency, ExistenceRequirement, OnRuntimeUpgrade, StorageVersion},
8+
},
9+
frame_system,
10+
sp_weights::Weight,
11+
};
12+
13+
use crate::Runtime;
14+
15+
type AccountId = <Runtime as frame_system::Config>::AccountId;
16+
type Agent = pallet_torus0::agent::Agent<Runtime>;
17+
18+
#[storage_alias(pallet_name)]
19+
type Key = StorageValue<polkadot_sdk::pallet_sudo::Pallet<Runtime>, AccountId, OptionQuery>;
20+
21+
/// Moves the allocator role to the current sudo key.
22+
pub struct MigrateAllocator;
23+
24+
impl OnRuntimeUpgrade for MigrateAllocator {
25+
fn on_runtime_upgrade() -> Weight {
26+
if StorageVersion::get::<pallet_governance::Pallet<Runtime>>() == StorageVersion::new(5) {
27+
if let Some(new_allocator) = sudo_key() {
28+
migrate_allocator(new_allocator);
29+
}
30+
31+
StorageVersion::new(6).put::<pallet_governance::Pallet<Runtime>>();
32+
}
33+
34+
Weight::zero()
35+
}
36+
}
37+
38+
fn sudo_key() -> Option<AccountId> {
39+
Key::get()
40+
}
41+
42+
fn migrate_allocator(new_allocator: AccountId) {
43+
let old_allocators = pallet_governance::Allocators::<Runtime>::iter_keys()
44+
.filter(|allocator| allocator != &new_allocator)
45+
.collect::<Vec<_>>();
46+
47+
let old_agent = old_allocators
48+
.iter()
49+
.find_map(pallet_torus0::Agents::<Runtime>::get);
50+
51+
pallet_governance::Whitelist::<Runtime>::insert(&new_allocator, ());
52+
replace_allocators(&new_allocator);
53+
register_allocator(&new_allocator, old_agent.as_ref());
54+
transfer_allocator_stake(&old_allocators, &new_allocator);
55+
56+
for old_allocator in old_allocators {
57+
let _ = pallet_torus0::agent::deregister::<Runtime>(old_allocator);
58+
}
59+
}
60+
61+
fn register_allocator(new_allocator: &AccountId, old_agent: Option<&Agent>) {
62+
if pallet_torus0::Agents::<Runtime>::contains_key(new_allocator) {
63+
return;
64+
}
65+
66+
if let Some(old_agent) = old_agent {
67+
fund_registration_burn(new_allocator);
68+
let _ = pallet_torus0::agent::register::<Runtime>(
69+
new_allocator.clone(),
70+
old_agent.name.to_vec(),
71+
old_agent.url.to_vec(),
72+
old_agent.metadata.to_vec(),
73+
);
74+
}
75+
}
76+
77+
fn replace_allocators(new_allocator: &AccountId) {
78+
let _ = pallet_governance::Allocators::<Runtime>::clear(u32::MAX, None);
79+
pallet_governance::Allocators::<Runtime>::insert(new_allocator, ());
80+
}
81+
82+
fn fund_registration_burn(new_allocator: &AccountId) {
83+
let _ = <Runtime as pallet_torus0::Config>::Currency::transfer(
84+
&pallet_governance::DaoTreasuryAddress::<Runtime>::get(),
85+
new_allocator,
86+
pallet_torus0::Burn::<Runtime>::get(),
87+
ExistenceRequirement::AllowDeath,
88+
);
89+
}
90+
91+
fn transfer_allocator_stake(old_allocators: &[AccountId], new_allocator: &AccountId) {
92+
if !pallet_torus0::Agents::<Runtime>::contains_key(new_allocator) {
93+
return;
94+
}
95+
96+
let stakes = pallet_torus0::StakingTo::<Runtime>::iter()
97+
.filter(|(_, staked, _)| old_allocators.contains(staked))
98+
.collect::<Vec<_>>();
99+
100+
for (staker, old_allocator, amount) in stakes {
101+
let _ = pallet_torus0::stake::transfer_stake::<Runtime>(
102+
staker,
103+
old_allocator,
104+
new_allocator.clone(),
105+
amount,
106+
);
107+
}
108+
}

0 commit comments

Comments
 (0)