// Copyright (C) Parity Technologies (UK) Ltd. // 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 . use super::*; use crate::{ configuration::HostConfiguration, initializer::SessionChangeNotification, mock::{ new_test_ext, Configuration, MockGenesisConfig, ParasShared, RuntimeOrigin, SessionInfo, System, Test, }, util::take_active_subset, }; use pezkuwi_primitives::{BlockNumber, SchedulerParams, ValidatorId, ValidatorIndex}; use pezsp_keyring::Sr25519Keyring; fn run_to_block( to: BlockNumber, new_session: impl Fn(BlockNumber) -> Option>, ) { while System::block_number() < to { let b = System::block_number(); SessionInfo::initializer_finalize(); ParasShared::initializer_finalize(); Configuration::initializer_finalize(); if let Some(notification) = new_session(b + 1) { Configuration::initializer_on_new_session(¬ification.session_index); ParasShared::initializer_on_new_session( notification.session_index, notification.random_seed, ¬ification.new_config, notification.validators.clone(), ); SessionInfo::initializer_on_new_session(¬ification); } System::on_finalize(b); System::on_initialize(b + 1); System::set_block_number(b + 1); Configuration::initializer_initialize(b + 1); ParasShared::initializer_initialize(b + 1); SessionInfo::initializer_initialize(b + 1); } } fn default_config() -> HostConfiguration { HostConfiguration { dispute_period: 2, needed_approvals: 3, scheduler_params: SchedulerParams { num_cores: 1, ..Default::default() }, ..Default::default() } } fn genesis_config() -> MockGenesisConfig { MockGenesisConfig { configuration: configuration::GenesisConfig { config: default_config() }, ..Default::default() } } fn session_changes(n: BlockNumber) -> Option> { if n.is_multiple_of(10) { Some(SessionChangeNotification { session_index: n / 10, ..Default::default() }) } else { None } } fn new_session_every_block(n: BlockNumber) -> Option> { Some(SessionChangeNotification { session_index: n, ..Default::default() }) } #[test] fn session_pruning_is_based_on_dispute_period() { new_test_ext(genesis_config()).execute_with(|| { // Dispute period starts at 2 let config = configuration::ActiveConfig::::get(); assert_eq!(config.dispute_period, 2); // Move to session 10 run_to_block(100, session_changes); // Earliest stored session is 10 - 2 = 8 assert_eq!(EarliestStoredSession::::get(), 8); // Pruning works as expected assert!(Sessions::::get(7).is_none()); assert!(Sessions::::get(8).is_some()); assert!(Sessions::::get(9).is_some()); // changing `dispute_period` works let dispute_period = 5; Configuration::set_dispute_period(RuntimeOrigin::root(), dispute_period).unwrap(); // Dispute period does not automatically change let config = configuration::ActiveConfig::::get(); assert_eq!(config.dispute_period, 2); // Two sessions later it will though run_to_block(120, session_changes); let config = configuration::ActiveConfig::::get(); assert_eq!(config.dispute_period, 5); run_to_block(200, session_changes); assert_eq!(EarliestStoredSession::::get(), 20 - dispute_period); // Increase dispute period even more let new_dispute_period = 16; Configuration::set_dispute_period(RuntimeOrigin::root(), new_dispute_period).unwrap(); run_to_block(210, session_changes); assert_eq!(EarliestStoredSession::::get(), 21 - dispute_period); // Two sessions later it kicks in run_to_block(220, session_changes); let config = configuration::ActiveConfig::::get(); assert_eq!(config.dispute_period, 16); // Earliest session stays the same assert_eq!(EarliestStoredSession::::get(), 21 - dispute_period); // We still don't have enough stored sessions to start pruning run_to_block(300, session_changes); assert_eq!(EarliestStoredSession::::get(), 21 - dispute_period); // now we do run_to_block(420, session_changes); assert_eq!(EarliestStoredSession::::get(), 42 - new_dispute_period); }) } #[test] fn session_info_is_based_on_config() { new_test_ext(genesis_config()).execute_with(|| { run_to_block(1, new_session_every_block); let session = Sessions::::get(&1).unwrap(); assert_eq!(session.needed_approvals, 3); // change some param Configuration::set_needed_approvals(RuntimeOrigin::root(), 42).unwrap(); // 2 sessions later run_to_block(3, new_session_every_block); let session = Sessions::::get(&3).unwrap(); assert_eq!(session.needed_approvals, 42); }) } #[test] fn session_info_active_subsets() { let unscrambled = vec![ Sr25519Keyring::Alice, Sr25519Keyring::Bob, Sr25519Keyring::Charlie, Sr25519Keyring::Dave, Sr25519Keyring::Eve, ]; let active_set = vec![ValidatorIndex(4), ValidatorIndex(0), ValidatorIndex(2)]; let unscrambled_validators: Vec = unscrambled.iter().map(|v| v.public().into()).collect(); let unscrambled_discovery: Vec = unscrambled.iter().map(|v| v.public().into()).collect(); let unscrambled_assignment: Vec = unscrambled.iter().map(|v| v.public().into()).collect(); let validators = take_active_subset(&active_set, &unscrambled_validators); new_test_ext(genesis_config()).execute_with(|| { ParasShared::set_active_validators_with_indices(active_set.clone(), validators.clone()); assert_eq!(shared::ActiveValidatorIndices::::get(), active_set); AssignmentKeysUnsafe::::set(unscrambled_assignment.clone()); crate::mock::set_discovery_authorities(unscrambled_discovery.clone()); assert_eq!(::authorities(), unscrambled_discovery); // invoke directly, because `run_to_block` will invoke `Shared` and clobber our // values. SessionInfo::initializer_on_new_session(&SessionChangeNotification { session_index: 1, validators: validators.clone(), ..Default::default() }); let session = Sessions::::get(&1).unwrap(); assert_eq!(session.validators.to_vec(), validators); assert_eq!( session.discovery_keys, take_active_subset_and_inactive(&active_set, &unscrambled_discovery), ); assert_eq!( session.assignment_keys, take_active_subset(&active_set, &unscrambled_assignment), ); }) }