diff --git a/Cargo.lock b/Cargo.lock index bdbf6ddac2685..15b3367460b6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9443,6 +9443,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "parity-scale-codec", "scale-info", "sp-arithmetic", diff --git a/prdoc/pr_3331.prdoc b/prdoc/pr_3331.prdoc new file mode 100644 index 0000000000000..5207d112e300d --- /dev/null +++ b/prdoc/pr_3331.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Use Relay Blocknumber in Pallet Broker + +doc: + - audience: Runtime Dev + description: | + Changing `sale_start`, `interlude_length` and `leading_length` in `pallet_broker` to use relay chain block numbers instead of parachain block numbers. + Relay chain block numbers are almost deterministic and more future proof. + +crates: + - name : pallet-broker diff --git a/substrate/frame/broker/Cargo.toml b/substrate/frame/broker/Cargo.toml index 31f9a6b63178d..8034f994e8d56 100644 --- a/substrate/frame/broker/Cargo.toml +++ b/substrate/frame/broker/Cargo.toml @@ -15,8 +15,12 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.10.0", default-features = false, features = [ + "derive", +] } bitvec = { version = "1.0.0", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } @@ -25,6 +29,7 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } +log = { workspace = true } [dev-dependencies] sp-io = { path = "../../primitives/io" } @@ -33,28 +38,29 @@ sp-io = { path = "../../primitives/io" } default = ["std"] std = [ - "bitvec/std", - "codec/std", - "frame-benchmarking?/std", - "frame-support/std", - "frame-system/std", - "scale-info/std", - "sp-arithmetic/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", + "bitvec/std", + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-arithmetic/std", + "sp-core/std", + "log/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", ] try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", - "sp-runtime/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", ] diff --git a/substrate/frame/broker/src/benchmarking.rs b/substrate/frame/broker/src/benchmarking.rs index 70f488e998cc8..122f4b3d778be 100644 --- a/substrate/frame/broker/src/benchmarking.rs +++ b/substrate/frame/broker/src/benchmarking.rs @@ -771,7 +771,7 @@ mod benches { let core_count = n.try_into().unwrap(); let config = new_config_record::(); - let now = frame_system::Pallet::::block_number(); + let now = Broker::::relay_height(); let price = 10u32.into(); let commit_timeslice = Broker::::latest_timeslice_ready_to_commit(&config); let sale = SaleInfoRecordOf:: { diff --git a/substrate/frame/broker/src/dispatchable_impls.rs b/substrate/frame/broker/src/dispatchable_impls.rs index f2451013251fb..ead8c94c63fa6 100644 --- a/substrate/frame/broker/src/dispatchable_impls.rs +++ b/substrate/frame/broker/src/dispatchable_impls.rs @@ -80,7 +80,7 @@ impl Pallet { last_committed_timeslice: commit_timeslice.saturating_sub(1), last_timeslice: Self::current_timeslice(), }; - let now = frame_system::Pallet::::block_number(); + let now = Self::relay_height(); let new_sale = SaleInfoRecord { sale_start: now, leadin_length: Zero::zero(), @@ -107,7 +107,7 @@ impl Pallet { let mut sale = SaleInfo::::get().ok_or(Error::::NoSales)?; ensure!(sale.first_core < status.core_count, Error::::Unavailable); ensure!(sale.cores_sold < sale.cores_offered, Error::::SoldOut); - let now = frame_system::Pallet::::block_number(); + let now = Self::relay_height(); ensure!(now > sale.sale_start, Error::::TooEarly); let price = Self::sale_price(&sale, now); ensure!(price_limit >= price, Error::::Overpriced); @@ -158,7 +158,7 @@ impl Pallet { let begin = sale.region_end; let price_cap = record.price + config.renewal_bump * record.price; - let now = frame_system::Pallet::::block_number(); + let now = Self::relay_height(); let price = Self::sale_price(&sale, now).min(price_cap); let new_record = AllowedRenewalRecord { price, completion: Complete(workload) }; AllowedRenewals::::remove(renewal_id); diff --git a/substrate/frame/broker/src/lib.rs b/substrate/frame/broker/src/lib.rs index a669463aa02d9..2962680edaf7e 100644 --- a/substrate/frame/broker/src/lib.rs +++ b/substrate/frame/broker/src/lib.rs @@ -25,6 +25,7 @@ mod benchmarking; mod core_mask; mod coretime_interface; mod dispatchable_impls; +mod migrations; #[cfg(test)] mod mock; mod nonfungible_impl; @@ -59,7 +60,10 @@ pub mod pallet { use sp_runtime::traits::{Convert, ConvertBack}; use sp_std::vec::Vec; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -274,10 +278,11 @@ pub mod pallet { }, /// A new sale has been initialized. SaleInitialized { - /// The local block number at which the sale will/did start. - sale_start: BlockNumberFor, - /// The length in blocks of the Leadin Period (where the price is decreasing). - leadin_length: BlockNumberFor, + /// The relay block number at which the sale will/did start. + sale_start: RelayBlockNumberOf, + /// The length in relay chain blocks of the Leadin Period (where the price is + /// decreasing). + leadin_length: RelayBlockNumberOf, /// The price of Bulk Coretime at the beginning of the Leadin Period. start_price: BalanceOf, /// The price of Bulk Coretime after the Leadin Period. diff --git a/substrate/frame/broker/src/migrations/mod.rs b/substrate/frame/broker/src/migrations/mod.rs new file mode 100644 index 0000000000000..d24bbf1b3a2a2 --- /dev/null +++ b/substrate/frame/broker/src/migrations/mod.rs @@ -0,0 +1,19 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// 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. + +/// V1 storage migrations for the broker pallet. +pub mod v1; diff --git a/substrate/frame/broker/src/migrations/v1.rs b/substrate/frame/broker/src/migrations/v1.rs new file mode 100644 index 0000000000000..b9c124397890d --- /dev/null +++ b/substrate/frame/broker/src/migrations/v1.rs @@ -0,0 +1,323 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// 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. + +//! Storage migrations for the broker pallet. + +use crate::*; +use frame_support::{pallet_prelude::*, storage_alias, traits::OnRuntimeUpgrade, BoundedVec}; +/// The log target. +const TARGET: &'static str = "runtime::broker::migration::v1"; + +/// The original data layout of the broker pallet without a specific version number. +pub mod v0 { + use super::*; + use frame_system::pallet_prelude::BlockNumberFor; + use sp_arithmetic::Perbill; + + #[storage_alias] + pub type Configuration = StorageValue, ConfigRecordOf, OptionQuery>; + pub type ConfigRecordOf = ConfigRecord, RelayBlockNumberOf>; + + #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] + pub struct ConfigRecord { + /// The number of Relay-chain blocks in advance which scheduling should be fixed and the + /// `Coretime::assign` API used to inform the Relay-chain. + pub advance_notice: RelayBlockNumber, + /// The length in blocks of the Interlude Period for forthcoming sales. + pub interlude_length: BlockNumber, + /// The length in blocks of the Leadin Period for forthcoming sales. + pub leadin_length: BlockNumber, + /// The length in timeslices of Regions which are up for sale in forthcoming sales. + pub region_length: Timeslice, + /// The proportion of cores available for sale which should be sold in order for the price + /// to remain the same in the next sale. + pub ideal_bulk_proportion: Perbill, + /// An artificial limit to the number of cores which are allowed to be sold. If `Some` then + /// no more cores will be sold than this. + pub limit_cores_offered: Option, + /// The amount by which the renewal price increases each sale period. + pub renewal_bump: Perbill, + /// The duration by which rewards for contributions to the InstaPool must be collected. + pub contribution_timeout: Timeslice, + } + + #[storage_alias] + pub type SaleInfo = StorageValue, SaleInfoRecordOf, OptionQuery>; + pub type SaleInfoRecordOf = SaleInfoRecord, BlockNumberFor>; + + /// The status of a Bulk Coretime Sale. + #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] + pub struct SaleInfoRecord { + /// The relay block number at which the sale will/did start. + pub sale_start: BlockNumber, + /// The length in relay chain blocks of the Leadin Period (where the price is decreasing). + pub leadin_length: BlockNumber, + /// The price of Bulk Coretime after the Leadin Period. + pub price: Balance, + /// The first timeslice of the Regions which are being sold in this sale. + pub region_begin: Timeslice, + /// The timeslice on which the Regions which are being sold in the sale terminate. (i.e. + /// One after the last timeslice which the Regions control.) + pub region_end: Timeslice, + /// The number of cores we want to sell, ideally. Selling this amount would result in no + /// change to the price for the next sale. + pub ideal_cores_sold: CoreIndex, + /// Number of cores which are/have been offered for sale. + pub cores_offered: CoreIndex, + /// The index of the first core which is for sale. Core of Regions which are sold have + /// incrementing indices from this. + pub first_core: CoreIndex, + /// The latest price at which Bulk Coretime was purchased until surpassing the ideal number + /// of cores were sold. + pub sellout_price: Option, + /// Number of cores which have been sold; never more than cores_offered. + pub cores_sold: CoreIndex, + } +} + +pub mod v1 { + use super::*; + use frame_system::pallet_prelude::BlockNumberFor; + + pub struct Migration(core::marker::PhantomData); + + impl OnRuntimeUpgrade for Migration + where + T: Config, + RelayBlockNumberOf: TryFrom>, + { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + ensure!(StorageVersion::get::>() == 0, "can only upgrade from version 0"); + + let (interlude_length, configuration_leadin_length) = + if let Some(config_record) = v0::Configuration::::get() { + (config_record.interlude_length, config_record.leadin_length) + } else { + ((0 as u32).into(), (0 as u32).into()) + }; + + log::info!(target: TARGET, "Configuration Pre-Migration: Interlude Length {:?} Leading Length {:?} ", interlude_length, configuration_leadin_length); + + let (sale_start, sale_info_leadin_length) = + if let Some(sale_info_record) = v0::SaleInfo::::get() { + (sale_info_record.sale_start, sale_info_record.leadin_length) + } else { + ((0 as u32).into(), (0 as u32).into()) + }; + + log::info!(target: TARGET, "SaleInfo Pre-Migration: Sale Start {:?} Interlude Length {:?} ", sale_start, sale_info_leadin_length); + + Ok((interlude_length, configuration_leadin_length, sale_start, sale_info_leadin_length) + .encode()) + } + + fn on_runtime_upgrade() -> Weight { + let mut weight = T::DbWeight::get().reads(1); + + if StorageVersion::get::>() != 0 { + log::warn!( + target: TARGET, + "skipping on_runtime_upgrade: executed on wrong storage version.\ + Expected version 0" + ); + return weight + } + + // using a u32::MAX as sentinel value in case TryFrom fails. + // Ref: https://github.com/paritytech/polkadot-sdk/pull/3331#discussion_r1499014975 + + if let Some(config_record) = v0::Configuration::::take() { + log::info!(target: TARGET, "migrating Configuration record"); + + let updated_interlude_length: RelayBlockNumberOf = + match TryFrom::try_from(config_record.interlude_length) { + Ok(val) => val, + Err(_) => u32::MAX.into(), + }; + + let updated_leadin_length: RelayBlockNumberOf = + match TryFrom::try_from(config_record.leadin_length) { + Ok(val) => val, + Err(_) => u32::MAX.into(), + }; + + let updated_config_record = ConfigRecord { + interlude_length: updated_interlude_length, + leadin_length: updated_leadin_length, + advance_notice: config_record.advance_notice, + region_length: config_record.region_length, + ideal_bulk_proportion: config_record.ideal_bulk_proportion, + limit_cores_offered: config_record.limit_cores_offered, + renewal_bump: config_record.renewal_bump, + contribution_timeout: config_record.contribution_timeout, + }; + Configuration::::put(updated_config_record); + } + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + if let Some(sale_info) = v0::SaleInfo::::take() { + log::info!(target: TARGET, "migrating SaleInfo record"); + + let updated_sale_start: RelayBlockNumberOf = + match TryFrom::try_from(sale_info.sale_start) { + Ok(val) => val, + Err(_) => u32::MAX.into(), + }; + + let updated_leadin_length: RelayBlockNumberOf = + match TryFrom::try_from(sale_info.leadin_length) { + Ok(val) => val, + Err(_) => u32::MAX.into(), + }; + + let updated_sale_info = SaleInfoRecord { + sale_start: updated_sale_start, + leadin_length: updated_leadin_length, + price: sale_info.price, + region_begin: sale_info.region_begin, + region_end: sale_info.region_end, + ideal_cores_sold: sale_info.ideal_cores_sold, + cores_offered: sale_info.cores_offered, + first_core: sale_info.first_core, + sellout_price: sale_info.sellout_price, + cores_sold: sale_info.cores_sold, + }; + SaleInfo::::put(updated_sale_info); + } + + StorageVersion::new(1).put::>(); + weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + ensure!(StorageVersion::get::>() == 1, "must upgrade"); + + let ( + old_interlude_length, + old_configuration_leadin_length, + old_sale_start, + old_sale_info_leadin_length, + ): (BlockNumberFor, BlockNumberFor, BlockNumberFor, BlockNumberFor) = + Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed"); + + if let Some(config_record) = Configuration::::get() { + ensure!( + verify_updated::( + old_configuration_leadin_length, + config_record.leadin_length + ), + "must migrate configuration leadin_length" + ); + + ensure!( + verify_updated::(old_interlude_length, config_record.interlude_length), + "must migrate configuration interlude_length" + ); + } + + if let Some(sale_info) = SaleInfo::::get() { + ensure!( + verify_updated::(old_sale_start, sale_info.sale_start), + "must migrate sale info sale_start" + ); + + ensure!( + verify_updated::(old_sale_info_leadin_length, sale_info.leadin_length), + "must migrate sale info leadin_length" + ); + } + + Ok(()) + } + } + + #[cfg(feature = "try-runtime")] + fn verify_updated(old_value: BlockNumberFor, new_value: RelayBlockNumberOf) -> bool + where + T: Config, + RelayBlockNumberOf: TryFrom>, + { + let val: RelayBlockNumberOf = match TryFrom::try_from(old_value) { + Ok(val) => val, + Err(_) => u32::MAX.into(), + }; + + val == new_value + } +} + +#[cfg(test)] +#[cfg(feature = "try-runtime")] +mod test { + use self::mock::new_test_ext; + + use super::*; + + use crate::{ + migrations::v1::v0::ConfigRecord, + mock::{Test as T, TestExt}, + types::*, + }; + use frame_system::pallet::Pallet as SPallet; + use sp_runtime::Perbill; + + #[allow(deprecated)] + #[test] + fn migration_works() { + new_test_ext().execute_with(|| { + assert_eq!(StorageVersion::get::>(), 0); + + // Testing with Random Values + let config_record = v0::ConfigRecord { + advance_notice: u32::MAX.into(), + interlude_length: (u32::MAX).into(), + leadin_length: (u32::MAX - 1).into(), + contribution_timeout: 0, + region_length: 0, + ideal_bulk_proportion: Perbill::one(), + limit_cores_offered: Some(1), + renewal_bump: Perbill::one(), + }; + + v0::Configuration::::put(config_record); + + let sale_info = v0::SaleInfoRecord { + sale_start: u64::MAX, + leadin_length: (u32::MAX - 1).into(), + price: 5u64, + region_begin: 0, + region_end: 1, + cores_offered: 1, + ideal_cores_sold: 3, + first_core: 3, + sellout_price: Some(5), + cores_sold: 5, + }; + + v0::SaleInfo::::put(sale_info); + + // Migrate. + let state = v1::Migration::::pre_upgrade().unwrap(); + let _weight = v1::Migration::::on_runtime_upgrade(); + v1::Migration::::post_upgrade(state).unwrap(); + + assert_eq!(StorageVersion::get::>(), 1); + }) + } +} diff --git a/substrate/frame/broker/src/tick_impls.rs b/substrate/frame/broker/src/tick_impls.rs index 388370bce4d4b..bc1a98b8cea42 100644 --- a/substrate/frame/broker/src/tick_impls.rs +++ b/substrate/frame/broker/src/tick_impls.rs @@ -146,7 +146,7 @@ impl Pallet { config: &ConfigRecordOf, status: &StatusRecord, ) -> Option<()> { - let now = frame_system::Pallet::::block_number(); + let now = Self::relay_height(); let pool_item = ScheduleItem { assignment: CoreAssignment::Pool, mask: CoreMask::complete() }; diff --git a/substrate/frame/broker/src/types.rs b/substrate/frame/broker/src/types.rs index 7e9f351723a5d..4f374d18699e3 100644 --- a/substrate/frame/broker/src/types.rs +++ b/substrate/frame/broker/src/types.rs @@ -21,7 +21,7 @@ use crate::{ }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::fungible::Inspect; -use frame_system::{pallet_prelude::BlockNumberFor, Config as SConfig}; +use frame_system::Config as SConfig; use scale_info::TypeInfo; use sp_arithmetic::Perbill; use sp_core::{ConstU32, RuntimeDebug}; @@ -205,11 +205,11 @@ pub struct PoolIoRecord { /// The status of a Bulk Coretime Sale. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct SaleInfoRecord { - /// The local block number at which the sale will/did start. - pub sale_start: BlockNumber, - /// The length in blocks of the Leadin Period (where the price is decreasing). - pub leadin_length: BlockNumber, +pub struct SaleInfoRecord { + /// The relay block number at which the sale will/did start. + pub sale_start: RelayBlockNumber, + /// The length in relay chain blocks of the Leadin Period (where the price is decreasing). + pub leadin_length: RelayBlockNumber, /// The price of Bulk Coretime after the Leadin Period. pub price: Balance, /// The first timeslice of the Regions which are being sold in this sale. @@ -231,7 +231,7 @@ pub struct SaleInfoRecord { /// Number of cores which have been sold; never more than cores_offered. pub cores_sold: CoreIndex, } -pub type SaleInfoRecordOf = SaleInfoRecord, BlockNumberFor>; +pub type SaleInfoRecordOf = SaleInfoRecord, RelayBlockNumberOf>; /// Record for Polkadot Core reservations (generally tasked with the maintenance of System /// Chains). @@ -253,14 +253,14 @@ pub type LeasesRecordOf = LeasesRecord<::MaxLeasedCores>; /// Configuration of this pallet. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct ConfigRecord { +pub struct ConfigRecord { /// The number of Relay-chain blocks in advance which scheduling should be fixed and the /// `Coretime::assign` API used to inform the Relay-chain. pub advance_notice: RelayBlockNumber, /// The length in blocks of the Interlude Period for forthcoming sales. - pub interlude_length: BlockNumber, + pub interlude_length: RelayBlockNumber, /// The length in blocks of the Leadin Period for forthcoming sales. - pub leadin_length: BlockNumber, + pub leadin_length: RelayBlockNumber, /// The length in timeslices of Regions which are up for sale in forthcoming sales. pub region_length: Timeslice, /// The proportion of cores available for sale which should be sold in order for the price @@ -274,16 +274,16 @@ pub struct ConfigRecord { /// The duration by which rewards for contributions to the InstaPool must be collected. pub contribution_timeout: Timeslice, } -pub type ConfigRecordOf = ConfigRecord, RelayBlockNumberOf>; +pub type ConfigRecordOf = ConfigRecord>; -impl ConfigRecord +impl ConfigRecord where - BlockNumber: sp_arithmetic::traits::Zero, + RelayBlockNumber: sp_arithmetic::traits::Zero, { /// Check the config for basic validity constraints. pub(crate) fn validate(&self) -> Result<(), ()> { if self.leadin_length.is_zero() { - return Err(()) + return Err(()); } Ok(()) diff --git a/substrate/frame/broker/src/utility_impls.rs b/substrate/frame/broker/src/utility_impls.rs index 3dba5be5b398b..69dacbc3c6009 100644 --- a/substrate/frame/broker/src/utility_impls.rs +++ b/substrate/frame/broker/src/utility_impls.rs @@ -24,7 +24,6 @@ use frame_support::{ OnUnbalanced, }, }; -use frame_system::pallet_prelude::BlockNumberFor; use sp_arithmetic::{ traits::{SaturatedConversion, Saturating}, FixedPointNumber, FixedU64, @@ -60,7 +59,7 @@ impl Pallet { T::PalletId::get().into_account_truncating() } - pub fn sale_price(sale: &SaleInfoRecordOf, now: BlockNumberFor) -> BalanceOf { + pub fn sale_price(sale: &SaleInfoRecordOf, now: RelayBlockNumberOf) -> BalanceOf { let num = now.saturating_sub(sale.sale_start).min(sale.leadin_length).saturated_into(); let through = FixedU64::from_rational(num, sale.leadin_length.saturated_into()); T::PriceAdapter::leadin_factor_at(through).saturating_mul_int(sale.price) @@ -105,7 +104,7 @@ impl Pallet { region_id.begin = last_committed_timeslice + 1; if region_id.begin >= region.end { Self::deposit_event(Event::RegionDropped { region_id, duration }); - return Ok(None) + return Ok(None); } } else { Workplan::::mutate_extant((region_id.begin, region_id.core), |p| { @@ -118,4 +117,9 @@ impl Pallet { Ok(Some((region_id, region))) } + + /// Returns the current block number of Relay Chain + pub(crate) fn relay_height() -> RelayBlockNumberOf { + <<::Coretime as CoretimeInterface>::RelayChainBlockNumberProvider as BlockNumberProvider>::current_block_number() + } }