Newer
Older
para_id,
test_genesis_head(max_head_size() as usize),
test_validation_code(max_code_size() as usize),
),
Error::<Test>::NotOwner
);
assert_ok!(Registrar::register(
Shawn Tabrizi
committed
test_genesis_head(max_head_size() as usize),
test_validation_code(max_code_size() as usize),
// Can skip pre-check and deregister para which's still onboarding.
assert_ok!(Registrar::deregister(RuntimeOrigin::root(), para_id));
// Can't do it again
para_id,
test_genesis_head(max_head_size() as usize),
test_validation_code(max_code_size() as usize),
),
Error::<Test>::NotReserved
);
assert_ok!(Registrar::reserve(RuntimeOrigin::signed(2)));
para_id + 1,
test_genesis_head((max_head_size() + 1) as usize),
test_validation_code(max_code_size() as usize),
),
Error::<Test>::HeadDataTooLarge
);
para_id + 1,
test_genesis_head(max_head_size() as usize),
test_validation_code((max_code_size() + 1) as usize),
),
Error::<Test>::CodeTooLarge
);
// Needs enough funds for deposit
BalancesError::<Test, _>::InsufficientBalance
);
new_test_ext().execute_with(|| {
const START_SESSION_INDEX: SessionIndex = 1;
run_to_session(START_SESSION_INDEX);
let para_id = LOWEST_PUBLIC_ID;
assert!(!Parachains::is_parathread(para_id));
let validation_code = test_validation_code(32);
assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
validation_code.clone(),
conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
run_to_session(START_SESSION_INDEX + 2);
assert!(Parachains::is_parathread(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);
});
}
#[test]
fn deregister_handles_basic_errors() {
new_test_ext().execute_with(|| {
const START_SESSION_INDEX: SessionIndex = 1;
run_to_session(START_SESSION_INDEX);
let para_id = LOWEST_PUBLIC_ID;
assert!(!Parachains::is_parathread(para_id));
let validation_code = test_validation_code(32);
assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
validation_code.clone(),
conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
run_to_session(START_SESSION_INDEX + 2);
assert!(Parachains::is_parathread(para_id));
// Owner check
assert_noop!(Registrar::deregister(RuntimeOrigin::signed(2), para_id,), BadOrigin);
assert_ok!(Registrar::make_parachain(para_id));
run_to_session(START_SESSION_INDEX + 4);
// Cant directly deregister parachain
Registrar::deregister(RuntimeOrigin::root(), para_id,),
#[test]
fn swap_works() {
new_test_ext().execute_with(|| {
const START_SESSION_INDEX: SessionIndex = 1;
run_to_session(START_SESSION_INDEX);
// Successfully register first two parachains
let para_1 = LOWEST_PUBLIC_ID;
let para_2 = LOWEST_PUBLIC_ID + 1;
let validation_code = test_validation_code(max_code_size() as usize);
assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
Shawn Tabrizi
committed
test_genesis_head(max_head_size() as usize),
validation_code.clone(),
assert_ok!(Registrar::reserve(RuntimeOrigin::signed(2)));
Shawn Tabrizi
committed
test_genesis_head(max_head_size() as usize),
validation_code.clone(),
conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
run_to_session(START_SESSION_INDEX + 2);
// Upgrade para 1 into a parachain
assert_ok!(Registrar::make_parachain(para_1));
// Set some mock swap data.
let mut swap_data = SwapData::get();
swap_data.insert(para_1, 69);
swap_data.insert(para_2, 1337);
SwapData::set(swap_data);
run_to_session(START_SESSION_INDEX + 4);
assert!(Parachains::is_parachain(para_1));
assert!(!Parachains::is_parathread(para_1));
assert!(!Parachains::is_parachain(para_2));
assert!(Parachains::is_parathread(para_2));
// Swap between parachain and parathread
assert_ok!(Registrar::swap(para_origin(para_1), para_1, para_2,));
assert_ok!(Registrar::swap(para_origin(para_2), para_2, para_1,));
System::assert_last_event(RuntimeEvent::Registrar(paras_registrar::Event::Swapped {
para_id: para_2,
other_id: para_1,
}));
run_to_session(START_SESSION_INDEX + 6);
assert!(!Parachains::is_parachain(para_1));
assert!(Parachains::is_parathread(para_1));
assert!(Parachains::is_parachain(para_2));
assert!(!Parachains::is_parathread(para_2));
// Data is swapped
assert_eq!(SwapData::get().get(¶_1).unwrap(), &1337);
assert_eq!(SwapData::get().get(¶_2).unwrap(), &69);
// Both paras initiate a swap
// Swap between parathread and parachain
assert_ok!(Registrar::swap(para_origin(para_1), para_1, para_2,));
assert_ok!(Registrar::swap(para_origin(para_2), para_2, para_1,));
System::assert_last_event(RuntimeEvent::Registrar(paras_registrar::Event::Swapped {
para_id: para_2,
other_id: para_1,
}));
// Data is swapped
assert_eq!(SwapData::get().get(¶_1).unwrap(), &69);
assert_eq!(SwapData::get().get(¶_2).unwrap(), &1337);
// Parachain to parachain swap
let para_3 = LOWEST_PUBLIC_ID + 2;
let validation_code = test_validation_code(max_code_size() as usize);
assert_ok!(Registrar::reserve(RuntimeOrigin::signed(3)));
assert_ok!(Registrar::register(
RuntimeOrigin::signed(3),
para_3,
test_genesis_head(max_head_size() as usize),
validation_code.clone(),
conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX + 6);
run_to_session(START_SESSION_INDEX + 8);
// Upgrade para 3 into a parachain
assert_ok!(Registrar::make_parachain(para_3));
// Set some mock swap data.
let mut swap_data = SwapData::get();
swap_data.insert(para_3, 777);
SwapData::set(swap_data);
run_to_session(START_SESSION_INDEX + 10);
// Both are parachains
assert!(Parachains::is_parachain(para_3));
assert!(!Parachains::is_parathread(para_3));
assert!(Parachains::is_parachain(para_1));
assert!(!Parachains::is_parathread(para_1));
// Both paras initiate a swap
// Swap between parachain and parachain
assert_ok!(Registrar::swap(para_origin(para_1), para_1, para_3,));
assert_ok!(Registrar::swap(para_origin(para_3), para_3, para_1,));
System::assert_last_event(RuntimeEvent::Registrar(paras_registrar::Event::Swapped {
para_id: para_3,
other_id: para_1,
}));
// Data is swapped
assert_eq!(SwapData::get().get(¶_3).unwrap(), &69);
assert_eq!(SwapData::get().get(¶_1).unwrap(), &777);
#[test]
fn para_lock_works() {
new_test_ext().execute_with(|| {
run_to_block(1);
assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
let para_id = LOWEST_PUBLIC_ID;
assert_ok!(Registrar::register(
vec![1; 3].into(),
));
assert_noop!(Registrar::add_lock(RuntimeOrigin::signed(2), para_id), BadOrigin);
// Once they begin onboarding, we lock them in.
assert_ok!(Registrar::add_lock(RuntimeOrigin::signed(1), para_id));
// Owner cannot pass origin check when checking lock
Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id),
// Owner cannot remove lock.
assert_noop!(Registrar::remove_lock(RuntimeOrigin::signed(1), para_id), BadOrigin);
// Para can.
assert_ok!(Registrar::remove_lock(para_origin(para_id), para_id));
// Owner can pass origin check again
assert_ok!(Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id));
});
}
#[test]
fn swap_handles_bad_states() {
new_test_ext().execute_with(|| {
const START_SESSION_INDEX: SessionIndex = 1;
run_to_session(START_SESSION_INDEX);
let para_1 = LOWEST_PUBLIC_ID;
let para_2 = LOWEST_PUBLIC_ID + 1;
// paras are not yet registered
assert!(!Parachains::is_parathread(para_1));
assert!(!Parachains::is_parathread(para_2));
// Cannot even start a swap
assert_noop!(
Registrar::swap(RuntimeOrigin::root(), para_1, para_2),
Error::<Test>::NotRegistered
);
// We register Paras 1 and 2
let validation_code = test_validation_code(32);
assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
assert_ok!(Registrar::reserve(RuntimeOrigin::signed(2)));
para_1,
test_genesis_head(32),
validation_code.clone(),
));
assert_ok!(Registrar::register(
para_2,
test_genesis_head(32),
validation_code.clone(),
conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
Registrar::swap(RuntimeOrigin::root(), para_2, para_1),
Error::<Test>::CannotSwap
);
run_to_session(START_SESSION_INDEX + 2);
// They are now a parathread.
assert!(Parachains::is_parathread(para_1));
assert!(Parachains::is_parathread(para_2));
// Cannot swap
assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
Registrar::swap(RuntimeOrigin::root(), para_2, para_1),
Error::<Test>::CannotSwap
);
// Some other external process will elevate one parathread to parachain
assert_ok!(Registrar::make_parachain(para_1));
// Cannot swap
assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
Registrar::swap(RuntimeOrigin::root(), para_2, para_1),
Error::<Test>::CannotSwap
);
run_to_session(START_SESSION_INDEX + 3);
assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
Registrar::swap(RuntimeOrigin::root(), para_2, para_1),
Error::<Test>::CannotSwap
);
run_to_session(START_SESSION_INDEX + 4);
// It is now a parachain.
assert!(Parachains::is_parachain(para_1));
assert!(Parachains::is_parathread(para_2));
// Swap works here.
assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_2, para_1));
assert!(System::events().iter().any(|r| matches!(
r.event,
RuntimeEvent::Registrar(paras_registrar::Event::Swapped { .. })
)));
run_to_session(START_SESSION_INDEX + 5);
assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
Registrar::swap(RuntimeOrigin::root(), para_2, para_1),
Error::<Test>::CannotSwap
);
run_to_session(START_SESSION_INDEX + 6);
// Swap worked!
assert!(Parachains::is_parachain(para_2));
assert!(Parachains::is_parathread(para_1));
assert!(System::events().iter().any(|r| matches!(
r.event,
RuntimeEvent::Registrar(paras_registrar::Event::Swapped { .. })
)));
// Something starts to downgrade a para
assert_ok!(Registrar::make_parathread(para_2));
run_to_session(START_SESSION_INDEX + 7);
assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
Registrar::swap(RuntimeOrigin::root(), para_2, para_1),
Error::<Test>::CannotSwap
);
run_to_session(START_SESSION_INDEX + 8);
assert!(Parachains::is_parathread(para_1));
assert!(Parachains::is_parathread(para_2));
});
}
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking {
use super::{Pallet as Registrar, *};
use crate::traits::Registrar as RegistrarT;
use primitives::{MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE};
use runtime_parachains::{paras, shared, Origin as ParaOrigin};
use frame_benchmarking::{account, benchmarks, whitelisted_caller};
fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
Shaun Wang
committed
let events = frame_system::Pallet::<T>::events();
let system_event: <T as frame_system::Config>::RuntimeEvent = generic_event.into();
// compare to the last event record
let frame_system::EventRecord { event, .. } = &events[events.len() - 1];
assert_eq!(event, &system_event);
}
fn register_para<T: Config>(id: u32) -> ParaId {
let para = ParaId::from(id);
let genesis_head = Registrar::<T>::worst_head_data();
let validation_code = Registrar::<T>::worst_validation_code();
let caller: T::AccountId = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
assert_ok!(Registrar::<T>::reserve(RawOrigin::Signed(caller.clone()).into()));
assert_ok!(Registrar::<T>::register(
RawOrigin::Signed(caller).into(),
para,
genesis_head,
validation_code.clone()
));
assert_ok!(runtime_parachains::paras::Pallet::<T>::add_trusted_validation_code(
frame_system::Origin::<T>::Root.into(),
validation_code,
}
fn para_origin(id: u32) -> ParaOrigin {
ParaOrigin::Parachain(id.into())
}
// This function moves forward to the next scheduled session for parachain lifecycle upgrades.
fn next_scheduled_session<T: Config>() {
shared::Pallet::<T>::set_session_index(shared::Pallet::<T>::scheduled_session());
paras::Pallet::<T>::test_on_new_session();
where_clause { where ParaOrigin: Into<<T as frame_system::Config>::RuntimeOrigin> }
reserve {
let caller: T::AccountId = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
}: _(RawOrigin::Signed(caller.clone()))
verify {
assert_last_event::<T>(Event::<T>::Reserved { para_id: LOWEST_PUBLIC_ID, who: caller }.into());
assert!(Paras::<T>::get(LOWEST_PUBLIC_ID).is_some());
assert_eq!(paras::Pallet::<T>::lifecycle(LOWEST_PUBLIC_ID), None);
let para = LOWEST_PUBLIC_ID;
let genesis_head = Registrar::<T>::worst_head_data();
let validation_code = Registrar::<T>::worst_validation_code();
let caller: T::AccountId = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
assert_ok!(Registrar::<T>::reserve(RawOrigin::Signed(caller.clone()).into()));
}: _(RawOrigin::Signed(caller.clone()), para, genesis_head, validation_code.clone())
assert_last_event::<T>(Event::<T>::Registered{ para_id: para, manager: caller }.into());
assert_eq!(paras::Pallet::<T>::lifecycle(para), Some(ParaLifecycle::Onboarding));
assert_ok!(runtime_parachains::paras::Pallet::<T>::add_trusted_validation_code(
frame_system::Origin::<T>::Root.into(),
validation_code,
));
assert_eq!(paras::Pallet::<T>::lifecycle(para), Some(ParaLifecycle::Parathread));
force_register {
let manager: T::AccountId = account("manager", 0, 0);
let deposit = 0u32.into();
let para = ParaId::from(69);
let genesis_head = Registrar::<T>::worst_head_data();
let validation_code = Registrar::<T>::worst_validation_code();
}: _(RawOrigin::Root, manager.clone(), deposit, para, genesis_head, validation_code.clone())
assert_last_event::<T>(Event::<T>::Registered { para_id: para, manager }.into());
assert_eq!(paras::Pallet::<T>::lifecycle(para), Some(ParaLifecycle::Onboarding));
assert_ok!(runtime_parachains::paras::Pallet::<T>::add_trusted_validation_code(
frame_system::Origin::<T>::Root.into(),
validation_code,
));
next_scheduled_session::<T>();
assert_eq!(paras::Pallet::<T>::lifecycle(para), Some(ParaLifecycle::Parathread));
let para = register_para::<T>(LOWEST_PUBLIC_ID.into());
let caller: T::AccountId = whitelisted_caller();
}: _(RawOrigin::Signed(caller), para)
assert_last_event::<T>(Event::<T>::Deregistered { para_id: para }.into());
let parathread = register_para::<T>(LOWEST_PUBLIC_ID.into());
let parachain = register_para::<T>((LOWEST_PUBLIC_ID + 1).into());
let parachain_origin = para_origin(parachain.into());
// Actually finish registration process
next_scheduled_session::<T>();
// Upgrade the parachain
Registrar::<T>::make_parachain(parachain)?;
next_scheduled_session::<T>();
assert_eq!(paras::Pallet::<T>::lifecycle(parachain), Some(ParaLifecycle::Parachain));
assert_eq!(paras::Pallet::<T>::lifecycle(parathread), Some(ParaLifecycle::Parathread));
let caller: T::AccountId = whitelisted_caller();
Registrar::<T>::swap(parachain_origin.into(), parachain, parathread)?;
}: _(RawOrigin::Signed(caller.clone()), parathread, parachain)
verify {
next_scheduled_session::<T>();
// Swapped!
assert_eq!(paras::Pallet::<T>::lifecycle(parachain), Some(ParaLifecycle::Parathread));
assert_eq!(paras::Pallet::<T>::lifecycle(parathread), Some(ParaLifecycle::Parachain));
schedule_code_upgrade {
let b in 1 .. MAX_CODE_SIZE;
let new_code = ValidationCode(vec![0; b as usize]);
let para_id = ParaId::from(1000);
}: _(RawOrigin::Root, para_id, new_code)
set_current_head {
let b in 1 .. MAX_HEAD_DATA_SIZE;
let new_head = HeadData(vec![0; b as usize]);
let para_id = ParaId::from(1000);
}: _(RawOrigin::Root, para_id, new_head)
impl_benchmark_test_suite!(
Registrar,
crate::integration_tests::new_test_ext(),
crate::integration_tests::Test,
);
}