From bf002b179ffaf7c1a10dc1add50ebac2928ad722 Mon Sep 17 00:00:00 2001 From: Gav Date: Thu, 6 Jul 2023 13:20:46 +0200 Subject: [PATCH 01/11] Add draft --- text/0004-coretime-interface.md | 376 ++++++++++++++++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100644 text/0004-coretime-interface.md diff --git a/text/0004-coretime-interface.md b/text/0004-coretime-interface.md new file mode 100644 index 000000000..847a0105c --- /dev/null +++ b/text/0004-coretime-interface.md @@ -0,0 +1,376 @@ +# RFC-1: Coretime Interface + +| | | +| --------------- | ------------------------------------------------------------------------------------------- | +| **Start Date** | 06 July 2023 | +| **Status** | Draft | +| **Description** | Agile periodic-sale-based model for assigning Coretime on the Polkadot Ubiquitous Computer. | +| **Authors** | Gavin Wood | +| **Licence** | MIT/Apache2 | + + +## Summary + +This proposes a periodic, sale-based method for assigning Polkadot Coretime. The method takes into account the need for long-term capital expenditure planning for teams building on Polkadot, yet also provides a means to allow Polkadot to capture long-term value in the resource which it sells. It supports the possibility of building secondary markets to make resource allocation more efficient and largely avoids the need for parameterisation. + +## Motivation + +### Present System + +The present system of allocating time for parachains on the cores of the Polkadot Ubiquitous Computer (aka "Polkadot") is through a process known as *slot auctions*. These are on-chain candle auctions which proceed for several days and result in a core being assigned to a single parachain for six months at a time up to 18 months in advance. Practically speaking, we only see two year periods being bid upon and leased. + +Funds behind the bids made in the slot auctions are merely locked, not consumed or paid and become unlocked and returned to the bidder on expiry of the lease period. A means of sharing the deposit trustlessly known as a *crowdloan* is available allowing token holders to contribute to the overall deposit of a chain without any counterparty risk. + +### Problems + +The present system is based on a model of one-core-per-parachain. This is a legacy interpretation of the Polkadot platform and is not a reflection of its present capabilities. By restricting ownership and usage to this model, more dynamic and resource-efficient means of utilising the Polkadot Ubiquitous Computer is lost. + +More specifically, it is impossible to lease out cores at anything less than six months, and apparently unrealistic to do so at anything less than two years. This cuts out the ability to dynamically manage the underlying resource, and generally experimentation, iteration and innovation are hampered. It bakes into the platform an assumption of permanence for anything deployed into it and restricts the market's ability to find a more optimal allocation of the finite resource. + +There is no ability to determine capital requirements for hosting a parachain beyond two years from the point of its initial deployment onto Polkadot. While it would be unreasonable to have perfect and indefinite cost predictions for any real-world platform, not having any clarity whatsoever beyond "market rates" two years hence can be a very off-putting prospect for teams to buy into. + +However, quite possibly the most substantial problem is both a perceived and often real high barrier to entry of the Polkadot ecosystem. By forcing innovators to either raise 7-figure sums through investors or appeal to the wider token-holding community, Polkadot makes it essentially difficult for a small band of innovators from deploying their technology into Polkadot. While not being actually permissioned, it is also far from the barrierless, permissionless ideal which an innovation platform such as Polkadot should be striving for. + +## Requirements + +1. The solution SHOULD provide an acceptable value-capture mechanism for the Polkadot network. +1. The solution SHOULD allow parachains and other projects deployed on to the Polkadot UC to make long-term capital expenditure predictions for the cost of ongoing deployment. +1. The solution SHOULD minimize the barriers to entry in the ecosystem. +1. The solution SHOULD work when the number of cores which the Polkadot UC can support changes over time. +1. The solution SHOULD facilitate the optimal allocation of work to core of the Polkadot UC. +1. The solution SHOULD avoid creating additional dependencies on functionality which the Relay-chain need not strictly provide for the delivery of the Polkadot UC. + +Furthermore, the design SHOULD be implementable and deployable in a timely fashion; three months from the acceptance of this RFC would seem reasonable. + +## Stakeholders + +Primary stakeholder sets are: + +- Protocol researchers and developers, largely represented by the Polkadot Fellowship and Parity Technologies' Engineering division. +- Polkadot Parachain teams both present and future, and their users. +- Polkadot DOT token holders. + +_Socialization:_ + +This RFC was presented at Polkadot Decoded 2023 Copenhagen on the Main Stage. A small amount of socialisation at the Parachain Summit preceeded it and some substantial discussion followed it. Parity Ecosystem team is currently soliciting views from ecosystem teams who would be key stakeholders. + +## Design + +### Overview + +Upon implementation of this proposal, slot auctions and associated crowdloans cease. Instead, Coretime on the Polkadot UC is sold by the Polkadot System in two separate formats: *Bulk* and *Instantaneous*. This proposal only mandates the implementation of *Bulk Coretime*; any mentions of *Instantaneous Coretime* is only intended to illustrate a possible final solution. + +*Bulk Coretime* is sold periodically and allocated any time in advance of its usage, whereas *Instantaneous Coretime* is sold immediately prior to usage on a block-by-block basis with an explicit allocation at the time of purchase. + +All Bulk Coretime sold by Polkadot is done so on a new system parachain known as the *Broker-chain*. Revenue from sales would be sent to the Polkadot Treasury. Owners of Bulk Coretime are tracked on this chain and the ownership status and properties (i.e. the specific period) of the owned Coretime are exposed over XCM as a non-fungible asset. + +At the request of the owner, the Broker-chain allows Bulk Coretime to be: + +1. Transferred in ownership. +2. Split into quantized, non-overlapping segments of Bulk Coretime with the same ownership. +3. Consumed in exchange for the allocation of a Core during its period. +4. Consumed in exchange for a pro-rata amount of the revenue from Instantaneous Core sales over its period. + +### Special Considerations + +As a migration mechanism, pre-existing leases (from the legacy lease/slots/crowdloan framework) SHALL be recorded in the Broker-chain and cores assigned to them. When the lease comes to expiry, there is a mechanism to gain a priority sale of Coretime to ensure that the Parachain suffers no downtime. + +Additionally, there is a renewal system which allows a core's Para assignment to be renewed unchanged with a known maximum price increase from month to month. Note that the intention behind renewals is only to ensure that committed Paras get some guarantees about price for predicting future costs. As such this price-capped renewal system only allows cores to be reused for their same tasks from month to month. In any other context, the regular sale system must be used and the regular price paid. + +### Relay-chain and Instantaneous Coretime + +Sales of Instantaneous Coretime are expected to happen on the Polkadot Relay-chain. The Relay-chain is expected to be responsible for: + +- holding non-transferable, non-refundable DOT balance information for collators. +- setting and adjusting the price of Instantaneous Coretime based on usage. +- allowing collators to consume their DOT balance in exchange for the ability to schedule one PoV for near-immediate usage. +- ensuring the Broker-chain has timely book-keeping information on Coretime sales revenue. This should include a total instantaneous revenue amount for each block number. + +### Broker-chain + +The Broker-chain is a new system parachain. It has the responsibility of providing the Relay-chain via UMP with scheduling information of: + +- The number of cores which should be made available during the next session. +- Which cores should be allocated to which para IDs. + +Any cores left unallocated are assumed by the Broker-chain to be used for Instantaneous Coretime sales. + +### Parameters + +This proposal includes a number of parameters which need not necessarily be fixed. They are stated here along with a value, either *suggested* in which case it is non-binding and the proposal should not be judged on the value since the governance mechanism of Polkadot is expected to specify/maintain it; or *specified* in which case the proposal should be judged on the merit of the value as-is. + +| Name | Value | +| ------------------- | ---------------------------- | +| `BULK_PERIOD` | `28 * DAYS` | +| `TIMESLICE` | `10 * MINUTES` | +| `BULK_TARGET` | `30` | +| `BULK_LIMIT` | `45` | +| `LEADIN_PERIOD` | `14 * DAYS` | +| `RENEWAL_PRICE_CAP` | `Perbill::from_percent(2)` | + +### Bulk Sales + +There is a periodic sale of Coretime happening at a period of `BULK_PERIOD`. A number of instances of Coretime spanning from `LEADIN_PERIOD` in the future to `LEADIN_PERIOD + BULK_PERIOD` in the future of a single Polkadot UC Core is offered by the Polkadot System at a fixed price. + +These instances which are owned by purchaser are called *regions*. This sale happens on the Broker-chain. Regions are quantized into atomic periods of `TIMESLICE`, into which `BULK_PERIOD` divides a whole number of times. The `Timeslice` type is a `u16` which can be multiplied by `TIMESLICE` to give a `BlockNumber` value indicating the same period in times of (Relay-chain) blocks. + +The Broker-chain aims to sell some `BULK_TARGET` of Cores, up to some `BULK_LIMIT`. It makes this sale in a single batch `LEADIN_PERIOD` prior to the beginning of the period being sold. The Broker chain publishes a price for this batch of sales for the `BULK_TARGET` period prior to the sale execution. + +Accounts may call a `purchase` function with the appropriate funds in place to have their funds reserved and signal an intention to purchase Bulk Coretime for the forthcoming period. One account may have only one pending purchase. Any number of accounts may attempt to `purchase` Bulk Coretime for the forthcoming period, but the order is recorded. + +If there are more purchase requests than available cores for purchase in this period, then requests are processed in incoming order. Any additional purchase orders are carried over but marked as such. A purchase is only cancellable if it was carried over. + +When a region of Bulk Coretime is initially issued through this purchase, the price it was purchased for is recorded, in addition to the beginning and end Relay-chain block numbers to which it corresponds. + +The Broker-chain SHALL record this information in a storage map called Regions, keyed by a `RegionId`. It shall map into a value of `RegionRecord`: + +```rust +enum RecordState { + Fresh { owner: AccountId }, + Instantaneous { beneficiary: AccountId }, + Assigned { target: ParaId }, +} +type CoreIndex = u16; +type CorePart = (u16, u64); // 80-bit bitmap. +type Timeslice = u32; // 80 block amounts. +struct RegionId { + core: (CoreIndex, CorePart), + begin: Timeslice, +} +struct RegionRecord { + end: Timeslice, + state: RecordState, +} +map RegionId => RegionRecord; + +// Simple example with a `u16` `CorePart` and bulk sold in 100 timeslices. +RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 0 } => + RegionRecord { end: 100u32, state: Fresh(Alice) }; +// First split @ 50 +RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 0 } => + RegionRecord { end: 50u32, state: Fresh(Alice) }; +RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 50 } => + RegionRecord { end: 100u32, state: Fresh(Alice) }; +// Share half of first 50 blocks +RegionId { core: (0u16, 0b1111_1111_0000_0000u16), begin: 0 } => + RegionRecord { end: 50u32, state: Fresh(Alice) }; +RegionId { core: (0u16, 0b0000_0000_1111_1111u16), begin: 0 } => + RegionRecord { end: 50u32, state: Fresh(Alice) }; +RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 50 } => + RegionRecord { end: 100u32, state: Fresh(Alice) }; +// Sell half of them to Bob +RegionId { core: (0u16, 0b1111_1111_0000_0000u16), begin: 0 } => + RegionRecord { end: 50u32, state: Fresh(Alice) }; +RegionId { core: (0u16, 0b0000_0000_1111_1111u16), begin: 0 } => + RegionRecord { end: 50u32, state: Fresh(Bob) }; +RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 50 } => + RegionRecord { end: 100u32, state: Fresh(Alice) }; +// Bob splits first 10 and assigns them to himself. +RegionId { core: (0u16, 0b1111_1111_0000_0000u16), begin: 0 } => + RegionRecord { end: 50u32, state: Fresh(Alice) }; +RegionId { core: (0u16, 0b0000_0000_1111_1111u16), begin: 0 } => + RegionRecord { end: 10u32, state: Fresh(Bob) }; +RegionId { core: (0u16, 0b0000_0000_1111_1111u16), begin: 10 } => + RegionRecord { end: 50u32, state: Fresh(Bob) }; +RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 50 } => + RegionRecord { end: 100u32, state: Fresh(Alice) }; +// Bob shares first 10 3 ways and sells smaller shares to Charlie and Dave +RegionId { core: (0u16, 0b1111_1111_0000_0000u16), begin: 0 } => + RegionRecord { end: 50u32, state: Fresh(Alice) }; +RegionId { core: (0u16, 0b0000_0000_1100_0000u16), begin: 0 } => + RegionRecord { end: 10u32, state: Fresh(Charlie) }; +RegionId { core: (0u16, 0b0000_0000_0011_0000u16), begin: 0 } => + RegionRecord { end: 10u32, state: Fresh(Dave) }; +RegionId { core: (0u16, 0b0000_0000_0000_1111u16), begin: 0 } => + RegionRecord { end: 10u32, state: Fresh(Bob) }; +RegionId { core: (0u16, 0b0000_0000_1111_1111u16), begin: 10 } => + RegionRecord { end: 50u32, state: Fresh(Bob) }; +RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 50 } => + RegionRecord { end: 100u32, state: Fresh(Alice) }; +// Bob assigns to his para B, Charlie and Dave assign to their paras C and D; Alice assigns to A +RegionId { core: (0u16, 0b1111_1111_0000_0000u16), begin: 0 } => + RegionRecord { end: 50u32, state: Assigned(A) }; +RegionId { core: (0u16, 0b0000_0000_1100_0000u16), begin: 0 } => + RegionRecord { end: 10u32, state: Assigned(C) }; +RegionId { core: (0u16, 0b0000_0000_0011_0000u16), begin: 0 } => + RegionRecord { end: 10u32, state: Assigned(D) }; +RegionId { core: (0u16, 0b0000_0000_0000_1111u16), begin: 0 } => + RegionRecord { end: 10u32, state: Assigned(B) }; +RegionId { core: (0u16, 0b0000_0000_1111_1111u16), begin: 10 } => + RegionRecord { end: 50u32, state: Assigned(B) }; +RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 50 } => + RegionRecord { end: 100u32, state: Assigned(A) }; +// Actual notifications to relay chain. +// Assumes: +// - Timeslice is 10 blocks. +// - Timeslice 0 begins at block #1000. +// - Relay needs 10 blocks notice of change. +// +// Block 990: +reassign_core(core: 0u16, begin: 1000, assignment: vec![(A, 8), (C, 2), (D, 2), (B, 4)]) +// Block 1090: +reassign_core(core: 0u16, begin: 1100, assignment: vec![(A, 8), (B, 8)]) +// Block 1490: +reassign_core(core: 0u16, begin: 1100, assignment: vec![(A, 16)]) +``` + + + +This map functions essentially as a linked list, with one region's `end` field acting as a reference to the next region's key's `begin` field. It is keyed by the sale index in order to allow the following sale period's Coretime to be manipulated during the `LEADIN_PERIOD` prior to it becoming allocatable. + +An additional storage map is maintained to keep the "heads" of this linked list. It is called `NextRegion` and it maps `CoreIndex` to `Timeslice`, to indicate the earliest stored region of the given core. + +Notably, if a region is split or transferred, then the `price` is reset to `None`, which has the effect of disallowing a price-increase-capped renewal. + +The Broker-chain provides feedback to the Relay-chain on which `ParaId` sets should be serviced on which cores, and does so as they change. Each block, the Broker-chain checks if the period of a `Timeslice` has elapsed. If so, it checks to see if any cores have a newly active `RegionRecord` value in the `Regions` map. If they do, it MUST notify the Relay-chain of the new responsibilities of the relevant `core`. In this case, it MUST remove the item from the `Regions` map and update the `NextRegion` map so it maps the relevant core to the value of removed record's `end` field. + +If the `RegionRecord` value for an elapsed `RegionId` has an `allocation` of `None`, then the item is not removed and the Relay-chain is instructed to place the core for instantaneous use. + +### Specific functions of the Broker-chain + +Several functions of the Broker-chain SHALL be exposed through dispatchables and/or a `nonfungible` trait implementation integrated into XCM: + +#### 1. Transfer of ownership + +A `transfer(region: RegionId, new_owner: AccountId)` dispatchable SHALL have the effect of altering the current `owner` field of `region` in the `Regions` map from the signed origin to `new_owner`. + +An implementation of the `nonfungible` trait SHOULD include equivalent functionality. `RegionId` SHOULD be used for the `AssetInstance` value. + +In both cases, the `price` field SHALL become `None`. + +#### 2. Split into segments + +A `split(region: RegionId, pivot: Timeslice)` dispatchable SHALL have the effect of mutating the Regions entry of key `region` so that the `end` field becomes `pivot` and create a new Regions entry of the same `core` but a `begin` equal to `pivot` whose `RegionRecord` has the same `owner`, `end` and `allocation` fields as the origin value of `region`. + +`price` in both records is/becomes `None`. + +Also: +- `owner` field of `region` must the equal to the Signed origin. +- `pivot` must equal neither the `begin` nor `end` fields of the `region`. + +#### 3. Consumed in exchange for allocation + +A dispatchable `allocate(region: RegionId, target: Vec)` SHALL be provided corresponding to the `allocate` function described above. + +It MUST be called with a Signed origin equal to the `owner` field of the value of the Regions map for the `region` key. The `allocation` field of this value MUST be `None` (a region may not be re-allocated). + +On success, the `allocation` value is changed to `Some` whose inner value is equal to `target`. + +If the `begin` field of the `region` parameter is less than the current `Timeslice` value, then it is removed and re-entered with the current `Timeslice` value plus one, unless this would be equal to or greater than the `end` field of the corresponding `RegionRecord` value. + +Initially `target` values with only one item MAY be supported. + +If the `RegionRecord`'s `price` field is `Some` (indicating that the Region is freshly purchased), then the Broker-chain SHALL record an entry in a storage map called AllowedRenewals. This maps a `CoreIndex` to a struct `RenewalRecord`: + +```rust +struct RenewalRecord { + target: Vec<(ParaId, u8)>, + price: Balance, + sale: SaleIndex, +} +``` + +#### 4. Renewals + +A dispatchable `renew(core: CoreIndex)` SHALL be provided. Any account may call `renew` to purchase Bulk Coretime and renew an active allocation for the given `core`. + +This MUST be called during the `LEADIN_PERIOD` prior to a Bulk sale (exactly like `purchase`) and has the same effect as `purchase` followed by `allocate` containing the same `Vec`, except that: + +1. The purchase always succeeds and as such must be processed prior to regular `purchase` orders. +2. The price of the purchase is the previous `price` incremented by `RENEWAL_PRICE_CAP` of itself or the regular price, whichever is lower. + +AllowedRenewals map is updated with the new information ready for the following Bulk sale. + +#### 5. Migrations from Legacy Slot Leases + +It is intended that paras which hold a lease from the legacy slot auction system are able to seamlessly transition into the Agile Coretime framework. + +A dispatchable `migrate(core: CoreIndex)` SHALL be provided. Any account may call `migrate` to purchase Bulk Coretime at the current price for the given `core`. + +This MUST be called during the `LEADIN_PERIOD` prior to a Bulk sale (exactly like `purchase`) and has the same effect as `purchase` followed by `allocate` with a value of `Vec` containing just one item equal to `target`, except that: + +1. The purchase always succeeds and as such MUST be processed prior to regular `purchase` orders. +2. There MUST be an ongoing legacy parachain lease whose parachain is assigned to `core` and which is due to expire during the Coretime period being purchased. + +AllowedRenewals map is updated with this information ready for the following Bulk sale. + +### Notes on Price Setting + +The specific price setting mechanism is out of scope for this proposal and should be covered in some other work. The present proposal assumes the existence of a price-setting mechanism which could take into account three parameters; two mostly fixed and one which changes each `BULK_PERIOD`. These parameters are `BULK_TARGET`, `BULK_LIMIT` and `CORES_SOLD` which is the actual number of cores sold for the present `BULK_PERIOD` and is always an unsigned integer at most `BULK_LIMIT`. + +In general we would expect the price to increase the closer `CORES_SOLD` gets to `BULK_LIMIT` and to decrease the closer it gets to zero. If it is exactly equal to `BULK_TARGET`, then we would expect the price to remain the same. + +A simple example of this would be the formula: + +``` +NEW_PRICE := IF CORES_OLD < BULK_TARGET THEN + OLD_PRICE - OLD_PRICE / 2 * CORES_SOLD / BULK_TARGET +ELSE + OLD_PRICE + OLD_PRICE / 2 * + (CORES_SOLD - BULK_TARGET) / (BULK_LIMIT - BULK_TARGET) +END IF +``` + +This exists only as a trivial example to demonstrate a basic solution exists, and should not be intended as a concrete proposal. + +### Notes on Instantaneous Core Sales + +For access to the Instantaneous Core sales we may include an `allocate_instantaneous` function. This should allocate the Coretime for usage by Polkadot to serve instantaneous requests and allow the `owner` to collect a pro-rata amount of total Instantaneous sales revenue. + +For an efficient market to form around the provision of Bulk-purchased Cores into the pool of cores available for Instantaneous Coretime purchase, it is crucial to ensure that price changes for the purchase of Instantaneous Coretime are reflected well in the revenues of private Coretime providers during the same period. + +In order to ensure this, then it is crucial that Instantaneous Coretime, once purchased, cannot be held indefinitely prior to eventual use since, if this were the case, a nefarious collator could purchase Coretime when cheap and utilize it some time later when expensive and deprive private Coretime providers of their revenue. It SHOULD therefore be assumed that Instantaneous Coretime, once purchased, has a definite and short "shelf-life", after which it becomes unusable. This incentivizes collators to avoid purchasing Coretime unless they expect to utilize it imminently and thus helps create an efficient market-feedback mechanism whereby a higher price will actually result in material revenues for private Coretime providers who contribute to the pool of Cores available to service Instantaneous Coretime purchases. + +### The Relay-chain API + +The Relay-chain provides a pallet-based API for the Broker-chain to utilize to inform it in real-time of allocation information for the cores and also to alter the number of cores in the next session. There are two functions which it should expose: + +- `fn set_core_count(count: u16)`: Sets the number of active cores from the next session onwards, identified from index `0` to index `count - 1` inclusive. +- `fn assign_core(core_index: u16, assignment: Option>, begin: BlockNumber, end_hint: Option)`: Requests the Relay-chain to provision core identified by `core_index` to process paras identified within the `assignment` vector relatively biased according to the accompanying `u16` *weight* parameter. The weight parameter indicates the ratio of blocks which *on average* should be being processed for the the given para compared to the other paras mentioned in the `assignment` vector. + +The Relay-chain should publish, through a well-known storage key, the number of blocks in advance which `assign_core` should be called to ensure that the core gets scheduled properly. We can denote this quantity `ADVANCE_NOTICE`. The Relay-chain MUST respect the core assignment provided that `assign_core` gets processed on a block whose number is no greater than `begin - ADVANCE_NOTICE`. + +## Implementation + +Implementation of this proposal comes in several phases: + +1. Finalise the specifics of implementation; this may be done through a design document or through a well-documented prototype implementation. +2. Implement the design, including all associated aspects such as unit tests, benchmarks and any support software needed. +3. If any new parachain is required, launch of this. +4. Formal audit of the implementation and any manual testing. +5. Announcement to the various stakeholders of the imminent changes. +6. Software integration and release. +7. Governance upgrade proposal(s). +8. Monitoring of the upgrade process. + +## Performance, Ergonomics and Compatibility + +No specific considerations. + +Parachains already deployed into the Polkadot UC MUST have a clear plan of action to migrate to an agile Coretime market. + +While this proposal does not introduce documentable features per se, adequate documentation must be provided to potential purchasers of Polkadot Coretime. This SHOULD include any alterations to the Polkadot-SDK software collection, most likely Cumulus. + +## Testing, Security and Privacy + +Regular testing through unit tests, integration tests, manual testnet tests, zombie-net tests and fuzzing SHOULD be conducted. + +A regular security review SHOULD be conducted prior to deployment through a review by the Web3 Foundation economic research group. + +Any final implementation MUST pass a professional external security audit. + +The proposal introduces no new privacy concerns. + +## Future Directions and Related Material + +RFC-2 proposes a means of implementing the high-level allocations within the Relay-chain. + +Additional work should specify the interface for the instantaneous market revenue so that the Broker chain can ensure Bulk Coretime placed in the instantaneous market is properly compensated. + +## Drawbacks, Alternatives and Unknowns + +None at present. + +## Prior Art and References + +None. From e2fdcc2df1beddb92791acbbf1e3a7a0a0c2b450 Mon Sep 17 00:00:00 2001 From: Gav Date: Thu, 6 Jul 2023 14:55:26 +0200 Subject: [PATCH 02/11] RFC-5 Coretime Interface --- text/0004-coretime-interface.md | 376 -------------------------------- text/0005-coretime-interface.md | 161 ++++++++++++++ 2 files changed, 161 insertions(+), 376 deletions(-) delete mode 100644 text/0004-coretime-interface.md create mode 100644 text/0005-coretime-interface.md diff --git a/text/0004-coretime-interface.md b/text/0004-coretime-interface.md deleted file mode 100644 index 847a0105c..000000000 --- a/text/0004-coretime-interface.md +++ /dev/null @@ -1,376 +0,0 @@ -# RFC-1: Coretime Interface - -| | | -| --------------- | ------------------------------------------------------------------------------------------- | -| **Start Date** | 06 July 2023 | -| **Status** | Draft | -| **Description** | Agile periodic-sale-based model for assigning Coretime on the Polkadot Ubiquitous Computer. | -| **Authors** | Gavin Wood | -| **Licence** | MIT/Apache2 | - - -## Summary - -This proposes a periodic, sale-based method for assigning Polkadot Coretime. The method takes into account the need for long-term capital expenditure planning for teams building on Polkadot, yet also provides a means to allow Polkadot to capture long-term value in the resource which it sells. It supports the possibility of building secondary markets to make resource allocation more efficient and largely avoids the need for parameterisation. - -## Motivation - -### Present System - -The present system of allocating time for parachains on the cores of the Polkadot Ubiquitous Computer (aka "Polkadot") is through a process known as *slot auctions*. These are on-chain candle auctions which proceed for several days and result in a core being assigned to a single parachain for six months at a time up to 18 months in advance. Practically speaking, we only see two year periods being bid upon and leased. - -Funds behind the bids made in the slot auctions are merely locked, not consumed or paid and become unlocked and returned to the bidder on expiry of the lease period. A means of sharing the deposit trustlessly known as a *crowdloan* is available allowing token holders to contribute to the overall deposit of a chain without any counterparty risk. - -### Problems - -The present system is based on a model of one-core-per-parachain. This is a legacy interpretation of the Polkadot platform and is not a reflection of its present capabilities. By restricting ownership and usage to this model, more dynamic and resource-efficient means of utilising the Polkadot Ubiquitous Computer is lost. - -More specifically, it is impossible to lease out cores at anything less than six months, and apparently unrealistic to do so at anything less than two years. This cuts out the ability to dynamically manage the underlying resource, and generally experimentation, iteration and innovation are hampered. It bakes into the platform an assumption of permanence for anything deployed into it and restricts the market's ability to find a more optimal allocation of the finite resource. - -There is no ability to determine capital requirements for hosting a parachain beyond two years from the point of its initial deployment onto Polkadot. While it would be unreasonable to have perfect and indefinite cost predictions for any real-world platform, not having any clarity whatsoever beyond "market rates" two years hence can be a very off-putting prospect for teams to buy into. - -However, quite possibly the most substantial problem is both a perceived and often real high barrier to entry of the Polkadot ecosystem. By forcing innovators to either raise 7-figure sums through investors or appeal to the wider token-holding community, Polkadot makes it essentially difficult for a small band of innovators from deploying their technology into Polkadot. While not being actually permissioned, it is also far from the barrierless, permissionless ideal which an innovation platform such as Polkadot should be striving for. - -## Requirements - -1. The solution SHOULD provide an acceptable value-capture mechanism for the Polkadot network. -1. The solution SHOULD allow parachains and other projects deployed on to the Polkadot UC to make long-term capital expenditure predictions for the cost of ongoing deployment. -1. The solution SHOULD minimize the barriers to entry in the ecosystem. -1. The solution SHOULD work when the number of cores which the Polkadot UC can support changes over time. -1. The solution SHOULD facilitate the optimal allocation of work to core of the Polkadot UC. -1. The solution SHOULD avoid creating additional dependencies on functionality which the Relay-chain need not strictly provide for the delivery of the Polkadot UC. - -Furthermore, the design SHOULD be implementable and deployable in a timely fashion; three months from the acceptance of this RFC would seem reasonable. - -## Stakeholders - -Primary stakeholder sets are: - -- Protocol researchers and developers, largely represented by the Polkadot Fellowship and Parity Technologies' Engineering division. -- Polkadot Parachain teams both present and future, and their users. -- Polkadot DOT token holders. - -_Socialization:_ - -This RFC was presented at Polkadot Decoded 2023 Copenhagen on the Main Stage. A small amount of socialisation at the Parachain Summit preceeded it and some substantial discussion followed it. Parity Ecosystem team is currently soliciting views from ecosystem teams who would be key stakeholders. - -## Design - -### Overview - -Upon implementation of this proposal, slot auctions and associated crowdloans cease. Instead, Coretime on the Polkadot UC is sold by the Polkadot System in two separate formats: *Bulk* and *Instantaneous*. This proposal only mandates the implementation of *Bulk Coretime*; any mentions of *Instantaneous Coretime* is only intended to illustrate a possible final solution. - -*Bulk Coretime* is sold periodically and allocated any time in advance of its usage, whereas *Instantaneous Coretime* is sold immediately prior to usage on a block-by-block basis with an explicit allocation at the time of purchase. - -All Bulk Coretime sold by Polkadot is done so on a new system parachain known as the *Broker-chain*. Revenue from sales would be sent to the Polkadot Treasury. Owners of Bulk Coretime are tracked on this chain and the ownership status and properties (i.e. the specific period) of the owned Coretime are exposed over XCM as a non-fungible asset. - -At the request of the owner, the Broker-chain allows Bulk Coretime to be: - -1. Transferred in ownership. -2. Split into quantized, non-overlapping segments of Bulk Coretime with the same ownership. -3. Consumed in exchange for the allocation of a Core during its period. -4. Consumed in exchange for a pro-rata amount of the revenue from Instantaneous Core sales over its period. - -### Special Considerations - -As a migration mechanism, pre-existing leases (from the legacy lease/slots/crowdloan framework) SHALL be recorded in the Broker-chain and cores assigned to them. When the lease comes to expiry, there is a mechanism to gain a priority sale of Coretime to ensure that the Parachain suffers no downtime. - -Additionally, there is a renewal system which allows a core's Para assignment to be renewed unchanged with a known maximum price increase from month to month. Note that the intention behind renewals is only to ensure that committed Paras get some guarantees about price for predicting future costs. As such this price-capped renewal system only allows cores to be reused for their same tasks from month to month. In any other context, the regular sale system must be used and the regular price paid. - -### Relay-chain and Instantaneous Coretime - -Sales of Instantaneous Coretime are expected to happen on the Polkadot Relay-chain. The Relay-chain is expected to be responsible for: - -- holding non-transferable, non-refundable DOT balance information for collators. -- setting and adjusting the price of Instantaneous Coretime based on usage. -- allowing collators to consume their DOT balance in exchange for the ability to schedule one PoV for near-immediate usage. -- ensuring the Broker-chain has timely book-keeping information on Coretime sales revenue. This should include a total instantaneous revenue amount for each block number. - -### Broker-chain - -The Broker-chain is a new system parachain. It has the responsibility of providing the Relay-chain via UMP with scheduling information of: - -- The number of cores which should be made available during the next session. -- Which cores should be allocated to which para IDs. - -Any cores left unallocated are assumed by the Broker-chain to be used for Instantaneous Coretime sales. - -### Parameters - -This proposal includes a number of parameters which need not necessarily be fixed. They are stated here along with a value, either *suggested* in which case it is non-binding and the proposal should not be judged on the value since the governance mechanism of Polkadot is expected to specify/maintain it; or *specified* in which case the proposal should be judged on the merit of the value as-is. - -| Name | Value | -| ------------------- | ---------------------------- | -| `BULK_PERIOD` | `28 * DAYS` | -| `TIMESLICE` | `10 * MINUTES` | -| `BULK_TARGET` | `30` | -| `BULK_LIMIT` | `45` | -| `LEADIN_PERIOD` | `14 * DAYS` | -| `RENEWAL_PRICE_CAP` | `Perbill::from_percent(2)` | - -### Bulk Sales - -There is a periodic sale of Coretime happening at a period of `BULK_PERIOD`. A number of instances of Coretime spanning from `LEADIN_PERIOD` in the future to `LEADIN_PERIOD + BULK_PERIOD` in the future of a single Polkadot UC Core is offered by the Polkadot System at a fixed price. - -These instances which are owned by purchaser are called *regions*. This sale happens on the Broker-chain. Regions are quantized into atomic periods of `TIMESLICE`, into which `BULK_PERIOD` divides a whole number of times. The `Timeslice` type is a `u16` which can be multiplied by `TIMESLICE` to give a `BlockNumber` value indicating the same period in times of (Relay-chain) blocks. - -The Broker-chain aims to sell some `BULK_TARGET` of Cores, up to some `BULK_LIMIT`. It makes this sale in a single batch `LEADIN_PERIOD` prior to the beginning of the period being sold. The Broker chain publishes a price for this batch of sales for the `BULK_TARGET` period prior to the sale execution. - -Accounts may call a `purchase` function with the appropriate funds in place to have their funds reserved and signal an intention to purchase Bulk Coretime for the forthcoming period. One account may have only one pending purchase. Any number of accounts may attempt to `purchase` Bulk Coretime for the forthcoming period, but the order is recorded. - -If there are more purchase requests than available cores for purchase in this period, then requests are processed in incoming order. Any additional purchase orders are carried over but marked as such. A purchase is only cancellable if it was carried over. - -When a region of Bulk Coretime is initially issued through this purchase, the price it was purchased for is recorded, in addition to the beginning and end Relay-chain block numbers to which it corresponds. - -The Broker-chain SHALL record this information in a storage map called Regions, keyed by a `RegionId`. It shall map into a value of `RegionRecord`: - -```rust -enum RecordState { - Fresh { owner: AccountId }, - Instantaneous { beneficiary: AccountId }, - Assigned { target: ParaId }, -} -type CoreIndex = u16; -type CorePart = (u16, u64); // 80-bit bitmap. -type Timeslice = u32; // 80 block amounts. -struct RegionId { - core: (CoreIndex, CorePart), - begin: Timeslice, -} -struct RegionRecord { - end: Timeslice, - state: RecordState, -} -map RegionId => RegionRecord; - -// Simple example with a `u16` `CorePart` and bulk sold in 100 timeslices. -RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 0 } => - RegionRecord { end: 100u32, state: Fresh(Alice) }; -// First split @ 50 -RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 0 } => - RegionRecord { end: 50u32, state: Fresh(Alice) }; -RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 50 } => - RegionRecord { end: 100u32, state: Fresh(Alice) }; -// Share half of first 50 blocks -RegionId { core: (0u16, 0b1111_1111_0000_0000u16), begin: 0 } => - RegionRecord { end: 50u32, state: Fresh(Alice) }; -RegionId { core: (0u16, 0b0000_0000_1111_1111u16), begin: 0 } => - RegionRecord { end: 50u32, state: Fresh(Alice) }; -RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 50 } => - RegionRecord { end: 100u32, state: Fresh(Alice) }; -// Sell half of them to Bob -RegionId { core: (0u16, 0b1111_1111_0000_0000u16), begin: 0 } => - RegionRecord { end: 50u32, state: Fresh(Alice) }; -RegionId { core: (0u16, 0b0000_0000_1111_1111u16), begin: 0 } => - RegionRecord { end: 50u32, state: Fresh(Bob) }; -RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 50 } => - RegionRecord { end: 100u32, state: Fresh(Alice) }; -// Bob splits first 10 and assigns them to himself. -RegionId { core: (0u16, 0b1111_1111_0000_0000u16), begin: 0 } => - RegionRecord { end: 50u32, state: Fresh(Alice) }; -RegionId { core: (0u16, 0b0000_0000_1111_1111u16), begin: 0 } => - RegionRecord { end: 10u32, state: Fresh(Bob) }; -RegionId { core: (0u16, 0b0000_0000_1111_1111u16), begin: 10 } => - RegionRecord { end: 50u32, state: Fresh(Bob) }; -RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 50 } => - RegionRecord { end: 100u32, state: Fresh(Alice) }; -// Bob shares first 10 3 ways and sells smaller shares to Charlie and Dave -RegionId { core: (0u16, 0b1111_1111_0000_0000u16), begin: 0 } => - RegionRecord { end: 50u32, state: Fresh(Alice) }; -RegionId { core: (0u16, 0b0000_0000_1100_0000u16), begin: 0 } => - RegionRecord { end: 10u32, state: Fresh(Charlie) }; -RegionId { core: (0u16, 0b0000_0000_0011_0000u16), begin: 0 } => - RegionRecord { end: 10u32, state: Fresh(Dave) }; -RegionId { core: (0u16, 0b0000_0000_0000_1111u16), begin: 0 } => - RegionRecord { end: 10u32, state: Fresh(Bob) }; -RegionId { core: (0u16, 0b0000_0000_1111_1111u16), begin: 10 } => - RegionRecord { end: 50u32, state: Fresh(Bob) }; -RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 50 } => - RegionRecord { end: 100u32, state: Fresh(Alice) }; -// Bob assigns to his para B, Charlie and Dave assign to their paras C and D; Alice assigns to A -RegionId { core: (0u16, 0b1111_1111_0000_0000u16), begin: 0 } => - RegionRecord { end: 50u32, state: Assigned(A) }; -RegionId { core: (0u16, 0b0000_0000_1100_0000u16), begin: 0 } => - RegionRecord { end: 10u32, state: Assigned(C) }; -RegionId { core: (0u16, 0b0000_0000_0011_0000u16), begin: 0 } => - RegionRecord { end: 10u32, state: Assigned(D) }; -RegionId { core: (0u16, 0b0000_0000_0000_1111u16), begin: 0 } => - RegionRecord { end: 10u32, state: Assigned(B) }; -RegionId { core: (0u16, 0b0000_0000_1111_1111u16), begin: 10 } => - RegionRecord { end: 50u32, state: Assigned(B) }; -RegionId { core: (0u16, 0b1111_1111_1111_1111u16), begin: 50 } => - RegionRecord { end: 100u32, state: Assigned(A) }; -// Actual notifications to relay chain. -// Assumes: -// - Timeslice is 10 blocks. -// - Timeslice 0 begins at block #1000. -// - Relay needs 10 blocks notice of change. -// -// Block 990: -reassign_core(core: 0u16, begin: 1000, assignment: vec![(A, 8), (C, 2), (D, 2), (B, 4)]) -// Block 1090: -reassign_core(core: 0u16, begin: 1100, assignment: vec![(A, 8), (B, 8)]) -// Block 1490: -reassign_core(core: 0u16, begin: 1100, assignment: vec![(A, 16)]) -``` - - - -This map functions essentially as a linked list, with one region's `end` field acting as a reference to the next region's key's `begin` field. It is keyed by the sale index in order to allow the following sale period's Coretime to be manipulated during the `LEADIN_PERIOD` prior to it becoming allocatable. - -An additional storage map is maintained to keep the "heads" of this linked list. It is called `NextRegion` and it maps `CoreIndex` to `Timeslice`, to indicate the earliest stored region of the given core. - -Notably, if a region is split or transferred, then the `price` is reset to `None`, which has the effect of disallowing a price-increase-capped renewal. - -The Broker-chain provides feedback to the Relay-chain on which `ParaId` sets should be serviced on which cores, and does so as they change. Each block, the Broker-chain checks if the period of a `Timeslice` has elapsed. If so, it checks to see if any cores have a newly active `RegionRecord` value in the `Regions` map. If they do, it MUST notify the Relay-chain of the new responsibilities of the relevant `core`. In this case, it MUST remove the item from the `Regions` map and update the `NextRegion` map so it maps the relevant core to the value of removed record's `end` field. - -If the `RegionRecord` value for an elapsed `RegionId` has an `allocation` of `None`, then the item is not removed and the Relay-chain is instructed to place the core for instantaneous use. - -### Specific functions of the Broker-chain - -Several functions of the Broker-chain SHALL be exposed through dispatchables and/or a `nonfungible` trait implementation integrated into XCM: - -#### 1. Transfer of ownership - -A `transfer(region: RegionId, new_owner: AccountId)` dispatchable SHALL have the effect of altering the current `owner` field of `region` in the `Regions` map from the signed origin to `new_owner`. - -An implementation of the `nonfungible` trait SHOULD include equivalent functionality. `RegionId` SHOULD be used for the `AssetInstance` value. - -In both cases, the `price` field SHALL become `None`. - -#### 2. Split into segments - -A `split(region: RegionId, pivot: Timeslice)` dispatchable SHALL have the effect of mutating the Regions entry of key `region` so that the `end` field becomes `pivot` and create a new Regions entry of the same `core` but a `begin` equal to `pivot` whose `RegionRecord` has the same `owner`, `end` and `allocation` fields as the origin value of `region`. - -`price` in both records is/becomes `None`. - -Also: -- `owner` field of `region` must the equal to the Signed origin. -- `pivot` must equal neither the `begin` nor `end` fields of the `region`. - -#### 3. Consumed in exchange for allocation - -A dispatchable `allocate(region: RegionId, target: Vec)` SHALL be provided corresponding to the `allocate` function described above. - -It MUST be called with a Signed origin equal to the `owner` field of the value of the Regions map for the `region` key. The `allocation` field of this value MUST be `None` (a region may not be re-allocated). - -On success, the `allocation` value is changed to `Some` whose inner value is equal to `target`. - -If the `begin` field of the `region` parameter is less than the current `Timeslice` value, then it is removed and re-entered with the current `Timeslice` value plus one, unless this would be equal to or greater than the `end` field of the corresponding `RegionRecord` value. - -Initially `target` values with only one item MAY be supported. - -If the `RegionRecord`'s `price` field is `Some` (indicating that the Region is freshly purchased), then the Broker-chain SHALL record an entry in a storage map called AllowedRenewals. This maps a `CoreIndex` to a struct `RenewalRecord`: - -```rust -struct RenewalRecord { - target: Vec<(ParaId, u8)>, - price: Balance, - sale: SaleIndex, -} -``` - -#### 4. Renewals - -A dispatchable `renew(core: CoreIndex)` SHALL be provided. Any account may call `renew` to purchase Bulk Coretime and renew an active allocation for the given `core`. - -This MUST be called during the `LEADIN_PERIOD` prior to a Bulk sale (exactly like `purchase`) and has the same effect as `purchase` followed by `allocate` containing the same `Vec`, except that: - -1. The purchase always succeeds and as such must be processed prior to regular `purchase` orders. -2. The price of the purchase is the previous `price` incremented by `RENEWAL_PRICE_CAP` of itself or the regular price, whichever is lower. - -AllowedRenewals map is updated with the new information ready for the following Bulk sale. - -#### 5. Migrations from Legacy Slot Leases - -It is intended that paras which hold a lease from the legacy slot auction system are able to seamlessly transition into the Agile Coretime framework. - -A dispatchable `migrate(core: CoreIndex)` SHALL be provided. Any account may call `migrate` to purchase Bulk Coretime at the current price for the given `core`. - -This MUST be called during the `LEADIN_PERIOD` prior to a Bulk sale (exactly like `purchase`) and has the same effect as `purchase` followed by `allocate` with a value of `Vec` containing just one item equal to `target`, except that: - -1. The purchase always succeeds and as such MUST be processed prior to regular `purchase` orders. -2. There MUST be an ongoing legacy parachain lease whose parachain is assigned to `core` and which is due to expire during the Coretime period being purchased. - -AllowedRenewals map is updated with this information ready for the following Bulk sale. - -### Notes on Price Setting - -The specific price setting mechanism is out of scope for this proposal and should be covered in some other work. The present proposal assumes the existence of a price-setting mechanism which could take into account three parameters; two mostly fixed and one which changes each `BULK_PERIOD`. These parameters are `BULK_TARGET`, `BULK_LIMIT` and `CORES_SOLD` which is the actual number of cores sold for the present `BULK_PERIOD` and is always an unsigned integer at most `BULK_LIMIT`. - -In general we would expect the price to increase the closer `CORES_SOLD` gets to `BULK_LIMIT` and to decrease the closer it gets to zero. If it is exactly equal to `BULK_TARGET`, then we would expect the price to remain the same. - -A simple example of this would be the formula: - -``` -NEW_PRICE := IF CORES_OLD < BULK_TARGET THEN - OLD_PRICE - OLD_PRICE / 2 * CORES_SOLD / BULK_TARGET -ELSE - OLD_PRICE + OLD_PRICE / 2 * - (CORES_SOLD - BULK_TARGET) / (BULK_LIMIT - BULK_TARGET) -END IF -``` - -This exists only as a trivial example to demonstrate a basic solution exists, and should not be intended as a concrete proposal. - -### Notes on Instantaneous Core Sales - -For access to the Instantaneous Core sales we may include an `allocate_instantaneous` function. This should allocate the Coretime for usage by Polkadot to serve instantaneous requests and allow the `owner` to collect a pro-rata amount of total Instantaneous sales revenue. - -For an efficient market to form around the provision of Bulk-purchased Cores into the pool of cores available for Instantaneous Coretime purchase, it is crucial to ensure that price changes for the purchase of Instantaneous Coretime are reflected well in the revenues of private Coretime providers during the same period. - -In order to ensure this, then it is crucial that Instantaneous Coretime, once purchased, cannot be held indefinitely prior to eventual use since, if this were the case, a nefarious collator could purchase Coretime when cheap and utilize it some time later when expensive and deprive private Coretime providers of their revenue. It SHOULD therefore be assumed that Instantaneous Coretime, once purchased, has a definite and short "shelf-life", after which it becomes unusable. This incentivizes collators to avoid purchasing Coretime unless they expect to utilize it imminently and thus helps create an efficient market-feedback mechanism whereby a higher price will actually result in material revenues for private Coretime providers who contribute to the pool of Cores available to service Instantaneous Coretime purchases. - -### The Relay-chain API - -The Relay-chain provides a pallet-based API for the Broker-chain to utilize to inform it in real-time of allocation information for the cores and also to alter the number of cores in the next session. There are two functions which it should expose: - -- `fn set_core_count(count: u16)`: Sets the number of active cores from the next session onwards, identified from index `0` to index `count - 1` inclusive. -- `fn assign_core(core_index: u16, assignment: Option>, begin: BlockNumber, end_hint: Option)`: Requests the Relay-chain to provision core identified by `core_index` to process paras identified within the `assignment` vector relatively biased according to the accompanying `u16` *weight* parameter. The weight parameter indicates the ratio of blocks which *on average* should be being processed for the the given para compared to the other paras mentioned in the `assignment` vector. - -The Relay-chain should publish, through a well-known storage key, the number of blocks in advance which `assign_core` should be called to ensure that the core gets scheduled properly. We can denote this quantity `ADVANCE_NOTICE`. The Relay-chain MUST respect the core assignment provided that `assign_core` gets processed on a block whose number is no greater than `begin - ADVANCE_NOTICE`. - -## Implementation - -Implementation of this proposal comes in several phases: - -1. Finalise the specifics of implementation; this may be done through a design document or through a well-documented prototype implementation. -2. Implement the design, including all associated aspects such as unit tests, benchmarks and any support software needed. -3. If any new parachain is required, launch of this. -4. Formal audit of the implementation and any manual testing. -5. Announcement to the various stakeholders of the imminent changes. -6. Software integration and release. -7. Governance upgrade proposal(s). -8. Monitoring of the upgrade process. - -## Performance, Ergonomics and Compatibility - -No specific considerations. - -Parachains already deployed into the Polkadot UC MUST have a clear plan of action to migrate to an agile Coretime market. - -While this proposal does not introduce documentable features per se, adequate documentation must be provided to potential purchasers of Polkadot Coretime. This SHOULD include any alterations to the Polkadot-SDK software collection, most likely Cumulus. - -## Testing, Security and Privacy - -Regular testing through unit tests, integration tests, manual testnet tests, zombie-net tests and fuzzing SHOULD be conducted. - -A regular security review SHOULD be conducted prior to deployment through a review by the Web3 Foundation economic research group. - -Any final implementation MUST pass a professional external security audit. - -The proposal introduces no new privacy concerns. - -## Future Directions and Related Material - -RFC-2 proposes a means of implementing the high-level allocations within the Relay-chain. - -Additional work should specify the interface for the instantaneous market revenue so that the Broker chain can ensure Bulk Coretime placed in the instantaneous market is properly compensated. - -## Drawbacks, Alternatives and Unknowns - -None at present. - -## Prior Art and References - -None. diff --git a/text/0005-coretime-interface.md b/text/0005-coretime-interface.md new file mode 100644 index 000000000..3b44555b2 --- /dev/null +++ b/text/0005-coretime-interface.md @@ -0,0 +1,161 @@ +# RFC-5: Coretime Interface + +| | | +| --------------- | ------------------------------------------------------------------------------------------- | +| **Start Date** | 06 July 2023 | +| **Description** | Interface for manipulating the usage of cores on the Polkadot Ubiquitous Computer. | +| **Authors** | Gavin Wood | + + +## Summary + +In the Agile Coretime model of the Polkadot Ubiquitous Computer, as proposed in RFC-1 and RFC-4, it is necessary for the allocating parachain (envisioned to be one or more pallets on a specialised Brokerage System Chain) to communicate the core assignments to the Relay-chain, which is responsible for ensuring those assignments are properly enacted. + +This is a proposal for the interface which will exist around the Relay-chain in order to communicate this information and instructions. + +## Motivation + +The overall motivation for splitting out functions from the Relay-chain onto System parachains is well understood. An well-understood interface is necessary for ensuring multiple chains are able to coordinate their efforts. + +## Requirements + +- The interface MUST allow the Relay-chain to be scheduled on a low-latency basis. +- Individual cores MUST be schedulable, both in full to a single task (a ParaId or the Instantaneous Coretime Pool) or to many unique tasks in differing ratios. +- Typical usage of the interface SHOULD NOT overload the VMP message system. +- Worst case usage of the interface MUST NOT cause the Polkadot system to fail. +- The interface MUST allow for the allocating chain to be notified of all accounting information relevant for making accurate rewards for contributing to the Instantaneous Coretime Pool. +- The interface MUST allow for Instantaneous Coretime Market Credits to be communicated. +- The interface MUST allow for the allocating chain to instruct changes to the number of cores which it is able to allocate. +- The interface MUST allow for the allocating chain to be notified of changes to the number of cores which are able to be allocated by the allocating chain. + +## Stakeholders + +Primary stakeholder sets are: + +- Developers of the Relay-chain core-management logic. +- Developers of the Brokerage System Chain and its pallets. + +_Socialization:_ + +This content of this RFC was discussed in the Polkdot Fellows channel. + +## Explanation + +The interface has two sections: The messages which the Relay-chain is able to receive from the allocating parachain (the *UMP message types*), and messages which the Relay-chain is able to send to the allocating parachain (the *DMP message types*). These messages are expected to be able to be implemented in a well-known pallet and called with the XCM `Transact` instruction. + +Future work may include these messages being introduced into the XCM standard. + +### UMP Message Types + +#### `request_core_count` + +Prototype: + +``` +fn request_core_count( + count: u16, +) +``` + +Requests the Relay-chain to alter the number of schedulable cores to `count`. Under normal operation, the Relay-chain SHOULD send a `notify_core_count(count)` message back. + +#### `request_revenue_info_at` + +Prototype: + +``` +fn request_revenue_at( + when: BlockNumber, +) +``` + +Requests that the Relay-chain send a `notify_revenue` message back at or soon after Relay-chain block number `when` whose `until` parameter is equal to `when`. + +#### `assign_core` + +Prototype: + +``` +type PartsOf57600 = u16; +enum CoreAssignment { + InstantaneousPool, + Task(ParaId), +} +fn assign_core( + core: CoreIndex, + begin: BlockNumber, + assignment: Vec<(CoreAssignment, PartsOf57600)>, + end_hint: Option, +) +``` + +Requirements: + +``` +assert!(core < core_count); +assert!(targets.iter().map(|x| x.0).is_sorted()); +assert_eq!(targets.iter().map(|x| x.0).unique().count(), targets.len()); +assert_eq!(targets.iter().map(|x| x.1).sum(), 57600); +``` + +Where: +- `core_count` is assumed to be the sole parameter in the last received `notify_core_count` message. + +Instructs the Relay-chain to ensure that the core indexed as `core` is utilised for a number of assignments in specific ratios given by `assignment` starting as soon after `begin` as possible. Core assignments take the form of a `CoreAssignment` value which can either task the core to a `ParaId` value or indicate that the core should be used in the Instantaneous Pool. Each assignment comes with a ratio value, represented as the numerator of the fraction with a denominator of 57,600. + +If `end_hint` is `Some` and the inner is greater than the current block number, then the Relay-chain should optimize in the expectation of receiving a new `assign_core(core, ...)` message at or prior to the block number of the inner value. Specific functionality should remain unchanged regardless of the `end_hint` value. + +On the choice of denominator: 57,600 is a highly composite number which factors into: 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 5, 5. By using it as the denominator we allow for various useful fractions to be perfectly represented including thirds, quarters, fifths, tenths, 80ths, percent and 256ths. + +### DMP Message Types + +#### `notify_core_count` + +Prototype: + +``` +fn notify_core_count( + count: u16, +) +``` + +Indicate that from this block onwards, the range of acceptable values of the `core` parameter of `assign_core` message is `[0, count)`. `assign_core` will be a no-op if provided with a value for `core` outside of this range. + +#### `notify_revenue_info` + +Prototype: + +``` +fn notify_revenue( + until: BlockNumber, + revenue: Balance, +) +``` + +Provide the amount of revenue accumulated from Instantaneous Coretime Sales from Relay-chain block number `last_until` to `until`, not including `until` itself. `last_until` is defined as being the `until` argument of the last `notify_revenue` message sent. + +This explicitly disregards the possibility of multiple parachains requesting and being notified of revenue information. The Relay-chain must be configured to ensure that only a single revenue information destination exists. + +## Performance, Ergonomics and Compatibility + +No specific considerations. + +## Testing, Security and Privacy + +Standard Polkadot testing and security auditing applies. + +The proposal introduces no new privacy concerns. + +## Future Directions and Related Material + +RFC-1 proposes a means of determining allocation of Coretime using this interface. + +RFC-3 proposes a means of implementing the high-level allocations within the Relay-chain. + +## Drawbacks, Alternatives and Unknowns + +None at present. + +## Prior Art and References + +None. From 165066f4b80b434b5790cd67ab8b22dfd3265df8 Mon Sep 17 00:00:00 2001 From: Gav Date: Thu, 6 Jul 2023 15:00:00 +0200 Subject: [PATCH 03/11] Credit Account --- text/0005-coretime-interface.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/text/0005-coretime-interface.md b/text/0005-coretime-interface.md index 3b44555b2..8048e64d4 100644 --- a/text/0005-coretime-interface.md +++ b/text/0005-coretime-interface.md @@ -71,6 +71,21 @@ fn request_revenue_at( Requests that the Relay-chain send a `notify_revenue` message back at or soon after Relay-chain block number `when` whose `until` parameter is equal to `when`. +#### `credit_account` + +Prototype: + +``` +fn credit_account( + who: AccountId, + amount: Balance, +) +``` + +Instructs the Relay-chain to add the `amount` of DOT to the Instantaneous Coretime Market Credit account of `who`. + +It is expected that Instantaneous Coretime Market Credit on the Relay-chain is NOT transferrable and only redeemable when used to assign cores in the Instantaneous Coretime Pool. + #### `assign_core` Prototype: From 7763b0b4dff67c16b1ac849ffec0937a1810dcde Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 7 Jul 2023 14:00:16 +0200 Subject: [PATCH 04/11] Update text/0005-coretime-interface.md --- text/0005-coretime-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0005-coretime-interface.md b/text/0005-coretime-interface.md index 8048e64d4..694e400c4 100644 --- a/text/0005-coretime-interface.md +++ b/text/0005-coretime-interface.md @@ -120,7 +120,7 @@ Instructs the Relay-chain to ensure that the core indexed as `core` is utilised If `end_hint` is `Some` and the inner is greater than the current block number, then the Relay-chain should optimize in the expectation of receiving a new `assign_core(core, ...)` message at or prior to the block number of the inner value. Specific functionality should remain unchanged regardless of the `end_hint` value. -On the choice of denominator: 57,600 is a highly composite number which factors into: 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 5, 5. By using it as the denominator we allow for various useful fractions to be perfectly represented including thirds, quarters, fifths, tenths, 80ths, percent and 256ths. +On the choice of denominator: 57,600 is a very composite number which factors into: 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 5, 5. By using it as the denominator we allow for various useful fractions to be perfectly represented including thirds, quarters, fifths, tenths, 80ths, percent and 256ths. ### DMP Message Types From f4d5cefe7b958f1d636380f4488114c60ffc59dd Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 7 Jul 2023 14:00:55 +0200 Subject: [PATCH 05/11] Update text/0005-coretime-interface.md --- text/0005-coretime-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0005-coretime-interface.md b/text/0005-coretime-interface.md index 694e400c4..7bdb1eb8e 100644 --- a/text/0005-coretime-interface.md +++ b/text/0005-coretime-interface.md @@ -147,7 +147,7 @@ fn notify_revenue( ) ``` -Provide the amount of revenue accumulated from Instantaneous Coretime Sales from Relay-chain block number `last_until` to `until`, not including `until` itself. `last_until` is defined as being the `until` argument of the last `notify_revenue` message sent. +Provide the amount of revenue accumulated from Instantaneous Coretime Sales from Relay-chain block number `last_until` to `until`, not including `until` itself. `last_until` is defined as being the `until` argument of the last `notify_revenue` message sent, or zero for the first call. This explicitly disregards the possibility of multiple parachains requesting and being notified of revenue information. The Relay-chain must be configured to ensure that only a single revenue information destination exists. From 2b7e973072db4da35526943b67ed0cf6026bc641 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 7 Jul 2023 14:01:03 +0200 Subject: [PATCH 06/11] Update text/0005-coretime-interface.md Co-authored-by: asynchronous rob --- text/0005-coretime-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0005-coretime-interface.md b/text/0005-coretime-interface.md index 7bdb1eb8e..4e8869b35 100644 --- a/text/0005-coretime-interface.md +++ b/text/0005-coretime-interface.md @@ -9,7 +9,7 @@ ## Summary -In the Agile Coretime model of the Polkadot Ubiquitous Computer, as proposed in RFC-1 and RFC-4, it is necessary for the allocating parachain (envisioned to be one or more pallets on a specialised Brokerage System Chain) to communicate the core assignments to the Relay-chain, which is responsible for ensuring those assignments are properly enacted. +In the Agile Coretime model of the Polkadot Ubiquitous Computer, as proposed in RFC-1 and RFC-3, it is necessary for the allocating parachain (envisioned to be one or more pallets on a specialised Brokerage System Chain) to communicate the core assignments to the Relay-chain, which is responsible for ensuring those assignments are properly enacted. This is a proposal for the interface which will exist around the Relay-chain in order to communicate this information and instructions. From 53b9b667fbf674658f3f5e2caab64e0210496182 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 7 Jul 2023 14:02:22 +0200 Subject: [PATCH 07/11] Update text/0005-coretime-interface.md --- text/0005-coretime-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0005-coretime-interface.md b/text/0005-coretime-interface.md index 4e8869b35..2926ac388 100644 --- a/text/0005-coretime-interface.md +++ b/text/0005-coretime-interface.md @@ -120,7 +120,7 @@ Instructs the Relay-chain to ensure that the core indexed as `core` is utilised If `end_hint` is `Some` and the inner is greater than the current block number, then the Relay-chain should optimize in the expectation of receiving a new `assign_core(core, ...)` message at or prior to the block number of the inner value. Specific functionality should remain unchanged regardless of the `end_hint` value. -On the choice of denominator: 57,600 is a very composite number which factors into: 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 5, 5. By using it as the denominator we allow for various useful fractions to be perfectly represented including thirds, quarters, fifths, tenths, 80ths, percent and 256ths. +On the choice of denominator: 57,600 is a very composite number which factors into: 2 ** 8, 3 ** 2, 5 ** 2. By using it as the denominator we allow for various useful fractions to be perfectly represented including thirds, quarters, fifths, tenths, 80ths, percent and 256ths. ### DMP Message Types From 246d9333972134916cd9015451e984b97877ff81 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sat, 8 Jul 2023 19:12:03 +0200 Subject: [PATCH 08/11] Update text/0005-coretime-interface.md --- text/0005-coretime-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0005-coretime-interface.md b/text/0005-coretime-interface.md index 2926ac388..72ff08fc7 100644 --- a/text/0005-coretime-interface.md +++ b/text/0005-coretime-interface.md @@ -141,7 +141,7 @@ Indicate that from this block onwards, the range of acceptable values of the `co Prototype: ``` -fn notify_revenue( +fn notify_revenue_info( until: BlockNumber, revenue: Balance, ) From 9bdea912ebf6ff9195ab54cb0dce3072c853d4d7 Mon Sep 17 00:00:00 2001 From: Gav Date: Thu, 13 Jul 2023 11:37:16 +0100 Subject: [PATCH 09/11] Add Rob as co-author and formalise the less formal elements --- text/0005-coretime-interface.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/text/0005-coretime-interface.md b/text/0005-coretime-interface.md index 72ff08fc7..b47b54284 100644 --- a/text/0005-coretime-interface.md +++ b/text/0005-coretime-interface.md @@ -4,7 +4,7 @@ | --------------- | ------------------------------------------------------------------------------------------- | | **Start Date** | 06 July 2023 | | **Description** | Interface for manipulating the usage of cores on the Polkadot Ubiquitous Computer. | -| **Authors** | Gavin Wood | +| **Authors** | Gavin Wood, Robert Habermeier | ## Summary @@ -22,7 +22,6 @@ The overall motivation for splitting out functions from the Relay-chain onto Sys - The interface MUST allow the Relay-chain to be scheduled on a low-latency basis. - Individual cores MUST be schedulable, both in full to a single task (a ParaId or the Instantaneous Coretime Pool) or to many unique tasks in differing ratios. - Typical usage of the interface SHOULD NOT overload the VMP message system. -- Worst case usage of the interface MUST NOT cause the Polkadot system to fail. - The interface MUST allow for the allocating chain to be notified of all accounting information relevant for making accurate rewards for contributing to the Instantaneous Coretime Pool. - The interface MUST allow for Instantaneous Coretime Market Credits to be communicated. - The interface MUST allow for the allocating chain to instruct changes to the number of cores which it is able to allocate. @@ -71,6 +70,8 @@ fn request_revenue_at( Requests that the Relay-chain send a `notify_revenue` message back at or soon after Relay-chain block number `when` whose `until` parameter is equal to `when`. +The period in to the past which `when` is allowed to be may be limited; if so the limit should be understood on a channel outside of this proposal. In the case that the request cannot be servied because `when` is too old a block then a `notify_revenue` message must still be returned, but its `revenue`` field may be `None`. + #### `credit_account` Prototype: @@ -143,14 +144,20 @@ Prototype: ``` fn notify_revenue_info( until: BlockNumber, - revenue: Balance, + revenue: Option, ) ``` -Provide the amount of revenue accumulated from Instantaneous Coretime Sales from Relay-chain block number `last_until` to `until`, not including `until` itself. `last_until` is defined as being the `until` argument of the last `notify_revenue` message sent, or zero for the first call. +Provide the amount of revenue accumulated from Instantaneous Coretime Sales from Relay-chain block number `last_until` to `until`, not including `until` itself. `last_until` is defined as being the `until` argument of the last `notify_revenue` message sent, or zero for the first call. If `revenue` is `None`, this indicates that the information is no longer available. This explicitly disregards the possibility of multiple parachains requesting and being notified of revenue information. The Relay-chain must be configured to ensure that only a single revenue information destination exists. +### Realistic Limits of the Usage + +For `request_revenue_info`, a successful request should be possible if `when` is no less than the Relay-chain block number on arrival of the message less 100,000. + +For `assign_core`, a successful request should be possible if `begin` is no less than the Relay-chain block number on arrival of the message plus 10 and `workload` contains no more than 100 items. + ## Performance, Ergonomics and Compatibility No specific considerations. From e93ce624af4ec9a121ca9158276a306209aa2205 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 13 Jul 2023 11:39:01 +0100 Subject: [PATCH 10/11] Update text/0005-coretime-interface.md Co-authored-by: asynchronous rob --- text/0005-coretime-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0005-coretime-interface.md b/text/0005-coretime-interface.md index b47b54284..c00124809 100644 --- a/text/0005-coretime-interface.md +++ b/text/0005-coretime-interface.md @@ -15,7 +15,7 @@ This is a proposal for the interface which will exist around the Relay-chain in ## Motivation -The overall motivation for splitting out functions from the Relay-chain onto System parachains is well understood. An well-understood interface is necessary for ensuring multiple chains are able to coordinate their efforts. +The background motivation for this interface is splitting out coretime allocation functions and secondary markets from the Relay-chain onto System parachains. A well-understood and general interface is necessary for ensuring the Relay-chain receives coretime allocation instructions from one or more System chains without introducing dependencies on the implementation details of either side. ## Requirements From 33d45a809d12481c32b6b1d129caf609bb7db7c6 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Mon, 17 Jul 2023 11:58:37 +0200 Subject: [PATCH 11/11] Update text/0005-coretime-interface.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Anton Vilhelm Ásgeirsson --- text/0005-coretime-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0005-coretime-interface.md b/text/0005-coretime-interface.md index c00124809..47d9adca2 100644 --- a/text/0005-coretime-interface.md +++ b/text/0005-coretime-interface.md @@ -70,7 +70,7 @@ fn request_revenue_at( Requests that the Relay-chain send a `notify_revenue` message back at or soon after Relay-chain block number `when` whose `until` parameter is equal to `when`. -The period in to the past which `when` is allowed to be may be limited; if so the limit should be understood on a channel outside of this proposal. In the case that the request cannot be servied because `when` is too old a block then a `notify_revenue` message must still be returned, but its `revenue`` field may be `None`. +The period in to the past which `when` is allowed to be may be limited; if so the limit should be understood on a channel outside of this proposal. In the case that the request cannot be serviced because `when` is too old a block then a `notify_revenue` message must still be returned, but its `revenue` field may be `None`. #### `credit_account`