Implement validation data refactor (#1585)

* update primitives

* correct parent_head field

* make hrmp field pub

* refactor validation data: runtime

* refactor validation data: messages

* add arguments to full_validation_data runtime API

* port runtime API

* mostly port over candidate validation

* remove some parameters from ValidationParams

* guide: update candidate validation

* update candidate outputs

* update ValidationOutputs in primitives

* port over candidate validation

* add a new test for no-transient behavior

* update util runtime API wrappers

* candidate backing

* fix missing imports

* change some fields of validation data around

* runtime API impl

* update candidate validation

* fix backing tests

* grumbles from review

* fix av-store tests

* fix some more crates

* fix provisioner tests

* fix availability distribution tests

* port collation-generation to new validation data

* fix overseer tests

* Update roadmap/implementers-guide/src/node/utility/candidate-validation.md

Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com>

Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com>
This commit is contained in:
Robert Habermeier
2020-08-18 14:41:40 +02:00
committed by GitHub
parent 3395044402
commit 262574fc49
36 changed files with 619 additions and 1153 deletions
+90 -59
View File
@@ -60,7 +60,7 @@ pub const INCLUSION_INHERENT_IDENTIFIER: InherentIdentifier = *b"inclusn0";
pub fn collator_signature_payload<H: AsRef<[u8]>>(
relay_parent: &H,
para_id: &Id,
validation_data_hash: &Hash,
persisted_validation_data_hash: &Hash,
pov_hash: &Hash,
) -> [u8; 100] {
// 32-byte hash length is protected in a test below.
@@ -68,7 +68,7 @@ pub fn collator_signature_payload<H: AsRef<[u8]>>(
payload[0..32].copy_from_slice(relay_parent.as_ref());
u32::from(*para_id).using_encoded(|s| payload[32..32 + s.len()].copy_from_slice(s));
payload[36..68].copy_from_slice(validation_data_hash.as_ref());
payload[36..68].copy_from_slice(persisted_validation_data_hash.as_ref());
payload[68..100].copy_from_slice(pov_hash.as_ref());
payload
@@ -77,7 +77,7 @@ pub fn collator_signature_payload<H: AsRef<[u8]>>(
fn check_collator_signature<H: AsRef<[u8]>>(
relay_parent: &H,
para_id: &Id,
validation_data_hash: &Hash,
persisted_validation_data_hash: &Hash,
pov_hash: &Hash,
collator: &CollatorId,
signature: &CollatorSignature,
@@ -85,7 +85,7 @@ fn check_collator_signature<H: AsRef<[u8]>>(
let payload = collator_signature_payload(
relay_parent,
para_id,
validation_data_hash,
persisted_validation_data_hash,
pov_hash,
);
@@ -96,14 +96,6 @@ fn check_collator_signature<H: AsRef<[u8]>>(
}
}
/// Compute the `validation_data_hash` from global & local validation data.
pub fn validation_data_hash<N: Encode>(
global: &GlobalValidationData<N>,
local: &LocalValidationData<N>,
) -> Hash {
BlakeTwo256::hash_of(&(global, local))
}
/// A unique descriptor of the candidate receipt.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default, Hash))]
@@ -114,16 +106,15 @@ pub struct CandidateDescriptor<H = Hash> {
pub relay_parent: H,
/// The collator's sr25519 public key.
pub collator: CollatorId,
/// The blake2-256 hash of the validation data. This is extra data derived from
/// The blake2-256 hash of the persisted validation data. This is extra data derived from
/// relay-chain state which may vary based on bitfields included before the candidate.
/// Thus it cannot be derived entirely from the relay-parent.
pub validation_data_hash: Hash,
pub persisted_validation_data_hash: Hash,
/// The blake2-256 hash of the pov.
pub pov_hash: Hash,
/// Signature on blake2-256 of components of this receipt:
/// The parachain index, the relay parent, the validation data hash, and the pov_hash.
pub signature: CollatorSignature,
}
impl<H: AsRef<[u8]>> CandidateDescriptor<H> {
@@ -132,7 +123,7 @@ impl<H: AsRef<[u8]>> CandidateDescriptor<H> {
check_collator_signature(
&self.relay_parent,
&self.para_id,
&self.validation_data_hash,
&self.persisted_validation_data_hash,
&self.pov_hash,
&self.collator,
&self.signature,
@@ -168,10 +159,11 @@ impl<H> CandidateReceipt<H> {
pub struct FullCandidateReceipt<H = Hash, N = BlockNumber> {
/// The inner candidate receipt.
pub inner: CandidateReceipt<H>,
/// The global validation schedule.
pub global_validation: GlobalValidationData<N>,
/// The local validation data.
pub local_validation: LocalValidationData<N>,
/// The validation data derived from the relay-chain state at that
/// point. The hash of the persisted validation data should
/// match the `persisted_validation_data_hash` in the descriptor
/// of the receipt.
pub validation_data: ValidationData<N>,
}
/// A candidate-receipt with commitments directly included.
@@ -224,17 +216,78 @@ impl Ord for CommittedCandidateReceipt {
}
}
/// Extra data that is needed along with the other fields in a `CandidateReceipt`
/// to fully validate the candidate. These fields are parachain-specific.
/// The validation data provide information about how to validate both the inputs and
/// outputs of a candidate.
///
/// There are two types of validation data: persisted and transient.
/// Their respective sections of the guide elaborate on their functionality in more detail.
///
/// This information is derived from the chain state and will vary from para to para,
/// although some of the fields may be the same for every para.
///
/// Persisted validation data are generally derived from some relay-chain state to form inputs
/// to the validation function, and as such need to be persisted by the availability system to
/// avoid dependence on availability of the relay-chain state. The backing phase of the
/// inclusion pipeline ensures that everything that is included in a valid fork of the
/// relay-chain already adheres to the transient constraints.
///
/// The validation data also serve the purpose of giving collators a means of ensuring that
/// their produced candidate and the commitments submitted to the relay-chain alongside it
/// will pass the checks done by the relay-chain when backing, and give validators
/// the same understanding when determining whether to second or attest to a candidate.
///
/// Since the commitments of the validation function are checked by the
/// relay-chain, secondary checkers can rely on the invariant that the relay-chain
/// only includes para-blocks for which these checks have already been done. As such,
/// there is no need for the validation data used to inform validators and collators about
/// the checks the relay-chain will perform to be persisted by the availability system.
/// Nevertheless, we expose it so the backing validators can validate the outputs of a
/// candidate before voting to submit it to the relay-chain and so collators can
/// collate candidates that satisfy the criteria implied these transient validation data.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default))]
pub struct LocalValidationData<N = BlockNumber> {
pub struct ValidationData<N = BlockNumber> {
/// The persisted validation data.
pub persisted: PersistedValidationData<N>,
/// The transient validation data.
pub transient: TransientValidationData<N>,
}
/// Validation data that needs to be persisted for secondary checkers.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default))]
pub struct PersistedValidationData<N = BlockNumber> {
/// The parent head-data.
pub parent_head: HeadData,
/// The relay-chain block number this is in the context of.
pub block_number: N,
/// The list of MQC heads for the inbound channels paired with the sender para ids. This
/// vector is sorted ascending by the para id and doesn't contain multiple entries with the same
/// sender.
pub hrmp_mqc_heads: Vec<(Id, Hash)>,
}
impl<N: Encode> PersistedValidationData<N> {
/// Compute the blake2-256 hash of the persisted validation data.
pub fn hash(&self) -> Hash {
BlakeTwo256::hash_of(self)
}
}
/// Validation data for checking outputs of the validation-function.
/// As such, they also inform the collator about how to construct the candidate.
///
/// These are transient because they are not necessary beyond the point where the
/// candidate is backed.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default))]
pub struct TransientValidationData<N = BlockNumber> {
/// The maximum code size permitted, in bytes.
pub max_code_size: u32,
/// The maximum head-data size permitted, in bytes.
pub max_head_data_size: u32,
/// The balance of the parachain at the moment of validation.
pub balance: Balance,
/// The blake2-256 hash of the validation code used to execute the candidate.
pub validation_code_hash: Hash,
/// Whether the parachain is allowed to upgrade its validation code.
///
/// This is `Some` if so, and contains the number of the minimum relay-chain
@@ -249,21 +302,6 @@ pub struct LocalValidationData<N = BlockNumber> {
pub code_upgrade_allowed: Option<N>,
}
/// 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.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default))]
pub struct GlobalValidationData<N = BlockNumber> {
/// The maximum code size permitted, in bytes.
pub max_code_size: u32,
/// The maximum head-data size permitted, in bytes.
pub max_head_data_size: u32,
/// The relay-chain block number this is in the context of.
pub block_number: N,
}
/// 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, Hash))]
@@ -434,25 +472,14 @@ pub enum CoreOccupied {
Parachain,
}
/// Validation data omitted from most candidate descriptor structs, as it can be derived from the
/// relay-parent.
#[derive(Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(PartialEq, Debug, Default))]
pub struct OmittedValidationData {
/// The global validation schedule.
pub global_validation: GlobalValidationData,
/// The local validation data.
pub local_validation: LocalValidationData,
}
/// This is the data we keep available for each candidate included in the relay chain.
#[derive(Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
pub struct AvailableData {
/// The Proof-of-Validation of the candidate.
pub pov: PoV,
/// The omitted validation data.
pub omitted_validation: OmittedValidationData,
/// The persisted validation data needed for secondary checks.
pub validation_data: PersistedValidationData,
}
/// A helper data-type for tracking validator-group rotations.
@@ -622,17 +649,21 @@ sp_api::decl_runtime_apis! {
/// cores can have paras assigned to them.
fn availability_cores() -> Vec<CoreState<N>>;
/// Yields the GlobalValidationData. This applies to all para candidates with the
/// relay-parent equal to the block in which context this is invoked in.
fn global_validation_data() -> GlobalValidationData<N>;
/// Yields the full validation data for the given ParaId along with an assumption that
/// should be used if the para currently occupieds a core.
///
/// Returns `None` if either the para is not registered or the assumption is `Freed`
/// and the para already occupies a core.
fn full_validation_data(para_id: Id, assumption: OccupiedCoreAssumption)
-> Option<ValidationData<N>>;
/// Yields the LocalValidationData for the given ParaId along with an assumption that
/// Yields the persisted validation data for the given ParaId along with an assumption that
/// should be used if the para currently occupies a core.
///
/// Returns `None` if either the para is not registered or the assumption is `Freed`
/// and the para already occupies a core.
fn local_validation_data(para_id: Id, assumption: OccupiedCoreAssumption)
-> Option<LocalValidationData<N>>;
fn persisted_validation_data(para_id: Id, assumption: OccupiedCoreAssumption)
-> Option<PersistedValidationData<N>>;
/// Returns the session index expected at a child of the block.
///