1use crate::{
17 descendant_validation::RelayParentVerificationError::InvalidNumberOfDescendants,
18 RelayChainStateProof,
19};
20use alloc::vec::Vec;
21use sp_consensus_babe::{
22 digests::{CompatibleDigestItem, NextEpochDescriptor},
23 AuthorityIndex,
24};
25use sp_runtime::{traits::Header, RuntimeAppPublic};
26
27pub(crate) fn verify_relay_parent_descendants<H: Header>(
59 relay_state_proof: &RelayChainStateProof,
60 relay_parent_descendants: Vec<H>,
61 relay_parent_state_root: H::Hash,
62 expected_rp_descendants_num: u32,
63) -> Result<(), RelayParentVerificationError<H>> {
64 if relay_parent_descendants.len() != (expected_rp_descendants_num + 1) as usize {
65 return Err(InvalidNumberOfDescendants {
66 expected: expected_rp_descendants_num + 1,
67 received: relay_parent_descendants.len(),
68 });
69 }
70
71 let Ok(mut current_authorities) = relay_state_proof.read_authorities() else {
72 return Err(RelayParentVerificationError::MissingAuthorities)
73 };
74 let mut maybe_next_authorities = relay_state_proof.read_next_authorities().ok().flatten();
75
76 let mut next_expected_parent_hash = None;
77
78 if let Some(relay_parent) = relay_parent_descendants.get(0) {
82 if *relay_parent.state_root() != relay_parent_state_root {
83 return Err(RelayParentVerificationError::InvalidStateRoot {
84 expected: relay_parent_state_root,
85 found: *relay_parent.state_root(),
86 });
87 }
88 };
89
90 for (index, mut current_header) in relay_parent_descendants.into_iter().enumerate() {
91 let sealed_header_hash = current_header.hash();
93 let relay_number = *current_header.number();
94
95 if let Some(expected_hash) = next_expected_parent_hash {
97 if *current_header.parent_hash() != expected_hash {
98 return Err(RelayParentVerificationError::InvalidChainSequence {
99 expected: expected_hash,
100 found: *current_header.parent_hash(),
101 number: relay_number,
102 });
103 }
104 }
105 next_expected_parent_hash = Some(sealed_header_hash);
106
107 log::debug!(target: crate::LOG_TARGET, "Validating header #{relay_number:?} ({sealed_header_hash:?})");
108 let (authority_index, next_epoch_descriptor) =
109 find_authority_idx_epoch_digest(¤t_header).ok_or_else(|| {
110 RelayParentVerificationError::MissingPredigest { hash: sealed_header_hash }
111 })?;
112
113 if let Some(descriptor) = next_epoch_descriptor {
118 if index != 0 {
121 let Some(next_authorities) = maybe_next_authorities else {
122 return Err(RelayParentVerificationError::MissingNextEpochAuthorities {
123 number: relay_number,
124 hash: sealed_header_hash,
125 });
126 };
127 log::debug!(
128 target: crate::LOG_TARGET,
129 "Header {sealed_header_hash:?} contains epoch change! \
130 Using next authority set to verify signatures going forward."
131 );
132 current_authorities = next_authorities;
136 maybe_next_authorities = Some(descriptor.authorities);
137 }
138 }
139
140 let Some(authority_id) = current_authorities.get(authority_index as usize) else {
141 return Err(RelayParentVerificationError::MissingAuthorityId);
142 };
143
144 let Some(seal) = current_header.digest_mut().pop() else {
145 return Err(RelayParentVerificationError::MissingSeal { hash: sealed_header_hash })
146 };
147 let Some(signature) = seal.as_babe_seal() else {
148 return Err(RelayParentVerificationError::InvalidSeal { hash: sealed_header_hash })
149 };
150
151 if !authority_id.0.verify(¤t_header.hash(), &signature) {
152 return Err(RelayParentVerificationError::InvalidSignature {
153 number: relay_number,
154 hash: sealed_header_hash,
155 });
156 }
157 log::debug!(target: crate::LOG_TARGET, "Validated header #{relay_number:?} ({sealed_header_hash:?})");
158 }
159
160 Ok(())
161}
162
163pub fn find_authority_idx_epoch_digest<H: Header>(
170 header: &H,
171) -> Option<(AuthorityIndex, Option<NextEpochDescriptor>)> {
172 let mut babe_pre_digest = None;
173 let mut next_epoch_digest = None;
174 for log in header.digest().logs() {
175 if let Some(digest) = log.as_babe_pre_digest() {
176 babe_pre_digest = Some(digest);
177 }
178
179 if let Some(digest) = log.as_next_epoch_descriptor() {
180 next_epoch_digest = Some(digest);
181 }
182 }
183
184 babe_pre_digest.map(|pd| (pd.authority_index(), next_epoch_digest))
185}
186
187#[derive(Debug, PartialEq)]
189pub(crate) enum RelayParentVerificationError<H: Header> {
190 InvalidNumberOfDescendants { expected: u32, received: usize },
192 MissingAuthorities,
194 InvalidStateRoot { expected: H::Hash, found: H::Hash },
196 InvalidChainSequence { expected: H::Hash, found: H::Hash, number: H::Number },
198 MissingPredigest { hash: H::Hash },
200 MissingSeal { hash: H::Hash },
202 InvalidSeal { hash: H::Hash },
204 MissingNextEpochAuthorities { number: H::Number, hash: H::Hash },
206 MissingAuthorityId,
208 InvalidSignature { number: H::Number, hash: H::Hash },
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215 use codec::{Decode, Encode};
216 use cumulus_primitives_core::relay_chain;
217 use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
218 use rstest::rstest;
219 use sp_consensus_babe::{
220 digests::{CompatibleDigestItem, NextEpochDescriptor, PreDigest, PrimaryPreDigest},
221 AuthorityId, AuthorityPair, BabeAuthorityWeight, ConsensusLog, BABE_ENGINE_ID,
222 };
223 use sp_core::{
224 sr25519::vrf::{VrfPreOutput, VrfProof, VrfSignature},
225 Pair, H256,
226 };
227 use sp_keyring::Sr25519Keyring;
228 use sp_runtime::{testing::Header as TestHeader, DigestItem};
229 const PARA_ID: u32 = 2000;
230
231 #[rstest]
234 fn test_verify_relay_parent_descendants_happy_case(
235 #[values(1, 2, 3, 4, 100)] num_headers: u64,
236 #[values(1, 3, 100, 1000)] num_authorities: u64,
237 ) {
238 let (relay_parent_descendants, authorities, _) =
239 build_relay_parent_descendants(num_headers, num_authorities, None);
240 let relay_state_proof = build_relay_chain_storage_proof(Some(authorities), None);
241
242 let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
244 let expected_number_of_descendants = (relay_parent_descendants.len() - 1) as u32;
246
247 assert!(verify_relay_parent_descendants(
248 &relay_state_proof,
249 relay_parent_descendants,
250 relay_parent_state_root,
251 expected_number_of_descendants,
252 )
253 .is_ok());
254 }
255
256 #[rstest]
257 fn test_verify_relay_parent_broken_state_root() {
258 let (relay_parent_descendants, authorities, _) =
259 build_relay_parent_descendants(10, 10, None);
260 let relay_state_proof = build_relay_chain_storage_proof(Some(authorities), None);
261
262 let relay_parent_state_root = H256::repeat_byte(0x9);
264
265 let expected_number_of_descendants = (relay_parent_descendants.len() - 1) as u32;
267
268 let result = verify_relay_parent_descendants(
269 &relay_state_proof,
270 relay_parent_descendants,
271 relay_parent_state_root,
272 expected_number_of_descendants,
273 );
274
275 assert_eq!(
276 result,
277 Err(RelayParentVerificationError::<TestHeader>::InvalidStateRoot {
278 expected: H256::repeat_byte(0x9),
279 found: H256::repeat_byte(0x0),
280 })
281 );
282 }
283
284 #[rstest]
285 #[case::too_few_1(1)]
286 #[case::too_few_2(8)]
287 #[case::too_many_1(10)]
289 #[case::too_many_2(100)]
290 fn test_incorrect_number_of_headers(#[case] expected_number_of_descendants: u32) {
291 let (relay_parent_descendants, authorities, _) =
292 build_relay_parent_descendants(10, 10, None);
293 let relay_state_proof = build_relay_chain_storage_proof(Some(authorities), None);
294
295 let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
297
298 let result = verify_relay_parent_descendants(
299 &relay_state_proof,
300 relay_parent_descendants,
301 relay_parent_state_root,
302 expected_number_of_descendants,
303 );
304
305 assert_eq!(
306 result,
307 Err(InvalidNumberOfDescendants::<TestHeader> {
308 expected: expected_number_of_descendants + 1,
309 received: 10,
310 })
311 );
312 }
313
314 #[rstest]
315 fn test_authorities_missing() {
316 let (relay_parent_descendants, _, _) = build_relay_parent_descendants(10, 10, None);
317 let relay_state_proof = build_relay_chain_storage_proof(None, None);
319
320 let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
322 let expected_number_of_descendants = (relay_parent_descendants.len() - 1) as u32;
324
325 let result = verify_relay_parent_descendants(
326 &relay_state_proof,
327 relay_parent_descendants,
328 relay_parent_state_root,
329 expected_number_of_descendants,
330 );
331
332 assert_eq!(result, Err(RelayParentVerificationError::<TestHeader>::MissingAuthorities));
333 }
334
335 #[rstest]
336 fn test_relay_parents_do_not_form_chain() {
337 let (mut relay_parent_descendants, authorities, _) =
338 build_relay_parent_descendants(10, 10, None);
339 let header_to_modify = relay_parent_descendants.get_mut(2).expect("Parent is available");
340 let expected_hash = header_to_modify.parent_hash;
341 header_to_modify.parent_hash = H256::repeat_byte(0x9);
343 let relay_state_proof = build_relay_chain_storage_proof(Some(authorities), None);
344
345 let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
347 let expected_number_of_descendants = (relay_parent_descendants.len() - 1) as u32;
349
350 let result = verify_relay_parent_descendants(
351 &relay_state_proof,
352 relay_parent_descendants,
353 relay_parent_state_root,
354 expected_number_of_descendants,
355 );
356
357 assert_eq!(
358 result,
359 Err(RelayParentVerificationError::<TestHeader>::InvalidChainSequence {
360 number: 2,
361 expected: expected_hash,
362 found: H256::repeat_byte(0x9),
363 })
364 );
365 }
366
367 #[rstest]
368 fn test_relay_parent_with_wrong_signature() {
369 let (mut relay_parent_descendants, authorities, _) =
370 build_relay_parent_descendants(10, 10, None);
371
372 let rp_to_modify = relay_parent_descendants.last_mut().expect("Parent is available");
374 rp_to_modify.digest_mut().logs.pop();
375 let invalid_signature =
376 Sr25519Keyring::Alice.sign(b"Not the signature you are looking for.");
377 rp_to_modify.digest_mut().push(DigestItem::babe_seal(invalid_signature.into()));
378 let expected_hash = rp_to_modify.hash();
379
380 let relay_state_proof = build_relay_chain_storage_proof(Some(authorities), None);
381
382 let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
384 let expected_number_of_descendants = (relay_parent_descendants.len() - 1) as u32;
386
387 let result = verify_relay_parent_descendants(
388 &relay_state_proof,
389 relay_parent_descendants,
390 relay_parent_state_root,
391 expected_number_of_descendants,
392 );
393
394 assert_eq!(
395 result,
396 Err(RelayParentVerificationError::<TestHeader>::InvalidSignature {
397 number: 9,
398 hash: expected_hash,
399 })
400 );
401 }
402
403 #[rstest]
404 fn test_verify_relay_parent_descendants_missing_next_authorities_with_epoch_change() {
405 sp_tracing::try_init_simple();
406 let (relay_parent_descendants, authorities, _) =
407 build_relay_parent_descendants(10, 10, Some(5));
408 let relay_state_proof = build_relay_chain_storage_proof(Some(authorities), None);
409
410 let expected_hash = relay_parent_descendants[5].hash();
411 let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
413 let expected_number_of_descendants = (relay_parent_descendants.len() - 1) as u32;
415
416 let result = verify_relay_parent_descendants(
417 &relay_state_proof,
418 relay_parent_descendants,
419 relay_parent_state_root,
420 expected_number_of_descendants,
421 );
422 assert_eq!(
423 result,
424 Err(RelayParentVerificationError::<TestHeader>::MissingNextEpochAuthorities {
425 number: 5,
426 hash: expected_hash,
427 })
428 );
429 }
430
431 #[rstest]
432 fn test_verify_relay_parent_descendants_happy_case_with_epoch_change(
433 #[values(1, 2, 3, 4, 100)] num_headers: u64,
434 #[values(1, 3, 100, 1000)] num_authorities: u64,
435 ) {
436 sp_tracing::try_init_simple();
437 let (relay_parent_descendants, authorities, next_authorities) =
438 build_relay_parent_descendants(num_headers, num_authorities, Some(5));
439 let relay_state_proof =
440 build_relay_chain_storage_proof(Some(authorities), Some(next_authorities));
441
442 let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
444 let expected_number_of_descendants = (relay_parent_descendants.len() - 1) as u32;
446
447 assert!(verify_relay_parent_descendants(
448 &relay_state_proof,
449 relay_parent_descendants,
450 relay_parent_state_root,
451 expected_number_of_descendants,
452 )
453 .is_ok());
454 }
455
456 #[rstest]
459 fn test_verify_relay_parent_with_epoch_change_at_positions(
460 #[values(0, 5, 10)] epoch_change_position: u64,
461 ) {
462 sp_tracing::try_init_simple();
463 let (relay_parent_descendants, authorities, next_authorities) =
464 build_relay_parent_descendants(10, 10, Some(epoch_change_position));
465 let relay_state_proof =
466 build_relay_chain_storage_proof(Some(authorities), Some(next_authorities));
467
468 let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
470 let expected_number_of_descendants = (relay_parent_descendants.len() - 1) as u32;
472
473 assert!(verify_relay_parent_descendants(
474 &relay_state_proof,
475 relay_parent_descendants,
476 relay_parent_state_root,
477 expected_number_of_descendants,
478 )
479 .is_ok());
480 }
481
482 fn build_relay_chain_storage_proof(
484 authorities: Option<Vec<(AuthorityId, BabeAuthorityWeight)>>,
485 next_authorities: Option<Vec<(AuthorityId, BabeAuthorityWeight)>>,
486 ) -> RelayChainStateProof {
487 let mut proof_builder = RelayStateSproofBuilder::default();
489 if let Some(authorities) = authorities {
490 proof_builder
491 .additional_key_values
492 .push((relay_chain::well_known_keys::AUTHORITIES.to_vec(), authorities.encode()));
493 }
494
495 if let Some(next_authorities) = next_authorities {
496 proof_builder.additional_key_values.push((
497 relay_chain::well_known_keys::NEXT_AUTHORITIES.to_vec(),
498 next_authorities.encode(),
499 ));
500 }
501 let (hash, relay_storage_proof) = proof_builder.into_state_root_and_proof();
502 RelayChainStateProof::new(PARA_ID.into(), hash, relay_storage_proof).unwrap()
503 }
504
505 fn generate_testing_vrf() -> VrfSignature {
508 let vrf_proof_bytes = [0u8; 64];
509 let proof: VrfProof = VrfProof::decode(&mut vrf_proof_bytes.as_slice()).unwrap();
510 let vrf_pre_out_bytes = [0u8; 32];
511 let pre_output: VrfPreOutput =
512 VrfPreOutput::decode(&mut vrf_pre_out_bytes.as_slice()).unwrap();
513 VrfSignature { pre_output, proof }
514 }
515
516 fn build_relay_parent_descendants(
520 num_headers: u64,
521 num_authorities: u64,
522 epoch_change_at: Option<u64>,
523 ) -> (
524 Vec<TestHeader>,
525 Vec<(AuthorityId, BabeAuthorityWeight)>,
526 Vec<(AuthorityId, BabeAuthorityWeight)>,
527 ) {
528 let (authorities, next_authorities) = generate_authority_pairs(num_authorities);
530 let authorities_for_storage = convert_to_authority_weight_pair(&authorities);
531 let next_authorities_for_storage = convert_to_authority_weight_pair(&next_authorities);
532
533 let mut headers = Vec::with_capacity(num_headers as usize);
535 let mut current_authorities = authorities.clone();
536 let mut previous_hash = None;
537
538 for block_number in 0..=num_headers - 1 {
539 let mut header = create_header(block_number, previous_hash);
540 let authority_index = (block_number as u32) % (num_authorities as u32);
541
542 add_pre_digest(&mut header, authority_index, block_number);
544
545 if epoch_change_at.map_or(false, |change_at| block_number == change_at) {
547 add_epoch_change_digest(&mut header, num_authorities);
548 if block_number > 0 {
549 current_authorities = next_authorities.clone();
550 }
551 }
552
553 let signature =
555 current_authorities[authority_index as usize].sign(header.hash().as_bytes());
556 header.digest_mut().push(DigestItem::babe_seal(signature.into()));
557
558 previous_hash = Some(header.hash());
559 headers.push(header);
560 }
561
562 (headers, authorities_for_storage, next_authorities_for_storage)
563 }
564
565 fn generate_authority_pairs(num_authorities: u64) -> (Vec<AuthorityPair>, Vec<AuthorityPair>) {
567 let authorities: Vec<_> = (0..num_authorities).map(|_| Pair::generate().0).collect();
568 let next_authorities: Vec<_> = (0..num_authorities).map(|_| Pair::generate().0).collect();
569 (authorities, next_authorities)
570 }
571
572 fn convert_to_authority_weight_pair(
573 authorities: &[AuthorityPair],
574 ) -> Vec<(AuthorityId, BabeAuthorityWeight)> {
575 authorities
576 .iter()
577 .map(|auth| (auth.public().into(), Default::default()))
578 .collect()
579 }
580
581 fn create_header(block_number: u64, previous_hash: Option<H256>) -> TestHeader {
582 let mut header = TestHeader::new_from_number(block_number);
583 if let Some(parent_hash) = previous_hash {
584 header.parent_hash = parent_hash;
585 }
586 header
587 }
588
589 fn add_pre_digest(header: &mut TestHeader, authority_index: u32, block_number: u64) {
590 let pre_digest = PrimaryPreDigest {
591 authority_index,
592 slot: block_number.into(),
593 vrf_signature: generate_testing_vrf(),
594 };
595 header
596 .digest_mut()
597 .push(DigestItem::babe_pre_digest(PreDigest::Primary(pre_digest)));
598 }
599
600 fn add_epoch_change_digest(header: &mut TestHeader, num_authorities: u64) {
601 let digest_authorities: Vec<(AuthorityId, BabeAuthorityWeight)> = (0..num_authorities)
602 .map(|_| {
603 let authority_pair: AuthorityPair = Pair::generate().0;
604 (authority_pair.public().into(), Default::default())
605 })
606 .collect();
607
608 header.digest_mut().push(DigestItem::Consensus(
609 BABE_ENGINE_ID,
610 ConsensusLog::NextEpochData(NextEpochDescriptor {
611 authorities: digest_authorities,
612 randomness: [0; 32],
613 })
614 .encode(),
615 ));
616 }
617}