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 Timeslice, 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;
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/// Counter for the total number of set bits over every core's `CoreMask`. `u32` so we don't
36/// ever get an overflow. This is 1/80th of a Polkadot Core per timeslice. Assuming timeslices are
37/// 80 blocks, then this indicates usage of a single core one time over a timeslice.
38pub type CoreMaskBitCount = u32;
39/// The same as `CoreMaskBitCount` but signed.
40pub type SignedCoreMaskBitCount = i32;
41/// A sequential index for identifying a sale period.
42pub type SaleIndex = u32;
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 Debug,
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/// The rest of the information describing a Region.
65#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
66pub struct RegionRecord<AccountId, Balance> {
67 /// The end of the Region.
68 pub end: Timeslice,
69 /// The owner of the Region.
70 pub owner: Option<AccountId>,
71 /// The amount paid to Polkadot for this Region, or `None` if renewal is not allowed.
72 pub paid: Option<Balance>,
73}
74pub type RegionRecordOf<T> = RegionRecord<<T as SConfig>::AccountId, BalanceOf<T>>;
75
76/// An distinct item which can be scheduled on a Polkadot Core.
77#[derive(
78 Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen,
79)]
80pub struct ScheduleItem {
81 /// The regularity parts in which this Item will be scheduled on the Core.
82 pub mask: CoreMask,
83 /// The job that the Core should be doing.
84 pub assignment: CoreAssignment,
85}
86pub type Schedule = BoundedVec<ScheduleItem, ConstU32<{ CORE_MASK_BITS as u32 }>>;
87
88/// The record body of a Region which was contributed to the Instantaneous Coretime Pool. This helps
89/// with making pro rata payments to contributors.
90#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
91pub struct ContributionRecord<AccountId> {
92 /// The end of the Region contributed.
93 pub length: Timeslice,
94 /// The identity of the contributor.
95 pub payee: AccountId,
96}
97pub type ContributionRecordOf<T> = ContributionRecord<<T as SConfig>::AccountId>;
98
99/// A per-timeslice bookkeeping record for tracking Instantaneous Coretime Pool activity and
100/// making proper payments to contributors.
101#[derive(Encode, Decode, Clone, Default, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
102pub struct InstaPoolHistoryRecord<Balance> {
103 /// The total amount of Coretime (measured in Core Mask Bits minus any contributions which have
104 /// already been paid out.
105 pub private_contributions: CoreMaskBitCount,
106 /// The total amount of Coretime (measured in Core Mask Bits contributed by the Polkadot System
107 /// in this timeslice.
108 pub system_contributions: CoreMaskBitCount,
109 /// The payout remaining for the `private_contributions`, or `None` if the revenue is not yet
110 /// known.
111 pub maybe_payout: Option<Balance>,
112}
113pub type InstaPoolHistoryRecordOf<T> = InstaPoolHistoryRecord<BalanceOf<T>>;
114
115/// How much of a core has been assigned or, if completely assigned, the workload itself.
116#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
117pub enum CompletionStatus {
118 /// The core is not fully assigned; the inner is the parts which have.
119 Partial(CoreMask),
120 /// The core is fully assigned; the inner is the workload which has been assigned.
121 Complete(Schedule),
122}
123impl CompletionStatus {
124 /// Return reference to the complete workload, or `None` if incomplete.
125 pub fn complete(&self) -> Option<&Schedule> {
126 match self {
127 Self::Complete(s) => Some(s),
128 Self::Partial(_) => None,
129 }
130 }
131 /// Return the complete workload, or `None` if incomplete.
132 pub fn drain_complete(self) -> Option<Schedule> {
133 match self {
134 Self::Complete(s) => Some(s),
135 Self::Partial(_) => None,
136 }
137 }
138 /// Return whether the workload is complete and includes the given task.
139 pub fn is_complete_and_contains_task(&self, task: TaskId) -> bool {
140 self.complete().map_or(false, |workload| {
141 workload.iter().any(|item| item.assignment == CoreAssignment::Task(task))
142 })
143 }
144}
145
146/// A record of a potential renewal.
147///
148/// The renewal will only actually be allowed if `CompletionStatus` is `Complete` at the time of
149/// renewal.
150#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
151pub struct PotentialRenewalRecord<Balance> {
152 /// The price for which the next renewal can be made.
153 pub price: Balance,
154 /// The workload which will be scheduled on the Core in the case a renewal is made, or if
155 /// incomplete, then the parts of the core which have been scheduled.
156 pub completion: CompletionStatus,
157}
158pub type PotentialRenewalRecordOf<T> = PotentialRenewalRecord<BalanceOf<T>>;
159
160/// General status of the system.
161#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
162pub struct StatusRecord {
163 /// The total number of cores which can be assigned (one plus the maximum index which can
164 /// be used in `Coretime::assign`).
165 pub core_count: CoreIndex,
166 /// The current size of the Instantaneous Coretime Pool, measured in
167 /// Core Mask Bits.
168 pub private_pool_size: CoreMaskBitCount,
169 /// The current amount of the Instantaneous Coretime Pool which is provided by the Polkadot
170 /// System, rather than provided as a result of privately operated Coretime.
171 pub system_pool_size: CoreMaskBitCount,
172 /// The last (Relay-chain) timeslice which we committed to the Relay-chain.
173 pub last_committed_timeslice: Timeslice,
174 /// The timeslice of the last time we ticked.
175 pub last_timeslice: Timeslice,
176}
177
178/// A record of flux in the InstaPool.
179#[derive(Encode, Decode, Clone, Copy, Default, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
180pub struct PoolIoRecord {
181 /// The total change of the portion of the pool supplied by purchased Bulk Coretime, measured
182 /// in Core Mask Bits.
183 pub private: SignedCoreMaskBitCount,
184 /// The total change of the portion of the pool supplied by the Polkadot System, measured in
185 /// Core Mask Bits.
186 pub system: SignedCoreMaskBitCount,
187}
188
189/// The status of a Bulk Coretime Sale.
190#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
191pub struct SaleInfoRecord<Balance, RelayBlockNumber> {
192 /// The relay block number at which the sale will/did start.
193 pub sale_start: RelayBlockNumber,
194 /// The length in blocks of the Leadin Period (where the price is decreasing).
195 pub leadin_length: RelayBlockNumber,
196 /// The price of Bulk Coretime after the Leadin Period.
197 pub end_price: Balance,
198 /// The first timeslice of the Regions which are being sold in this sale.
199 pub region_begin: Timeslice,
200 /// The timeslice on which the Regions which are being sold in the sale terminate. (i.e. One
201 /// after the last timeslice which the Regions control.)
202 pub region_end: Timeslice,
203 /// The number of cores we want to sell, ideally. Selling this amount would result in no
204 /// change to the price for the next sale.
205 pub ideal_cores_sold: CoreIndex,
206 /// Number of cores which are/have been offered for sale.
207 pub cores_offered: CoreIndex,
208 /// The index of the first core which is for sale. Core of Regions which are sold have
209 /// incrementing indices from this.
210 pub first_core: CoreIndex,
211 /// The price at which cores have been sold out.
212 ///
213 /// Will only be `None` if no core was offered for sale.
214 pub sellout_price: Option<Balance>,
215 /// Number of cores which have been sold; never more than cores_offered.
216 pub cores_sold: CoreIndex,
217 /// Identifier for the current sale.
218 pub sale_index: SaleIndex,
219}
220pub type SaleInfoRecordOf<T> = SaleInfoRecord<BalanceOf<T>, RelayBlockNumberOf<T>>;
221
222/// Record for Polkadot Core reservations (generally tasked with the maintenance of System
223/// Chains).
224pub type ReservationsRecord<Max> = BoundedVec<Schedule, Max>;
225pub type ReservationsRecordOf<T> = ReservationsRecord<<T as Config>::MaxReservedCores>;
226
227/// Information on a single legacy lease.
228#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
229pub struct LeaseRecordItem {
230 /// The timeslice until the lease is valid.
231 pub until: Timeslice,
232 /// The task which the lease is for.
233 pub task: TaskId,
234}
235
236/// Record for Polkadot Core legacy leases.
237pub type LeasesRecord<Max> = BoundedVec<LeaseRecordItem, Max>;
238pub type LeasesRecordOf<T> = LeasesRecord<<T as Config>::MaxLeasedCores>;
239
240/// Record for On demand core sales.
241///
242/// The blocknumber is the relay chain block height `until` which the original request
243/// for revenue was made.
244#[derive(
245 Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen,
246)]
247pub struct OnDemandRevenueRecord<RelayBlockNumber, RelayBalance> {
248 /// The height of the Relay-chain at the time the revenue request was made.
249 pub until: RelayBlockNumber,
250 /// The accumulated balance of on demand sales made on the relay chain.
251 pub amount: RelayBalance,
252}
253
254pub type OnDemandRevenueRecordOf<T> =
255 OnDemandRevenueRecord<RelayBlockNumberOf<T>, RelayBalanceOf<T>>;
256
257/// Configuration of this pallet.
258#[derive(
259 Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen,
260)]
261pub struct ConfigRecord<RelayBlockNumber> {
262 /// The number of Relay-chain blocks in advance which scheduling should be fixed and the
263 /// `Coretime::assign` API used to inform the Relay-chain.
264 pub advance_notice: RelayBlockNumber,
265 /// The length in blocks of the Interlude Period for forthcoming sales.
266 pub interlude_length: RelayBlockNumber,
267 /// The length in blocks of the Leadin Period for forthcoming sales.
268 pub leadin_length: RelayBlockNumber,
269 /// The length in timeslices of Regions which are up for sale in forthcoming sales.
270 pub region_length: Timeslice,
271 /// The proportion of cores available for sale which should be sold.
272 ///
273 /// If more cores are sold than this, then further sales will no longer be considered in
274 /// determining the sellout price. In other words the sellout price will be the last price
275 /// paid, without going over this limit.
276 pub ideal_bulk_proportion: Perbill,
277 /// An artificial limit to the number of cores which are allowed to be sold. If `Some` then
278 /// no more cores will be sold than this.
279 pub limit_cores_offered: Option<CoreIndex>,
280 /// The amount by which the renewal price increases each sale period.
281 pub renewal_bump: Perbill,
282 /// The duration by which rewards for contributions to the InstaPool must be collected.
283 pub contribution_timeout: Timeslice,
284}
285pub type ConfigRecordOf<T> = ConfigRecord<RelayBlockNumberOf<T>>;
286
287impl<RelayBlockNumber> ConfigRecord<RelayBlockNumber>
288where
289 RelayBlockNumber: sp_arithmetic::traits::Zero,
290{
291 /// Check the config for basic validity constraints.
292 pub(crate) fn validate(&self) -> Result<(), ()> {
293 if self.leadin_length.is_zero() {
294 return Err(());
295 }
296
297 Ok(())
298 }
299}
300
301/// A record containing information regarding auto-renewal for a specific core.
302#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
303pub struct AutoRenewalRecord {
304 /// The core for which auto renewal is enabled.
305 pub core: CoreIndex,
306 /// The task assigned to the core. We keep track of it so we don't have to look it up when
307 /// performing auto-renewal.
308 pub task: TaskId,
309 /// Specifies when the upcoming renewal should be performed. This is used for lease holding
310 /// tasks to ensure that the renewal process does not begin until the lease expires.
311 pub next_renewal: Timeslice,
312}