diff --git a/.github/workflows/runtimes-matrix.json b/.github/workflows/runtimes-matrix.json
index f599883850..265924dc10 100644
--- a/.github/workflows/runtimes-matrix.json
+++ b/.github/workflows/runtimes-matrix.json
@@ -58,6 +58,7 @@
"name": "coretime-kusama",
"package": "coretime-kusama-runtime",
"path": "system-parachains/coretime/coretime-kusama",
+ "uri": "wss://kusama-coretime-rpc.polkadot.io:443",
"is_relay": false
},
{
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 13a53d17b1..b991c1dfdf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
- Add `pallet-vesting` to Asset Hubs ([polkadot-fellows/runtimes#269](https://github.com/polkadot-fellows/runtimes/pull/269))
+- Fix Kusama Coretime launch issues: import leases and fix renewals for short leases ([polkadot-fellows/runtimes#276](https://github.com/polkadot-fellows/runtimes/pull/276))
### Fixed
diff --git a/Cargo.lock b/Cargo.lock
index d027c561b1..3845488f4e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -7282,9 +7282,9 @@ dependencies = [
[[package]]
name = "pallet-broker"
-version = "0.7.0"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd8cfe04e8c3f9ca8342ac785f2b1aee6140e1809546fc6f3a99fad20a8dfbf9"
+checksum = "3626d7e8e49b153b84c74594e1fb4b6d64720b5a9588297d3ba3c049c3b3b9e3"
dependencies = [
"bitvec",
"frame-benchmarking",
diff --git a/Cargo.toml b/Cargo.toml
index 77df62b3f2..88f7f83653 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -68,7 +68,7 @@ pallet-bridge-grandpa = { version = "0.8.0", default-features = false }
pallet-bridge-messages = { version = "0.8.0", default-features = false }
pallet-bridge-parachains = { version = "0.8.0", default-features = false }
pallet-bridge-relayers = { version = "0.8.0", default-features = false }
-pallet-broker = { version = "0.7.0", default-features = false }
+pallet-broker = { version = "0.7.1", default-features = false }
pallet-child-bounties = { version = "28.0.0", default-features = false }
pallet-collator-selection = { version = "10.0.0", default-features = false }
pallet-collective = { version = "29.0.0", default-features = false }
diff --git a/relay/kusama/Cargo.toml b/relay/kusama/Cargo.toml
index 44f6a79367..9c73470343 100644
--- a/relay/kusama/Cargo.toml
+++ b/relay/kusama/Cargo.toml
@@ -21,7 +21,7 @@ kusama-runtime-constants = { package = "kusama-runtime-constants", path = "const
sp-api = { workspace = true }
inherents = { package = "sp-inherents", default-features = false , version = "27.0.0" }
offchain-primitives = { package = "sp-offchain", default-features = false , version = "27.0.0" }
-sp-std = { package = "sp-std", workspace = true }
+sp-std = { workspace = true }
sp-application-crypto = { workspace = true }
sp-arithmetic = { workspace = true }
sp-genesis-builder = { workspace = true }
diff --git a/system-parachains/coretime/coretime-kusama/src/lib.rs b/system-parachains/coretime/coretime-kusama/src/lib.rs
index 7500be16bb..0da38ad843 100644
--- a/system-parachains/coretime/coretime-kusama/src/lib.rs
+++ b/system-parachains/coretime/coretime-kusama/src/lib.rs
@@ -23,6 +23,7 @@
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
mod coretime;
+mod migrations;
#[cfg(test)]
mod tests;
mod weights;
@@ -106,7 +107,10 @@ pub type UncheckedExtrinsic =
generic::UncheckedExtrinsic
;
/// Migrations to apply on runtime upgrade.
-pub type Migrations = (pallet_xcm::migration::MigrateToLatestXcmVersion,);
+pub type Migrations = (
+ pallet_xcm::migration::MigrateToLatestXcmVersion,
+ migrations::bootstrapping::ImportLeases,
+);
/// Executive: handles dispatch to the various modules.
pub type Executive = frame_executive::Executive<
@@ -129,7 +133,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("coretime-kusama"),
impl_name: create_runtime_str!("coretime-kusama"),
authoring_version: 1,
- spec_version: 1_002_000,
+ spec_version: 1_002_002,
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
transaction_version: 0,
diff --git a/system-parachains/coretime/coretime-kusama/src/migrations.rs b/system-parachains/coretime/coretime-kusama/src/migrations.rs
new file mode 100644
index 0000000000..94e8903b09
--- /dev/null
+++ b/system-parachains/coretime/coretime-kusama/src/migrations.rs
@@ -0,0 +1,253 @@
+// Copyright (C) Parity Technologies and the various Polkadot contributors, see Contributions.md
+// for a list of specific contributors.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/// The XCM Transact which was meant to set the leases as part of the Kusama relay runtime upgrade
+/// did not have enough weight. Therefore the leases were not migrated.
+///
+/// This migration populates the leases and restarts the sale from whichever timeslice it runs.
+///
+/// This does not affect storage structure, only values.
+pub mod bootstrapping {
+ use crate::{weights, Runtime, RuntimeOrigin};
+ use frame_support::{pallet_prelude::*, traits::OnRuntimeUpgrade};
+ #[cfg(feature = "try-runtime")]
+ use pallet_broker::{
+ AllowedRenewalId, AllowedRenewalRecord, AllowedRenewals, Configuration,
+ CoreAssignment::{Pool, Task},
+ CoreMask, LeaseRecordItem, SaleInfo, SaleInfoRecordOf, Schedule, ScheduleItem, Workplan,
+ };
+ use pallet_broker::{Leases, WeightInfo};
+ #[cfg(feature = "try-runtime")]
+ use sp_runtime::TryRuntimeError;
+ #[cfg(feature = "try-runtime")]
+ use sp_std::vec::Vec;
+
+ /// The log target.
+ const TARGET: &str = "runtime::bootstrapping::import-leases";
+
+ // Alias into the broker weights for this runtime.
+ type BrokerWeights = weights::pallet_broker::WeightInfo;
+
+ pub struct ImportLeases;
+
+ impl OnRuntimeUpgrade for ImportLeases {
+ fn on_runtime_upgrade() -> Weight {
+ // This migration contains hardcoded values only relevant to Kusama Coretime
+ // 1002000 before it has any leases. These checks could be tightened.
+ if Leases::::decode_len().unwrap_or(0) > 0 {
+ // Already has leases, bail
+ log::error!(target: TARGET, "This migration includes hardcoded values not relevant to this runtime. Bailing.");
+ return ::DbWeight::get().reads(1);
+ }
+
+ for (para_id, end) in LEASES {
+ match pallet_broker::Pallet::::set_lease(
+ RuntimeOrigin::root(),
+ para_id,
+ end,
+ ) {
+ Ok(_) =>
+ log::info!(target: TARGET, "Importing lease for parachain {}", ¶_id),
+ Err(_) =>
+ log::error!(target: TARGET, "Importing lease for parachain {} failed!", ¶_id),
+ }
+ }
+
+ // The values used in referendum 375 included 52 cores. Replaying this here shifts the
+ // start of the sale, while crucially populating the workplan with the leases and
+ // recalculating the number of cores to be offered. However, there are 4 system
+ // parachains + 1 pool core + 47 leases + 3 cores for the open market, therefore we need
+ // to start sales with 55 cores.
+ let core_count = pallet_broker::Reservations::::decode_len().unwrap_or(0)
+ as u16 + pallet_broker::Leases::::decode_len().unwrap_or(0)
+ as u16 + 3;
+
+ match pallet_broker::Pallet::::request_core_count(
+ RuntimeOrigin::root(),
+ core_count,
+ ) {
+ Ok(_) => log::info!(target: TARGET, "Request for 55 cores sent."),
+ Err(_) => log::error!(target: TARGET, "Request for 55 cores failed to send."),
+ }
+ match pallet_broker::Pallet::::start_sales(
+ RuntimeOrigin::root(),
+ 5_000_000_000_000,
+ core_count,
+ ) {
+ Ok(_) => log::info!(target: TARGET, "Sales started"),
+ Err(_) => log::error!(target: TARGET, "Start sales failed!"),
+ }
+
+ // Weight for setting every lease and starting the sales, plus one read for leases
+ // check.
+ BrokerWeights::set_lease()
+ .saturating_mul(LEASES.len() as u64)
+ .saturating_add(BrokerWeights::request_core_count(55))
+ .saturating_add(BrokerWeights::start_sales(55))
+ .saturating_add(::DbWeight::get().reads(1))
+ }
+
+ #[cfg(feature = "try-runtime")]
+ fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> {
+ if Leases::::decode_len().unwrap_or(0) > 0 {
+ return Ok(Vec::new())
+ }
+ let sale_info = SaleInfo::::get().unwrap();
+ Ok(sale_info.encode())
+ }
+
+ #[cfg(feature = "try-runtime")]
+ fn post_upgrade(state: Vec) -> Result<(), TryRuntimeError> {
+ if state.is_empty() {
+ return Ok(())
+ }
+ let prev_sale_info = >::decode(&mut &state[..]).unwrap();
+
+ log::info!(target: TARGET, "Checking migration.");
+
+ let sale_info = SaleInfo::::get().unwrap();
+ let now = frame_system::Pallet::::block_number();
+ let config = Configuration::::get().unwrap();
+
+ // Check the sale start has changed as expected and the cores_offered is the correct
+ // number.
+ assert_eq!(sale_info.sale_start, now + config.interlude_length);
+ assert!(sale_info.region_begin > prev_sale_info.region_begin);
+ assert_eq!(sale_info.cores_offered, 3);
+
+ // The workplan entries start from the region begin reported by the new SaleInfo.
+ let workplan_start = sale_info.region_begin;
+
+ // Check the reservations are still in the workplan out of an abundance of caution.
+ for (core_id, task) in
+ [Task(1000), Task(1001), Task(1002), Task(1005), Pool].into_iter().enumerate()
+ {
+ assert_eq!(
+ Workplan::::get((workplan_start, core_id as u16)),
+ Some(Schedule::truncate_from(Vec::from([ScheduleItem {
+ mask: CoreMask::complete(),
+ assignment: task,
+ }])))
+ );
+ }
+
+ // Because we also run start_sales, 12 expiring leases are removed from the original 47,
+ // leaving 35.
+ let leases = Leases::::get();
+ assert_eq!(
+ leases.len(),
+ LEASES.iter().filter(|(_, l)| sale_info.region_end <= *l).count()
+ );
+
+ // Iterate through hardcoded leases and check they're all correctly in state (leases or
+ // allowedrenewals) and scheduled in the workplan.
+ for (i, (para_id, until)) in LEASES.iter().enumerate() {
+ // Add the system parachains and pool core as an offset - these should come before
+ // the leases.
+ let core_id = i as u16 + 5;
+ // This is the entry found in Workplan and AllowedRenewal
+ let workload = Schedule::truncate_from(Vec::from([ScheduleItem {
+ mask: CoreMask::complete(),
+ assignment: Task(*para_id),
+ }]));
+
+ // Check that the 12 who no longer have a lease can renew.
+ if !leases.contains(&LeaseRecordItem { until: *until, task: *para_id }) {
+ assert_eq!(
+ AllowedRenewals::::get(AllowedRenewalId {
+ core: core_id,
+ when: sale_info.region_end,
+ }),
+ Some(AllowedRenewalRecord {
+ price: 5_000_000_000_000,
+ completion: pallet_broker::CompletionStatus::Complete(workload.clone())
+ })
+ );
+ }
+ // They should all be in the workplan for next sale.
+ assert_eq!(Workplan::::get((workplan_start, core_id)), Some(workload));
+ }
+
+ // Ensure we have requested the correct number of events.
+ assert!(frame_system::Pallet::::read_events_no_consensus().any(|e| {
+ match e.event {
+ crate::RuntimeEvent::Broker(
+ pallet_broker::Event::::CoreCountRequested { core_count },
+ ) => {
+ log::info!("{core_count:?}");
+
+ core_count == 55
+ },
+ _ => false,
+ }
+ }));
+
+ Ok(())
+ }
+ }
+
+ // Hardcoded para ids and their end timeslice.
+ // Calculated using https://github.com/seadanda/coretime-scripts/blob/main/get_leases.py
+ const LEASES: [(u32, u32); 47] = [
+ (2000, 340200),
+ (2001, 302400),
+ (2004, 332640),
+ (2007, 317520),
+ (2011, 325080),
+ (2012, 309960),
+ (2015, 287280),
+ (2023, 309960),
+ (2024, 309960),
+ (2048, 302400),
+ (2084, 340200),
+ (2085, 294840),
+ (2087, 340200),
+ (2088, 287280),
+ (2090, 340200),
+ (2092, 287280),
+ (2095, 332640),
+ (2096, 332640),
+ (2105, 325080),
+ (2106, 325080),
+ (2110, 317520),
+ (2113, 332640),
+ (2114, 317520),
+ (2119, 340200),
+ (2121, 332640),
+ (2123, 294840),
+ (2124, 287280),
+ (2125, 294840),
+ (2222, 302400),
+ (2233, 294840),
+ (2236, 317520),
+ (2239, 332640),
+ (2241, 325080),
+ (2274, 294840),
+ (2275, 294840),
+ (2281, 302400),
+ (3334, 309960),
+ (3336, 317520),
+ (3338, 317520),
+ (3339, 325080),
+ (3340, 325080),
+ (3343, 317520),
+ (3344, 340200),
+ (3345, 325080),
+ (3347, 287280),
+ (3348, 287280),
+ (3350, 340200),
+ ];
+}