Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
6 changes: 4 additions & 2 deletions node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ use node_runtime::{
AuthorityDiscoveryConfig, BabeConfig, Balance, BalancesConfig, ContentWorkingGroupConfig,
CouncilConfig, CouncilElectionConfig, DataObjectStorageRegistryConfig,
DataObjectTypeRegistryConfig, ElectionParameters, GrandpaConfig, ImOnlineConfig, IndicesConfig,
MembersConfig, Perbill, ProposalsCodexConfig, SessionConfig, SessionKeys, Signature,
StakerStatus, StakingConfig, SudoConfig, SystemConfig, VersionedStoreConfig, DAYS, WASM_BINARY,
MembersConfig, MigrationConfig, Perbill, ProposalsCodexConfig, SessionConfig, SessionKeys,
Signature, StakerStatus, StakingConfig, SudoConfig, SystemConfig, VersionedStoreConfig, DAYS,
WASM_BINARY,
};
pub use node_runtime::{AccountId, GenesisConfig};
use primitives::{sr25519, Pair, Public};
Expand Down Expand Up @@ -297,6 +298,7 @@ pub fn testnet_genesis(
channel_banner_constraint: crate::forum_config::new_validation(5, 1024),
channel_title_constraint: crate::forum_config::new_validation(5, 1024),
}),
migration: Some(MigrationConfig {}),
proposals_codex: Some(ProposalsCodexConfig {
set_validator_count_proposal_voting_period: 43200u32,
set_validator_count_proposal_grace_period: 0u32,
Expand Down
35 changes: 34 additions & 1 deletion runtime-modules/content-working-group/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@ pub enum CuratorExitInitiationOrigin {

/// The curator exiting is the origin.
Curator,

/// The system is initiating exit of a curator
Root,
}

/// The exit stage of a curators involvement in the working group.
Expand Down Expand Up @@ -1887,7 +1890,7 @@ decl_module! {
origin,
curator_id: CuratorId<T>,
rationale_text: Vec<u8>
) {
) {

// Ensure lead is set and is origin signer
Self::ensure_origin_is_set_lead(origin)?;
Expand All @@ -1910,6 +1913,31 @@ decl_module! {
);
}

/// Lead can terminate and active curator
pub fn terminate_curator_role_as_root(
origin,
curator_id: CuratorId<T>,
rationale_text: Vec<u8>
) {

// Ensure origin is root
ensure_root(origin)?;

// Ensuring curator actually exists and is active
let curator = Self::ensure_active_curator_exists(&curator_id)?;

//
// == MUTATION SAFE ==
//

Self::deactivate_curator(
&curator_id,
&curator,
&CuratorExitInitiationOrigin::Root,
&rationale_text
);
}

/// Replace the current lead. First unsets the active lead if there is one.
/// If a value is provided for new_lead it will then set that new lead.
/// It is responsibility of the caller to ensure the new lead can be set
Expand Down Expand Up @@ -2669,6 +2697,7 @@ impl<T: Trait> Module<T> {
let unstaking_period = match curator_exit_summary.origin {
CuratorExitInitiationOrigin::Lead => stake_profile.termination_unstaking_period,
CuratorExitInitiationOrigin::Curator => stake_profile.exit_unstaking_period,
CuratorExitInitiationOrigin::Root => stake_profile.termination_unstaking_period,
};

(
Expand All @@ -2687,6 +2716,9 @@ impl<T: Trait> Module<T> {
CuratorExitInitiationOrigin::Curator => {
RawEvent::CuratorExited(curator_id.clone())
}
CuratorExitInitiationOrigin::Root => {
RawEvent::TerminatedCurator(curator_id.clone())
}
},
)
};
Expand Down Expand Up @@ -2837,6 +2869,7 @@ impl<T: Trait> Module<T> {
let event = match curator_exit_summary.origin {
CuratorExitInitiationOrigin::Lead => RawEvent::TerminatedCurator(curator_id),
CuratorExitInitiationOrigin::Curator => RawEvent::CuratorExited(curator_id),
CuratorExitInitiationOrigin::Root => RawEvent::TerminatedCurator(curator_id),
};

Self::deposit_event(event);
Expand Down
24 changes: 24 additions & 0 deletions runtime-modules/governance/src/election.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,30 @@ impl<T: Trait> Module<T> {
}
}

pub fn stop_election_and_dissolve_council() -> Result {
// Stop running election
if Self::is_election_running() {
// cannot fail since we checked that election is running and we are using root
// origin.
Self::force_stop_election(system::RawOrigin::Root.into())?;
}

// Return stakes from the council seat to their stake holders
Self::initialize_transferable_stakes(<council::Module<T>>::active_council());
Self::unlock_transferable_stakes();
Self::clear_transferable_stakes();

// Clear the council seats
// Cannot fail when passing root origin
council::Module::<T>::set_council(system::RawOrigin::Root.into(), vec![])?;
council::TermEndsAt::<T>::put(system::Module::<T>::block_number());

// Start a new election after clearing the council
Self::start_election(vec![])?;

Ok(())
}

// PRIVATE MUTABLES

/// Starts an election. Will fail if an election is already running
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -892,12 +892,12 @@ construct_runtime!(
RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage},
Sudo: sudo,
// Joystream
Migration: migration::{Module, Call, Storage, Event<T>, Config},
CouncilElection: election::{Module, Call, Storage, Event<T>, Config<T>},
Council: council::{Module, Call, Storage, Event<T>, Config<T>},
Memo: memo::{Module, Call, Storage, Event<T>},
Members: members::{Module, Call, Storage, Event<T>, Config<T>},
Forum: forum::{Module, Call, Storage, Event<T>, Config<T>},
Migration: migration::{Module, Call, Storage, Event<T>},
Actors: actors::{Module, Call, Storage, Event<T>, Config},
DataObjectTypeRegistry: data_object_type_registry::{Module, Call, Storage, Event<T>, Config<T>},
DataDirectory: data_directory::{Module, Call, Storage, Event<T>},
Expand Down
159 changes: 135 additions & 24 deletions runtime/src/migration.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,153 @@
use crate::VERSION;
use common::currency::BalanceOf;
use rstd::prelude::*;
use sr_primitives::{print, traits::Zero};
use srml_support::{decl_event, decl_module, decl_storage};
use sudo;
use srml_support::{debug, decl_event, decl_module, decl_storage};
use system;

impl<T: Trait> Module<T> {
/// This method is called from on_initialize() when a runtime upgrade is detected. This
/// happens when the runtime spec version is found to be higher than the stored value.
/// Important to note this method should be carefully maintained, because it runs on every runtime
/// upgrade.
fn runtime_upgraded() {
print("running runtime initializers...");
print("Running runtime upgraded handler");

// ...
// add initialization of modules introduced in new runtime release. This
// Add initialization of modules introduced in new runtime release. Typically this
// would be any new storage values that need an initial value which would not
// have been initialized with config() or build() mechanism.
// ...
// have been initialized with config() or build() chainspec construction mechanism.
// Other tasks like resetting values, migrating values etc.

// Runtime Upgrade Code for going from Rome to Constantinople

// Create the Council mint. If it fails, we can't do anything about it here.
let _ = governance::council::Module::<T>::create_new_council_mint(
governance::council::Module::<T>::create_new_council_mint(minting::BalanceOf::<T>::zero())
.err()
.map(|err| {
debug::warn!(
"Failed to create a mint for council during migration: {:?}",
err
);
});

// Reset Council
governance::election::Module::<T>::stop_election_and_dissolve_council()
.err()
.map(|err| {
debug::warn!("Failed to dissolve council during migration: {:?}", err);
});

// Reset working group mint capacity
content_working_group::Module::<T>::set_mint_capacity(
system::RawOrigin::Root.into(),
minting::BalanceOf::<T>::zero(),
);
)
.err()
.map(|err| {
debug::warn!(
"Failed to reset mint for working group during migration: {:?}",
err
);
});

// Deactivate active curators
let termination_reason = "resetting curators".as_bytes().to_vec();

for (curator_id, ref curator) in content_working_group::CuratorById::<T>::enumerate() {
// Skip non-active curators
if curator.stage != content_working_group::CuratorRoleStage::Active {
continue;
}

content_working_group::Module::<T>::terminate_curator_role_as_root(
system::RawOrigin::Root.into(),
curator_id,
termination_reason.clone(),
)
.err()
.map(|err| {
debug::warn!(
"Failed to terminate curator {:?} during migration: {:?}",
curator_id,
err
);
});
}

Self::deposit_event(RawEvent::Migrated(
<system::Module<T>>::block_number(),
VERSION.spec_version,
));
// Deactivate all storage providers, except Joystream providers (member id 0 in Rome runtime)
let joystream_providers =
roles::actors::AccountIdsByMemberId::<T>::get(T::MemberId::from(0));

// Is there an intersect() like call to check if vector contains some elements from
// another vector?.. below implementation just seems
// silly to have to do in a filter predicate.
let storage_providers_to_remove: Vec<T::AccountId> =
roles::actors::Module::<T>::actor_account_ids()
.into_iter()
.filter(|account| {
for provider in joystream_providers.as_slice() {
if *account == *provider {
return false;
}
}
return true;
})
.collect();

for provider in storage_providers_to_remove {
roles::actors::Module::<T>::remove_actor(system::RawOrigin::Root.into(), provider)
.err()
.map(|err| {
debug::warn!(
"Failed to remove storage provider during migration: {:?}",
err
);
});
}

// Remove any pending storage entry requests, no stake is lost because only a fee is paid
// to make a request.
let no_requests: roles::actors::Requests<T> = vec![];
roles::actors::RoleEntryRequests::<T>::put(no_requests);

// Set Storage Role reward to zero
if let Some(parameters) =
roles::actors::Parameters::<T>::get(roles::actors::Role::StorageProvider)
{
roles::actors::Module::<T>::set_role_parameters(
system::RawOrigin::Root.into(),
roles::actors::Role::StorageProvider,
roles::actors::RoleParameters {
reward: BalanceOf::<T>::zero(),
..parameters
},
)
.err()
.map(|err| {
debug::warn!(
"Failed to set zero reward for storage role during migration: {:?}",
err
);
});
}
}
}

pub trait Trait:
system::Trait
+ storage::data_directory::Trait
+ storage::data_object_storage_registry::Trait
+ forum::Trait
+ sudo::Trait
+ governance::council::Trait
system::Trait + governance::election::Trait + content_working_group::Trait + roles::actors::Trait
{
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}

decl_storage! {
trait Store for Module<T: Trait> as Migration {
/// Records at what runtime spec version the store was initialized. This allows the runtime
/// to know when to run initialize code if it was installed as an update.
pub SpecVersion get(spec_version) build(|_| VERSION.spec_version) : Option<u32>;
/// Records at what runtime spec version the store was initialized. At genesis this will be
/// initialized to Some(VERSION.spec_version). It is an Option because the first time the module
/// was introduced was as a runtime upgrade and type was never changed.
/// When the runtime is upgraded the spec version be updated.
pub SpecVersion get(spec_version) build(|_config: &GenesisConfig| {
VERSION.spec_version
}) : Option<u32>;
}
}

Expand All @@ -57,11 +163,16 @@ decl_module! {

fn on_initialize(_now: T::BlockNumber) {
if Self::spec_version().map_or(true, |spec_version| VERSION.spec_version > spec_version) {
// mark store version with current version of the runtime
// Mark store version with current version of the runtime
SpecVersion::put(VERSION.spec_version);

// run migrations and store initializers
// Run migrations and store initializers
Self::runtime_upgraded();

Self::deposit_event(RawEvent::Migrated(
<system::Module<T>>::block_number(),
VERSION.spec_version,
));
}
}
}
Expand Down