mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 09:51:02 +00:00
Parathreads Feature Branch (#6969)
* First baby steps * Split scheduler into several modules * Towards a more modular approach for scheduling * move free_cores; IntoInterator -> BTreeMap * Move clear() * Move more functions out of scheduler * Change weight composition * More abstraction * Further refactor * clippy * fmt * fix test-runtime * Add parathreads pallet to construct_runtime! * Make all runtimes use (Parachains, Parathreads) scheduling * Delete commented out code * Remove parathreads scheduler from westend, rococo, and kusama * fix rococo, westend, and kusama config * Revert "fix rococo, westend, and kusama config" This reverts commit 59e4de380d5c7d17eaaba5e2c2b81405de3465e3. * Revert "Remove parathreads scheduler from westend, rococo, and kusama" This reverts commit 4c44255296083ac5670560790ed77104917890a4. * Remove CoreIndex from free_cores * Remove unnecessary struct for parathreads * parathreads provider take 1 * Comment out parathread tests * Pop into lookahead * fmt * Fill lookahead with two entries for parachains * fmt * Current stage * Towards ab parathreads * no AB use * Make tests typecheck * quick hack to set scheduling lookahead to 1 * Fix scheduler tests * fix paras_inherent tests * misc * Update more of a test * cfg(test) * some cleanup * Undo paras_inherent changes * Adjust paras inherent tests * Undo changes to v2 primitives * Undo v2 mod changes to tests * minor * Remove parathreads assigner and pallet * minor * minor * more cleanup * fmt * minor * minor * minor * Remove on_new_session from assignment provider * Make adder collator integration test pass * disable failing unit tests * minor * minor * re-enable one unit test * minor * handle retries, add concluded para to pop interface * comment out unused code * Remove core_para from interface * Remove first claimqueue element on clear if None instead removing all Nones * Move claimqueue get out of loop * Use VecDeque instead of Ved in ClaimQueue * Make occupied() AB ready(?) * handle freed disputed in clear_and_fill_claimqueue * clear_and_fill_claimqueue returns scheduled Vec * Rename and minor refactor * return position of assignment taken from claimqueue * minor * Fix session boundary parachains number change + extended test * Fix runtimes * Fix polkadot runtime * Remove polkadot pallet from benchmarks * fix test runtime * Add storage migration * Minor refactor * Minor * migratin typechecks * Add migration to runtimes * Towards modular scheduling II (#6568) * Add post migration check * pebkac * Disable migrations but mine * Revert "Disable migrations but mine" This reverts commit 4fa5c5a370c199944a7e0926f50b08626bfbad4c. * Move scheduler migration * Revert "Move scheduler migration" This reverts commit a16b1659a907950bae048a9f7010f2aa76e02b6d. * Fix migration * cleanup * Don't lose retries value anymore * comment out test function * Remove retries value from Assignment again * minor * Make collator for parathreads optional * data type refactor * update scheduler tests * Change test function cfg * comment out test function * Try cfg(test) only * fix cfg flags * Add get_max_retries function to provider interface (#7047) * Fix merge commit * pebkac * fix merge * update cargo.lock * fix merge * fix merge * Use btreemap instead of vec, fix scheduler calls. * Use imported `ScheduledCore` * Remove unused import in inclusion tests * Use keys() instead of mapping over a BTreeMap * Fix migrations for parachains scheduler * Use BlockNumberFor<T> everywhere in scheduler * Add on demand assignment provider pallet (#7110) * Address some PR comments * minor * more cleanup * find_map and timeout availability fixes * Change default scheduling_lookahead to 1 * Add on demand assignment provider pallet * Move test-runtime to new assignment provider * Run cargo format on scheduler tests * minor * Mutate cores in single loop * timeout predicate simplification * claimqueue desired size fix * Replace expect by ok_or * More improvements * Fix push back order and next_up_on_timeout * minor * session change docs * Add pre_new_session call to hand pre session updates * Remove sc_network dependency and PeerId from unnecessary data structures * Remove unnecessary peer_ids * Add OnDemandOrdering proxy (#7156) * Add OnDemandBidding proxy * Fix names * OnDemandAssigner for rococo only * Check PeerId in collator protocol before fetching collation * On occupied, remove non occupied cores from the claimqueue front and refill * Add missing docs * Comment out unused field * fix ScheduledCore in tests * Fix the fix * pebkac * fmt * Fix occupied dropping * Remove double import * ScheduledCore fixes * Readd sc-network dep * pebkac * OpaquePeerId -> PeerId in can_collate interface * Cargo.lock update for interface change * Remove checks not needed anymore? * Drop occupied core on session change if it would time out after the new session * Add on demand assignment provider pallet * Move test-runtime to new assignment provider * Run cargo format on scheduler tests * Add OnDemandOrdering proxy (#7156) * Add OnDemandBidding proxy * Fix names * OnDemandAssigner for rococo only * Remove unneeded config values * Update comments * Use and_then for queue position * Return the max size of the spot queue on error * Add comments to add_parathread_entry * Add module comments * Add log for when can_collate fails * Change assigner queue type to `Assignment` * Update assignment provider tests * More logs * Remove unused keyring import * disable can_collate * comment out can_collate * Can collate first checks set if empty * Move can_collate call to collation advertisement * Fix backing test * map to loop * Remove obsolete check * Move invalid collation test from backing to collator-protocol * fix unused imports * fix test * fix Debug derivation * Increase time limit on zombienet predicates * Increase zombienet timeout * Minor * Address some PR comments * Address PR comments * Comment out failing assert due to on-demand assigner missing * remove collator_restrictions info from backing * Move can_collate to ActiveParas * minor * minor * Update weight information for on demand config * Add ttl to parasentry * Fix tests missing parasentry ttl * Adjust scheduler tests to use ttl default values * Use match instead of if let for ttl drop * Use RuntimeDebug trait for `ParasEntry` fields * Add comments to on demand assignment pallet * Fix spot traffic calculation * Revert runtimedebug changes to primitives * Remove runtimedebug derivation from `ParasEntry` * Mention affinity in pallet level docs * Use RuntimeDebug trait for ParasEntry child types * Remove collator restrictions * Fix primitive versioning and other merge issues * Fix tests post merge * Fix node side tests * Edit parascheduler migration for clarity * Move parascheduler migration up to next release * Remove vestiges from merge * Fix tests * Refactor ttl handling * Remove unused things from scheduler tests * Move on demand assigner to own directory * Update documentation * Remove unused sc-network dependency in primitives Was used for collator restrictions * Remove unused import * Reenable scheduler test * Remove unused storage value * Enable timeout predicate test and fix fn Turns out that the issue with the compiler is fixed and we can now use impl Trait in the manner used here. * Remove unused imports * Add benchmarking entry for perbill in config * Correct typo * Address review comments * Log out errors when calculating spot traffic. * Change parascheduler's log target name * Update scheduler_common documentation * Use mutate for affinity fns, add tests * Add another on demand affinity test * Unify parathreads and parachains in HostConfig (take 2) (#7452) * Unify parathreads and parachains in HostConfig * Fixed missed occurences * Remove commented out lines * `HostConfiguration v7` * Fix version check * Add `MigrateToV7` to `Unreleased` * fmt * fmt * Fix compilation errors after the rebase * Update runtime/parachains/src/scheduler/tests.rs Co-authored-by: Anton Vilhelm Ásgeirsson <antonva@users.noreply.github.com> * Update runtime/parachains/src/scheduler/tests.rs Co-authored-by: Anton Vilhelm Ásgeirsson <antonva@users.noreply.github.com> * fmt * Fix migration test * Fix tests * Remove unneeded assert from tests * parathread_cores -> on_demand_cores; parathread_retries -> on_demand_retries * Fix a compilation error in tests * Remove unused `use` * update colander image version --------- Co-authored-by: alexgparity <alex.gremm@parity.io> Co-authored-by: Anton Vilhelm Ásgeirsson <antonva@users.noreply.github.com> Co-authored-by: Javier Viola <javier@parity.io> * Fix branch after merge with master * Refactor out duplicate checks into a helper fn * Fix tests post merge * Rename add_parathread_assignment, add test * Update docs * Remove unused on_finalize function * Add weight info to on demand pallet * Update runtime/parachains/src/configuration.rs Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> * Update runtime/parachains/src/scheduler_common/mod.rs Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> * Update runtime/parachains/src/assigner_on_demand/mod.rs Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> * Add benchmarking to on demand pallet * Make place_order test check for success * Add on demand benchmarks * Add local test weights to rococo runtime * Modify TTL drop behaviour to not skip claims Previous behaviour would jump a new claim from the assignment provider ahead in the claimqueue, assuming lookahead is larger than 1. * Refactor ttl test to test claimqueue order * Disable place_order ext. when no on_demand cores * Use default genesis config for benchmark tests * Refactor config builder param * Move lifecycle test from scheduler to on demand * Remove unneeded lifecycle test Paras module via the parachain assignment provider doesn't provide new assignments if a parachain loses it's lease. The on demand assignment provider doesn't provide an assignment that is not a parathread. * Re enable validator shuffle test * More realistic weights for place_order * Remove redundant import * Fix backwards compatibility (hopefully) * ".git/.scripts/commands/bench/bench.sh" --subcommand=runtime --runtime=rococo --target_dir=polkadot --pallet=runtime_parachains::assigner_on_demand * Fix tests. * Fix off-by-one. * Re enable claimqueue fills test * Re enable schedule_rotates_groups test * Fix fill_claimqueue_fills test * Re enable next_up_on_timeout test, move fn * Do not pop from assignment provider when retrying * Fix tests missing collator in scheduledcore * Add comment about timeout predicate. * Rename parasentry retries to availability timeouts * Re enable schedule_schedules... test * Refactor prune retried test to new scheduler * Have all scheduler tests use genesis_cfg fn * Update docs * Update copyright notices on new files * Rename is_parachain_core to is_bulk_core * Remove erroneous TODO * Simplify import * ".git/.scripts/commands/bench/bench.sh" --subcommand=runtime --runtime=rococo --target_dir=polkadot --pallet=runtime_parachains::configuration * Revert AdvertiseCollation order shuffle * Refactor place_order into keepalive and allowdeath * Revert rename of hrmp max inbound channels parachain encompasses both on demand and slot auction / bulk. * Restore availability_timeout_predicate function * Clean up leftover comments * Update runtime/parachains/src/scheduler/tests.rs Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> * ".git/.scripts/commands/bench/bench.sh" --subcommand=runtime --runtime=westend --target_dir=polkadot --pallet=runtime_parachains::configuration --------- Co-authored-by: alexgparity <alex.gremm@parity.io> Co-authored-by: alexgparity <115470171+alexgparity@users.noreply.github.com> Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> Co-authored-by: Javier Viola <javier@parity.io> Co-authored-by: eskimor <eskimor@no-such-url.com> Co-authored-by: command-bot <> * On Demand - update weights and small nits (#7605) * Remove collator restriction test in inclusion On demand parachains won't have collator restrictions implemented in this way but will instead use a preferred collator registered to a `ParaId` in `paras_registrar`. * Remove redundant config guard for test fns * Update weights * Update WeightInfo for on_demand assigner * Unify assignment provider parameters into one call (#7606) * Combine assignmentprovider params into one fn call * Move scheduler_common to a module under scheduler * Fix ttl handling in benchmark builder * Run cargo format * Remove obsolete test. * Small improvement. * Use same migration pattern as config module * Remove old TODO * Change log target name for assigner on demand * Fix migration * Fix clippy warnings * Add HostConfiguration storage migration to V8 * Add `MigrateToV8` to unreleased migrations for all runtimes * Fix storage version check for config v8 * Set `StorageVersion` to 8 in `MigrateToV8` * Remove dups. * Update primitives/src/v5/mod.rs Co-authored-by: Bastian Köcher <git@kchr.de> --------- Co-authored-by: alexgparity <alex.gremm@parity.io> Co-authored-by: alexgparity <115470171+alexgparity@users.noreply.github.com> Co-authored-by: antonva <anton.asgeirsson@parity.io> Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> Co-authored-by: Anton Vilhelm Ásgeirsson <antonva@users.noreply.github.com> Co-authored-by: Javier Viola <javier@parity.io> Co-authored-by: eskimor <eskimor@no-such-url.com> Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
@@ -0,0 +1,558 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot 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.
|
||||
|
||||
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
|
||||
use crate::{
|
||||
assigner_on_demand::{mock_helpers::GenesisConfigBuilder, Error},
|
||||
initializer::SessionChangeNotification,
|
||||
mock::{
|
||||
new_test_ext, Balances, OnDemandAssigner, Paras, ParasShared, RuntimeOrigin, Scheduler,
|
||||
System, Test,
|
||||
},
|
||||
paras::{ParaGenesisArgs, ParaKind},
|
||||
};
|
||||
use frame_support::{assert_noop, assert_ok, error::BadOrigin};
|
||||
use pallet_balances::Error as BalancesError;
|
||||
use primitives::{
|
||||
v5::{Assignment, ValidationCode},
|
||||
BlockNumber, SessionIndex,
|
||||
};
|
||||
use sp_std::collections::btree_map::BTreeMap;
|
||||
|
||||
fn schedule_blank_para(id: ParaId, parakind: ParaKind) {
|
||||
let validation_code: ValidationCode = vec![1, 2, 3].into();
|
||||
assert_ok!(Paras::schedule_para_initialize(
|
||||
id,
|
||||
ParaGenesisArgs {
|
||||
genesis_head: Vec::new().into(),
|
||||
validation_code: validation_code.clone(),
|
||||
para_kind: parakind,
|
||||
}
|
||||
));
|
||||
|
||||
assert_ok!(Paras::add_trusted_validation_code(RuntimeOrigin::root(), validation_code));
|
||||
}
|
||||
|
||||
fn run_to_block(
|
||||
to: BlockNumber,
|
||||
new_session: impl Fn(BlockNumber) -> Option<SessionChangeNotification<BlockNumber>>,
|
||||
) {
|
||||
while System::block_number() < to {
|
||||
let b = System::block_number();
|
||||
|
||||
Scheduler::initializer_finalize();
|
||||
Paras::initializer_finalize(b);
|
||||
|
||||
if let Some(notification) = new_session(b + 1) {
|
||||
let mut notification_with_session_index = notification;
|
||||
// We will make every session change trigger an action queue. Normally this may require
|
||||
// 2 or more session changes.
|
||||
if notification_with_session_index.session_index == SessionIndex::default() {
|
||||
notification_with_session_index.session_index = ParasShared::scheduled_session();
|
||||
}
|
||||
Paras::initializer_on_new_session(¬ification_with_session_index);
|
||||
Scheduler::initializer_on_new_session(¬ification_with_session_index);
|
||||
}
|
||||
|
||||
System::on_finalize(b);
|
||||
|
||||
System::on_initialize(b + 1);
|
||||
System::set_block_number(b + 1);
|
||||
|
||||
Paras::initializer_initialize(b + 1);
|
||||
Scheduler::initializer_initialize(b + 1);
|
||||
|
||||
// In the real runtime this is expected to be called by the `InclusionInherent` pallet.
|
||||
Scheduler::update_claimqueue(BTreeMap::new(), b + 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spot_traffic_capacity_zero_returns_none() {
|
||||
match OnDemandAssigner::calculate_spot_traffic(
|
||||
FixedU128::from(u128::MAX),
|
||||
0u32,
|
||||
u32::MAX,
|
||||
Perbill::from_percent(100),
|
||||
Perbill::from_percent(1),
|
||||
) {
|
||||
Ok(_) => panic!("Error"),
|
||||
Err(e) => assert_eq!(e, SpotTrafficCalculationErr::QueueCapacityIsZero),
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spot_traffic_queue_size_larger_than_capacity_returns_none() {
|
||||
match OnDemandAssigner::calculate_spot_traffic(
|
||||
FixedU128::from(u128::MAX),
|
||||
1u32,
|
||||
2u32,
|
||||
Perbill::from_percent(100),
|
||||
Perbill::from_percent(1),
|
||||
) {
|
||||
Ok(_) => panic!("Error"),
|
||||
Err(e) => assert_eq!(e, SpotTrafficCalculationErr::QueueSizeLargerThanCapacity),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spot_traffic_calculation_identity() {
|
||||
match OnDemandAssigner::calculate_spot_traffic(
|
||||
FixedU128::from_u32(1),
|
||||
1000,
|
||||
100,
|
||||
Perbill::from_percent(10),
|
||||
Perbill::from_percent(3),
|
||||
) {
|
||||
Ok(res) => {
|
||||
assert_eq!(res, FixedU128::from_u32(1))
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spot_traffic_calculation_u32_max() {
|
||||
match OnDemandAssigner::calculate_spot_traffic(
|
||||
FixedU128::from_u32(1),
|
||||
u32::MAX,
|
||||
u32::MAX,
|
||||
Perbill::from_percent(100),
|
||||
Perbill::from_percent(3),
|
||||
) {
|
||||
Ok(res) => {
|
||||
assert_eq!(res, FixedU128::from_u32(1))
|
||||
},
|
||||
_ => panic!("Error"),
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spot_traffic_calculation_u32_traffic_max() {
|
||||
match OnDemandAssigner::calculate_spot_traffic(
|
||||
FixedU128::from(u128::MAX),
|
||||
u32::MAX,
|
||||
u32::MAX,
|
||||
Perbill::from_percent(1),
|
||||
Perbill::from_percent(1),
|
||||
) {
|
||||
Ok(res) => assert_eq!(res, FixedU128::from(u128::MAX)),
|
||||
_ => panic!("Error"),
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sustained_target_increases_spot_traffic() {
|
||||
let mut traffic = FixedU128::from_u32(1u32);
|
||||
for _ in 0..50 {
|
||||
traffic = OnDemandAssigner::calculate_spot_traffic(
|
||||
traffic,
|
||||
100,
|
||||
12,
|
||||
Perbill::from_percent(10),
|
||||
Perbill::from_percent(100),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
assert_eq!(traffic, FixedU128::from_inner(2_718_103_312_071_174_015u128))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spot_traffic_can_decrease() {
|
||||
let traffic = FixedU128::from_u32(100u32);
|
||||
match OnDemandAssigner::calculate_spot_traffic(
|
||||
traffic,
|
||||
100u32,
|
||||
0u32,
|
||||
Perbill::from_percent(100),
|
||||
Perbill::from_percent(100),
|
||||
) {
|
||||
Ok(new_traffic) =>
|
||||
assert_eq!(new_traffic, FixedU128::from_inner(50_000_000_000_000_000_000u128)),
|
||||
_ => panic!("Error"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spot_traffic_decreases_over_time() {
|
||||
let mut traffic = FixedU128::from_u32(100u32);
|
||||
for _ in 0..5 {
|
||||
traffic = OnDemandAssigner::calculate_spot_traffic(
|
||||
traffic,
|
||||
100u32,
|
||||
0u32,
|
||||
Perbill::from_percent(100),
|
||||
Perbill::from_percent(100),
|
||||
)
|
||||
.unwrap();
|
||||
println!("{traffic}");
|
||||
}
|
||||
assert_eq!(traffic, FixedU128::from_inner(3_125_000_000_000_000_000u128))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn place_order_works() {
|
||||
let alice = 1u64;
|
||||
let amt = 10_000_000u128;
|
||||
let para_id = ParaId::from(111);
|
||||
|
||||
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
|
||||
// Initialize the parathread and wait for it to be ready.
|
||||
schedule_blank_para(para_id, ParaKind::Parathread);
|
||||
|
||||
assert!(!Paras::is_parathread(para_id));
|
||||
|
||||
run_to_block(100, |n| if n == 100 { Some(Default::default()) } else { None });
|
||||
|
||||
assert!(Paras::is_parathread(para_id));
|
||||
|
||||
// Does not work unsigned
|
||||
assert_noop!(
|
||||
OnDemandAssigner::place_order_allow_death(RuntimeOrigin::none(), amt, para_id),
|
||||
BadOrigin
|
||||
);
|
||||
|
||||
// Does not work with max_amount lower than fee
|
||||
let low_max_amt = 1u128;
|
||||
assert_noop!(
|
||||
OnDemandAssigner::place_order_allow_death(
|
||||
RuntimeOrigin::signed(alice),
|
||||
low_max_amt,
|
||||
para_id,
|
||||
),
|
||||
Error::<Test>::SpotPriceHigherThanMaxAmount,
|
||||
);
|
||||
|
||||
// Does not work with insufficient balance
|
||||
assert_noop!(
|
||||
OnDemandAssigner::place_order_allow_death(RuntimeOrigin::signed(alice), amt, para_id),
|
||||
BalancesError::<Test, _>::InsufficientBalance
|
||||
);
|
||||
|
||||
// Works
|
||||
Balances::make_free_balance_be(&alice, amt);
|
||||
run_to_block(101, |n| if n == 101 { Some(Default::default()) } else { None });
|
||||
assert_ok!(OnDemandAssigner::place_order_allow_death(
|
||||
RuntimeOrigin::signed(alice),
|
||||
amt,
|
||||
para_id
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn place_order_keep_alive_keeps_alive() {
|
||||
let alice = 1u64;
|
||||
let amt = 1u128; // The same as crate::mock's EXISTENTIAL_DEPOSIT
|
||||
let max_amt = 10_000_000u128;
|
||||
let para_id = ParaId::from(111);
|
||||
|
||||
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
|
||||
// Initialize the parathread and wait for it to be ready.
|
||||
schedule_blank_para(para_id, ParaKind::Parathread);
|
||||
Balances::make_free_balance_be(&alice, amt);
|
||||
|
||||
assert!(!Paras::is_parathread(para_id));
|
||||
run_to_block(100, |n| if n == 100 { Some(Default::default()) } else { None });
|
||||
assert!(Paras::is_parathread(para_id));
|
||||
|
||||
assert_noop!(
|
||||
OnDemandAssigner::place_order_keep_alive(
|
||||
RuntimeOrigin::signed(alice),
|
||||
max_amt,
|
||||
para_id
|
||||
),
|
||||
BalancesError::<Test, _>::InsufficientBalance
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_on_demand_assignment_works() {
|
||||
let para_a = ParaId::from(111);
|
||||
let assignment = Assignment::new(para_a);
|
||||
|
||||
let mut genesis = GenesisConfigBuilder::default();
|
||||
genesis.on_demand_max_queue_size = 1;
|
||||
new_test_ext(genesis.build()).execute_with(|| {
|
||||
// Initialize the parathread and wait for it to be ready.
|
||||
schedule_blank_para(para_a, ParaKind::Parathread);
|
||||
|
||||
// `para_a` is not onboarded as a parathread yet.
|
||||
assert_noop!(
|
||||
OnDemandAssigner::add_on_demand_assignment(
|
||||
assignment.clone(),
|
||||
QueuePushDirection::Back
|
||||
),
|
||||
Error::<Test>::InvalidParaId
|
||||
);
|
||||
|
||||
assert!(!Paras::is_parathread(para_a));
|
||||
run_to_block(100, |n| if n == 100 { Some(Default::default()) } else { None });
|
||||
assert!(Paras::is_parathread(para_a));
|
||||
|
||||
// `para_a` is now onboarded as a valid parathread.
|
||||
assert_ok!(OnDemandAssigner::add_on_demand_assignment(
|
||||
assignment.clone(),
|
||||
QueuePushDirection::Back
|
||||
));
|
||||
|
||||
// Max queue size is 1, queue should be full.
|
||||
assert_noop!(
|
||||
OnDemandAssigner::add_on_demand_assignment(assignment, QueuePushDirection::Back),
|
||||
Error::<Test>::QueueFull
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spotqueue_push_directions() {
|
||||
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
|
||||
let para_a = ParaId::from(111);
|
||||
let para_b = ParaId::from(222);
|
||||
let para_c = ParaId::from(333);
|
||||
|
||||
schedule_blank_para(para_a, ParaKind::Parathread);
|
||||
schedule_blank_para(para_b, ParaKind::Parathread);
|
||||
schedule_blank_para(para_c, ParaKind::Parathread);
|
||||
|
||||
run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None });
|
||||
|
||||
let assignment_a = Assignment { para_id: para_a };
|
||||
let assignment_b = Assignment { para_id: para_b };
|
||||
let assignment_c = Assignment { para_id: para_c };
|
||||
|
||||
assert_ok!(OnDemandAssigner::add_on_demand_assignment(
|
||||
assignment_a.clone(),
|
||||
QueuePushDirection::Front
|
||||
));
|
||||
assert_ok!(OnDemandAssigner::add_on_demand_assignment(
|
||||
assignment_b.clone(),
|
||||
QueuePushDirection::Front
|
||||
));
|
||||
|
||||
assert_ok!(OnDemandAssigner::add_on_demand_assignment(
|
||||
assignment_c.clone(),
|
||||
QueuePushDirection::Back
|
||||
));
|
||||
|
||||
assert_eq!(OnDemandAssigner::queue_size(), 3);
|
||||
assert_eq!(
|
||||
OnDemandAssigner::get_queue(),
|
||||
VecDeque::from(vec![assignment_b, assignment_a, assignment_c])
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn affinity_changes_work() {
|
||||
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
|
||||
let para_a = ParaId::from(111);
|
||||
schedule_blank_para(para_a, ParaKind::Parathread);
|
||||
|
||||
run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None });
|
||||
|
||||
let assignment_a = Assignment { para_id: para_a };
|
||||
// There should be no affinity before starting.
|
||||
assert!(OnDemandAssigner::get_affinity_map(para_a).is_none());
|
||||
|
||||
// Add enough assignments to the order queue.
|
||||
for _ in 0..10 {
|
||||
OnDemandAssigner::add_on_demand_assignment(
|
||||
assignment_a.clone(),
|
||||
QueuePushDirection::Front,
|
||||
)
|
||||
.expect("Invalid paraid or queue full");
|
||||
}
|
||||
|
||||
// There should be no affinity before the scheduler pops.
|
||||
assert!(OnDemandAssigner::get_affinity_map(para_a).is_none());
|
||||
|
||||
OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), None);
|
||||
|
||||
// Affinity count is 1 after popping.
|
||||
assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 1);
|
||||
|
||||
OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_a));
|
||||
|
||||
// Affinity count is 1 after popping with a previous para.
|
||||
assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 1);
|
||||
assert_eq!(OnDemandAssigner::queue_size(), 8);
|
||||
|
||||
for _ in 0..3 {
|
||||
OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), None);
|
||||
}
|
||||
|
||||
// Affinity count is 4 after popping 3 times without a previous para.
|
||||
assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 4);
|
||||
assert_eq!(OnDemandAssigner::queue_size(), 5);
|
||||
|
||||
for _ in 0..5 {
|
||||
OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_a));
|
||||
}
|
||||
|
||||
// Affinity count should still be 4 but queue should be empty.
|
||||
assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 4);
|
||||
assert_eq!(OnDemandAssigner::queue_size(), 0);
|
||||
|
||||
// Pop 4 times and get to exactly 0 (None) affinity.
|
||||
for _ in 0..4 {
|
||||
OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_a));
|
||||
}
|
||||
assert!(OnDemandAssigner::get_affinity_map(para_a).is_none());
|
||||
|
||||
// Decreasing affinity beyond 0 should still be None.
|
||||
OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_a));
|
||||
assert!(OnDemandAssigner::get_affinity_map(para_a).is_none());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn affinity_prohibits_parallel_scheduling() {
|
||||
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
|
||||
let para_a = ParaId::from(111);
|
||||
let para_b = ParaId::from(222);
|
||||
|
||||
schedule_blank_para(para_a, ParaKind::Parathread);
|
||||
schedule_blank_para(para_b, ParaKind::Parathread);
|
||||
|
||||
run_to_block(11, |n| if n == 11 { Some(Default::default()) } else { None });
|
||||
|
||||
let assignment_a = Assignment { para_id: para_a };
|
||||
let assignment_b = Assignment { para_id: para_b };
|
||||
|
||||
// There should be no affinity before starting.
|
||||
assert!(OnDemandAssigner::get_affinity_map(para_a).is_none());
|
||||
assert!(OnDemandAssigner::get_affinity_map(para_b).is_none());
|
||||
|
||||
// Add 2 assignments for para_a for every para_b.
|
||||
OnDemandAssigner::add_on_demand_assignment(assignment_a.clone(), QueuePushDirection::Back)
|
||||
.expect("Invalid paraid or queue full");
|
||||
|
||||
OnDemandAssigner::add_on_demand_assignment(assignment_a.clone(), QueuePushDirection::Back)
|
||||
.expect("Invalid paraid or queue full");
|
||||
|
||||
OnDemandAssigner::add_on_demand_assignment(assignment_b.clone(), QueuePushDirection::Back)
|
||||
.expect("Invalid paraid or queue full");
|
||||
|
||||
assert_eq!(OnDemandAssigner::queue_size(), 3);
|
||||
|
||||
// Approximate having 1 core.
|
||||
for _ in 0..3 {
|
||||
OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), None);
|
||||
}
|
||||
|
||||
// Affinity on one core is meaningless.
|
||||
assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 2);
|
||||
assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().count, 1);
|
||||
assert_eq!(
|
||||
OnDemandAssigner::get_affinity_map(para_a).unwrap().core_idx,
|
||||
OnDemandAssigner::get_affinity_map(para_b).unwrap().core_idx
|
||||
);
|
||||
|
||||
// Clear affinity
|
||||
OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_a));
|
||||
OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_a));
|
||||
OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_b));
|
||||
|
||||
// Add 2 assignments for para_a for every para_b.
|
||||
OnDemandAssigner::add_on_demand_assignment(assignment_a.clone(), QueuePushDirection::Back)
|
||||
.expect("Invalid paraid or queue full");
|
||||
|
||||
OnDemandAssigner::add_on_demand_assignment(assignment_a.clone(), QueuePushDirection::Back)
|
||||
.expect("Invalid paraid or queue full");
|
||||
|
||||
OnDemandAssigner::add_on_demand_assignment(assignment_b.clone(), QueuePushDirection::Back)
|
||||
.expect("Invalid paraid or queue full");
|
||||
|
||||
// Approximate having 2 cores.
|
||||
for _ in 0..3 {
|
||||
OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), None);
|
||||
OnDemandAssigner::pop_assignment_for_core(CoreIndex(1), None);
|
||||
}
|
||||
|
||||
// Affinity should be the same as before, but on different cores.
|
||||
assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().count, 2);
|
||||
assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().count, 1);
|
||||
assert_eq!(OnDemandAssigner::get_affinity_map(para_a).unwrap().core_idx, CoreIndex(0));
|
||||
assert_eq!(OnDemandAssigner::get_affinity_map(para_b).unwrap().core_idx, CoreIndex(1));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_place_order_when_no_on_demand_cores() {
|
||||
let mut genesis = GenesisConfigBuilder::default();
|
||||
genesis.on_demand_cores = 0;
|
||||
let para_id = ParaId::from(10);
|
||||
let alice = 1u64;
|
||||
let amt = 10_000_000u128;
|
||||
|
||||
new_test_ext(genesis.build()).execute_with(|| {
|
||||
schedule_blank_para(para_id, ParaKind::Parathread);
|
||||
Balances::make_free_balance_be(&alice, amt);
|
||||
|
||||
assert!(!Paras::is_parathread(para_id));
|
||||
|
||||
run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None });
|
||||
|
||||
assert!(Paras::is_parathread(para_id));
|
||||
|
||||
assert_noop!(
|
||||
OnDemandAssigner::place_order_allow_death(RuntimeOrigin::signed(alice), amt, para_id),
|
||||
Error::<Test>::NoOnDemandCores
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn on_demand_orders_cannot_be_popped_if_lifecycle_changes() {
|
||||
let para_id = ParaId::from(10);
|
||||
let assignment = Assignment { para_id };
|
||||
|
||||
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
|
||||
// Register the para_id as a parathread
|
||||
schedule_blank_para(para_id, ParaKind::Parathread);
|
||||
|
||||
assert!(!Paras::is_parathread(para_id));
|
||||
run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None });
|
||||
assert!(Paras::is_parathread(para_id));
|
||||
|
||||
// Add two assignments for a para_id with a valid lifecycle.
|
||||
assert_ok!(OnDemandAssigner::add_on_demand_assignment(
|
||||
assignment.clone(),
|
||||
QueuePushDirection::Back
|
||||
));
|
||||
assert_ok!(OnDemandAssigner::add_on_demand_assignment(
|
||||
assignment.clone(),
|
||||
QueuePushDirection::Back
|
||||
));
|
||||
|
||||
// First pop is fine
|
||||
assert!(OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), None) == Some(assignment));
|
||||
|
||||
// Deregister para
|
||||
assert_ok!(Paras::schedule_para_cleanup(para_id));
|
||||
|
||||
// Run to new session and verify that para_id is no longer a valid parathread.
|
||||
assert!(Paras::is_parathread(para_id));
|
||||
run_to_block(20, |n| if n == 20 { Some(Default::default()) } else { None });
|
||||
assert!(!Paras::is_parathread(para_id));
|
||||
|
||||
// Second pop should be None.
|
||||
assert!(OnDemandAssigner::pop_assignment_for_core(CoreIndex(0), Some(para_id)) == None);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user