Validate code when scheduling uprades from registrar (#3232)

Currently, anyone can registrar a code that exceeds the code size limit
when performing the upgrade from the registrar. This PR fixes that and
adds a new test to cover this.

cc @bkchr @eskimor
This commit is contained in:
Sergej Sakac
2024-02-14 18:00:03 +01:00
committed by GitHub
parent 7ec692d11c
commit 7e7c488ba8
11 changed files with 146 additions and 61 deletions
+2 -2
View File
@@ -57,8 +57,8 @@ pub use v6::{
UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode, UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode,
ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation,
ValidityError, ASSIGNMENT_KEY_TYPE_ID, LEGACY_MIN_BACKING_VOTES, LOWEST_PUBLIC_ID, ValidityError, ASSIGNMENT_KEY_TYPE_ID, LEGACY_MIN_BACKING_VOTES, LOWEST_PUBLIC_ID,
MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, MIN_CODE_SIZE,
PARACHAINS_INHERENT_IDENTIFIER, PARACHAIN_KEY_TYPE_ID, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, PARACHAINS_INHERENT_IDENTIFIER, PARACHAIN_KEY_TYPE_ID,
}; };
#[cfg(feature = "std")] #[cfg(feature = "std")]
+3
View File
@@ -362,6 +362,9 @@ pub const PARACHAINS_INHERENT_IDENTIFIER: InherentIdentifier = *b"parachn0";
/// The key type ID for parachain assignment key. /// The key type ID for parachain assignment key.
pub const ASSIGNMENT_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"asgn"); pub const ASSIGNMENT_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"asgn");
/// Compressed or not the wasm blob can never be less than 9 bytes.
pub const MIN_CODE_SIZE: u32 = 9;
/// Maximum compressed code size we support right now. /// Maximum compressed code size we support right now.
/// At the moment we have runtime upgrade on chain, which restricts scalability severely. If we want /// At the moment we have runtime upgrade on chain, which restricts scalability severely. If we want
/// to have bigger values, we should fix that first. /// to have bigger values, we should fix that first.
+1 -1
View File
@@ -126,7 +126,7 @@ pub fn dummy_candidate_descriptor<H: AsRef<[u8]>>(relay_parent: H) -> CandidateD
/// Create meaningless validation code. /// Create meaningless validation code.
pub fn dummy_validation_code() -> ValidationCode { pub fn dummy_validation_code() -> ValidationCode {
ValidationCode(vec![1, 2, 3]) ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9])
} }
/// Create meaningless head data. /// Create meaningless head data.
@@ -36,6 +36,7 @@ use pallet_identity::{self, legacy::IdentityInfo};
use parity_scale_codec::Encode; use parity_scale_codec::Encode;
use primitives::{ use primitives::{
BlockNumber, HeadData, Id as ParaId, SessionIndex, ValidationCode, LOWEST_PUBLIC_ID, BlockNumber, HeadData, Id as ParaId, SessionIndex, ValidationCode, LOWEST_PUBLIC_ID,
MAX_CODE_SIZE,
}; };
use runtime_parachains::{ use runtime_parachains::{
configuration, origin, paras, shared, Origin as ParaOrigin, ParaLifecycle, configuration, origin, paras, shared, Origin as ParaOrigin, ParaLifecycle,
@@ -315,7 +316,7 @@ pub fn new_test_ext() -> TestExternalities {
let mut t = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap(); let mut t = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
configuration::GenesisConfig::<Test> { configuration::GenesisConfig::<Test> {
config: configuration::HostConfiguration { config: configuration::HostConfiguration {
max_code_size: 2 * 1024 * 1024, // 2 MB max_code_size: MAX_CODE_SIZE,
max_head_data_size: 1 * 1024 * 1024, // 1 MB max_head_data_size: 1 * 1024 * 1024, // 1 MB
..Default::default() ..Default::default()
}, },
@@ -26,7 +26,7 @@ use frame_support::{
traits::{Currency, Get, ReservableCurrency}, traits::{Currency, Get, ReservableCurrency},
}; };
use frame_system::{self, ensure_root, ensure_signed}; use frame_system::{self, ensure_root, ensure_signed};
use primitives::{HeadData, Id as ParaId, ValidationCode, LOWEST_PUBLIC_ID}; use primitives::{HeadData, Id as ParaId, ValidationCode, LOWEST_PUBLIC_ID, MIN_CODE_SIZE};
use runtime_parachains::{ use runtime_parachains::{
configuration, ensure_parachain, configuration, ensure_parachain,
paras::{self, ParaGenesisArgs, SetGoAhead}, paras::{self, ParaGenesisArgs, SetGoAhead},
@@ -182,8 +182,8 @@ pub mod pallet {
ParaLocked, ParaLocked,
/// The ID given for registration has not been reserved. /// The ID given for registration has not been reserved.
NotReserved, NotReserved,
/// Registering parachain with empty code is not allowed. /// The validation code is invalid.
EmptyCode, InvalidCode,
/// Cannot perform a parachain slot / lifecycle swap. Check that the state of both paras /// Cannot perform a parachain slot / lifecycle swap. Check that the state of both paras
/// are correct for the swap to work. /// are correct for the swap to work.
CannotSwap, CannotSwap,
@@ -657,7 +657,7 @@ impl<T: Config> Pallet<T> {
para_kind: ParaKind, para_kind: ParaKind,
) -> Result<(ParaGenesisArgs, BalanceOf<T>), sp_runtime::DispatchError> { ) -> Result<(ParaGenesisArgs, BalanceOf<T>), sp_runtime::DispatchError> {
let config = configuration::Pallet::<T>::config(); let config = configuration::Pallet::<T>::config();
ensure!(validation_code.0.len() > 0, Error::<T>::EmptyCode); ensure!(validation_code.0.len() >= MIN_CODE_SIZE as usize, Error::<T>::InvalidCode);
ensure!(validation_code.0.len() <= config.max_code_size as usize, Error::<T>::CodeTooLarge); ensure!(validation_code.0.len() <= config.max_code_size as usize, Error::<T>::CodeTooLarge);
ensure!( ensure!(
genesis_head.0.len() <= config.max_head_data_size as usize, genesis_head.0.len() <= config.max_head_data_size as usize,
@@ -712,7 +712,7 @@ mod tests {
}; };
use frame_system::limits; use frame_system::limits;
use pallet_balances::Error as BalancesError; use pallet_balances::Error as BalancesError;
use primitives::{Balance, BlockNumber, SessionIndex}; use primitives::{Balance, BlockNumber, SessionIndex, MAX_CODE_SIZE};
use runtime_parachains::{configuration, origin, shared}; use runtime_parachains::{configuration, origin, shared};
use sp_core::H256; use sp_core::H256;
use sp_io::TestExternalities; use sp_io::TestExternalities;
@@ -849,7 +849,7 @@ mod tests {
configuration::GenesisConfig::<Test> { configuration::GenesisConfig::<Test> {
config: configuration::HostConfiguration { config: configuration::HostConfiguration {
max_code_size: 2 * 1024 * 1024, // 2 MB max_code_size: MAX_CODE_SIZE,
max_head_data_size: 1 * 1024 * 1024, // 1 MB max_head_data_size: 1 * 1024 * 1024, // 1 MB
..Default::default() ..Default::default()
}, },
@@ -1032,6 +1032,51 @@ mod tests {
}); });
} }
#[test]
fn schedule_code_upgrade_validates_code() {
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)));
assert_eq!(Balances::reserved_balance(&1), <Test as Config>::ParaDeposit::get());
assert_ok!(Registrar::register(
RuntimeOrigin::signed(1),
para_id,
test_genesis_head(32),
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));
let new_code = test_validation_code(0);
assert_noop!(
Registrar::schedule_code_upgrade(
RuntimeOrigin::signed(1),
para_id,
new_code.clone(),
),
paras::Error::<Test>::InvalidCode
);
let new_code = test_validation_code(max_code_size() as usize + 1);
assert_noop!(
Registrar::schedule_code_upgrade(
RuntimeOrigin::signed(1),
para_id,
new_code.clone(),
),
paras::Error::<Test>::InvalidCode
);
});
}
#[test] #[test]
fn register_handles_basic_errors() { fn register_handles_basic_errors() {
new_test_ext().execute_with(|| { new_test_ext().execute_with(|| {
@@ -1310,7 +1355,7 @@ mod tests {
RuntimeOrigin::signed(1), RuntimeOrigin::signed(1),
para_id, para_id,
vec![1; 3].into(), vec![1; 3].into(),
vec![1, 2, 3].into(), test_validation_code(32)
)); ));
assert_noop!(Registrar::add_lock(RuntimeOrigin::signed(2), para_id), BadOrigin); assert_noop!(Registrar::add_lock(RuntimeOrigin::signed(2), para_id), BadOrigin);
@@ -1473,7 +1518,7 @@ mod benchmarking {
use crate::traits::Registrar as RegistrarT; use crate::traits::Registrar as RegistrarT;
use frame_support::assert_ok; use frame_support::assert_ok;
use frame_system::RawOrigin; use frame_system::RawOrigin;
use primitives::{MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE}; use primitives::{MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MIN_CODE_SIZE};
use runtime_parachains::{paras, shared, Origin as ParaOrigin}; use runtime_parachains::{paras, shared, Origin as ParaOrigin};
use sp_runtime::traits::Bounded; use sp_runtime::traits::Bounded;
@@ -1604,7 +1649,7 @@ mod benchmarking {
} }
schedule_code_upgrade { schedule_code_upgrade {
let b in 1 .. MAX_CODE_SIZE; let b in MIN_CODE_SIZE .. MAX_CODE_SIZE;
let new_code = ValidationCode(vec![0; b as usize]); let new_code = ValidationCode(vec![0; b as usize]);
let para_id = ParaId::from(1000); let para_id = ParaId::from(1000);
}: _(RawOrigin::Root, para_id, new_code) }: _(RawOrigin::Root, para_id, new_code)
@@ -281,7 +281,7 @@ impl<BlockNumber: Default + From<u32>> Default for HostConfiguration<BlockNumber
validation_upgrade_cooldown: Default::default(), validation_upgrade_cooldown: Default::default(),
validation_upgrade_delay: 2u32.into(), validation_upgrade_delay: 2u32.into(),
code_retention_period: Default::default(), code_retention_period: Default::default(),
max_code_size: Default::default(), max_code_size: MAX_CODE_SIZE,
max_pov_size: Default::default(), max_pov_size: Default::default(),
max_head_data_size: Default::default(), max_head_data_size: Default::default(),
coretime_cores: Default::default(), coretime_cores: Default::default(),
@@ -1233,7 +1233,7 @@ fn candidate_checks() {
para_id: chain_a, para_id: chain_a,
relay_parent: System::parent_hash(), relay_parent: System::parent_hash(),
pov_hash: Hash::repeat_byte(1), pov_hash: Hash::repeat_byte(1),
new_validation_code: Some(vec![5, 6, 7, 8].into()), new_validation_code: Some(dummy_validation_code()),
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
hrmp_watermark: RELAY_PARENT_NUM, hrmp_watermark: RELAY_PARENT_NUM,
..Default::default() ..Default::default()
@@ -1257,7 +1257,7 @@ fn candidate_checks() {
assert_eq!(expected_at, 12); assert_eq!(expected_at, 12);
Paras::schedule_code_upgrade( Paras::schedule_code_upgrade(
chain_a, chain_a,
vec![1, 2, 3, 4].into(), vec![9, 8, 7, 6, 5, 4, 3, 2, 1].into(),
expected_at, expected_at,
&cfg, &cfg,
SetGoAhead::Yes, SetGoAhead::Yes,
@@ -1317,7 +1317,7 @@ fn candidate_checks() {
pov_hash: Hash::repeat_byte(1), pov_hash: Hash::repeat_byte(1),
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
hrmp_watermark: RELAY_PARENT_NUM, hrmp_watermark: RELAY_PARENT_NUM,
validation_code: ValidationCode(vec![1]), validation_code: ValidationCode(vec![9, 8, 7, 6, 5, 4, 3, 2, 1]),
..Default::default() ..Default::default()
} }
.build(); .build();
@@ -1726,7 +1726,7 @@ fn can_include_candidate_with_ok_code_upgrade() {
relay_parent: System::parent_hash(), relay_parent: System::parent_hash(),
pov_hash: Hash::repeat_byte(1), pov_hash: Hash::repeat_byte(1),
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(), persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
new_validation_code: Some(vec![1, 2, 3].into()), new_validation_code: Some(vec![9, 8, 7, 6, 5, 4, 3, 2, 1].into()),
hrmp_watermark: RELAY_PARENT_NUM, hrmp_watermark: RELAY_PARENT_NUM,
..Default::default() ..Default::default()
} }
@@ -2133,7 +2133,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() {
shared::Pallet::<Test>::set_active_validators_ascending(validator_public.clone()); shared::Pallet::<Test>::set_active_validators_ascending(validator_public.clone());
shared::Pallet::<Test>::set_session_index(5); shared::Pallet::<Test>::set_session_index(5);
let new_validation_code: ValidationCode = vec![1, 2, 3, 4, 5].into(); let new_validation_code: ValidationCode = vec![9, 8, 7, 6, 5, 4, 3, 2, 1].into();
let new_validation_code_hash = new_validation_code.hash(); let new_validation_code_hash = new_validation_code.hash();
// Otherwise upgrade is no-op. // Otherwise upgrade is no-op.
@@ -27,10 +27,10 @@ const SESSION_INDEX: SessionIndex = 1;
const VALIDATOR_NUM: usize = 800; const VALIDATOR_NUM: usize = 800;
const CAUSES_NUM: usize = 100; const CAUSES_NUM: usize = 100;
fn validation_code() -> ValidationCode { fn validation_code() -> ValidationCode {
ValidationCode(vec![0]) ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9])
} }
fn old_validation_code() -> ValidationCode { fn old_validation_code() -> ValidationCode {
ValidationCode(vec![1]) ValidationCode(vec![9, 8, 7, 6, 5, 4, 3, 2, 1])
} }
/// Prepares the PVF check statement and the validator signature to pass into /// Prepares the PVF check statement and the validator signature to pass into
+15 -2
View File
@@ -119,7 +119,7 @@ use frame_system::pallet_prelude::*;
use parity_scale_codec::{Decode, Encode}; use parity_scale_codec::{Decode, Encode};
use primitives::{ use primitives::{
ConsensusLog, HeadData, Id as ParaId, PvfCheckStatement, SessionIndex, UpgradeGoAhead, ConsensusLog, HeadData, Id as ParaId, PvfCheckStatement, SessionIndex, UpgradeGoAhead,
UpgradeRestriction, ValidationCode, ValidationCodeHash, ValidatorSignature, UpgradeRestriction, ValidationCode, ValidationCodeHash, ValidatorSignature, MIN_CODE_SIZE,
}; };
use scale_info::{Type, TypeInfo}; use scale_info::{Type, TypeInfo};
use sp_core::RuntimeDebug; use sp_core::RuntimeDebug;
@@ -679,6 +679,8 @@ pub mod pallet {
PvfCheckSubjectInvalid, PvfCheckSubjectInvalid,
/// Parachain cannot currently schedule a code upgrade. /// Parachain cannot currently schedule a code upgrade.
CannotUpgradeCode, CannotUpgradeCode,
/// Invalid validation code size.
InvalidCode,
} }
/// All currently active PVF pre-checking votes. /// All currently active PVF pre-checking votes.
@@ -1230,6 +1232,10 @@ impl<T: Config> Pallet<T> {
// Check that we can schedule an upgrade at all. // Check that we can schedule an upgrade at all.
ensure!(Self::can_upgrade_validation_code(id), Error::<T>::CannotUpgradeCode); ensure!(Self::can_upgrade_validation_code(id), Error::<T>::CannotUpgradeCode);
let config = configuration::Pallet::<T>::config(); let config = configuration::Pallet::<T>::config();
// Validation code sanity checks:
ensure!(new_code.0.len() >= MIN_CODE_SIZE as usize, Error::<T>::InvalidCode);
ensure!(new_code.0.len() <= config.max_code_size as usize, Error::<T>::InvalidCode);
let current_block = frame_system::Pallet::<T>::block_number(); let current_block = frame_system::Pallet::<T>::block_number();
// Schedule the upgrade with a delay just like if a parachain triggered the upgrade. // Schedule the upgrade with a delay just like if a parachain triggered the upgrade.
let upgrade_block = current_block.saturating_add(config.validation_upgrade_delay); let upgrade_block = current_block.saturating_add(config.validation_upgrade_delay);
@@ -1890,7 +1896,14 @@ impl<T: Config> Pallet<T> {
) -> Weight { ) -> Weight {
let mut weight = T::DbWeight::get().reads(1); let mut weight = T::DbWeight::get().reads(1);
// Enacting this should be prevented by the `can_schedule_upgrade` // Should be prevented by checks in `schedule_code_upgrade_external`
let new_code_len = new_code.0.len();
if new_code_len < MIN_CODE_SIZE as usize || new_code_len > cfg.max_code_size as usize {
log::warn!(target: LOG_TARGET, "attempted to schedule an upgrade with invalid new validation code",);
return weight
}
// Enacting this should be prevented by the `can_upgrade_validation_code`
if FutureCodeHash::<T>::contains_key(&id) { if FutureCodeHash::<T>::contains_key(&id) {
// This branch should never be reached. Signalling an upgrade is disallowed for a para // This branch should never be reached. Signalling an upgrade is disallowed for a para
// that already has one upgrade scheduled. // that already has one upgrade scheduled.
+48 -38
View File
@@ -67,6 +67,16 @@ fn submit_super_majority_pvf_votes(
.for_each(sign_and_include_pvf_check_statement); .for_each(sign_and_include_pvf_check_statement);
} }
fn test_validation_code_1() -> ValidationCode {
let validation_code = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
ValidationCode(validation_code)
}
fn test_validation_code_2() -> ValidationCode {
let validation_code = vec![9, 8, 7, 6, 5, 4, 3, 2, 1];
ValidationCode(validation_code)
}
fn run_to_block(to: BlockNumber, new_session: Option<Vec<BlockNumber>>) { fn run_to_block(to: BlockNumber, new_session: Option<Vec<BlockNumber>>) {
let keystore: KeystorePtr = Arc::new(LocalKeystore::in_memory()); let keystore: KeystorePtr = Arc::new(LocalKeystore::in_memory());
for validator in VALIDATORS.iter() { for validator in VALIDATORS.iter() {
@@ -284,7 +294,7 @@ fn para_past_code_pruning_in_initialize() {
let id = ParaId::from(0u32); let id = ParaId::from(0u32);
let at_block: BlockNumber = 10; let at_block: BlockNumber = 10;
let included_block: BlockNumber = 12; let included_block: BlockNumber = 12;
let validation_code = ValidationCode(vec![4, 5, 6]); let validation_code = test_validation_code_2();
Paras::increase_code_ref(&validation_code.hash(), &validation_code); Paras::increase_code_ref(&validation_code.hash(), &validation_code);
PastCodeHash::<Test>::insert(&(id, at_block), &validation_code.hash()); PastCodeHash::<Test>::insert(&(id, at_block), &validation_code.hash());
@@ -377,8 +387,8 @@ fn note_past_code_sets_up_pruning_correctly() {
let id_a = ParaId::from(0u32); let id_a = ParaId::from(0u32);
let id_b = ParaId::from(1u32); let id_b = ParaId::from(1u32);
Paras::note_past_code(id_a, 10, 12, ValidationCode(vec![1, 2, 3]).hash()); Paras::note_past_code(id_a, 10, 12, test_validation_code_1().hash());
Paras::note_past_code(id_b, 20, 23, ValidationCode(vec![4, 5, 6]).hash()); Paras::note_past_code(id_b, 20, 23, test_validation_code_2().hash());
assert_eq!(PastCodePruning::<Test>::get(), vec![(id_a, 12), (id_b, 23)]); assert_eq!(PastCodePruning::<Test>::get(), vec![(id_a, 12), (id_b, 23)]);
assert_eq!( assert_eq!(
@@ -398,7 +408,7 @@ fn code_upgrade_applied_after_delay() {
let validation_upgrade_delay = 5; let validation_upgrade_delay = 5;
let validation_upgrade_cooldown = 10; let validation_upgrade_cooldown = 10;
let original_code = ValidationCode(vec![1, 2, 3]); let original_code = test_validation_code_1();
let paras = vec![( let paras = vec![(
0u32.into(), 0u32.into(),
ParaGenesisArgs { ParaGenesisArgs {
@@ -425,7 +435,7 @@ fn code_upgrade_applied_after_delay() {
check_code_is_stored(&original_code); check_code_is_stored(&original_code);
let para_id = ParaId::from(0); let para_id = ParaId::from(0);
let new_code = ValidationCode(vec![4, 5, 6]); let new_code = test_validation_code_2();
// Wait for at least one session change to set active validators. // Wait for at least one session change to set active validators.
const EXPECTED_SESSION: SessionIndex = 1; const EXPECTED_SESSION: SessionIndex = 1;
@@ -516,7 +526,7 @@ fn code_upgrade_applied_without_setting_go_ahead_signal() {
let validation_upgrade_delay = 5; let validation_upgrade_delay = 5;
let validation_upgrade_cooldown = 10; let validation_upgrade_cooldown = 10;
let original_code = ValidationCode(vec![1, 2, 3]); let original_code = test_validation_code_1();
let paras = vec![( let paras = vec![(
0u32.into(), 0u32.into(),
ParaGenesisArgs { ParaGenesisArgs {
@@ -543,7 +553,7 @@ fn code_upgrade_applied_without_setting_go_ahead_signal() {
check_code_is_stored(&original_code); check_code_is_stored(&original_code);
let para_id = ParaId::from(0); let para_id = ParaId::from(0);
let new_code = ValidationCode(vec![4, 5, 6]); let new_code = test_validation_code_2();
// Wait for at least one session change to set active validators. // Wait for at least one session change to set active validators.
const EXPECTED_SESSION: SessionIndex = 1; const EXPECTED_SESSION: SessionIndex = 1;
@@ -637,7 +647,7 @@ fn code_upgrade_applied_after_delay_even_when_late() {
let validation_upgrade_delay = 5; let validation_upgrade_delay = 5;
let validation_upgrade_cooldown = 10; let validation_upgrade_cooldown = 10;
let original_code = ValidationCode(vec![1, 2, 3]); let original_code = test_validation_code_1();
let paras = vec![( let paras = vec![(
0u32.into(), 0u32.into(),
ParaGenesisArgs { ParaGenesisArgs {
@@ -662,7 +672,7 @@ fn code_upgrade_applied_after_delay_even_when_late() {
new_test_ext(genesis_config).execute_with(|| { new_test_ext(genesis_config).execute_with(|| {
let para_id = ParaId::from(0); let para_id = ParaId::from(0);
let new_code = ValidationCode(vec![4, 5, 6]); let new_code = test_validation_code_2();
// Wait for at least one session change to set active validators. // Wait for at least one session change to set active validators.
const EXPECTED_SESSION: SessionIndex = 1; const EXPECTED_SESSION: SessionIndex = 1;
@@ -750,8 +760,8 @@ fn submit_code_change_when_not_allowed_is_err() {
new_test_ext(genesis_config).execute_with(|| { new_test_ext(genesis_config).execute_with(|| {
let para_id = ParaId::from(0); let para_id = ParaId::from(0);
let new_code = ValidationCode(vec![4, 5, 6]); let new_code = test_validation_code_1();
let newer_code = ValidationCode(vec![4, 5, 6, 7]); let newer_code = test_validation_code_2();
// Wait for at least one session change to set active validators. // Wait for at least one session change to set active validators.
const EXPECTED_SESSION: SessionIndex = 1; const EXPECTED_SESSION: SessionIndex = 1;
@@ -832,8 +842,8 @@ fn upgrade_restriction_elapsed_doesnt_mean_can_upgrade() {
new_test_ext(genesis_config).execute_with(|| { new_test_ext(genesis_config).execute_with(|| {
let para_id = 0u32.into(); let para_id = 0u32.into();
let new_code = ValidationCode(vec![4, 5, 6]); let new_code = test_validation_code_1();
let newer_code = ValidationCode(vec![4, 5, 6, 7]); let newer_code = test_validation_code_2();
// Wait for at least one session change to set active validators. // Wait for at least one session change to set active validators.
const EXPECTED_SESSION: SessionIndex = 1; const EXPECTED_SESSION: SessionIndex = 1;
@@ -880,7 +890,7 @@ fn full_parachain_cleanup_storage() {
let code_retention_period = 20; let code_retention_period = 20;
let validation_upgrade_delay = 1 + 5; let validation_upgrade_delay = 1 + 5;
let original_code = ValidationCode(vec![1, 2, 3]); let original_code = test_validation_code_1();
let paras = vec![( let paras = vec![(
0u32.into(), 0u32.into(),
ParaGenesisArgs { ParaGenesisArgs {
@@ -910,7 +920,7 @@ fn full_parachain_cleanup_storage() {
check_code_is_stored(&original_code); check_code_is_stored(&original_code);
let para_id = ParaId::from(0); let para_id = ParaId::from(0);
let new_code = ValidationCode(vec![4, 5, 6]); let new_code = test_validation_code_2();
// Wait for at least one session change to set active validators. // Wait for at least one session change to set active validators.
const EXPECTED_SESSION: SessionIndex = 1; const EXPECTED_SESSION: SessionIndex = 1;
@@ -993,8 +1003,8 @@ fn full_parachain_cleanup_storage() {
fn cannot_offboard_ongoing_pvf_check() { fn cannot_offboard_ongoing_pvf_check() {
let para_id = ParaId::from(0); let para_id = ParaId::from(0);
let existing_code: ValidationCode = vec![1, 2, 3].into(); let existing_code = test_validation_code_1();
let new_code: ValidationCode = vec![3, 2, 1].into(); let new_code = test_validation_code_2();
let paras = vec![( let paras = vec![(
para_id, para_id,
@@ -1152,7 +1162,7 @@ fn code_hash_at_returns_up_to_end_of_code_retention_period() {
ParaGenesisArgs { ParaGenesisArgs {
para_kind: ParaKind::Parachain, para_kind: ParaKind::Parachain,
genesis_head: dummy_head_data(), genesis_head: dummy_head_data(),
validation_code: vec![1, 2, 3].into(), validation_code: test_validation_code_1(),
}, },
)]; )];
@@ -1174,8 +1184,8 @@ fn code_hash_at_returns_up_to_end_of_code_retention_period() {
const EXPECTED_SESSION: SessionIndex = 1; const EXPECTED_SESSION: SessionIndex = 1;
let para_id = ParaId::from(0); let para_id = ParaId::from(0);
let old_code: ValidationCode = vec![1, 2, 3].into(); let old_code = test_validation_code_1();
let new_code: ValidationCode = vec![4, 5, 6].into(); let new_code = test_validation_code_2();
Paras::schedule_code_upgrade( Paras::schedule_code_upgrade(
para_id, para_id,
new_code.clone(), new_code.clone(),
@@ -1219,7 +1229,7 @@ fn code_hash_at_returns_up_to_end_of_code_retention_period() {
#[test] #[test]
fn code_ref_is_cleaned_correctly() { fn code_ref_is_cleaned_correctly() {
new_test_ext(Default::default()).execute_with(|| { new_test_ext(Default::default()).execute_with(|| {
let code: ValidationCode = vec![1, 2, 3].into(); let code = test_validation_code_1();
Paras::increase_code_ref(&code.hash(), &code); Paras::increase_code_ref(&code.hash(), &code);
Paras::increase_code_ref(&code.hash(), &code); Paras::increase_code_ref(&code.hash(), &code);
@@ -1244,8 +1254,8 @@ fn pvf_check_coalescing_onboarding_and_upgrade() {
let a = ParaId::from(111); let a = ParaId::from(111);
let b = ParaId::from(222); let b = ParaId::from(222);
let existing_code: ValidationCode = vec![1, 2, 3].into(); let existing_code = test_validation_code_1();
let validation_code: ValidationCode = vec![3, 2, 1].into(); let validation_code = test_validation_code_2();
let paras = vec![( let paras = vec![(
a, a,
@@ -1320,7 +1330,7 @@ fn pvf_check_coalescing_onboarding_and_upgrade() {
fn pvf_check_onboarding_reject_on_expiry() { fn pvf_check_onboarding_reject_on_expiry() {
let pvf_voting_ttl = 2; let pvf_voting_ttl = 2;
let a = ParaId::from(111); let a = ParaId::from(111);
let validation_code: ValidationCode = vec![3, 2, 1].into(); let validation_code = test_validation_code_1();
let genesis_config = MockGenesisConfig { let genesis_config = MockGenesisConfig {
configuration: crate::configuration::GenesisConfig { configuration: crate::configuration::GenesisConfig {
@@ -1368,8 +1378,8 @@ fn pvf_check_onboarding_reject_on_expiry() {
#[test] #[test]
fn pvf_check_upgrade_reject() { fn pvf_check_upgrade_reject() {
let a = ParaId::from(111); let a = ParaId::from(111);
let old_code: ValidationCode = vec![1, 2, 3].into(); let old_code = test_validation_code_1();
let new_code: ValidationCode = vec![3, 2, 1].into(); let new_code = test_validation_code_2();
let paras = vec![( let paras = vec![(
a, a,
@@ -1437,8 +1447,8 @@ fn pvf_check_upgrade_reject() {
#[test] #[test]
fn pvf_check_submit_vote() { fn pvf_check_submit_vote() {
let code_a: ValidationCode = vec![3, 2, 1].into(); let code_a = test_validation_code_1();
let code_b: ValidationCode = vec![1, 2, 3].into(); let code_b = test_validation_code_2();
let check = |stmt: PvfCheckStatement| -> (Result<_, _>, Result<_, _>) { let check = |stmt: PvfCheckStatement| -> (Result<_, _>, Result<_, _>) {
let validators = &[ let validators = &[
@@ -1554,8 +1564,8 @@ fn pvf_check_submit_vote() {
#[test] #[test]
fn include_pvf_check_statement_refunds_weight() { fn include_pvf_check_statement_refunds_weight() {
let a = ParaId::from(111); let a = ParaId::from(111);
let old_code: ValidationCode = vec![1, 2, 3].into(); let old_code = test_validation_code_1();
let new_code: ValidationCode = vec![3, 2, 1].into(); let new_code = test_validation_code_2();
let paras = vec![( let paras = vec![(
a, a,
@@ -1620,7 +1630,7 @@ fn include_pvf_check_statement_refunds_weight() {
fn add_trusted_validation_code_inserts_with_no_users() { fn add_trusted_validation_code_inserts_with_no_users() {
// This test is to ensure that trusted validation code is inserted into the storage // This test is to ensure that trusted validation code is inserted into the storage
// with the reference count equal to 0. // with the reference count equal to 0.
let validation_code = ValidationCode(vec![1, 2, 3]); let validation_code = test_validation_code_1();
new_test_ext(Default::default()).execute_with(|| { new_test_ext(Default::default()).execute_with(|| {
assert_ok!(Paras::add_trusted_validation_code( assert_ok!(Paras::add_trusted_validation_code(
RuntimeOrigin::root(), RuntimeOrigin::root(),
@@ -1634,7 +1644,7 @@ fn add_trusted_validation_code_inserts_with_no_users() {
fn add_trusted_validation_code_idempotent() { fn add_trusted_validation_code_idempotent() {
// This test makes sure that calling add_trusted_validation_code twice with the same // This test makes sure that calling add_trusted_validation_code twice with the same
// parameters is a no-op. // parameters is a no-op.
let validation_code = ValidationCode(vec![1, 2, 3]); let validation_code = test_validation_code_1();
new_test_ext(Default::default()).execute_with(|| { new_test_ext(Default::default()).execute_with(|| {
assert_ok!(Paras::add_trusted_validation_code( assert_ok!(Paras::add_trusted_validation_code(
RuntimeOrigin::root(), RuntimeOrigin::root(),
@@ -1653,7 +1663,7 @@ fn add_trusted_validation_code_idempotent() {
fn poke_unused_validation_code_removes_code_cleanly() { fn poke_unused_validation_code_removes_code_cleanly() {
// This test makes sure that calling poke_unused_validation_code with a code that is currently // This test makes sure that calling poke_unused_validation_code with a code that is currently
// in the storage but has no users will remove it cleanly from the storage. // in the storage but has no users will remove it cleanly from the storage.
let validation_code = ValidationCode(vec![1, 2, 3]); let validation_code = test_validation_code_1();
new_test_ext(Default::default()).execute_with(|| { new_test_ext(Default::default()).execute_with(|| {
assert_ok!(Paras::add_trusted_validation_code( assert_ok!(Paras::add_trusted_validation_code(
RuntimeOrigin::root(), RuntimeOrigin::root(),
@@ -1672,7 +1682,7 @@ fn poke_unused_validation_code_removes_code_cleanly() {
#[test] #[test]
fn poke_unused_validation_code_doesnt_remove_code_with_users() { fn poke_unused_validation_code_doesnt_remove_code_with_users() {
let para_id = 100.into(); let para_id = 100.into();
let validation_code = ValidationCode(vec![1, 2, 3]); let validation_code = test_validation_code_1();
new_test_ext(Default::default()).execute_with(|| { new_test_ext(Default::default()).execute_with(|| {
// First we add the code to the storage. // First we add the code to the storage.
assert_ok!(Paras::add_trusted_validation_code( assert_ok!(Paras::add_trusted_validation_code(
@@ -1708,7 +1718,7 @@ fn increase_code_ref_doesnt_have_allergy_on_add_trusted_validation_code() {
// to a disaster. // to a disaster.
// NOTE that this test is extra paranoid, as it is not really possible to hit // NOTE that this test is extra paranoid, as it is not really possible to hit
// `decrease_code_ref` without calling `increase_code_ref` first. // `decrease_code_ref` without calling `increase_code_ref` first.
let code = ValidationCode(vec![1, 2, 3]); let code = test_validation_code_1();
new_test_ext(Default::default()).execute_with(|| { new_test_ext(Default::default()).execute_with(|| {
assert_ok!(Paras::add_trusted_validation_code(RuntimeOrigin::root(), code.clone())); assert_ok!(Paras::add_trusted_validation_code(RuntimeOrigin::root(), code.clone()));
@@ -1732,7 +1742,7 @@ fn add_trusted_validation_code_insta_approval() {
// `add_trusted_validation_code` and uses the `CodeByHash::contains_key` which is what // `add_trusted_validation_code` and uses the `CodeByHash::contains_key` which is what
// `add_trusted_validation_code` uses. // `add_trusted_validation_code` uses.
let para_id = 100.into(); let para_id = 100.into();
let validation_code = ValidationCode(vec![1, 2, 3]); let validation_code = test_validation_code_1();
let validation_upgrade_delay = 25; let validation_upgrade_delay = 25;
let minimum_validation_upgrade_delay = 2; let minimum_validation_upgrade_delay = 2;
let genesis_config = MockGenesisConfig { let genesis_config = MockGenesisConfig {
@@ -1779,7 +1789,7 @@ fn add_trusted_validation_code_enacts_existing_pvf_vote() {
// already going through PVF pre-checking voting will conclude the voting and enact the // already going through PVF pre-checking voting will conclude the voting and enact the
// code upgrade. // code upgrade.
let para_id = 100.into(); let para_id = 100.into();
let validation_code = ValidationCode(vec![1, 2, 3]); let validation_code = test_validation_code_1();
let validation_upgrade_delay = 25; let validation_upgrade_delay = 25;
let minimum_validation_upgrade_delay = 2; let minimum_validation_upgrade_delay = 2;
let genesis_config = MockGenesisConfig { let genesis_config = MockGenesisConfig {
@@ -1868,7 +1878,7 @@ fn verify_para_head_is_externally_accessible() {
#[test] #[test]
fn most_recent_context() { fn most_recent_context() {
let validation_code: ValidationCode = vec![1, 2, 3].into(); let validation_code = test_validation_code_1();
let genesis_config = MockGenesisConfig::default(); let genesis_config = MockGenesisConfig::default();
+13
View File
@@ -0,0 +1,13 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
title: Validate code when scheduling uprades
doc:
- audience: Runtime User
description: |
Adds checks to ensure that the validation code is valid before scheduling
a code upgrade.
crates:
- name: polkadot-runtime-parachains