referrerpolicy=no-referrer-when-downgrade

cumulus_pallet_parachain_system/
descendant_validation.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// SPDX-License-Identifier: Apache-2.0
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// 	http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use 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
27/// Verifies that the provided relay parent descendants form a valid chain
28/// and are signed by relay chain authorities. If relay chain descendants shall be checked,
29/// a set of authorities for the epoch of the relay parent must be provided in the
30/// relay chain state proof. If any of the descendants indicate the beginning of a new epoch,
31/// the authority set for the next relay chain epoch must be included in the state proof too.
32///
33/// # Parameters
34///
35/// - `relay_state_proof`: The proof of the relay chain state, which contains details about the
36///   authority sets and other chain data.
37/// - `relay_parent_descendants`: A vector of relay chain headers representing the descendants of
38///   the relay parent that need to be validated. The first item in this vector must be the relay
39///   parent itself.
40/// - `relay_parent_state_root`: The state root hash of the relay parent. This
41///   will be matched with the first relay parent header from the descendants.
42///   **Note:** This parameter can be removed once the hash of the relay parent is available
43///   to the runtime. https://github.com/paritytech/polkadot-sdk/issues/83
44/// - `expected_rp_descendants_num`: The expected number of headers in the
45///   `relay_parent_descendants`. A mismatch will cause the function to return an error.
46///
47/// # Errors
48///
49/// This function will error under the following scenarios:
50///
51/// - The number of headers in `relay_parent_descendants` does not match
52///   `expected_rp_descendants_num`.
53/// - No authorities are provided in the state proof.
54/// - The state root of the provided relay parent does not match the expected value.
55/// - A relay header does not contain a BABE pre-digest.
56/// - A header with an invalid seal signature is found, or the authorities required to verify the
57///   signature are missing (current or next epoch).
58pub(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	// Verify that the state root of the first block is the same as the one
79	// from the relay parent. In the PVF, we don't have the relay parent header hash
80	// available, so we need to use the storage root here to establish a chain.
81	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		// Hash calculated while seal is intact
92		let sealed_header_hash = current_header.hash();
93		let relay_number = *current_header.number();
94
95		// Verify that the blocks actually form a chain
96		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(&current_header).ok_or_else(|| {
110				RelayParentVerificationError::MissingPredigest { hash: sealed_header_hash }
111			})?;
112
113		// Once we have seen a next epoch descriptor, we must always use the authorities of the
114		// next epoch. If the relay parent contains epoch descriptor, we shall not rotate
115		// authorities. As in that case the authorities in the state proof reflect the
116		// new authorities already.
117		if let Some(descriptor) = next_epoch_descriptor {
118			// If the relay parent itself contains the epoch change, we must _not_ use the next
119			// authorities, as they have already been rotated in storage.
120			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				// Rotate authorities, all headers following are to
133				// be verified against the new authorities. The authorities for the next epoch
134				// have been signed by a current authority, we can use it for further epochs.
135				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(&current_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
163/// Extract babe digest items from the header.
164/// - [AuthorityIndex]: We extract the authority index from the babe predigest. We use it to verify
165///   that a correct authority from the authority set signed the header.
166/// - [NextEpochDescriptor]: We extract it because we need to know which block starts a new epoch on
167///   the relay chain. Epoch change indicates a switch in authority set, so we need to verify
168///   following signatures against the new authorities.
169pub 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/// Errors that can occur during descendant validation
188#[derive(Debug, PartialEq)]
189pub(crate) enum RelayParentVerificationError<H: Header> {
190	/// The number of descendants provided doesn't match the expected count
191	InvalidNumberOfDescendants { expected: u32, received: usize },
192	/// No authorities were provided in the state proof
193	MissingAuthorities,
194	/// The state root of the relay parent doesn't match
195	InvalidStateRoot { expected: H::Hash, found: H::Hash },
196	/// The chain sequence is invalid (parent hash doesn't match expected hash)
197	InvalidChainSequence { expected: H::Hash, found: H::Hash, number: H::Number },
198	/// The header is missing the required pre-digest
199	MissingPredigest { hash: H::Hash },
200	/// The header is missing the required seal
201	MissingSeal { hash: H::Hash },
202	/// The header contains an invalid seal
203	InvalidSeal { hash: H::Hash },
204	/// Next epoch authorities are missing when they are required
205	MissingNextEpochAuthorities { number: H::Number, hash: H::Hash },
206	/// Unable to find the authority ID at the expected index
207	MissingAuthorityId,
208	/// The signature verification failed
209	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	/// Verify a header chain with different lengths and different number of authorities included in
232	/// the storage proof.
233	#[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		// Make sure that the first relay parent has the correct state root set
243		let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
244		// Expected number of parents passed to the function does not include actual relay parent
245		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		// Set a erroneous state root
263		let relay_parent_state_root = H256::repeat_byte(0x9);
264
265		// Expected number of parents passed to the function does not include actual relay parent
266		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	// 9 would be just right, but we want to panic
288	#[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		// Make sure that the first relay parent has the correct state root set
296		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		// No authorities, this is bad!
318		let relay_state_proof = build_relay_chain_storage_proof(None, None);
319
320		// Make sure that the first relay parent has the correct state root set
321		let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
322		// Expected number of parents passed to the function does not include actual relay parent
323		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		// Parent hash does not point to the proper parent, incomplete chain
342		header_to_modify.parent_hash = H256::repeat_byte(0x9);
343		let relay_state_proof = build_relay_chain_storage_proof(Some(authorities), None);
344
345		// Make sure that the first relay parent has the correct state root set
346		let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
347		// Expected number of parents passed to the function does not include actual relay parent
348		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		// Pop the seal of the last descendant and put some invalid signature into the digests
373		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		// Make sure that the first relay parent has the correct state root set
383		let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
384		// Expected number of parents passed to the function does not include actual relay parent
385		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		// Make sure that the first relay parent has the correct state root set
412		let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
413		// Expected number of parents passed to the function does not include actual relay parent
414		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		// Make sure that the first relay parent has the correct state root set
443		let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
444		// Expected number of parents passed to the function does not include actual relay parent
445		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	/// Test some interesting epoch change positions, like epoch change on RP directly, and last
457	/// block.
458	#[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		// Make sure that the first relay parent has the correct state root set
469		let relay_parent_state_root = relay_parent_descendants.get(0).unwrap().state_root;
470		// Expected number of parents passed to the function does not include actual relay parent
471		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	/// Helper function to create a mock `RelayChainStateProof`.
483	fn build_relay_chain_storage_proof(
484		authorities: Option<Vec<(AuthorityId, BabeAuthorityWeight)>>,
485		next_authorities: Option<Vec<(AuthorityId, BabeAuthorityWeight)>>,
486	) -> RelayChainStateProof {
487		// Create a mock implementation or structure, adjust this to match the proof's definition
488		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	/// This method generates some vrf data, but only to make the compiler happy.
506	/// This data is not verified and we don't care :).
507	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	/// Build a chain of relay parent descendants.
517	///
518	/// Returns the relay parent header as well as the current and next epoch authorities.
519	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		// Generate initial authorities
529		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		// Generate headers chain
534		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
543			add_pre_digest(&mut header, authority_index, block_number);
544
545			// Handle epoch change if needed
546			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			// Sign and seal header
554			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	// Helper functions
566	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}