mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-19 05:21:03 +00:00
Inclusion Module (#1242)
* add availability bitfield types to primitives * begin inclusion module * use GitHub issue link for limitation * fix some compiler errors * integrate validators into initializer * add generic signing context * make signing-context more generic * fix issues with inclusion module * add TODO * guide: add validators and session index to inclusion * guide: add session index to change notification * implement session change logic * add BackedCandidate type * guide: refine inclusion pipeline * guide: rename group_on to group_validators * guide: add check about collator for parathread * guide: add last_code_upgrade to paras and use in inclusion * implement Paras::last_code_upgrade * implement most checks in process_candidates * make candidate receipt structs more generic * make BackedCandidate struct more generic * use hash param, not block number * check that candidate is in context of the parent block * include inclusion module in initializer * implement enact-candidate * check that only occupied cores have bits set * finish implementing bitfield processing * restructure consistency checks on candidates * make some more primitives generic * signature checking logic for backed candidates * finish implementing process_candidates * implement collect_pending * add some trait implementations to primitives * implement InclusionInherent and squash warnings * test bitfield signing checks * rename parachain head to para_head * fix note_new_head bug in paras * test bitfield enactment in inclusion * helpers for candidate checks * add test for most candidate checks * add test for backing setting storage * test session change logic * remove extraneous type parameter * remove some allow(unused)s * extract threshold computation to const fn * remove some more allow(unused)s * improve doc * add debug assertion * fix primitive test compilation * tag unanimous variant as unused
This commit is contained in:
committed by
GitHub
parent
7accc6e499
commit
879892d3f9
@@ -176,20 +176,20 @@ pub struct DutyRoster {
|
||||
/// These are global parameters that apply to all parachain candidates in a block.
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Default))]
|
||||
pub struct GlobalValidationSchedule {
|
||||
pub struct GlobalValidationSchedule<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: BlockNumber,
|
||||
pub block_number: N,
|
||||
}
|
||||
|
||||
/// Extra data that is needed along with the other fields in a `CandidateReceipt`
|
||||
/// to fully validate the candidate. These fields are parachain-specific.
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Default))]
|
||||
pub struct LocalValidationData {
|
||||
pub struct LocalValidationData<N = BlockNumber> {
|
||||
/// The parent head-data.
|
||||
pub parent_head: HeadData,
|
||||
/// The balance of the parachain at the moment of validation.
|
||||
@@ -205,28 +205,28 @@ pub struct LocalValidationData {
|
||||
/// 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.
|
||||
pub code_upgrade_allowed: Option<BlockNumber>,
|
||||
pub code_upgrade_allowed: Option<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))]
|
||||
pub struct CandidateCommitments {
|
||||
pub struct CandidateCommitments<H = Hash> {
|
||||
/// Fees paid from the chain to the relay chain validators.
|
||||
pub fees: Balance,
|
||||
/// Messages destined to be interpreted by the Relay chain itself.
|
||||
pub upward_messages: Vec<UpwardMessage>,
|
||||
/// The root of a block's erasure encoding Merkle tree.
|
||||
pub erasure_root: Hash,
|
||||
pub erasure_root: H,
|
||||
/// New validation code.
|
||||
pub new_validation_code: Option<ValidationCode>,
|
||||
}
|
||||
|
||||
/// Get a collator signature payload on a relay-parent, block-data combo.
|
||||
pub fn collator_signature_payload(
|
||||
relay_parent: &Hash,
|
||||
pub fn collator_signature_payload<H: AsRef<[u8]>>(
|
||||
relay_parent: &H,
|
||||
parachain_index: &Id,
|
||||
pov_block_hash: &Hash,
|
||||
pov_block_hash: &H,
|
||||
) -> [u8; 68] {
|
||||
// 32-byte hash length is protected in a test below.
|
||||
let mut payload = [0u8; 68];
|
||||
@@ -238,10 +238,10 @@ pub fn collator_signature_payload(
|
||||
payload
|
||||
}
|
||||
|
||||
fn check_collator_signature(
|
||||
relay_parent: &Hash,
|
||||
fn check_collator_signature<H: AsRef<[u8]>>(
|
||||
relay_parent: &H,
|
||||
parachain_index: &Id,
|
||||
pov_block_hash: &Hash,
|
||||
pov_block_hash: &H,
|
||||
collator: &CollatorId,
|
||||
signature: &CollatorSignature,
|
||||
) -> Result<(),()> {
|
||||
@@ -258,12 +258,12 @@ fn check_collator_signature(
|
||||
/// All data pertaining to the execution of a parachain candidate.
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Default))]
|
||||
pub struct CandidateReceipt {
|
||||
pub struct CandidateReceipt<H = Hash, N = BlockNumber> {
|
||||
/// The ID of the parachain this is a candidate for.
|
||||
pub parachain_index: Id,
|
||||
/// The hash of the relay-chain block this should be executed in
|
||||
/// the context of.
|
||||
pub relay_parent: Hash,
|
||||
pub relay_parent: H,
|
||||
/// The head-data
|
||||
pub head_data: HeadData,
|
||||
/// The collator's relay-chain account ID
|
||||
@@ -271,16 +271,16 @@ pub struct CandidateReceipt {
|
||||
/// Signature on blake2-256 of the block data by collator.
|
||||
pub signature: CollatorSignature,
|
||||
/// The hash of the PoV-block.
|
||||
pub pov_block_hash: Hash,
|
||||
pub pov_block_hash: H,
|
||||
/// The global validation schedule.
|
||||
pub global_validation: GlobalValidationSchedule,
|
||||
pub global_validation: GlobalValidationSchedule<N>,
|
||||
/// The local validation data.
|
||||
pub local_validation: LocalValidationData,
|
||||
pub local_validation: LocalValidationData<N>,
|
||||
/// Commitments made as a result of validation.
|
||||
pub commitments: CandidateCommitments,
|
||||
pub commitments: CandidateCommitments<H>,
|
||||
}
|
||||
|
||||
impl CandidateReceipt {
|
||||
impl<H: AsRef<[u8]>, N> CandidateReceipt<H, N> {
|
||||
/// Check integrity vs. provided block data.
|
||||
pub fn check_signature(&self) -> Result<(), ()> {
|
||||
check_collator_signature(
|
||||
@@ -294,7 +294,7 @@ impl CandidateReceipt {
|
||||
|
||||
/// Abridge this `CandidateReceipt`, splitting it into an `AbridgedCandidateReceipt`
|
||||
/// and its omitted component.
|
||||
pub fn abridge(self) -> (AbridgedCandidateReceipt, OmittedValidationData) {
|
||||
pub fn abridge(self) -> (AbridgedCandidateReceipt<H>, OmittedValidationData<N>) {
|
||||
let CandidateReceipt {
|
||||
parachain_index,
|
||||
relay_parent,
|
||||
@@ -345,11 +345,11 @@ impl Ord for CandidateReceipt {
|
||||
/// is necessary for validation of the parachain candidate.
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Default))]
|
||||
pub struct OmittedValidationData {
|
||||
pub struct OmittedValidationData<N = BlockNumber> {
|
||||
/// The global validation schedule.
|
||||
pub global_validation: GlobalValidationSchedule,
|
||||
pub global_validation: GlobalValidationSchedule<N>,
|
||||
/// The local validation data.
|
||||
pub local_validation: LocalValidationData,
|
||||
pub local_validation: LocalValidationData<N>,
|
||||
}
|
||||
|
||||
/// An abridged candidate-receipt.
|
||||
@@ -359,14 +359,14 @@ pub struct OmittedValidationData {
|
||||
/// be re-generated from relay-chain state.
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Default))]
|
||||
pub struct AbridgedCandidateReceipt {
|
||||
pub struct AbridgedCandidateReceipt<H = Hash> {
|
||||
/// The ID of the parachain this is a candidate for.
|
||||
pub parachain_index: Id,
|
||||
/// The hash of the relay-chain block this should be executed in
|
||||
/// the context of.
|
||||
// NOTE: the fact that the hash includes this value means that code depends
|
||||
// on this for deduplication. Removing this field is likely to break things.
|
||||
pub relay_parent: Hash,
|
||||
pub relay_parent: H,
|
||||
/// The head-data
|
||||
pub head_data: HeadData,
|
||||
/// The collator's relay-chain account ID
|
||||
@@ -374,12 +374,23 @@ pub struct AbridgedCandidateReceipt {
|
||||
/// Signature on blake2-256 of the block data by collator.
|
||||
pub signature: CollatorSignature,
|
||||
/// The hash of the pov-block.
|
||||
pub pov_block_hash: Hash,
|
||||
pub pov_block_hash: H,
|
||||
/// Commitments made as a result of validation.
|
||||
pub commitments: CandidateCommitments,
|
||||
pub commitments: CandidateCommitments<H>,
|
||||
}
|
||||
|
||||
impl AbridgedCandidateReceipt {
|
||||
impl<H: AsRef<[u8]> + Encode> AbridgedCandidateReceipt<H> {
|
||||
/// Check integrity vs. provided block data.
|
||||
pub fn check_signature(&self) -> Result<(), ()> {
|
||||
check_collator_signature(
|
||||
&self.relay_parent,
|
||||
&self.parachain_index,
|
||||
&self.pov_block_hash,
|
||||
&self.collator,
|
||||
&self.signature,
|
||||
)
|
||||
}
|
||||
|
||||
/// Compute the hash of the abridged candidate receipt.
|
||||
///
|
||||
/// This is often used as the canonical hash of the receipt, rather than
|
||||
@@ -391,7 +402,9 @@ impl AbridgedCandidateReceipt {
|
||||
use runtime_primitives::traits::{BlakeTwo256, Hash};
|
||||
BlakeTwo256::hash_of(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl AbridgedCandidateReceipt {
|
||||
/// Combine the abridged candidate receipt with the omitted data,
|
||||
/// forming a full `CandidateReceipt`.
|
||||
pub fn complete(self, omitted: OmittedValidationData) -> CandidateReceipt {
|
||||
@@ -616,13 +629,42 @@ pub enum ValidityAttestation {
|
||||
Explicit(ValidatorSignature),
|
||||
}
|
||||
|
||||
impl ValidityAttestation {
|
||||
/// Get a reference to the signature.
|
||||
pub fn signature(&self) -> &ValidatorSignature {
|
||||
match *self {
|
||||
ValidityAttestation::Implicit(ref sig) => sig,
|
||||
ValidityAttestation::Explicit(ref sig) => sig,
|
||||
}
|
||||
}
|
||||
|
||||
/// Produce the underlying signed payload of the attestation, given the hash of the candidate,
|
||||
/// which should be known in context.
|
||||
pub fn signed_payload<H: Encode>(
|
||||
&self,
|
||||
candidate_hash: Hash,
|
||||
signing_context: &SigningContext<H>,
|
||||
) -> Vec<u8> {
|
||||
match *self {
|
||||
ValidityAttestation::Implicit(_) => (
|
||||
Statement::Candidate(candidate_hash),
|
||||
signing_context,
|
||||
).encode(),
|
||||
ValidityAttestation::Explicit(_) => (
|
||||
Statement::Valid(candidate_hash),
|
||||
signing_context,
|
||||
).encode(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A type returned by runtime with current session index and a parent hash.
|
||||
#[derive(Clone, Eq, PartialEq, Default, Decode, Encode, RuntimeDebug)]
|
||||
pub struct SigningContext {
|
||||
pub struct SigningContext<H = Hash> {
|
||||
/// Current session index.
|
||||
pub session_index: sp_staking::SessionIndex,
|
||||
/// Hash of the parent.
|
||||
pub parent_hash: Hash,
|
||||
pub parent_hash: H,
|
||||
}
|
||||
|
||||
/// An attested candidate. This is submitted to the relay chain by a block author.
|
||||
@@ -683,9 +725,9 @@ impl From<BitVec<bitvec::order::Lsb0, u8>> for AvailabilityBitfield {
|
||||
|
||||
impl AvailabilityBitfield {
|
||||
/// Encodes the signing payload into the given buffer.
|
||||
pub fn encode_signing_payload_into(
|
||||
pub fn encode_signing_payload_into<H: Encode>(
|
||||
&self,
|
||||
signing_context: &SigningContext,
|
||||
signing_context: &SigningContext<H>,
|
||||
buf: &mut Vec<u8>,
|
||||
) {
|
||||
self.0.encode_to(buf);
|
||||
@@ -693,10 +735,9 @@ impl AvailabilityBitfield {
|
||||
}
|
||||
|
||||
/// Encodes the signing payload into a fresh byte-vector.
|
||||
pub fn encode_signing_payload(
|
||||
pub fn encode_signing_payload<H: Encode>(
|
||||
&self,
|
||||
signing_context:
|
||||
&SigningContext,
|
||||
signing_context: &SigningContext<H>,
|
||||
) -> Vec<u8> {
|
||||
let mut v = Vec::new();
|
||||
self.encode_signing_payload_into(signing_context, &mut v);
|
||||
@@ -724,7 +765,7 @@ pub fn check_availability_bitfield_signature<H: Encode>(
|
||||
bitfield: &AvailabilityBitfield,
|
||||
validator: &ValidatorId,
|
||||
signature: &ValidatorSignature,
|
||||
signing_context: &SigningContext,
|
||||
signing_context: &SigningContext<H>,
|
||||
payload_encode_buf: Option<&mut Vec<u8>>,
|
||||
) -> Result<(),()> {
|
||||
use runtime_primitives::traits::AppVerify;
|
||||
@@ -750,15 +791,67 @@ pub struct SignedAvailabilityBitfields(pub Vec<SignedAvailabilityBitfield>);
|
||||
// After https://github.com/paritytech/polkadot/issues/1250
|
||||
// they should be unified to this type.
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
|
||||
pub struct BackedCandidate {
|
||||
pub struct BackedCandidate<H = Hash> {
|
||||
/// The candidate referred to.
|
||||
pub candidate: AbridgedCandidateReceipt,
|
||||
pub candidate: AbridgedCandidateReceipt<H>,
|
||||
/// The validity votes themselves, expressed as signatures.
|
||||
pub validity_votes: Vec<ValidityAttestation>,
|
||||
/// The indices of the validators within the group, expressed as a bitfield.
|
||||
pub validator_indices: BitVec<bitvec::order::Lsb0, u8>,
|
||||
}
|
||||
|
||||
/// Verify the backing of the given candidate.
|
||||
///
|
||||
/// Provide a lookup from the index of a validator within the group assigned to this para,
|
||||
/// as opposed to the index of the validator within the overall validator set, as well as
|
||||
/// the number of validators in the group.
|
||||
///
|
||||
/// Also provide the signing context.
|
||||
///
|
||||
/// Returns either an error, indicating that one of the signatures was invalid or that the index
|
||||
/// was out-of-bounds, or the number of signatures checked.
|
||||
pub fn check_candidate_backing<H: AsRef<[u8]> + Encode>(
|
||||
backed: &BackedCandidate<H>,
|
||||
signing_context: &SigningContext<H>,
|
||||
group_len: usize,
|
||||
validator_lookup: impl Fn(usize) -> Option<ValidatorId>,
|
||||
) -> Result<usize, ()> {
|
||||
use runtime_primitives::traits::AppVerify;
|
||||
|
||||
if backed.validator_indices.len() != group_len {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
if backed.validity_votes.len() > group_len {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
// this is known, even in runtime, to be blake2-256.
|
||||
let hash: Hash = backed.candidate.hash();
|
||||
|
||||
let mut signed = 0;
|
||||
for ((val_in_group_idx, _), attestation) in backed.validator_indices.iter().enumerate()
|
||||
.filter(|(_, signed)| **signed)
|
||||
.zip(backed.validity_votes.iter())
|
||||
{
|
||||
let validator_id = validator_lookup(val_in_group_idx).ok_or(())?;
|
||||
let payload = attestation.signed_payload(hash.clone(), signing_context);
|
||||
let sig = attestation.signature();
|
||||
|
||||
if sig.verify(&payload[..], &validator_id) {
|
||||
signed += 1;
|
||||
} else {
|
||||
return Err(())
|
||||
}
|
||||
}
|
||||
|
||||
if signed != backed.validity_votes.len() {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
Ok(signed)
|
||||
}
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// The API for querying the state of parachains on-chain.
|
||||
#[api_version(3)]
|
||||
@@ -811,9 +904,9 @@ mod tests {
|
||||
assert_eq!(h.as_ref().len(), 32);
|
||||
|
||||
let _payload = collator_signature_payload(
|
||||
&[1; 32].into(),
|
||||
&Hash::from([1; 32]),
|
||||
&5u32.into(),
|
||||
&[2; 32].into(),
|
||||
&Hash::from([2; 32]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user