Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

CandidateBackingSubsystem #1312

Merged
merged 24 commits into from
Jul 9, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f40c165
Updates guide for CandidateBacking
montekki Jun 24, 2020
4031bc7
Move assignment types to primitives
montekki Jun 25, 2020
7f23f7d
Merge branch 'master' into fs-candidate-backing-subsystem
montekki Jun 25, 2020
45ead89
Initial implementation.
montekki Jun 27, 2020
81220d8
More functionality
montekki Jul 1, 2020
7572a13
Merge branch 'master' into fs-candidate-backing-subsystem
montekki Jul 2, 2020
a7d5e86
use assert_matches
montekki Jul 2, 2020
697accf
Changes to report misbehaviors
montekki Jul 2, 2020
2ce747e
Some fixes after a review
montekki Jul 3, 2020
af9f34a
Remove a blank line
montekki Jul 3, 2020
245cc96
Update guide and some types
montekki Jul 4, 2020
63124aa
Adds run_job function
montekki Jul 4, 2020
1b744ed
Some comments and refactorings
montekki Jul 4, 2020
96ba9dd
Merge branch 'master' into fs-candidate-backing-subsystem
montekki Jul 4, 2020
481ab97
Merge branch 'master' into fs-candidate-backing-subsystem
montekki Jul 7, 2020
f52aa09
Fix review
montekki Jul 7, 2020
0f8e2b9
Merge branch 'master' into fs-candidate-backing-subsystem
montekki Jul 7, 2020
e4aed7c
Remove warnings
montekki Jul 7, 2020
05d7dc6
Use summary in kicking off validation
montekki Jul 7, 2020
994eefd
Parallelize requests
montekki Jul 8, 2020
d879df6
Validation provides local and global validation params
montekki Jul 8, 2020
fef54e1
Test issued validity tracking
montekki Jul 8, 2020
e8fd8f3
Nits from review
montekki Jul 9, 2020
e137f37
Merge branch 'master' into fs-candidate-backing-subsystem
montekki Jul 9, 2020
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
79 changes: 53 additions & 26 deletions roadmap/implementors-guide/src/node/backing/candidate-backing.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,41 @@

The Candidate Backing subsystem ensures every parablock considered for relay block inclusion has been seconded by at least one validator, and approved by a quorum. Parablocks for which no validator will assert correctness are discarded. If the block later proves invalid, the initial backers are slashable; this gives polkadot a rational threat model during subsequent stages.

Its role is to produce backable candidates for inclusion in new relay-chain blocks. It does so by issuing signed [`Statement`s](../../types/backing.md#statement-type) and tracking received statements signed by other validators. Once enough statements are received, they can be combined into backing for specific candidates.
Its role is to produce backable candidates for inclusion in new relay-chain blocks. It does so by issuing signed [`Statement`s][Statement] and tracking received statements signed by other validators. Once enough statements are received, they can be combined into backing for specific candidates.

Note that though the candidate backing subsystem attempts to produce as many backable candidates as possible, it does _not_ attempt to choose a single authoritative one. The choice of which actually gets included is ultimately up to the block author, by whatever metrics it may use; those are opaque to this subsystem.

Once a sufficient quorum has agreed that a candidate is valid, this subsystem notifies the [Provisioner](../utility/provisioner.md), which in turn engages block production mechanisms to include the parablock.
Once a sufficient quorum has agreed that a candidate is valid, this subsystem notifies the [Provisioner][PV], which in turn engages block production mechanisms to include the parablock.

## Protocol

The [Candidate Selection subsystem](candidate-selection.md) is the primary source of non-overseer messages into this subsystem. That subsystem generates appropriate [`CandidateBackingMessage`s](../../types/overseer-protocol.md#candidate-backing-message), and passes them to this subsystem.
Input: [`CandidateBackingMessage`][CBM]

This subsystem validates the candidates and generates an appropriate [`Statement`](../../types/backing.md#statement-type). All `Statement`s are then passed on to the [Statement Distribution subsystem](statement-distribution.md) to be gossiped to peers. When this subsystem decides that a candidate is invalid, and it was recommended to us to second by our own Candidate Selection subsystem, a message is sent to the Candidate Selection subsystem with the candidate's hash so that the collator which recommended it can be penalized.
Output:

- [`CandidateValidationMessage`][CVM]
- [`RuntimeApiMessage`][RAM]
- [`CandidateSelectionMessage`][CSM]
- [`ProvisionerMessage`][PM]
- PoV Distribution (Statement Distribution)

## Functionality

The [Candidate Selection][CS] subsystem is the primary source of non-overseer messages into this subsystem. That subsystem generates appropriate [`CandidateBackingMessage`s][CBM] and passes them to this subsystem.

This subsystem requests validation from the [Candidate Validation][CV] and generates an appropriate [`Statement`][Statement]. All `Statement`s are then passed on to the [Statement Distribution][SD] subsystem to be gossiped to peers. When [Candidate Validation][CV] decides that a candidate is invalid, and it was recommended to us to second by our own [Candidate Selection][CS] subsystem, a message is sent to the [Candidate Selection][CS] subsystem with the candidate's hash so that the collator which recommended it can be penalized.

The subsystem should maintain a set of handles to Candidate Backing Jobs that are currently live, as well as the relay-parent to which they correspond.

### On Overseer Signal

* If the signal is an [`OverseerSignal`](../../types/overseer-protocol.md#overseer-signal)`::StartWork(relay_parent)`, spawn a Candidate Backing Job with the given relay parent, storing a bidirectional channel with the Candidate Backing Job in the set of handles.
* If the signal is an [`OverseerSignal`](../../types/overseer-protocol.md#overseer-signal)`::StopWork(relay_parent)`, cease the Candidate Backing Job under that relay parent, if any.
* If the signal is an [`OverseerSignal`][OverseerSignal]`::StartWork(relay_parent)`, spawn a Candidate Backing Job with the given relay parent, storing a bidirectional channel with the Candidate Backing Job in the set of handles.
* If the signal is an [`OverseerSignal`][OverseerSignal]`::StopWork(relay_parent)`, cease the Candidate Backing Job under that relay parent, if any.

### On `CandidateBackingMessage`
### On Receiving `CandidateBackingMessage`

* If the message corresponds to a particular relay-parent, forward the message to the Candidate Backing Job for that relay-parent, if any is live.
* If the message is a [`CandidateBackingMessage`][CBM]`::RegisterBackingWatcher`, register the watcher and trigger it each time a new candidate is backable. Also trigger it once initially if there are any backable candidates at the time of receipt.
* If the message is a [`CandidateBackingMessage`][CBM]`::Second`, sign and dispatch a `Seconded` statement only if we have not seconded any other candidate and have not signed a `Valid` statement for the requested candidate. Signing both a `Seconded` and `Valid` message is a double-voting misbehavior with a heavy penalty, and this could occur if another validator has seconded the same candidate and we've received their message before the internal seconding request.

> big TODO: "contextual execution"
>
Expand All @@ -39,36 +50,37 @@ The subsystem should maintain a set of handles to Candidate Backing Jobs that ar

The Candidate Backing Job represents the work a node does for backing candidates with respect to a particular relay-parent.

The goal of a Candidate Backing Job is to produce as many backable candidates as possible. This is done via signed [`Statement`s](../../types/backing.md#statement-type) by validators. If a candidate receives a majority of supporting Statements from the Parachain Validators currently assigned, then that candidate is considered backable.
The goal of a Candidate Backing Job is to produce as many backable candidates as possible. This is done via signed [`Statement`s][STMT] by validators. If a candidate receives a majority of supporting Statements from the Parachain Validators currently assigned, then that candidate is considered backable.

### On Startup

* Fetch current validator set, validator -> parachain assignments from runtime API.
* Fetch current validator set, validator -> parachain assignments from [`Runtime API`][RA] subsystem using [`RuntimeApiRequest::Validators`][RAM] and [`RuntimeApiRequest::DutyRoster`][RAM]
montekki marked this conversation as resolved.
Show resolved Hide resolved
* Determine if the node controls a key in the current validator set. Call this the local key if so.
* If the local key exists, extract the parachain head and validation function for the parachain the local key is assigned to.
* If the local key exists, extract the parachain head and validation function from the [`Runtime API`][RA] for the parachain the local key is assigned to by issuing a [`RuntimeApiRequest::Validators`][RAM]
* Issue a [`RuntimeApiRequest::SigningContext`][RAM] message to get a context that will later be used upon signing.

### On Receiving New Signed Statement
### On Receiving New Candidate Backing Message

```rust
if let Statement::Seconded(candidate) = signed.statement {
if candidate is unknown and in local assignment {
spawn_validation_work(candidate, parachain head, validation function)
```rust,ignore
match msg {
CandidateBackingMessage::Second(hash, candidate) => {
if candidate is unknown and in local assignment {
spawn_validation_work(candidate, parachain head, validation function)
}
}
}

// add `Seconded` statements and `Valid` statements to a quorum. If quorum reaches validator-group
// majority, send a `BlockAuthorshipProvisioning::BackableCandidate(relay_parent, Candidate, Backing)` message.
```

### Spawning Validation Work
Add `Seconded` statements and `Valid` statements to a quorum. If quorum reaches validator-group majority, send a [`ProvisionerMessage::ProvisionableData(ProvisionableData::BackedCandidate(BackedCandidate))`][PM] message.

### Validating Candidates.

```rust
```rust,ignore
montekki marked this conversation as resolved.
Show resolved Hide resolved
fn spawn_validation_work(candidate, parachain head, validation function) {
asynchronously {
let pov = (fetch pov block).await

// dispatched to sub-process (OS process) pool.
let valid = validate_candidate(candidate, validation function, parachain head, pov).await;
let valid = (validate pov block).await;
if valid {
// make PoV available for later distribution. Send data to the availability store to keep.
// sign and dispatch `valid` statement to network if we have not seconded the given candidate.
Expand All @@ -84,9 +96,24 @@ fn spawn_validation_work(candidate, parachain head, validation function) {
Create a `(sender, receiver)` pair.
Dispatch a `PovFetchSubsystemMessage(relay_parent, candidate_hash, sender)` and listen on the receiver for a response.

### On Receiving `CandidateBackingMessage`
### Validate PoV Block

* If the message is a `CandidateBackingMessage::RegisterBackingWatcher`, register the watcher and trigger it each time a new candidate is backable. Also trigger it once initially if there are any backable candidates at the time of receipt.
* If the message is a `CandidateBackingMessage::Second`, sign and dispatch a `Seconded` statement only if we have not seconded any other candidate and have not signed a `Valid` statement for the requested candidate. Signing both a `Seconded` and `Valid` message is a double-voting misbehavior with a heavy penalty, and this could occur if another validator has seconded the same candidate and we've received their message before the internal seconding request.
Create a `(sender, receiver)` pair.
Dispatch a `CandidateValidationMessage::Validate(validation function, candidate, pov, sender)` and listen on the receiver for a response.

> TODO: send statements to Statement Distribution subsystem, handle shutdown signal from candidate backing subsystem

[OverseerSignal]: ../../types/overseer-protocol.md#overseer-signal
[Statement]: ../../types/backing.md#statement-type
[STMT]: ../../types/backing.md#statement-type
[CSM]: ../../types/overseer-protocol.md#candidate-selection-message
[RAM]: ../../types/overseer-protocol.md#runtime-api-message
[CVM]: ../../types/overseer-protocol.md#validation-request-type
[PM]: ../../types/overseer-protocol.md#provisioner-message
[CBM]: ../../types/overseer-protocol.md#candidate-backing-message

[CS]: candidate-selection.md
[CV]: ../utility/candidate-validation.md
[SD]: statement-distribution.md
[RA]: ../utility/runtime-api.md
[PV]: ../utility/provisioner.md
2 changes: 2 additions & 0 deletions roadmap/implementors-guide/src/types/overseer-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ Other subsystems query this data by sending these messages.
enum RuntimeApiRequest {
/// Get the current validator set.
Validators(ResponseChannel<Vec<ValidatorId>>),
/// Get the assignments of validators to parachains.
DutyRoster(ResponseChannel<DutyRoster>),
montekki marked this conversation as resolved.
Show resolved Hide resolved
/// Get a signing context for bitfields and statements.
SigningContext(ResponseChannel<SigningContext>),
/// Get the validation code for a specific para, assuming execution under given block number, and
Expand Down