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
+28
View File
@@ -231,6 +231,8 @@ decl_error! {
InvalidSignature,
/// Extra untagged validity votes along with candidate.
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)
.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!(
candidate.validity_votes.len() >= majority_of(validator_group.len()),
Error::<T>::NotEnoughValidityVotes,
@@ -1287,6 +1297,7 @@ mod tests {
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots,
fees: 0,
block_data_hash: Default::default(),
@@ -1308,6 +1319,7 @@ mod tests {
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![],
fees: 0,
block_data_hash: Default::default(),
@@ -1718,6 +1730,7 @@ mod tests {
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![],
fees: 0,
block_data_hash: Default::default(),
@@ -1750,6 +1763,7 @@ mod tests {
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![],
fees: 0,
block_data_hash: Default::default(),
@@ -1766,6 +1780,7 @@ mod tests {
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(vec![2, 3, 4]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![],
fees: 0,
block_data_hash: Default::default(),
@@ -1806,6 +1821,7 @@ mod tests {
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![],
fees: 0,
block_data_hash: Default::default(),
@@ -1844,6 +1860,7 @@ mod tests {
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![]),
egress_queue_roots: vec![],
fees: 0,
block_data_hash: Default::default(),
@@ -1878,10 +1895,18 @@ mod tests {
assert_eq!(Parachains::ingress(ParaId::from(99), None), Some(Vec::new()));
init_block();
for i in 1..10 {
run_to_block(i);
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 {
validity_votes: vec![],
validator_indices: BitVec::new(),
@@ -1890,6 +1915,7 @@ mod tests {
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]),
parent_head: parent_head.clone(),
egress_queue_roots: from_a.clone(),
fees: 0,
block_data_hash: Default::default(),
@@ -1907,6 +1933,7 @@ mod tests {
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]),
parent_head,
egress_queue_roots: from_b.clone(),
fees: 0,
block_data_hash: Default::default(),
@@ -1969,6 +1996,7 @@ mod tests {
collator: Default::default(),
signature: Default::default(),
head_data: HeadData(vec![1, 2, 3]),
parent_head: HeadData(vec![4, 5, 6]),
egress_queue_roots: Vec::new(),
fees: 0,
block_data_hash: Default::default(),
+3 -2
View File
@@ -836,13 +836,14 @@ mod tests {
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 candidate = CandidateReceipt {
parachain_index: id,
collator: collator.public(),
signature: block_data_hash.using_encoded(|d| collator.sign(d)),
head_data: HeadData(head_data.to_vec()),
parent_head: HeadData(parent_head.to_vec()),
egress_queue_roots: vec![],
fees: 0,
block_data_hash,
@@ -1117,7 +1118,7 @@ mod tests {
(user_id(0), Some((col.clone(), Retriable::WithRetries(0))))
]);
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);
+1 -1
View File
@@ -78,7 +78,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("polkadot"),
impl_name: create_runtime_str!("parity-polkadot"),
authoring_version: 2,
spec_version: 1001,
spec_version: 1002,
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
};