* dispute subsystem files * rename * fix linkcheck * flesh out section README * coordinator schema * DisputeCoordinatorMessage * stub & coordinator protocol * dispute coordinator * add some more message fields * move links to bottom * dispute participation * Cleen It Up ! * runtime: store candidate receipts in dispute state yeah, this is a little heavier. why are you reading this? * Revert "runtime: store candidate receipts in dispute state" This reverts commit 51c10bfd4d866e287e6bd88f317ed57ed987eaee. * add dispute availability statement type and prepare for availability * add 'spam slots' to disputes runtmie * return Spam Slots info from runtime * rework `ImportStatement` to `ImportStatements` * some more methods for dispute coordinator * candidates-included runtime API * algo for providing disputes to runtime. * handle signing with coordinator * dispute coordinator chain ops * remove dead file * remove keystore from dispute participation * adjust ApprovedAncestor to return the necssary data * discuss how approved ancestor and determine undisputed chain are used together * add TODO * initiate disputes from approval voting * route statements from candidate backing and approval voting * fix guide build
8.9 KiB
Candidate Backing
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 Statements 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, which in turn engages block production mechanisms to include the parablock.
Protocol
Input: CandidateBackingMessage
Output:
CandidateValidationMessageRuntimeApiMessageCandidateSelectionMessageProvisionerMessageAvailabilityDistributionMessageStatementDistributionMessage
Functionality
The Candidate Selection subsystem is the primary source of non-overseer messages into this subsystem. That subsystem generates appropriate CandidateBackingMessages and passes them to this subsystem.
This subsystem requests validation from the Candidate Validation and generates an appropriate Statement. All Statements are then passed on to the Statement Distribution subsystem to be gossiped to peers. When Candidate Validation 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.
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::ActiveLeavesUpdate:- spawn a Candidate Backing Job for each
activatedhead, storing a bidirectional channel with the Candidate Backing Job in the set of handles. - cease the Candidate Backing Job for each
deactivatedhead, if any.
- spawn a Candidate Backing Job for each
- If the signal is an
OverseerSignal::Conclude: Forward conclude messages to all jobs, wait a small amount of time for them to join, and then exit.
On Receiving CandidateBackingMessage
- If the message is a
CandidateBackingMessage::GetBackedCandidates, get all backable candidates from the statement table and send them back. - If the message is a
CandidateBackingMessage::Second, sign and dispatch aSecondedstatement only if we have not seconded any other candidate and have not signed aValidstatement for the requested candidate. Signing both aSecondedandValidmessage 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. - If the message is a
CandidateBackingMessage::Statement, count the statement to the quorum. If the statement in the message isSecondedand it contains a candidate that belongs to our assignment, request the correspondingPoVfrom the backing node viaAvailabilityDistributionand launch validation. Issue our ownValidorInvalidstatement as a result.
If the seconding node did not provide us with the PoV we will retry fetching from other backing validators.
big TODO: "contextual execution"
- At the moment we only allow inclusion of new parachain candidates validated by current validators.
- Allow inclusion of old parachain candidates validated by current validators.
- Allow inclusion of old parachain candidates validated by old validators.
This will probably blur the lines between jobs, will probably require inter-job communication and a short-term memory of recently backable, but not backed candidates.
Candidate Backing Job
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 Statements 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 APIsubsystem usingRuntimeApiRequest::ValidatorsandRuntimeApiRequest::ValidatorGroups - 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 from the
Runtime APIfor the parachain the local key is assigned to by issuing aRuntimeApiRequest::Validators - Issue a
RuntimeApiRequest::SigningContextmessage to get a context that will later be used upon signing.
On Receiving New Candidate Backing Message
match msg {
GetBackedCandidates(hashes, tx) => {
// Send back a set of backable candidates.
}
CandidateBackingMessage::Second(hash, candidate) => {
if candidate is unknown and in local assignment {
if spawn_validation_work(candidate, parachain head, validation function).await == Valid {
send(DistributePoV(pov))
}
}
}
CandidateBackingMessage::Statement(hash, statement) => {
// count to the votes on this candidate
if let Statement::Seconded(candidate) = statement {
if candidate.parachain_id == our_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 ProvisionerMessage::ProvisionableData(ProvisionableData::BackedCandidate(CandidateReceipt)) message.
Invalid statements that conflict with already witnessed Seconded and Valid statements for the given candidate, statements that are double-votes, self-contradictions and so on, should result in issuing a ProvisionerMessage::MisbehaviorReport message for each newly detected case of this kind.
On each incoming statement, DisputeCoordinatorMessage::ImportStatement should be issued.
Validating Candidates.
fn spawn_validation_work(candidate, parachain head, validation function) {
asynchronously {
let pov = (fetch pov block).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.
} else {
// sign and dispatch `invalid` statement to network.
}
}
}
Fetch Pov Block
Create a (sender, receiver) pair.
Dispatch a [AvailabilityDistributionMessage][PDM]::FetchPoV{ validator_index, pov_hash, candidate_hash, tx, } and listen on the passed receiver for a response. Availability distribution will send the request to the validator specified by validator_index`, which might not be serving it for whatever reasons, therefore we need to retry with other backing validators in that case.
Validate PoV Block
Create a (sender, receiver) pair.
Dispatch a CandidateValidationMessage::Validate(validation function, candidate, pov, sender) and listen on the receiver for a response.
Distribute Signed Statement
Dispatch a [StatementDistributionMessage][PDM]::Share(relay_parent, SignedFullStatement).