Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions node/collation-generation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

//! The collation generation subsystem is the interface between polkadot and the collators.
//!
//! # Protocol
//!
//! On every `ActiveLeavesUpdate`:
//!
//! * If there is no collation generation config, ignore.
//! * Otherwise, for each `activated` head in the update:
//! * Determine if the para is scheduled on any core by fetching the `availability_cores` Runtime API.
//! * Determine an occupied core assumption to make about the para. Scheduled cores can make [`OccupiedCoreAssumption::Free`].
//! * TODO: What does this mean?
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's worth mentioning assumptions mechanism here. In short, collation generation only builds new candidates when the parachain core is free, meaning, previous candidate accepted by the runtime reached availability threshold. See pending availability in the inclusion pallet for reference.

This will change with asynchronous backing.

To understand the assumption mechanism: it is also used by candidate validation. When validation data is supplied with candidate, we try to match it with Runtime. The main "matching" point here is parachain head. With free or timed-out assumption the runtime will ignore pending-availability candidate and read latest para head.
With included-assumption it will apply pendind-availability candidate (if any) to the storage and return new para head. This is ok because storage changes done during api calls are discarded.

//! * Use the Runtime API subsystem to fetch the full validation data.
//! * Invoke the `collator`, and use its outputs to produce a [`CandidateReceipt`], signed with the configuration's `key`.
//! * Dispatch a [`CollatorProtocolMessage::DistributeCollation`](receipt, pov)`.

#![deny(missing_docs)]

Expand Down
1 change: 0 additions & 1 deletion node/overseer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,6 @@ pub struct Overseer<SupportsParachains> {

#[subsystem(CollatorProtocolMessage, sends: [
NetworkBridgeTxMessage,
RuntimeApiMessage,
CandidateBackingMessage,
])]
collator_protocol: CollatorProtocol,
Expand Down
3 changes: 3 additions & 0 deletions roadmap/implementers-guide/src/node/collators/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Collators

Collators are special nodes which bridge a parachain to the relay chain. They are simultaneously full nodes of the parachain, and at least light clients of the relay chain. Their overall contribution to the system is the generation of Proofs of Validity for parachain candidates.

The **Collation Generation** subsystem triggers collators to produce collations
and then forwards them to **Collator Protocol** to circulate to validators.
119 changes: 102 additions & 17 deletions roadmap/implementers-guide/src/node/collators/collation-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,32 @@ The collation generation subsystem is executed on collator nodes and produces ca

## Protocol

Input: `CollationGenerationMessage`
Collation generation for Parachains currently works in the following way:

```rust
enum CollationGenerationMessage {
Initialize(CollationGenerationConfig),
}
```
1. A new relay chain block is imported.
2. The collation generation subsystem checks if the core associated to
the parachain is free and if yes, continues.
3. Collation generation calls our collator callback to generate a PoV.
4. Authoring logic determines if the current node should build a PoV.
5. Build new PoV and give it back to collation generation.

## Messages

No more than one initialization message should ever be sent to the collation generation subsystem.
### Incoming

Output: `CollationDistributionMessage`
- `ActiveLeaves`
- Notification of a change in the set of active leaves.
- Triggers collation generation procedure outlined in "Protocol" section.
- `CollationGenerationMessage::Initialize`
- Initializes the subsystem. Carries a config.
- No more than one initialization message should ever be sent to the collation
generation subsystem.
- Sent by a collator to initialize this subsystem.

### Outgoing

- `CollatorProtocolMessage::DistributeCollation`
- Provides a generated collation to distribute to validators.

## Functionality

Expand Down Expand Up @@ -94,15 +109,85 @@ pub struct CollationGenerationConfig {

The configuration should be optional, to allow for the case where the node is not run with the capability to collate.

On `ActiveLeavesUpdate`:
### Summary in plain English

- **Collation (output of a collator)**

- Contains the PoV (proof to verify the state transition of the
parachain) and other data.

- **Collation result**

- Contains the collation, and an optional result sender for a
collation-seconded signal.

- **Collation seconded signal**

- The signal that is returned when a collation was seconded by a
validator.

- **Collation function**

- Called with the relay chain block the parablock will be built on top
of.
- Called with the validation data.
- Provides information about the state of the parachain on the relay
chain.

- **Collation generation config**

- Contains collator's authentication key, collator function, and
parachain ID.

## With Async Backing

### Protocol
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was it discussed somewhere? As long as we don't have a plan for collation generation, we shouldn't put it into the guide. We're still in the middle of cumulus changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops sorry, thought I removed this section.


- This will be more complicated as block production isn't bound to
importing a relay chain block anymore.

- Parachains will build new blocks in fixed time frames as standalone
chains are doing this, e.g. every 6 seconds.

- To support this we will need to separate the logic that determines
when to build a block, from the logic that determines on which relay
chain block to build.

### When to build

- For determining on when to build a new block we can reuse the slots
logic from Substrate.
- We will let it run with the requested slot duration of the Parachain.
- Then we will implement a custom `SlotWorker`.
- Every time this slot worker is triggered we will need to trigger
some logic to determine the next relay chain block to build on top
of.
- It will return the relay chain block in which context the block
should be built on, and the parachain block to build on top of.

### On which relay block to build

- This logic should be generic and should support sync / async backing.
- For **synchronous backing** we will check the best relay chain block
to check if the core of our parachain is free.
- The parachain slot should be calculated based on the timestamp and
this should be calculated using `relay_chain_slot * slot_duration`.
- For **asynchronous backing** we will be more free to choose the block
to build on, as we can also build on older relay chain blocks as well.
- We will probably need some kind of runtime api for the Parachain to
check if we want to build on a given relay chain block.
- So, for example to reject building too many parachain blocks on the
same relay chain block.
- The parachain slot should be calculated based on the timestamp and
this should be calculating using `relay_chain_slot * slot_duration +
parachain_slot_duration * unincluded_segment_len`.

## Glossary

- *Slot:* Time is divided into discrete slots. Each validator in the validator
set produces a verifiable random value, using a VRF, per slot. If below a
threshold, this allows the validator to author a new block for that slot.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leftover


* If there is no collation generation config, ignore.
* Otherwise, for each `activated` head in the update:
* Determine if the para is scheduled on any core by fetching the `availability_cores` Runtime API.
* Determine an occupied core assumption to make about the para. Scheduled cores can make `OccupiedCoreAssumption::Free`.
* Use the Runtime API subsystem to fetch the full validation data.
* Invoke the `collator`, and use its outputs to produce a `CandidateReceipt`, signed with the configuration's `key`.
* Dispatch a [`CollatorProtocolMessage`][CPM]`::DistributeCollation(receipt, pov)`.
- *VRF:* Verifiable random function.

[CP]: collator-protocol.md
[CPM]: ../../types/overseer-protocol.md#collatorprotocolmessage