Skip to content

Commit

Permalink
[coretime-kusama] Bump broker and add migration to import leases to f…
Browse files Browse the repository at this point in the history
…ix launch issues (#276)

For the transition to coretime, the relay runtime upgrade includes a
migration which sends a few XCMs to the coretime chain with Transacts.
This calls `set_lease` (a broker extrinsic on the coretime chain) for
all the leases that are currently in the relay state to get them a lease
on the coretime chain.
This happened yesterday but the XCM didn't have enough weight and so the
leases weren't migrated over. We decided to make a runtime upgrade since
there was a bug with the renewals for short leases anyway. This PR
solves both issues.

The bump to the broker pallet fixes a bug where very short leases
(ending in the first 28 days after running start_sales) could not be
renewed.

This PR includes a migration which does three things:
1. Imports a hardcoded list of leases into the state
2. Adds three cores to ensure there are enough cores for everyone to
renew while also leaving the intended 3 for the open market
3. restarts sales

The migration also tests the renewal fix with try-runtime.

- [ ] Does not require a CHANGELOG entry

---------

Co-authored-by: Bastian Köcher <[email protected]>
Co-authored-by: Bastian Köcher <[email protected]>
  • Loading branch information
3 people committed Apr 19, 2024
1 parent b6fbf15 commit 8c8575f
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 9 deletions.
1 change: 1 addition & 0 deletions .github/workflows/runtimes-matrix.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
{
Expand Down
5 changes: 2 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Fixed

- Bumped `bp-header-chain` dependency and added migration to Polkadot Bridge Hub to unstuck
bridge with Kusama. Details may be found in relevant
[polkadot-sdk](https://github.com/paritytech/polkadot-sdk/pull/4208) PR.
- Polkadot Bridge Hub: Unstuck bridge with Kusama ([polkadot-fellows/runtimes#277](https://github.com/polkadot-fellows/runtimes/pull/277))
- 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))

## [1.2.1] 09.04.2024

Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
2 changes: 1 addition & 1 deletion relay/kusama/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
8 changes: 6 additions & 2 deletions system-parachains/coretime/coretime-kusama/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));

mod coretime;
mod migrations;
#[cfg(test)]
mod tests;
mod weights;
Expand Down Expand Up @@ -106,7 +107,10 @@ pub type UncheckedExtrinsic =
generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;

/// Migrations to apply on runtime upgrade.
pub type Migrations = (pallet_xcm::migration::MigrateToLatestXcmVersion<Runtime>,);
pub type Migrations = (
pallet_xcm::migration::MigrateToLatestXcmVersion<Runtime>,
migrations::bootstrapping::ImportLeases,
);

/// Executive: handles dispatch to the various modules.
pub type Executive = frame_executive::Executive<
Expand All @@ -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,
Expand Down
253 changes: 253 additions & 0 deletions system-parachains/coretime/coretime-kusama/src/migrations.rs
Original file line number Diff line number Diff line change
@@ -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<Runtime>;

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::<Runtime>::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 <Runtime as frame_system::Config>::DbWeight::get().reads(1);
}

for (para_id, end) in LEASES {
match pallet_broker::Pallet::<Runtime>::set_lease(
RuntimeOrigin::root(),
para_id,
end,
) {
Ok(_) =>
log::info!(target: TARGET, "Importing lease for parachain {}", &para_id),
Err(_) =>
log::error!(target: TARGET, "Importing lease for parachain {} failed!", &para_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::<Runtime>::decode_len().unwrap_or(0)
as u16 + pallet_broker::Leases::<Runtime>::decode_len().unwrap_or(0)
as u16 + 3;

match pallet_broker::Pallet::<Runtime>::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::<Runtime>::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(<Runtime as frame_system::Config>::DbWeight::get().reads(1))
}

#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
if Leases::<Runtime>::decode_len().unwrap_or(0) > 0 {
return Ok(Vec::new())
}
let sale_info = SaleInfo::<Runtime>::get().unwrap();
Ok(sale_info.encode())
}

#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {
if state.is_empty() {
return Ok(())
}
let prev_sale_info = <SaleInfoRecordOf<Runtime>>::decode(&mut &state[..]).unwrap();

log::info!(target: TARGET, "Checking migration.");

let sale_info = SaleInfo::<Runtime>::get().unwrap();
let now = frame_system::Pallet::<Runtime>::block_number();
let config = Configuration::<Runtime>::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::<Runtime>::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::<Runtime>::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::<Runtime>::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::<Runtime>::get((workplan_start, core_id)), Some(workload));
}

// Ensure we have requested the correct number of events.
assert!(frame_system::Pallet::<Runtime>::read_events_no_consensus().any(|e| {
match e.event {
crate::RuntimeEvent::Broker(
pallet_broker::Event::<Runtime>::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),
];
}

0 comments on commit 8c8575f

Please sign in to comment.