mod.rs 74.1 KiB
Newer Older
		/// Every time a new feature flag is assigned it should take this value.
		/// and this should be incremented.
		FirstUnassigned = 2,
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use bitvec::bitvec;
	use primitives::sr25519;

	pub fn dummy_committed_candidate_receipt() -> CommittedCandidateReceipt {
		let zeros = Hash::zero();

		CommittedCandidateReceipt {
			descriptor: CandidateDescriptor {
				para_id: 0.into(),
				relay_parent: zeros,
				collator: CollatorId::from(sr25519::Public::default()),
				persisted_validation_data_hash: zeros,
				pov_hash: zeros,
				erasure_root: zeros,
				signature: CollatorSignature::from(sr25519::Signature::default()),
				para_head: zeros,
				validation_code_hash: ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]).hash(),
			},
			commitments: CandidateCommitments {
				head_data: HeadData(vec![]),
				upward_messages: vec![].try_into().expect("empty vec fits within bounds"),
				new_validation_code: None,
				horizontal_messages: vec![].try_into().expect("empty vec fits within bounds"),
				processed_downward_messages: 0,
				hrmp_watermark: 0_u32,
			},
		}
	}

	#[test]
	fn group_rotation_info_calculations() {
		let info =
			GroupRotationInfo { session_start_block: 10u32, now: 15, group_rotation_frequency: 5 };

		assert_eq!(info.next_rotation_at(), 20);
		assert_eq!(info.last_rotation_at(), 15);
	}

	#[test]
	fn group_for_core_is_core_for_group() {
		for cores in 1..=256 {
			for rotations in 0..(cores * 2) {
				let info = GroupRotationInfo {
					session_start_block: 0u32,
					now: rotations,
					group_rotation_frequency: 1,
				};

				for core in 0..cores {
					let group = info.group_for_core(CoreIndex(core), cores as usize);
					assert_eq!(info.core_for_group(group, cores as usize).0, core);
				}
			}
		}
	}

	#[test]
	fn collator_signature_payload_is_valid() {
		// if this fails, collator signature verification code has to be updated.
		let h = Hash::default();
		assert_eq!(h.as_ref().len(), 32);

		let _payload = collator_signature_payload(
			&Hash::repeat_byte(1),
			&5u32.into(),
			&Hash::repeat_byte(2),
			&Hash::repeat_byte(3),
			&Hash::repeat_byte(4).into(),
		);
	}

	#[test]
	fn test_byzantine_threshold() {
		assert_eq!(byzantine_threshold(0), 0);
		assert_eq!(byzantine_threshold(1), 0);
		assert_eq!(byzantine_threshold(2), 0);
		assert_eq!(byzantine_threshold(3), 0);
		assert_eq!(byzantine_threshold(4), 1);
		assert_eq!(byzantine_threshold(5), 1);
		assert_eq!(byzantine_threshold(6), 1);
		assert_eq!(byzantine_threshold(7), 2);
	}

	#[test]
	fn test_supermajority_threshold() {
		assert_eq!(supermajority_threshold(0), 0);
		assert_eq!(supermajority_threshold(1), 1);
		assert_eq!(supermajority_threshold(2), 2);
		assert_eq!(supermajority_threshold(3), 3);
		assert_eq!(supermajority_threshold(4), 3);
		assert_eq!(supermajority_threshold(5), 4);
		assert_eq!(supermajority_threshold(6), 5);
		assert_eq!(supermajority_threshold(7), 5);
	}

	#[test]
	fn balance_bigger_than_usize() {
		let zero_b: Balance = 0;
		let zero_u: usize = 0;

		assert!(zero_b.leading_zeros() >= zero_u.leading_zeros());

	#[test]
	fn test_backed_candidate_injected_core_index() {
		let initial_validator_indices = bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1];
		let mut candidate = BackedCandidate::new(
			dummy_committed_candidate_receipt(),
			vec![],
			initial_validator_indices.clone(),
			None,
		);

		// No core index supplied, ElasticScalingMVP is off.
		let (validator_indices, core_index) = candidate.validator_indices_and_core_index(false);
		assert_eq!(validator_indices, initial_validator_indices.as_bitslice());
		assert!(core_index.is_none());

		// No core index supplied, ElasticScalingMVP is on. Still, decoding will be ok if backing
		// group size is <= 8, to give a chance to parachains that don't have multiple cores
		// assigned.
		let (validator_indices, core_index) = candidate.validator_indices_and_core_index(true);
		assert_eq!(validator_indices, initial_validator_indices.as_bitslice());
		assert!(core_index.is_none());

		let encoded_validator_indices = candidate.validator_indices.clone();
		candidate.set_validator_indices_and_core_index(validator_indices.into(), core_index);
		assert_eq!(candidate.validator_indices, encoded_validator_indices);

		// No core index supplied, ElasticScalingMVP is on. Decoding is corrupted if backing group
		// size larger than 8.
		let candidate = BackedCandidate::new(
			dummy_committed_candidate_receipt(),
			vec![],
			bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1, 0, 1, 0, 1, 0],
			None,
		);
		let (validator_indices, core_index) = candidate.validator_indices_and_core_index(true);
		assert_eq!(validator_indices, bitvec![u8, bitvec::order::Lsb0; 0].as_bitslice());
		assert!(core_index.is_some());

		// Core index supplied, ElasticScalingMVP is off. Core index will be treated as normal
		// validator indices. Runtime will check against this.
		let candidate = BackedCandidate::new(
			dummy_committed_candidate_receipt(),
			vec![],
			bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1],
			Some(CoreIndex(10)),
		);
		let (validator_indices, core_index) = candidate.validator_indices_and_core_index(false);
		assert_eq!(
			validator_indices,
			bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0]
		);
		assert!(core_index.is_none());

		// Core index supplied, ElasticScalingMVP is on.
		let mut candidate = BackedCandidate::new(
			dummy_committed_candidate_receipt(),
			vec![],
			bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1],
			Some(CoreIndex(10)),
		);
		let (validator_indices, core_index) = candidate.validator_indices_and_core_index(true);
		assert_eq!(validator_indices, bitvec![u8, bitvec::order::Lsb0; 0, 1, 0, 1]);
		assert_eq!(core_index, Some(CoreIndex(10)));

		let encoded_validator_indices = candidate.validator_indices.clone();
		candidate.set_validator_indices_and_core_index(validator_indices.into(), core_index);
		assert_eq!(candidate.validator_indices, encoded_validator_indices);
	}