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

Implementations to allow easier unbricking of parachains #5429

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions polkadot/runtime/common/src/assigned_slots/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,8 @@ mod tests {
type NextSessionRotation = crate::mock::TestNextSessionRotation;
type OnNewHead = ();
type AssignCoretime = ();
type UnbrickOrigin = EnsureRoot<Self::AccountId>;
type MinTimeToAllowUnbrick = ConstU32<5>;
}

impl parachains_shared::Config for Test {
Expand Down
2 changes: 2 additions & 0 deletions polkadot/runtime/common/src/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ impl paras::Config for Test {
type NextSessionRotation = crate::mock::TestNextSessionRotation;
type OnNewHead = ();
type AssignCoretime = ();
type UnbrickOrigin = EnsureRoot<AccountId>;
type MinTimeToAllowUnbrick = ConstU32<5>;
}

parameter_types! {
Expand Down
8 changes: 5 additions & 3 deletions polkadot/runtime/common/src/paras_registrar/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ mod tests {
assert_noop, assert_ok, derive_impl, parameter_types,
traits::{OnFinalize, OnInitialize},
};
use frame_system::limits;
use frame_system::{limits, EnsureRoot};
use pallet_balances::Error as BalancesError;
use polkadot_primitives::{Balance, BlockNumber, SessionIndex, MAX_CODE_SIZE};
use polkadot_runtime_parachains::{configuration, origin, shared};
Expand Down Expand Up @@ -823,6 +823,8 @@ mod tests {
type NextSessionRotation = crate::mock::TestNextSessionRotation;
type OnNewHead = ();
type AssignCoretime = ();
type UnbrickOrigin = EnsureRoot<Self::AccountId>;
type MinTimeToAllowUnbrick = frame_support::traits::ConstU32<5>;
}

impl configuration::Config for Test {
Expand Down Expand Up @@ -989,7 +991,7 @@ mod tests {
assert!(Parachains::is_parathread(para_id));
assert!(!Parachains::is_parachain(para_id));
// Deregister it
assert_ok!(Registrar::deregister(RuntimeOrigin::root(), para_id,));
assert_ok!(Registrar::deregister(RuntimeOrigin::root(), para_id));
run_to_session(START_SESSION_INDEX + 8);
// It is nothing
assert!(!Parachains::is_parathread(para_id));
Expand Down Expand Up @@ -1180,7 +1182,7 @@ mod tests {

run_to_session(START_SESSION_INDEX + 2);
assert!(Parachains::is_parathread(para_id));
assert_ok!(Registrar::deregister(RuntimeOrigin::root(), para_id,));
assert_ok!(Registrar::deregister(RuntimeOrigin::root(), para_id));
run_to_session(START_SESSION_INDEX + 4);
assert!(paras::Pallet::<Test>::lifecycle(para_id).is_none());
assert_eq!(Balances::reserved_balance(&1), 0);
Expand Down
10 changes: 8 additions & 2 deletions polkadot/runtime/parachains/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ use polkadot_primitives::CoreIndex;

use codec::Decode;
use frame_support::{
assert_ok, derive_impl, parameter_types,
assert_ok, derive_impl, ord_parameter_types, parameter_types,
traits::{
Currency, ProcessMessage, ProcessMessageError, ValidatorSet, ValidatorSetWithIdentification,
},
weights::{Weight, WeightMeter},
PalletId,
};
use frame_support_test::TestRandomness;
use frame_system::limits;
use frame_system::{limits, EnsureSignedBy};
use polkadot_primitives::{
AuthorityDiscoveryId, Balance, BlockNumber, CandidateHash, Moment, SessionIndex, UpwardMessage,
ValidationCode, ValidatorIndex,
Expand Down Expand Up @@ -229,6 +229,10 @@ impl frame_support::traits::EstimateNextSessionRotation<u32> for TestNextSession
}
}

ord_parameter_types! {
pub const One: u64 = 1;
}

impl crate::paras::Config for Test {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = crate::paras::TestWeightInfo;
Expand All @@ -237,6 +241,8 @@ impl crate::paras::Config for Test {
type NextSessionRotation = TestNextSessionRotation;
type OnNewHead = ();
type AssignCoretime = ();
type UnbrickOrigin = EnsureSignedBy<One, AccountId>;
type MinTimeToAllowUnbrick = ConstU32<5>;
}

impl crate::dmp::Config for Test {}
Expand Down
51 changes: 51 additions & 0 deletions polkadot/runtime/parachains/src/paras/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ pub trait WeightInfo {
fn force_queue_action() -> Weight;
fn add_trusted_validation_code(c: u32) -> Weight;
fn poke_unused_validation_code() -> Weight;
fn unbrick() -> Weight;

fn include_pvf_check_statement_finalize_upgrade_accept() -> Weight;
fn include_pvf_check_statement_finalize_upgrade_reject() -> Weight;
Expand Down Expand Up @@ -596,6 +597,10 @@ impl WeightInfo for TestWeightInfo {
// This special value is to distinguish from the finalizing variants above in tests.
Weight::MAX - Weight::from_parts(1, 1)
}
fn unbrick() -> Weight {
// This special value is to distinguish from the finalizing variants above in tests.
Weight::MAX - Weight::from_parts(1, 1)
}
}

#[frame_support::pallet]
Expand Down Expand Up @@ -642,6 +647,13 @@ pub mod pallet {
///
/// TODO: Remove once coretime is the standard across all chains.
type AssignCoretime: AssignCoretime;

/// A valid origin able to call the `unbrick` method.
type UnbrickOrigin: EnsureOrigin<Self::RuntimeOrigin>;

/// The minimum time (in blocks) that needs to have passed since the
/// last head update to allow unbricking a parachain.
type MinTimeToAllowUnbrick: Get<BlockNumberFor<Self>>;
}

#[pallet::event]
Expand Down Expand Up @@ -696,6 +708,8 @@ pub mod pallet {
CannotUpgradeCode,
/// Invalid validation code size.
InvalidCode,
/// Para cannot be considered as bricked
ParaNotBricked,
}

/// All currently active PVF pre-checking votes.
Expand Down Expand Up @@ -1149,6 +1163,43 @@ pub mod pallet {
MostRecentContext::<T>::insert(&para, context);
Ok(())
}

/// Allows a given origin to update the head and validation code for a para
/// if certain time has elapsed since last noted head.
#[pallet::call_index(9)]
#[pallet::weight(<T as Config>::WeightInfo::force_set_most_recent_context())]
pub fn unbrick(
origin: OriginFor<T>,
para: ParaId,
maybe_new_code: Option<ValidationCode>,
maybe_new_head: Option<HeadData>,
) -> DispatchResult {
T::UnbrickOrigin::ensure_origin(origin)?;
ensure!(
frame_system::Pallet::<T>::block_number() -
MostRecentContext::<T>::get(para)
.unwrap_or(frame_system::Pallet::<T>::block_number()) >
T::MinTimeToAllowUnbrick::get(),
Error::<T>::ParaNotBricked
);

if let Some(new_code) = maybe_new_code {
let new_code_hash = new_code.hash();
Self::increase_code_ref(&new_code_hash, &new_code);
Self::set_current_code(
para,
new_code_hash,
frame_system::Pallet::<T>::block_number(),
);
Self::deposit_event(Event::CurrentCodeUpdated(para));
}

if let Some(new_head) = maybe_new_head {
Self::set_current_head(para, new_head);
}

Ok(())
}
}

#[pallet::validate_unsigned]
Expand Down
100 changes: 99 additions & 1 deletion polkadot/runtime/parachains/src/paras/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

use super::*;
use frame_support::{assert_err, assert_ok, assert_storage_noop};
use frame_support::{assert_err, assert_noop, assert_ok, assert_storage_noop};
use polkadot_primitives::{vstaging::SchedulerParams, BlockNumber, PARACHAIN_KEY_TYPE_ID};
use polkadot_primitives_test_helpers::{dummy_head_data, dummy_validation_code, validator_pubkeys};
use sc_keystore::LocalKeystore;
Expand Down Expand Up @@ -2013,3 +2013,101 @@ fn parachains_cache_preserves_order() {
assert_eq!(Parachains::<Test>::get(), vec![a, c]);
});
}

fn setup_para_unbrick_tests(para_id: ParaId) -> sp_io::TestExternalities {
let validation_code = test_validation_code_1();

let genesis_config = MockGenesisConfig::default();

let mut t = new_test_ext(genesis_config);

t.execute_with(|| {
const EXPECTED_SESSION: SessionIndex = 1;
run_to_block(1, Some(vec![1]));

assert_ok!(Paras::schedule_para_initialize(
para_id,
ParaGenesisArgs {
para_kind: ParaKind::Parachain,
genesis_head: vec![1].into(),
validation_code: validation_code.clone(),
},
));
submit_super_majority_pvf_votes(&validation_code, EXPECTED_SESSION, true);

// Two sessions pass, so action queue is triggered.
run_to_block(4, Some(vec![3, 4]));

// Progress para to the new head and check that the recent context is updated.
Paras::note_new_head(para_id, vec![4, 5, 6].into(), 3);
});

t
}

#[test]
fn para_unbrick_fails_if_invalid_origin() {
let para_id = ParaId::from(111);

setup_para_unbrick_tests(para_id).execute_with(|| {
// Unbrick Fails
assert_noop!(
Paras::unbrick(RuntimeOrigin::signed(2), para_id, None, None),
DispatchError::BadOrigin
);
})
}

#[test]
fn para_unbrick_fails_if_minimum_time_not_met() {
let para_id = ParaId::from(111);

setup_para_unbrick_tests(para_id).execute_with(|| {
run_to_block(8, Some(vec![6]));

// Unbrick Fails
assert_noop!(
Paras::unbrick(RuntimeOrigin::signed(1), para_id, None, None),
paras::Error::<Test>::ParaNotBricked
);
})
}

#[test]
fn para_unbrick_works_updates_code() {
let para_id = ParaId::from(111);
let new_validation_code = test_validation_code_2();

setup_para_unbrick_tests(para_id).execute_with(|| {
run_to_block(9, Some(vec![9, 10]));

// Unbrick Fails
assert_ok!(Paras::unbrick(
RuntimeOrigin::signed(1),
para_id,
Some(new_validation_code),
None
));

System::assert_has_event(paras::Event::CurrentCodeUpdated(para_id).into());
})
}

#[test]
fn para_unbrick_works_notes_head() {
let para_id = ParaId::from(111);

setup_para_unbrick_tests(para_id).execute_with(|| {
run_to_block(9, Some(vec![9, 10]));

// Unbrick Fails
assert_ok!(Paras::unbrick(
RuntimeOrigin::signed(1),
para_id,
None,
Some(vec![7, 8, 9].into())
));

System::assert_has_event(paras::Event::CurrentHeadUpdated(para_id).into());
})
}
2 changes: 2 additions & 0 deletions polkadot/runtime/rococo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,8 @@ impl parachains_paras::Config for Runtime {
type NextSessionRotation = Babe;
type OnNewHead = Registrar;
type AssignCoretime = CoretimeAssignmentProvider;
type UnbrickOrigin = EnsureNever<()>;
type MinTimeToAllowUnbrick = ConstU32<{ 2 * HOURS }>;
}

parameter_types! {
Expand Down
3 changes: 3 additions & 0 deletions polkadot/runtime/test-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use alloc::{
vec::Vec,
};
use codec::Encode;
use frame_system::{EnsureNever, EnsureRoot};
use pallet_transaction_payment::FungibleAdapter;

use polkadot_runtime_parachains::{
Expand Down Expand Up @@ -550,6 +551,8 @@ impl parachains_paras::Config for Runtime {
type NextSessionRotation = Babe;
type OnNewHead = ();
type AssignCoretime = ();
type UnbrickOrigin = EnsureRoot<AccountId>;
type MinTimeToAllowUnbrick = ConstU64<{ 2 * HOURS }>;
}

parameter_types! {
Expand Down
13 changes: 8 additions & 5 deletions polkadot/runtime/westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ use frame_support::{
genesis_builder_helper::{build_state, get_preset},
parameter_types,
traits::{
fungible::HoldConsideration, tokens::UnityOrOuterConversion, ConstU32, Contains, EitherOf,
EitherOfDiverse, EnsureOriginWithArg, EverythingBut, FromContains, InstanceFilter,
KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage, ProcessMessageError,
VariantCountOf, WithdrawReasons,
fungible::HoldConsideration, tokens::UnityOrOuterConversion, ConstU32, ConstU64, Contains,
EitherOf, EitherOfDiverse, EnsureOriginWithArg, EverythingBut, FromContains,
InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage,
ProcessMessageError, VariantCountOf, WithdrawReasons,
},
weights::{ConstantMultiplier, WeightMeter, WeightToFee as _},
PalletId,
Expand Down Expand Up @@ -1109,7 +1109,8 @@ impl InstanceFilter<RuntimeCall> for ProxyType {
matches!(
c,
RuntimeCall::Staking(..) |
RuntimeCall::Session(..) | RuntimeCall::Utility(..) |
RuntimeCall::Session(..) |
RuntimeCall::Utility(..) |
RuntimeCall::FastUnstake(..) |
RuntimeCall::VoterList(..) |
RuntimeCall::NominationPools(..)
Expand Down Expand Up @@ -1209,6 +1210,8 @@ impl parachains_paras::Config for Runtime {
type NextSessionRotation = Babe;
type OnNewHead = ();
type AssignCoretime = CoretimeAssignmentProvider;
type UnbrickOrigin = EnsureRoot<AccountId>;
type MinTimeToAllowUnbrick = ConstU64<{ 2 * HOURS }>;
}

parameter_types! {
Expand Down
Loading