Files
pezkuwi-sdk/pezkuwi/runtime/teyrchains/src/configuration/tests.rs
T
pezkuwichain 4666047395 chore: add Dijital Kurdistan Tech Institute to copyright headers
Updated 4763 files with dual copyright:
- Parity Technologies (UK) Ltd.
- Dijital Kurdistan Tech Institute
2025-12-27 21:28:36 +03:00

587 lines
20 KiB
Rust

// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
// This file is part of Pezkuwi.
// Pezkuwi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Pezkuwi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
use super::*;
use crate::{
configuration,
mock::{new_test_ext, Configuration, MockGenesisConfig, ParasShared, RuntimeOrigin, Test},
};
use bitvec::{bitvec, prelude::Lsb0};
use pezframe_support::{assert_err, assert_ok};
fn on_new_session(session_index: SessionIndex) -> (HostConfiguration<u32>, HostConfiguration<u32>) {
ParasShared::set_session_index(session_index);
let SessionChangeOutcome { prev_config, new_config } =
Configuration::initializer_on_new_session(&session_index);
let new_config = new_config.unwrap_or_else(|| prev_config.clone());
(prev_config, new_config)
}
#[test]
fn default_is_consistent() {
new_test_ext(Default::default()).execute_with(|| {
configuration::ActiveConfig::<Test>::get().panic_if_not_consistent();
});
}
#[test]
fn scheduled_session_is_two_sessions_from_now() {
new_test_ext(Default::default()).execute_with(|| {
// The logic here is really tested only with scheduled_session = 2. It should work
// with other values, but that should receive a more rigorous testing.
on_new_session(1);
assert_eq!(Configuration::scheduled_session(), 3);
});
}
#[test]
fn initializer_on_new_session() {
new_test_ext(Default::default()).execute_with(|| {
let (prev_config, new_config) = on_new_session(1);
assert_eq!(prev_config, new_config);
assert_ok!(Configuration::set_validation_upgrade_delay(RuntimeOrigin::root(), 100));
let (prev_config, new_config) = on_new_session(2);
assert_eq!(prev_config, new_config);
let (prev_config, new_config) = on_new_session(3);
assert_eq!(prev_config, HostConfiguration::default());
assert_eq!(new_config, HostConfiguration { validation_upgrade_delay: 100, ..prev_config });
});
}
#[test]
fn config_changes_after_2_session_boundary() {
new_test_ext(Default::default()).execute_with(|| {
let old_config = configuration::ActiveConfig::<Test>::get();
let mut config = old_config.clone();
config.validation_upgrade_delay = 100;
assert!(old_config != config);
assert_ok!(Configuration::set_validation_upgrade_delay(RuntimeOrigin::root(), 100));
// Verify that the current configuration has not changed and that there is a scheduled
// change for the SESSION_DELAY sessions in advance.
assert_eq!(configuration::ActiveConfig::<Test>::get(), old_config);
assert_eq!(PendingConfigs::<Test>::get(), vec![(2, config.clone())]);
on_new_session(1);
// One session has passed, we should be still waiting for the pending configuration.
assert_eq!(configuration::ActiveConfig::<Test>::get(), old_config);
assert_eq!(PendingConfigs::<Test>::get(), vec![(2, config.clone())]);
on_new_session(2);
assert_eq!(configuration::ActiveConfig::<Test>::get(), config);
assert_eq!(PendingConfigs::<Test>::get(), vec![]);
})
}
#[test]
fn consecutive_changes_within_one_session() {
new_test_ext(Default::default()).execute_with(|| {
let old_config = configuration::ActiveConfig::<Test>::get();
let mut config = old_config.clone();
config.validation_upgrade_delay = 100;
config.validation_upgrade_cooldown = 100;
assert!(old_config != config);
assert_ok!(Configuration::set_validation_upgrade_delay(RuntimeOrigin::root(), 100));
assert_ok!(Configuration::set_validation_upgrade_cooldown(RuntimeOrigin::root(), 100));
assert_eq!(configuration::ActiveConfig::<Test>::get(), old_config);
assert_eq!(PendingConfigs::<Test>::get(), vec![(2, config.clone())]);
on_new_session(1);
assert_eq!(configuration::ActiveConfig::<Test>::get(), old_config);
assert_eq!(PendingConfigs::<Test>::get(), vec![(2, config.clone())]);
on_new_session(2);
assert_eq!(configuration::ActiveConfig::<Test>::get(), config);
assert_eq!(PendingConfigs::<Test>::get(), vec![]);
});
}
#[test]
fn pending_next_session_but_we_upgrade_once_more() {
new_test_ext(Default::default()).execute_with(|| {
let initial_config = configuration::ActiveConfig::<Test>::get();
let intermediate_config =
HostConfiguration { validation_upgrade_delay: 100, ..initial_config.clone() };
let final_config = HostConfiguration {
validation_upgrade_delay: 100,
validation_upgrade_cooldown: 99,
..initial_config.clone()
};
assert_ok!(Configuration::set_validation_upgrade_delay(RuntimeOrigin::root(), 100));
assert_eq!(configuration::ActiveConfig::<Test>::get(), initial_config);
assert_eq!(PendingConfigs::<Test>::get(), vec![(2, intermediate_config.clone())]);
on_new_session(1);
// We are still waiting until the pending configuration is applied and we add another
// update.
assert_ok!(Configuration::set_validation_upgrade_cooldown(RuntimeOrigin::root(), 99));
// This should result in yet another configuration change scheduled.
assert_eq!(configuration::ActiveConfig::<Test>::get(), initial_config);
assert_eq!(
PendingConfigs::<Test>::get(),
vec![(2, intermediate_config.clone()), (3, final_config.clone())]
);
on_new_session(2);
assert_eq!(configuration::ActiveConfig::<Test>::get(), intermediate_config);
assert_eq!(PendingConfigs::<Test>::get(), vec![(3, final_config.clone())]);
on_new_session(3);
assert_eq!(configuration::ActiveConfig::<Test>::get(), final_config);
assert_eq!(PendingConfigs::<Test>::get(), vec![]);
});
}
#[test]
fn scheduled_session_config_update_while_next_session_pending() {
new_test_ext(Default::default()).execute_with(|| {
let initial_config = configuration::ActiveConfig::<Test>::get();
let intermediate_config =
HostConfiguration { validation_upgrade_delay: 100, ..initial_config.clone() };
let final_config = HostConfiguration {
validation_upgrade_delay: 100,
validation_upgrade_cooldown: 99,
code_retention_period: 98,
..initial_config.clone()
};
assert_ok!(Configuration::set_validation_upgrade_delay(RuntimeOrigin::root(), 100));
assert_eq!(configuration::ActiveConfig::<Test>::get(), initial_config);
assert_eq!(PendingConfigs::<Test>::get(), vec![(2, intermediate_config.clone())]);
on_new_session(1);
// The second call should fall into the case where we already have a pending config
// update for the scheduled_session, but we want to update it once more.
assert_ok!(Configuration::set_validation_upgrade_cooldown(RuntimeOrigin::root(), 99));
assert_ok!(Configuration::set_code_retention_period(RuntimeOrigin::root(), 98));
// This should result in yet another configuration change scheduled.
assert_eq!(configuration::ActiveConfig::<Test>::get(), initial_config);
assert_eq!(
PendingConfigs::<Test>::get(),
vec![(2, intermediate_config.clone()), (3, final_config.clone())]
);
on_new_session(2);
assert_eq!(configuration::ActiveConfig::<Test>::get(), intermediate_config);
assert_eq!(PendingConfigs::<Test>::get(), vec![(3, final_config.clone())]);
on_new_session(3);
assert_eq!(configuration::ActiveConfig::<Test>::get(), final_config);
assert_eq!(PendingConfigs::<Test>::get(), vec![]);
});
}
#[test]
fn invariants() {
new_test_ext(Default::default()).execute_with(|| {
assert_err!(
Configuration::set_max_code_size(RuntimeOrigin::root(), MAX_CODE_SIZE + 1),
Error::<Test>::InvalidNewValue
);
assert_err!(
Configuration::set_max_pov_size(RuntimeOrigin::root(), POV_SIZE_HARD_LIMIT + 1),
Error::<Test>::InvalidNewValue
);
assert_err!(
Configuration::set_max_head_data_size(RuntimeOrigin::root(), MAX_HEAD_DATA_SIZE + 1),
Error::<Test>::InvalidNewValue
);
assert_err!(
Configuration::set_paras_availability_period(RuntimeOrigin::root(), 0),
Error::<Test>::InvalidNewValue
);
assert_err!(
Configuration::set_no_show_slots(RuntimeOrigin::root(), 0),
Error::<Test>::InvalidNewValue
);
ActiveConfig::<Test>::put(HostConfiguration {
minimum_validation_upgrade_delay: 11,
scheduler_params: SchedulerParams {
paras_availability_period: 10,
..Default::default()
},
..Default::default()
});
assert_err!(
Configuration::set_paras_availability_period(RuntimeOrigin::root(), 12),
Error::<Test>::InvalidNewValue
);
assert_err!(
Configuration::set_minimum_validation_upgrade_delay(RuntimeOrigin::root(), 9),
Error::<Test>::InvalidNewValue
);
assert_err!(
Configuration::set_validation_upgrade_delay(RuntimeOrigin::root(), 0),
Error::<Test>::InvalidNewValue
);
});
}
#[test]
fn consistency_bypass_works() {
new_test_ext(Default::default()).execute_with(|| {
assert_err!(
Configuration::set_max_code_size(RuntimeOrigin::root(), MAX_CODE_SIZE + 1),
Error::<Test>::InvalidNewValue
);
assert_ok!(Configuration::set_bypass_consistency_check(RuntimeOrigin::root(), true));
assert_ok!(Configuration::set_max_code_size(RuntimeOrigin::root(), MAX_CODE_SIZE + 1));
assert_eq!(
configuration::ActiveConfig::<Test>::get().max_code_size,
HostConfiguration::<u32>::default().max_code_size
);
on_new_session(1);
on_new_session(2);
assert_eq!(configuration::ActiveConfig::<Test>::get().max_code_size, MAX_CODE_SIZE + 1);
});
}
#[test]
fn setting_pending_config_members() {
new_test_ext(Default::default()).execute_with(|| {
let new_config = HostConfiguration {
async_backing_params: AsyncBackingParams {
allowed_ancestry_len: 0,
max_candidate_depth: 0,
},
validation_upgrade_cooldown: 100,
validation_upgrade_delay: 10,
code_retention_period: 5,
max_code_size: 100_000,
max_pov_size: 1024,
max_head_data_size: 1_000,
max_validators: None,
dispute_period: 239,
dispute_post_conclusion_acceptance_period: 10,
no_show_slots: 240,
n_delay_tranches: 241,
zeroth_delay_tranche_width: 242,
needed_approvals: 242,
relay_vrf_modulo_samples: 243,
max_upward_queue_count: 1337,
max_upward_queue_size: 228,
max_downward_message_size: 2048,
max_upward_message_size: 448,
max_upward_message_num_per_candidate: 5,
hrmp_sender_deposit: 22,
hrmp_recipient_deposit: 4905,
hrmp_channel_max_capacity: 3921,
hrmp_channel_max_total_size: 7687,
hrmp_max_teyrchain_inbound_channels: 37,
hrmp_channel_max_message_size: 8192,
hrmp_max_teyrchain_outbound_channels: 10,
hrmp_max_message_num_per_candidate: 20,
pvf_voting_ttl: 3,
minimum_validation_upgrade_delay: 20,
executor_params: Default::default(),
approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 1 },
minimum_backing_votes: 5,
node_features: bitvec![u8, Lsb0; 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1],
#[allow(deprecated)]
scheduler_params: SchedulerParams {
group_rotation_frequency: 20,
paras_availability_period: 10,
max_validators_per_core: None,
lookahead: 3,
num_cores: 2,
max_availability_timeouts: 0,
on_demand_queue_max_size: 10_000u32,
on_demand_base_fee: 10_000_000u128,
on_demand_fee_variability: Perbill::from_percent(3),
on_demand_target_queue_utilization: Perbill::from_percent(25),
ttl: 5u32,
},
};
Configuration::set_validation_upgrade_cooldown(
RuntimeOrigin::root(),
new_config.validation_upgrade_cooldown,
)
.unwrap();
Configuration::set_validation_upgrade_delay(
RuntimeOrigin::root(),
new_config.validation_upgrade_delay,
)
.unwrap();
Configuration::set_code_retention_period(
RuntimeOrigin::root(),
new_config.code_retention_period,
)
.unwrap();
Configuration::set_max_code_size(RuntimeOrigin::root(), new_config.max_code_size).unwrap();
Configuration::set_max_pov_size(RuntimeOrigin::root(), new_config.max_pov_size).unwrap();
Configuration::set_max_head_data_size(RuntimeOrigin::root(), new_config.max_head_data_size)
.unwrap();
Configuration::set_coretime_cores(
RuntimeOrigin::root(),
new_config.scheduler_params.num_cores,
)
.unwrap();
Configuration::set_group_rotation_frequency(
RuntimeOrigin::root(),
new_config.scheduler_params.group_rotation_frequency,
)
.unwrap();
// This comes out of order to satisfy the validity criteria for the chain and thread
// availability periods.
Configuration::set_minimum_validation_upgrade_delay(
RuntimeOrigin::root(),
new_config.minimum_validation_upgrade_delay,
)
.unwrap();
Configuration::set_paras_availability_period(
RuntimeOrigin::root(),
new_config.scheduler_params.paras_availability_period,
)
.unwrap();
Configuration::set_scheduling_lookahead(
RuntimeOrigin::root(),
new_config.scheduler_params.lookahead,
)
.unwrap();
Configuration::set_max_validators_per_core(
RuntimeOrigin::root(),
new_config.scheduler_params.max_validators_per_core,
)
.unwrap();
Configuration::set_max_validators(RuntimeOrigin::root(), new_config.max_validators)
.unwrap();
Configuration::set_dispute_period(RuntimeOrigin::root(), new_config.dispute_period)
.unwrap();
Configuration::set_dispute_post_conclusion_acceptance_period(
RuntimeOrigin::root(),
new_config.dispute_post_conclusion_acceptance_period,
)
.unwrap();
Configuration::set_no_show_slots(RuntimeOrigin::root(), new_config.no_show_slots).unwrap();
Configuration::set_n_delay_tranches(RuntimeOrigin::root(), new_config.n_delay_tranches)
.unwrap();
Configuration::set_zeroth_delay_tranche_width(
RuntimeOrigin::root(),
new_config.zeroth_delay_tranche_width,
)
.unwrap();
Configuration::set_needed_approvals(RuntimeOrigin::root(), new_config.needed_approvals)
.unwrap();
Configuration::set_relay_vrf_modulo_samples(
RuntimeOrigin::root(),
new_config.relay_vrf_modulo_samples,
)
.unwrap();
Configuration::set_max_upward_queue_count(
RuntimeOrigin::root(),
new_config.max_upward_queue_count,
)
.unwrap();
Configuration::set_max_upward_queue_size(
RuntimeOrigin::root(),
new_config.max_upward_queue_size,
)
.unwrap();
Configuration::set_max_downward_message_size(
RuntimeOrigin::root(),
new_config.max_downward_message_size,
)
.unwrap();
Configuration::set_max_upward_message_size(
RuntimeOrigin::root(),
new_config.max_upward_message_size,
)
.unwrap();
Configuration::set_max_upward_message_num_per_candidate(
RuntimeOrigin::root(),
new_config.max_upward_message_num_per_candidate,
)
.unwrap();
Configuration::set_hrmp_sender_deposit(
RuntimeOrigin::root(),
new_config.hrmp_sender_deposit,
)
.unwrap();
Configuration::set_hrmp_recipient_deposit(
RuntimeOrigin::root(),
new_config.hrmp_recipient_deposit,
)
.unwrap();
Configuration::set_hrmp_channel_max_capacity(
RuntimeOrigin::root(),
new_config.hrmp_channel_max_capacity,
)
.unwrap();
Configuration::set_hrmp_channel_max_total_size(
RuntimeOrigin::root(),
new_config.hrmp_channel_max_total_size,
)
.unwrap();
Configuration::set_hrmp_max_teyrchain_inbound_channels(
RuntimeOrigin::root(),
new_config.hrmp_max_teyrchain_inbound_channels,
)
.unwrap();
Configuration::set_hrmp_channel_max_message_size(
RuntimeOrigin::root(),
new_config.hrmp_channel_max_message_size,
)
.unwrap();
Configuration::set_hrmp_max_teyrchain_outbound_channels(
RuntimeOrigin::root(),
new_config.hrmp_max_teyrchain_outbound_channels,
)
.unwrap();
Configuration::set_hrmp_max_message_num_per_candidate(
RuntimeOrigin::root(),
new_config.hrmp_max_message_num_per_candidate,
)
.unwrap();
Configuration::set_pvf_voting_ttl(RuntimeOrigin::root(), new_config.pvf_voting_ttl)
.unwrap();
Configuration::set_minimum_backing_votes(
RuntimeOrigin::root(),
new_config.minimum_backing_votes,
)
.unwrap();
Configuration::set_node_feature(RuntimeOrigin::root(), 1, true).unwrap();
Configuration::set_node_feature(RuntimeOrigin::root(), 1, true).unwrap();
Configuration::set_node_feature(RuntimeOrigin::root(), 3, true).unwrap();
Configuration::set_node_feature(RuntimeOrigin::root(), 10, true).unwrap();
Configuration::set_node_feature(RuntimeOrigin::root(), 10, false).unwrap();
Configuration::set_node_feature(RuntimeOrigin::root(), 11, true).unwrap();
assert_eq!(PendingConfigs::<Test>::get(), vec![(shared::SESSION_DELAY, new_config)],);
})
}
#[test]
fn non_root_cannot_set_config() {
new_test_ext(Default::default()).execute_with(|| {
assert!(Configuration::set_validation_upgrade_delay(RuntimeOrigin::signed(1), 100).is_err());
});
}
#[test]
fn verify_externally_accessible() {
// This test verifies that the value can be accessed through the well known keys and the
// host configuration decodes into the abridged version.
use pezkuwi_primitives::{well_known_keys, AbridgedHostConfiguration};
new_test_ext(Default::default()).execute_with(|| {
let mut ground_truth = HostConfiguration::default();
ground_truth.async_backing_params =
AsyncBackingParams { allowed_ancestry_len: 111, max_candidate_depth: 222 };
// Make sure that the configuration is stored in the storage.
ActiveConfig::<Test>::put(ground_truth.clone());
// Extract the active config via the well known key.
let raw_active_config = pezsp_io::storage::get(well_known_keys::ACTIVE_CONFIG)
.expect("config must be present in storage under ACTIVE_CONFIG");
let abridged_config = AbridgedHostConfiguration::decode(&mut &raw_active_config[..])
.expect("HostConfiguration must be decodable into AbridgedHostConfiguration");
assert_eq!(
abridged_config,
AbridgedHostConfiguration {
max_code_size: ground_truth.max_code_size,
max_head_data_size: ground_truth.max_head_data_size,
max_upward_queue_count: ground_truth.max_upward_queue_count,
max_upward_queue_size: ground_truth.max_upward_queue_size,
max_upward_message_size: ground_truth.max_upward_message_size,
max_upward_message_num_per_candidate: ground_truth
.max_upward_message_num_per_candidate,
hrmp_max_message_num_per_candidate: ground_truth.hrmp_max_message_num_per_candidate,
validation_upgrade_cooldown: ground_truth.validation_upgrade_cooldown,
validation_upgrade_delay: ground_truth.validation_upgrade_delay,
async_backing_params: ground_truth.async_backing_params,
},
);
});
}
#[test]
fn active_config_hrmp_channel_size_and_capacity_ratio_works() {
pezframe_support::parameter_types! {
pub Ratio100: Percent = Percent::from_percent(100);
pub Ratio50: Percent = Percent::from_percent(50);
}
let mut genesis: MockGenesisConfig = Default::default();
genesis.configuration.config.hrmp_channel_max_message_size = 1024;
genesis.configuration.config.hrmp_channel_max_capacity = 100;
new_test_ext(genesis).execute_with(|| {
let active_config = configuration::ActiveConfig::<Test>::get();
assert_eq!(active_config.hrmp_channel_max_message_size, 1024);
assert_eq!(active_config.hrmp_channel_max_capacity, 100);
assert_eq!(
ActiveConfigHrmpChannelSizeAndCapacityRatio::<Test, Ratio100>::get(),
(1024, 100)
);
assert_eq!(ActiveConfigHrmpChannelSizeAndCapacityRatio::<Test, Ratio50>::get(), (512, 50));
// change ActiveConfig
assert_ok!(Configuration::set_hrmp_channel_max_message_size(
RuntimeOrigin::root(),
active_config.hrmp_channel_max_message_size * 4
));
assert_ok!(Configuration::set_hrmp_channel_max_capacity(
RuntimeOrigin::root(),
active_config.hrmp_channel_max_capacity * 4
));
on_new_session(1);
on_new_session(2);
let active_config = configuration::ActiveConfig::<Test>::get();
assert_eq!(active_config.hrmp_channel_max_message_size, 4096);
assert_eq!(active_config.hrmp_channel_max_capacity, 400);
assert_eq!(
ActiveConfigHrmpChannelSizeAndCapacityRatio::<Test, Ratio100>::get(),
(4096, 400)
);
assert_eq!(
ActiveConfigHrmpChannelSizeAndCapacityRatio::<Test, Ratio50>::get(),
(2048, 200)
);
})
}