pallet_broker/types.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use crate::{
19 Config, CoreAssignment, CoreIndex, CoreMask, CoretimeInterface, RCBlockNumberOf, TaskId,
20 CORE_MASK_BITS,
21};
22use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
23use frame_support::traits::fungible::Inspect;
24use frame_system::Config as SConfig;
25use scale_info::TypeInfo;
26use sp_arithmetic::Perbill;
27use sp_core::{ConstU32, RuntimeDebug};
28use sp_runtime::BoundedVec;
29
30pub type BalanceOf<T> = <<T as Config>::Currency as Inspect<<T as SConfig>::AccountId>>::Balance;
31pub type RelayBalanceOf<T> = <<T as Config>::Coretime as CoretimeInterface>::Balance;
32pub type RelayBlockNumberOf<T> = RCBlockNumberOf<<T as Config>::Coretime>;
33pub type RelayAccountIdOf<T> = <<T as Config>::Coretime as CoretimeInterface>::AccountId;
34
35/// Relay-chain block number with a fixed divisor of Config::TimeslicePeriod.
36pub type Timeslice = u32;
37/// Counter for the total number of set bits over every core's `CoreMask`. `u32` so we don't
38/// ever get an overflow. This is 1/80th of a Polkadot Core per timeslice. Assuming timeslices are
39/// 80 blocks, then this indicates usage of a single core one time over a timeslice.
40pub type CoreMaskBitCount = u32;
41/// The same as `CoreMaskBitCount` but signed.
42pub type SignedCoreMaskBitCount = i32;
43
44/// Whether a core assignment is revokable or not.
45#[derive(
46 Encode,
47 Decode,
48 DecodeWithMemTracking,
49 Copy,
50 Clone,
51 PartialEq,
52 Eq,
53 RuntimeDebug,
54 TypeInfo,
55 MaxEncodedLen,
56)]
57pub enum Finality {
58 /// The region remains with the same owner allowing the assignment to be altered.
59 Provisional,
60 /// The region is removed; the assignment may be eligible for renewal.
61 Final,
62}
63
64/// Self-describing identity for a Region of Bulk Coretime.
65#[derive(
66 Encode,
67 Decode,
68 DecodeWithMemTracking,
69 Copy,
70 Clone,
71 PartialEq,
72 Eq,
73 RuntimeDebug,
74 TypeInfo,
75 MaxEncodedLen,
76)]
77pub struct RegionId {
78 /// The timeslice at which this Region begins.
79 pub begin: Timeslice,
80 /// The index of the Polkadot Core on which this Region will be scheduled.
81 pub core: CoreIndex,
82 /// The regularity parts in which this Region will be scheduled.
83 pub mask: CoreMask,
84}
85impl From<u128> for RegionId {
86 fn from(x: u128) -> Self {
87 Self { begin: (x >> 96) as u32, core: (x >> 80) as u16, mask: x.into() }
88 }
89}
90impl From<RegionId> for u128 {
91 fn from(x: RegionId) -> Self {
92 ((x.begin as u128) << 96) | ((x.core as u128) << 80) | u128::from(x.mask)
93 }
94}
95#[test]
96fn region_id_converts_u128() {
97 let r = RegionId { begin: 0x12345678u32, core: 0xabcdu16, mask: 0xdeadbeefcafef00d0123.into() };
98 let u = 0x12345678_abcd_deadbeefcafef00d0123u128;
99 assert_eq!(RegionId::from(u), r);
100 assert_eq!(u128::from(r), u);
101}
102
103/// The rest of the information describing a Region.
104#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
105pub struct RegionRecord<AccountId, Balance> {
106 /// The end of the Region.
107 pub end: Timeslice,
108 /// The owner of the Region.
109 pub owner: Option<AccountId>,
110 /// The amount paid to Polkadot for this Region, or `None` if renewal is not allowed.
111 pub paid: Option<Balance>,
112}
113pub type RegionRecordOf<T> = RegionRecord<<T as SConfig>::AccountId, BalanceOf<T>>;
114
115/// An distinct item which can be scheduled on a Polkadot Core.
116#[derive(
117 Encode,
118 Decode,
119 DecodeWithMemTracking,
120 Clone,
121 PartialEq,
122 Eq,
123 RuntimeDebug,
124 TypeInfo,
125 MaxEncodedLen,
126)]
127pub struct ScheduleItem {
128 /// The regularity parts in which this Item will be scheduled on the Core.
129 pub mask: CoreMask,
130 /// The job that the Core should be doing.
131 pub assignment: CoreAssignment,
132}
133pub type Schedule = BoundedVec<ScheduleItem, ConstU32<{ CORE_MASK_BITS as u32 }>>;
134
135/// The record body of a Region which was contributed to the Instantaneous Coretime Pool. This helps
136/// with making pro rata payments to contributors.
137#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
138pub struct ContributionRecord<AccountId> {
139 /// The end of the Region contributed.
140 pub length: Timeslice,
141 /// The identity of the contributor.
142 pub payee: AccountId,
143}
144pub type ContributionRecordOf<T> = ContributionRecord<<T as SConfig>::AccountId>;
145
146/// A per-timeslice bookkeeping record for tracking Instantaneous Coretime Pool activity and
147/// making proper payments to contributors.
148#[derive(Encode, Decode, Clone, Default, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
149pub struct InstaPoolHistoryRecord<Balance> {
150 /// The total amount of Coretime (measured in Core Mask Bits minus any contributions which have
151 /// already been paid out.
152 pub private_contributions: CoreMaskBitCount,
153 /// The total amount of Coretime (measured in Core Mask Bits contributed by the Polkadot System
154 /// in this timeslice.
155 pub system_contributions: CoreMaskBitCount,
156 /// The payout remaining for the `private_contributions`, or `None` if the revenue is not yet
157 /// known.
158 pub maybe_payout: Option<Balance>,
159}
160pub type InstaPoolHistoryRecordOf<T> = InstaPoolHistoryRecord<BalanceOf<T>>;
161
162/// How much of a core has been assigned or, if completely assigned, the workload itself.
163#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
164pub enum CompletionStatus {
165 /// The core is not fully assigned; the inner is the parts which have.
166 Partial(CoreMask),
167 /// The core is fully assigned; the inner is the workload which has been assigned.
168 Complete(Schedule),
169}
170impl CompletionStatus {
171 /// Return reference to the complete workload, or `None` if incomplete.
172 pub fn complete(&self) -> Option<&Schedule> {
173 match self {
174 Self::Complete(s) => Some(s),
175 Self::Partial(_) => None,
176 }
177 }
178 /// Return the complete workload, or `None` if incomplete.
179 pub fn drain_complete(self) -> Option<Schedule> {
180 match self {
181 Self::Complete(s) => Some(s),
182 Self::Partial(_) => None,
183 }
184 }
185}
186
187/// The identity of a possibly renewable Core workload.
188#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
189pub struct PotentialRenewalId {
190 /// The core whose workload at the sale ending with `when` may be renewed to begin at `when`.
191 pub core: CoreIndex,
192 /// The point in time that the renewable workload on `core` ends and a fresh renewal may begin.
193 pub when: Timeslice,
194}
195
196/// A record of a potential renewal.
197///
198/// The renewal will only actually be allowed if `CompletionStatus` is `Complete` at the time of
199/// renewal.
200#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
201pub struct PotentialRenewalRecord<Balance> {
202 /// The price for which the next renewal can be made.
203 pub price: Balance,
204 /// The workload which will be scheduled on the Core in the case a renewal is made, or if
205 /// incomplete, then the parts of the core which have been scheduled.
206 pub completion: CompletionStatus,
207}
208pub type PotentialRenewalRecordOf<T> = PotentialRenewalRecord<BalanceOf<T>>;
209
210/// General status of the system.
211#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
212pub struct StatusRecord {
213 /// The total number of cores which can be assigned (one plus the maximum index which can
214 /// be used in `Coretime::assign`).
215 pub core_count: CoreIndex,
216 /// The current size of the Instantaneous Coretime Pool, measured in
217 /// Core Mask Bits.
218 pub private_pool_size: CoreMaskBitCount,
219 /// The current amount of the Instantaneous Coretime Pool which is provided by the Polkadot
220 /// System, rather than provided as a result of privately operated Coretime.
221 pub system_pool_size: CoreMaskBitCount,
222 /// The last (Relay-chain) timeslice which we committed to the Relay-chain.
223 pub last_committed_timeslice: Timeslice,
224 /// The timeslice of the last time we ticked.
225 pub last_timeslice: Timeslice,
226}
227
228/// A record of flux in the InstaPool.
229#[derive(
230 Encode, Decode, Clone, Copy, Default, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen,
231)]
232pub struct PoolIoRecord {
233 /// The total change of the portion of the pool supplied by purchased Bulk Coretime, measured
234 /// in Core Mask Bits.
235 pub private: SignedCoreMaskBitCount,
236 /// The total change of the portion of the pool supplied by the Polkadot System, measured in
237 /// Core Mask Bits.
238 pub system: SignedCoreMaskBitCount,
239}
240
241/// The status of a Bulk Coretime Sale.
242#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
243pub struct SaleInfoRecord<Balance, RelayBlockNumber> {
244 /// The relay block number at which the sale will/did start.
245 pub sale_start: RelayBlockNumber,
246 /// The length in blocks of the Leadin Period (where the price is decreasing).
247 pub leadin_length: RelayBlockNumber,
248 /// The price of Bulk Coretime after the Leadin Period.
249 pub end_price: Balance,
250 /// The first timeslice of the Regions which are being sold in this sale.
251 pub region_begin: Timeslice,
252 /// The timeslice on which the Regions which are being sold in the sale terminate. (i.e. One
253 /// after the last timeslice which the Regions control.)
254 pub region_end: Timeslice,
255 /// The number of cores we want to sell, ideally. Selling this amount would result in no
256 /// change to the price for the next sale.
257 pub ideal_cores_sold: CoreIndex,
258 /// Number of cores which are/have been offered for sale.
259 pub cores_offered: CoreIndex,
260 /// The index of the first core which is for sale. Core of Regions which are sold have
261 /// incrementing indices from this.
262 pub first_core: CoreIndex,
263 /// The price at which cores have been sold out.
264 ///
265 /// Will only be `None` if no core was offered for sale.
266 pub sellout_price: Option<Balance>,
267 /// Number of cores which have been sold; never more than cores_offered.
268 pub cores_sold: CoreIndex,
269}
270pub type SaleInfoRecordOf<T> = SaleInfoRecord<BalanceOf<T>, RelayBlockNumberOf<T>>;
271
272/// Record for Polkadot Core reservations (generally tasked with the maintenance of System
273/// Chains).
274pub type ReservationsRecord<Max> = BoundedVec<Schedule, Max>;
275pub type ReservationsRecordOf<T> = ReservationsRecord<<T as Config>::MaxReservedCores>;
276
277/// Information on a single legacy lease.
278#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
279pub struct LeaseRecordItem {
280 /// The timeslice until the lease is valid.
281 pub until: Timeslice,
282 /// The task which the lease is for.
283 pub task: TaskId,
284}
285
286/// Record for Polkadot Core legacy leases.
287pub type LeasesRecord<Max> = BoundedVec<LeaseRecordItem, Max>;
288pub type LeasesRecordOf<T> = LeasesRecord<<T as Config>::MaxLeasedCores>;
289
290/// Record for On demand core sales.
291///
292/// The blocknumber is the relay chain block height `until` which the original request
293/// for revenue was made.
294#[derive(
295 Encode,
296 Decode,
297 DecodeWithMemTracking,
298 Clone,
299 PartialEq,
300 Eq,
301 RuntimeDebug,
302 TypeInfo,
303 MaxEncodedLen,
304)]
305pub struct OnDemandRevenueRecord<RelayBlockNumber, RelayBalance> {
306 /// The height of the Relay-chain at the time the revenue request was made.
307 pub until: RelayBlockNumber,
308 /// The accumulated balance of on demand sales made on the relay chain.
309 pub amount: RelayBalance,
310}
311
312pub type OnDemandRevenueRecordOf<T> =
313 OnDemandRevenueRecord<RelayBlockNumberOf<T>, RelayBalanceOf<T>>;
314
315/// Configuration of this pallet.
316#[derive(
317 Encode,
318 Decode,
319 DecodeWithMemTracking,
320 Clone,
321 PartialEq,
322 Eq,
323 RuntimeDebug,
324 TypeInfo,
325 MaxEncodedLen,
326)]
327pub struct ConfigRecord<RelayBlockNumber> {
328 /// The number of Relay-chain blocks in advance which scheduling should be fixed and the
329 /// `Coretime::assign` API used to inform the Relay-chain.
330 pub advance_notice: RelayBlockNumber,
331 /// The length in blocks of the Interlude Period for forthcoming sales.
332 pub interlude_length: RelayBlockNumber,
333 /// The length in blocks of the Leadin Period for forthcoming sales.
334 pub leadin_length: RelayBlockNumber,
335 /// The length in timeslices of Regions which are up for sale in forthcoming sales.
336 pub region_length: Timeslice,
337 /// The proportion of cores available for sale which should be sold.
338 ///
339 /// If more cores are sold than this, then further sales will no longer be considered in
340 /// determining the sellout price. In other words the sellout price will be the last price
341 /// paid, without going over this limit.
342 pub ideal_bulk_proportion: Perbill,
343 /// An artificial limit to the number of cores which are allowed to be sold. If `Some` then
344 /// no more cores will be sold than this.
345 pub limit_cores_offered: Option<CoreIndex>,
346 /// The amount by which the renewal price increases each sale period.
347 pub renewal_bump: Perbill,
348 /// The duration by which rewards for contributions to the InstaPool must be collected.
349 pub contribution_timeout: Timeslice,
350}
351pub type ConfigRecordOf<T> = ConfigRecord<RelayBlockNumberOf<T>>;
352
353impl<RelayBlockNumber> ConfigRecord<RelayBlockNumber>
354where
355 RelayBlockNumber: sp_arithmetic::traits::Zero,
356{
357 /// Check the config for basic validity constraints.
358 pub(crate) fn validate(&self) -> Result<(), ()> {
359 if self.leadin_length.is_zero() {
360 return Err(())
361 }
362
363 Ok(())
364 }
365}
366
367/// A record containing information regarding auto-renewal for a specific core.
368#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
369pub struct AutoRenewalRecord {
370 /// The core for which auto renewal is enabled.
371 pub core: CoreIndex,
372 /// The task assigned to the core. We keep track of it so we don't have to look it up when
373 /// performing auto-renewal.
374 pub task: TaskId,
375 /// Specifies when the upcoming renewal should be performed. This is used for lease holding
376 /// tasks to ensure that the renewal process does not begin until the lease expires.
377 pub next_renewal: Timeslice,
378}