candidate.md 9.88 KB
Newer Older
1
2
3
# Candidate Types

Para candidates are some of the most common types, both within the runtime and on the Node-side.
asynchronous rob's avatar
asynchronous rob committed
4
Candidates are the fundamental datatype for advancing parachains and parathreads, encapsulating the collator's signature, the context of the parablock, the commitments to the output, and a commitment to the data which proves it valid.
5
6
7

In a way, this entire guide is about these candidates: how they are scheduled, constructed, backed, included, and challenged.

8
This section will describe the base candidate type, its components, and variants that contain extra data.
9

10
11
12
13
14
15
16
17
## Para Id

A unique 32-bit identifier referring to a specific para (chain or thread). The relay-chain runtime guarantees that `ParaId`s are unique for the duration of any session, but recycling and reuse over a longer period of time is permitted.

```rust
struct ParaId(u32);
```

18
## Candidate Receipt
19

20
Much info in a [`FullCandidateReceipt`](#full-candidate-receipt) is duplicated from the relay-chain state. When the corresponding relay-chain state is considered widely available, the Candidate Receipt should be favored over the `FullCandidateReceipt`.
21

22
Examples of situations where the state is readily available includes within the scope of work done by subsystems working on a given relay-parent, or within the logic of the runtime importing a backed candidate.
23
24

```rust
25
/// A candidate-receipt.
26
struct CandidateReceipt {
27
28
29
30
31
32
33
34
35
	/// The descriptor of the candidate.
	descriptor: CandidateDescriptor,
	/// The hash of the encoded commitments made as a result of candidate execution.
	commitments_hash: Hash,
}
```

## Full Candidate Receipt

36
This is the full receipt type. The `GlobalValidationData` and the `LocalValidationData` are technically redundant with the `inner.relay_parent`, which uniquely describes the a block in the blockchain from whose state these values are derived. The [`CandidateReceipt`](#candidate-receipt) variant is often used instead for this reason.
37
38
39
40
41
42
43

However, the Full Candidate Receipt type is useful as a means of avoiding the implicit dependency on availability of old blockchain state. In situations such as availability and approval, having the full description of the candidate within a self-contained struct is convenient.

```rust
/// All data pertaining to the execution of a para candidate.
struct FullCandidateReceipt {
	inner: CandidateReceipt,
44
	/// The global validation schedule.
45
	global_validation: GlobalValidationData,
46
47
48
49
50
	/// The local validation data.
	local_validation: LocalValidationData,
}
```

51
## Committed Candidate Receipt
52

53
This is a variant of the candidate receipt which includes the commitments of the candidate receipt alongside the descriptor. This should be favored over the [`Candidate Receipt`](#candidate-receipt) in situations where the candidate is not going to be executed but the actual data committed to is important. This is often the case in the backing phase.
54

55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
The hash of the committed candidate receipt will be the same as the corresponding [`Candidate Receipt`](#candidate-receipt), because it is computed by first hashing the encoding of the commitments to form a plain [`Candidate Receipt`](#candidate-receipt).

```rust
/// A candidate-receipt with commitments directly included.
struct CommittedCandidateReceipt {
	/// The descriptor of the candidate.
	descriptor: CandidateDescriptor,
	/// The commitments of the candidate receipt.
	commitments: CandidateCommitments,
}
```

## Candidate Descriptor

This struct is pure description of the candidate, in a lightweight format.
70
71

```rust
72
73
/// A unique descriptor of the candidate receipt.
struct CandidateDescriptor {
74
	/// The ID of the para this is a candidate for.
75
	para_id: ParaId,
76
77
78
79
	/// The hash of the relay-chain block this is executed in the context of.
	relay_parent: Hash,
	/// The collator's sr25519 public key.
	collator: CollatorId,
80
	/// The blake2-256 hash of the local and global validation data. These are extra parameters
81
82
	/// derived from relay-chain state that influence the validity of the block.
	validation_data_hash: Hash,
83
84
	/// The blake2-256 hash of the pov-block.
	pov_hash: Hash,
85
86
87
	/// Signature on blake2-256 of components of this receipt:
	/// The parachain index, the relay parent, the validation data hash, and the pov_hash.
	signature: CollatorSignature,
88
89
90
}
```

91

92
## GlobalValidationData
93
94
95
96
97
98
99
100

The global validation schedule comprises of information describing the global environment for para execution, as derived from a particular relay-parent. These are parameters that will apply to all parablocks executed in the context of this relay-parent.

```rust
/// Extra data that is needed along with the other fields in a `CandidateReceipt`
/// to fully validate the candidate.
///
/// These are global parameters that apply to all candidates in a block.
101
struct GlobalValidationData {
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
	/// The maximum code size permitted, in bytes.
	max_code_size: u32,
	/// The maximum head-data size permitted, in bytes.
	max_head_data_size: u32,
	/// The relay-chain block number this is in the context of.
	block_number: BlockNumber,
}
```

## LocalValidationData

This is validation data needed for execution of candidate pertaining to a specific para and relay-chain block.

Unlike the [`GlobalValidationData`](#globalvalidationdata), which only depends on a relay-parent, this is parameterized both by a relay-parent and a choice of one of two options:
  1. Assume that the candidate pending availability on this para at the onset of the relay-parent is included.
  1. Assume that the candidate pending availability on this para at the onset of the relay-parent is timed-out.

This choice can also be expressed as a choice of which parent head of the para will be built on - either optimistically on the candidate pending availability or pessimistically on the one that is surely included.

121
Para validation happens optimistically before the block is authored, so it is not possible to predict with 100% accuracy what will happen in the earlier phase of the [`InclusionInherent`](../runtime/inclusioninherent.md) module where new availability bitfields and availability timeouts are processed. This is what will eventually define whether a candidate can be backed within a specific relay-chain block.
122

123
124
125
126
127
128
Design-wise we should maintain two properties about this data structure:

1. The `LocalValidationData` should be relatively lightweight primarly because it is constructed during inclusion for each candidate.
1. To make contextual execution possible, `LocalValidationData` should be constructable only having access to the latest relay-chain state for the past `k` blocks. That implies
either that the relay-chain should maintain all the required data accessible or somehow provided indirectly with a header-chain proof and a state proof from there.

129
> TODO: determine if balance/fees are even needed here.
130
> TODO: message queue watermarks (first downward messages, then XCMP channels)
131
132
133
134

```rust
/// Extra data that is needed along with the other fields in a `CandidateReceipt`
/// to fully validate the candidate. These fields are parachain-specific.
135
struct LocalValidationData {
136
	/// The parent head-data.
137
	parent_head: HeadData,
138
	/// The balance of the parachain at the moment of validation.
139
	balance: Balance,
140
	/// The blake2-256 hash of the validation code used to execute the candidate.
141
	validation_code_hash: Hash,
142
143
144
145
146
147
148
149
150
151
152
	/// Whether the parachain is allowed to upgrade its validation code.
	///
	/// This is `Some` if so, and contains the number of the minimum relay-chain
	/// height at which the upgrade will be applied, if an upgrade is signaled
	/// now.
	///
	/// A parachain should enact its side of the upgrade at the end of the first
	/// parablock executing in the context of a relay-chain block with at least this
	/// height. This may be equal to the current perceived relay-chain block height, in
	/// which case the code upgrade should be applied at the end of the signaling
	/// block.
153
	code_upgrade_allowed: Option<BlockNumber>,
154
155
156
157
158
159
160
161
162
163
164
}
```

## HeadData

Head data is a type-safe abstraction around bytes (`Vec<u8>`) for the purposes of representing heads of parachains or parathreads.

```rust
struct HeadData(Vec<u8>);
```

165
## Candidate Commitments
166
167
168
169
170
171
172

The execution and validation of parachain or parathread candidates produces a number of values which either must be committed to on the relay chain or committed to the state of the relay chain.

```rust
/// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default))]
173
struct CandidateCommitments {
174
	/// Fees paid from the chain to the relay chain validators.
175
	fees: Balance,
176
	/// Messages destined to be interpreted by the Relay chain itself.
177
	upward_messages: Vec<UpwardMessage>,
178
	/// The root of a block's erasure encoding Merkle tree.
179
	erasure_root: Hash,
180
	/// New validation code.
181
182
183
	new_validation_code: Option<ValidationCode>,
	/// The head-data produced as a result of execution.
	head_data: HeadData,
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
}
```

## Signing Context

This struct provides context to signatures by combining with various payloads to localize the signature to a particular session index and relay-chain hash. Having these fields included in the signature makes misbehavior attribution much simpler.

```rust
struct SigningContext {
	/// The relay-chain block hash this signature is in the context of.
	parent_hash: Hash,
	/// The session index this signature is in the context of.
	session_index: SessionIndex,
}
```
asynchronous rob's avatar
asynchronous rob committed
199
200
201
202
203
204
205
206
207
208

## Validation Outputs

This struct encapsulates the outputs of candidate validation.

```rust
struct ValidationOutputs {
	/// The head-data produced by validation.
	head_data: HeadData,
	/// The global validation schedule.
209
	global_validation_data: GlobalValidationData,
asynchronous rob's avatar
asynchronous rob committed
210
211
212
213
214
215
216
217
218
219
	/// The local validation data.
	local_validation_data: LocalValidationData,
	/// Upwards messages to the relay chain.
	upwards_messages: Vec<UpwardsMessage>,
	/// Fees paid to the validators of the relay-chain.
	fees: Balance,
	/// The new validation code submitted by the execution, if any.
	new_validation_code: Option<ValidationCode>,
}
```