Include parent head in CandidateReceipt (#826)

* runtime: candidate receipt must pass parent head

* construct parachain candidates using correct parent_head

* validate that the parent header is correct in candidate receipt

* fix test fallout

* bump runtime versions
This commit is contained in:
Robert Habermeier
2020-02-10 10:14:12 +01:00
committed by GitHub
parent 703ac8bbbc
commit 1c2aff5b4d
11 changed files with 86 additions and 20 deletions
+3
View File
@@ -459,6 +459,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: Default::default(), head_data: Default::default(),
parent_head: Default::default(),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 0, fees: 0,
block_data_hash: block_data_1.hash(), block_data_hash: block_data_1.hash(),
@@ -471,6 +472,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: Default::default(), head_data: Default::default(),
parent_head: Default::default(),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 0, fees: 0,
block_data_hash: block_data_2.hash(), block_data_hash: block_data_2.hash(),
@@ -575,6 +577,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: Default::default(), head_data: Default::default(),
parent_head: Default::default(),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 0, fees: 0,
block_data_hash: block_data.hash(), block_data_hash: block_data.hash(),
+2
View File
@@ -285,6 +285,7 @@ mod tests {
collator: primary.clone().into(), collator: primary.clone().into(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]), head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![], egress_queue_roots: vec![],
fees: 0, fees: 0,
block_data_hash: [3; 32].into(), block_data_hash: [3; 32].into(),
@@ -314,6 +315,7 @@ mod tests {
collator: primary, collator: primary,
signature: Default::default(), signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]), head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![], egress_queue_roots: vec![],
fees: 0, fees: 0,
block_data_hash: [3; 32].into(), block_data_hash: [3; 32].into(),
+1
View File
@@ -906,6 +906,7 @@ mod tests {
parachain_index: 5.into(), parachain_index: 5.into(),
collator: [255; 32].unchecked_into(), collator: [255; 32].unchecked_into(),
head_data: HeadData(vec![9, 9, 9]), head_data: HeadData(vec![9, 9, 9]),
parent_head: HeadData(vec![]),
signature: Default::default(), signature: Default::default(),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 1_000_000, fees: 1_000_000,
+1
View File
@@ -173,6 +173,7 @@ fn fetches_from_those_with_knowledge() {
parachain_index: 5.into(), parachain_index: 5.into(),
collator: [255; 32].unchecked_into(), collator: [255; 32].unchecked_into(),
head_data: HeadData(vec![9, 9, 9]), head_data: HeadData(vec![9, 9, 9]),
parent_head: HeadData(vec![]),
signature: Default::default(), signature: Default::default(),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 1_000_000, fees: 1_000_000,
+2
View File
@@ -292,6 +292,8 @@ pub struct CandidateReceipt {
pub signature: CollatorSignature, pub signature: CollatorSignature,
/// The head-data /// The head-data
pub head_data: HeadData, pub head_data: HeadData,
/// The parent head-data.
pub parent_head: HeadData,
/// Egress queue roots. Must be sorted lexicographically (ascending) /// Egress queue roots. Must be sorted lexicographically (ascending)
/// by parachain ID. /// by parachain ID.
pub egress_queue_roots: Vec<(Id, Hash)>, pub egress_queue_roots: Vec<(Id, Hash)>,
+28
View File
@@ -231,6 +231,8 @@ decl_error! {
InvalidSignature, InvalidSignature,
/// Extra untagged validity votes along with candidate. /// Extra untagged validity votes along with candidate.
UntaggedVotes, UntaggedVotes,
/// Wrong parent head for parachain receipt.
ParentMismatch,
} }
} }
@@ -781,6 +783,14 @@ impl<T: Trait> Module<T> {
let validator_group = validator_groups.group_for(para_id) let validator_group = validator_groups.group_for(para_id)
.ok_or(Error::<T>::NoValidatorGroup)?; .ok_or(Error::<T>::NoValidatorGroup)?;
let actual_head = Self::parachain_head(&para_id)
.map(primitives::parachain::HeadData);
ensure!(
actual_head.as_ref() == Some(&candidate.candidate.parent_head),
Error::<T>::ParentMismatch,
);
ensure!( ensure!(
candidate.validity_votes.len() >= majority_of(validator_group.len()), candidate.validity_votes.len() >= majority_of(validator_group.len()),
Error::<T>::NotEnoughValidityVotes, Error::<T>::NotEnoughValidityVotes,
@@ -1287,6 +1297,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]), head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots, egress_queue_roots,
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
@@ -1308,6 +1319,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]), head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![], egress_queue_roots: vec![],
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
@@ -1718,6 +1730,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]), head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![], egress_queue_roots: vec![],
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
@@ -1750,6 +1763,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]), head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![], egress_queue_roots: vec![],
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
@@ -1766,6 +1780,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(vec![2, 3, 4]), head_data: HeadData(vec![2, 3, 4]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![], egress_queue_roots: vec![],
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
@@ -1806,6 +1821,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]), head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![], egress_queue_roots: vec![],
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
@@ -1844,6 +1860,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]), head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![], egress_queue_roots: vec![],
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
@@ -1878,10 +1895,18 @@ mod tests {
assert_eq!(Parachains::ingress(ParaId::from(99), None), Some(Vec::new())); assert_eq!(Parachains::ingress(ParaId::from(99), None), Some(Vec::new()));
init_block(); init_block();
for i in 1..10 { for i in 1..10 {
run_to_block(i); run_to_block(i);
let from_a = vec![(1.into(), [i as u8; 32].into())]; let from_a = vec![(1.into(), [i as u8; 32].into())];
let parent_head = HeadData(if i == 1 {
vec![]
} else {
vec![1, 2, 3]
});
let mut candidate_a = AttestedCandidate { let mut candidate_a = AttestedCandidate {
validity_votes: vec![], validity_votes: vec![],
validator_indices: BitVec::new(), validator_indices: BitVec::new(),
@@ -1890,6 +1915,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]), head_data: HeadData(vec![1, 2, 3]),
parent_head: parent_head.clone(),
egress_queue_roots: from_a.clone(), egress_queue_roots: from_a.clone(),
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
@@ -1907,6 +1933,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]), head_data: HeadData(vec![1, 2, 3]),
parent_head,
egress_queue_roots: from_b.clone(), egress_queue_roots: from_b.clone(),
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
@@ -1969,6 +1996,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]), head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![4, 5, 6]),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
+3 -2
View File
@@ -836,13 +836,14 @@ mod tests {
LOWEST_USER_ID + i LOWEST_USER_ID + i
} }
fn attest(id: ParaId, collator: &CollatorPair, head_data: &[u8], block_data: &[u8]) -> AttestedCandidate { fn attest(id: ParaId, collator: &CollatorPair, head_data: &[u8], parent_head: &[u8], block_data: &[u8]) -> AttestedCandidate {
let block_data_hash = BlakeTwo256::hash(block_data); let block_data_hash = BlakeTwo256::hash(block_data);
let candidate = CandidateReceipt { let candidate = CandidateReceipt {
parachain_index: id, parachain_index: id,
collator: collator.public(), collator: collator.public(),
signature: block_data_hash.using_encoded(|d| collator.sign(d)), signature: block_data_hash.using_encoded(|d| collator.sign(d)),
head_data: HeadData(head_data.to_vec()), head_data: HeadData(head_data.to_vec()),
parent_head: HeadData(parent_head.to_vec()),
egress_queue_roots: vec![], egress_queue_roots: vec![],
fees: 0, fees: 0,
block_data_hash, block_data_hash,
@@ -1117,7 +1118,7 @@ mod tests {
(user_id(0), Some((col.clone(), Retriable::WithRetries(0)))) (user_id(0), Some((col.clone(), Retriable::WithRetries(0))))
]); ]);
assert_ok!(Parachains::set_heads(Origin::NONE, vec![ assert_ok!(Parachains::set_heads(Origin::NONE, vec![
attest(user_id(0), &Sr25519Keyring::One.pair().into(), &[3; 3], &[0; 0]) attest(user_id(0), &Sr25519Keyring::One.pair().into(), &[3; 3], &[3; 3], &[0; 0])
])); ]));
run_to_block(6); run_to_block(6);
+1 -1
View File
@@ -78,7 +78,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("polkadot"), spec_name: create_runtime_str!("polkadot"),
impl_name: create_runtime_str!("parity-polkadot"), impl_name: create_runtime_str!("parity-polkadot"),
authoring_version: 2, authoring_version: 2,
spec_version: 1001, spec_version: 1002,
impl_version: 0, impl_version: 0,
apis: RUNTIME_API_VERSIONS, apis: RUNTIME_API_VERSIONS,
}; };
+28 -9
View File
@@ -68,7 +68,7 @@ pub async fn collation_fetch<C: Collators, P>(
collators: C, collators: C,
client: Arc<P>, client: Arc<P>,
max_block_data_size: Option<u64>, max_block_data_size: Option<u64>,
) -> Result<(Collation, OutgoingMessages, Balance),C::Error> ) -> Result<(Collation, OutgoingMessages, HeadData, Balance),C::Error>
where where
P::Api: ParachainHost<Block, Error = sp_blockchain::Error>, P::Api: ParachainHost<Block, Error = sp_blockchain::Error>,
C: Collators + Unpin, C: Collators + Unpin,
@@ -89,8 +89,8 @@ pub async fn collation_fetch<C: Collators, P>(
); );
match res { match res {
Ok((messages, fees)) => { Ok((messages, parent_head, fees)) => {
return Ok((collation, messages, fees)) return Ok((collation, messages, parent_head, fees))
} }
Err(e) => { Err(e) => {
debug!("Failed to validate parachain due to API error: {}", e); debug!("Failed to validate parachain due to API error: {}", e);
@@ -148,6 +148,10 @@ pub enum Error {
/// Candidate block collation info doesn't match candidate receipt. /// Candidate block collation info doesn't match candidate receipt.
#[display(fmt = "Got receipt mismatch for candidate {:?}", candidate)] #[display(fmt = "Got receipt mismatch for candidate {:?}", candidate)]
CandidateReceiptMismatch { candidate: Hash }, CandidateReceiptMismatch { candidate: Hash },
/// The parent header given in the candidate did not match current relay-chain
/// state.
#[display(fmt = "Got unexpected parachain parent.")]
ParentMismatch { expected: HeadData, got: HeadData },
} }
impl std::error::Error for Error { impl std::error::Error for Error {
@@ -406,7 +410,7 @@ pub fn validate_incoming(
// A utility function that implements most of the collation validation logic. // A utility function that implements most of the collation validation logic.
// //
// Reused by `validate_collation` and `validate_receipt`. // Reused by `validate_collation` and `validate_receipt`.
// Returns outgoing messages and fees charged for later reuse. // Returns outgoing messages, parent nead data, and fees charged for later reuse.
fn do_validation<P>( fn do_validation<P>(
client: &P, client: &P,
relay_parent: &BlockId, relay_parent: &BlockId,
@@ -417,7 +421,7 @@ fn do_validation<P>(
head_data: &HeadData, head_data: &HeadData,
queue_roots: &Vec<(ParaId, Hash)>, queue_roots: &Vec<(ParaId, Hash)>,
upward_messages: &Vec<UpwardMessage>, upward_messages: &Vec<UpwardMessage>,
) -> Result<(OutgoingMessages, Balance), Error> where ) -> Result<(OutgoingMessages, HeadData, Balance), Error> where
P: ProvideRuntimeApi<Block>, P: ProvideRuntimeApi<Block>,
P::Api: ParachainHost<Block, Error = sp_blockchain::Error>, P::Api: ParachainHost<Block, Error = sp_blockchain::Error>,
{ {
@@ -443,7 +447,7 @@ fn do_validation<P>(
validate_incoming(&roots, &pov_block.ingress)?; validate_incoming(&roots, &pov_block.ingress)?;
let params = ValidationParams { let params = ValidationParams {
parent_head: chain_status.head_data.0, parent_head: chain_status.head_data.0.clone(),
block_data: pov_block.block_data.0.clone(), block_data: pov_block.block_data.0.clone(),
ingress: pov_block.ingress.0.iter() ingress: pov_block.ingress.0.iter()
.flat_map(|&(source, ref messages)| { .flat_map(|&(source, ref messages)| {
@@ -471,7 +475,7 @@ fn do_validation<P>(
fees_charged fees_charged
)?; )?;
Ok((messages, fees)) Ok((messages, chain_status.head_data, fees))
} else { } else {
Err(Error::WrongHeadData { Err(Error::WrongHeadData {
expected: head_data.0.clone(), expected: head_data.0.clone(),
@@ -491,6 +495,7 @@ fn do_validation<P>(
/// encoding's root returning both for re-use. /// encoding's root returning both for re-use.
pub fn produce_receipt_and_chunks( pub fn produce_receipt_and_chunks(
n_validators: usize, n_validators: usize,
parent_head: HeadData,
pov: &PoVBlock, pov: &PoVBlock,
messages: &OutgoingMessages, messages: &OutgoingMessages,
fees: Balance, fees: Balance,
@@ -523,6 +528,7 @@ pub fn produce_receipt_and_chunks(
collator: info.collator.clone(), collator: info.collator.clone(),
signature: info.signature.clone(), signature: info.signature.clone(),
head_data: info.head_data.clone(), head_data: info.head_data.clone(),
parent_head,
egress_queue_roots: info.egress_queue_roots.clone(), egress_queue_roots: info.egress_queue_roots.clone(),
fees, fees,
block_data_hash: info.block_data_hash.clone(), block_data_hash: info.block_data_hash.clone(),
@@ -547,7 +553,7 @@ pub fn validate_receipt<P>(
P: ProvideRuntimeApi<Block>, P: ProvideRuntimeApi<Block>,
P::Api: ParachainHost<Block, Error = sp_blockchain::Error>, P::Api: ParachainHost<Block, Error = sp_blockchain::Error>,
{ {
let (messages, _fees) = do_validation( let (messages, parent_head, _fees) = do_validation(
client, client,
relay_parent, relay_parent,
pov_block, pov_block,
@@ -559,12 +565,20 @@ pub fn validate_receipt<P>(
&receipt.upward_messages, &receipt.upward_messages,
)?; )?;
if parent_head != receipt.parent_head {
return Err(Error::ParentMismatch {
expected: receipt.parent_head.clone(),
got: parent_head,
});
}
let api = client.runtime_api(); let api = client.runtime_api();
let validators = api.validators(&relay_parent)?; let validators = api.validators(&relay_parent)?;
let n_validators = validators.len(); let n_validators = validators.len();
let (validated_receipt, chunks) = produce_receipt_and_chunks( let (validated_receipt, chunks) = produce_receipt_and_chunks(
n_validators, n_validators,
parent_head,
pov_block, pov_block,
&messages, &messages,
receipt.fees, receipt.fees,
@@ -582,6 +596,7 @@ pub fn validate_receipt<P>(
} }
/// Check whether a given collation is valid. Returns `Ok` on success, error otherwise. /// Check whether a given collation is valid. Returns `Ok` on success, error otherwise.
/// Returns outgoing messages, parent head-data, and fees.
/// ///
/// This assumes that basic validity checks have been done: /// This assumes that basic validity checks have been done:
/// - Block data hash is the same as linked in collation info. /// - Block data hash is the same as linked in collation info.
@@ -590,7 +605,7 @@ pub fn validate_collation<P>(
relay_parent: &BlockId, relay_parent: &BlockId,
collation: &Collation, collation: &Collation,
max_block_data_size: Option<u64>, max_block_data_size: Option<u64>,
) -> Result<(OutgoingMessages, Balance), Error> where ) -> Result<(OutgoingMessages, HeadData, Balance), Error> where
P: ProvideRuntimeApi<Block>, P: ProvideRuntimeApi<Block>,
P::Api: ParachainHost<Block, Error = sp_blockchain::Error>, P::Api: ParachainHost<Block, Error = sp_blockchain::Error>,
{ {
@@ -698,6 +713,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(Vec::new()), head_data: HeadData(Vec::new()),
parent_head: HeadData(Vec::new()),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
@@ -717,6 +733,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(Vec::new()), head_data: HeadData(Vec::new()),
parent_head: HeadData(Vec::new()),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
@@ -735,6 +752,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(Vec::new()), head_data: HeadData(Vec::new()),
parent_head: HeadData(Vec::new()),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
@@ -753,6 +771,7 @@ mod tests {
collator: Default::default(), collator: Default::default(),
signature: Default::default(), signature: Default::default(),
head_data: HeadData(Vec::new()), head_data: HeadData(Vec::new()),
parent_head: HeadData(Vec::new()),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 0, fees: 0,
block_data_hash: Default::default(), block_data_hash: Default::default(),
+15 -7
View File
@@ -576,7 +576,9 @@ mod tests {
use super::*; use super::*;
use sp_keyring::Sr25519Keyring; use sp_keyring::Sr25519Keyring;
use primitives::crypto::UncheckedInto; use primitives::crypto::UncheckedInto;
use polkadot_primitives::parachain::{AvailableMessages, BlockData, ConsolidatedIngress, Collation}; use polkadot_primitives::parachain::{
AvailableMessages, BlockData, ConsolidatedIngress, Collation, HeadData,
};
use polkadot_erasure_coding::{self as erasure}; use polkadot_erasure_coding::{self as erasure};
use availability_store::ProvideGossipMessages; use availability_store::ProvideGossipMessages;
use futures::future; use futures::future;
@@ -662,7 +664,8 @@ mod tests {
parachain_index: para_id, parachain_index: para_id,
collator: [1; 32].unchecked_into(), collator: [1; 32].unchecked_into(),
signature: Default::default(), signature: Default::default(),
head_data: ::polkadot_primitives::parachain::HeadData(vec![1, 2, 3, 4]), head_data: HeadData(vec![1, 2, 3, 4]),
parent_head: HeadData(vec![]),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 1_000_000, fees: 1_000_000,
block_data_hash: [2; 32].into(), block_data_hash: [2; 32].into(),
@@ -718,7 +721,8 @@ mod tests {
parachain_index: para_id, parachain_index: para_id,
collator: [1; 32].unchecked_into(), collator: [1; 32].unchecked_into(),
signature: Default::default(), signature: Default::default(),
head_data: ::polkadot_primitives::parachain::HeadData(vec![1, 2, 3, 4]), head_data: HeadData(vec![1, 2, 3, 4]),
parent_head: HeadData(vec![]),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 1_000_000, fees: 1_000_000,
block_data_hash: [2; 32].into(), block_data_hash: [2; 32].into(),
@@ -755,7 +759,8 @@ mod tests {
parachain_index: para_id, parachain_index: para_id,
collator: [1; 32].unchecked_into(), collator: [1; 32].unchecked_into(),
signature: Default::default(), signature: Default::default(),
head_data: ::polkadot_primitives::parachain::HeadData(vec![1, 2, 3, 4]), head_data: HeadData(vec![1, 2, 3, 4]),
parent_head: HeadData(vec![]),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 1_000_000, fees: 1_000_000,
block_data_hash, block_data_hash,
@@ -819,7 +824,8 @@ mod tests {
parachain_index: para_id, parachain_index: para_id,
collator: [1; 32].unchecked_into(), collator: [1; 32].unchecked_into(),
signature: Default::default(), signature: Default::default(),
head_data: ::polkadot_primitives::parachain::HeadData(vec![1, 2, 3, 4]), head_data: HeadData(vec![1, 2, 3, 4]),
parent_head: HeadData(vec![]),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 1_000_000, fees: 1_000_000,
block_data_hash: [2; 32].into(), block_data_hash: [2; 32].into(),
@@ -902,7 +908,8 @@ mod tests {
parachain_index: para_id, parachain_index: para_id,
collator: [1; 32].unchecked_into(), collator: [1; 32].unchecked_into(),
signature: Default::default(), signature: Default::default(),
head_data: ::polkadot_primitives::parachain::HeadData(vec![1, 2, 3, 4]), head_data: HeadData(vec![1, 2, 3, 4]),
parent_head: HeadData(vec![]),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 1_000_000, fees: 1_000_000,
block_data_hash: [2; 32].into(), block_data_hash: [2; 32].into(),
@@ -969,7 +976,8 @@ mod tests {
parachain_index: para_id, parachain_index: para_id,
collator: [1; 32].unchecked_into(), collator: [1; 32].unchecked_into(),
signature: Default::default(), signature: Default::default(),
head_data: ::polkadot_primitives::parachain::HeadData(vec![1, 2, 3, 4]), head_data: HeadData(vec![1, 2, 3, 4]),
parent_head: HeadData(vec![]),
egress_queue_roots: Vec::new(), egress_queue_roots: Vec::new(),
fees: 1_000_000, fees: 1_000_000,
block_data_hash: [2; 32].into(), block_data_hash: [2; 32].into(),
@@ -396,10 +396,11 @@ impl<C, N, P, SP> ParachainValidationInstances<C, N, P, SP> where
max_block_data_size, max_block_data_size,
).await { ).await {
Ok(collation_work) => { Ok(collation_work) => {
let (collation, outgoing_targeted, fees_charged) = collation_work; let (collation, outgoing_targeted, parent_head, fees_charged) = collation_work;
match crate::collation::produce_receipt_and_chunks( match crate::collation::produce_receipt_and_chunks(
authorities_num, authorities_num,
parent_head,
&collation.pov, &collation.pov,
&outgoing_targeted, &outgoing_targeted,
fees_charged, fees_charged,