Skip to content
Snippets Groups Projects
generic.rs 36.6 KiB
Newer Older

		// insert two invalidity votes from authority 2 with different signatures
		{
			let statement = SignedStatement {
				statement: Statement::Invalid(Digest(100)),
				signature: Signature(3),
				sender: AuthorityId(3),
			};

			table.import_statement(&context, statement);
			assert!(!table.detected_misbehavior.contains_key(&AuthorityId(3)));

			let invalid_statement = SignedStatement {
				statement: Statement::Invalid(Digest(100)),
				signature: Signature(333),
				sender: AuthorityId(3),
			};

			table.import_statement(&context, invalid_statement);
			assert!(table.detected_misbehavior.contains_key(&AuthorityId(3)));
		}
	}

	#[test]
	fn issue_and_vote_is_misbehavior() {
		let context = TestContext {
			authorities: {
				let mut map = HashMap::new();
				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
				map
			}
		};

		let mut table = create();
		let statement = SignedStatement {
			statement: Statement::Candidate(Candidate(2, 100)),
			signature: Signature(1),
			sender: AuthorityId(1),
		};
		let candidate_digest = Digest(100);

		table.import_statement(&context, statement);
		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));

		let extra_vote = SignedStatement {
			statement: Statement::Valid(candidate_digest.clone()),
			signature: Signature(1),
			sender: AuthorityId(1),
		};

		table.import_statement(&context, extra_vote);
		assert_eq!(
			table.detected_misbehavior.get(&AuthorityId(1)).unwrap(),
			&Misbehavior::ValidityDoubleVote(ValidityDoubleVote::IssuedAndValidity(
				(Candidate(2, 100), Signature(1)),
				(Digest(100), Signature(1)),
			))
		);
	}

	#[test]
	fn candidate_can_be_included() {
		let validity_threshold = 6;
		let availability_threshold = 34;

		let mut candidate = CandidateData::<TestContext> {
			group_id: GroupId(4),
			candidate: Candidate(4, 12345),
			validity_votes: HashMap::new(),
			availability_votes: HashMap::new(),
			indicated_bad_by: Vec::new(),
		};

		assert!(!candidate.can_be_included(validity_threshold, availability_threshold));

		for i in 0..validity_threshold {
			candidate.validity_votes.insert(AuthorityId(i + 100), ValidityVote::Valid(Signature(i + 100)));
		}

		assert!(!candidate.can_be_included(validity_threshold, availability_threshold));

		for i in 0..availability_threshold {
			candidate.availability_votes.insert(AuthorityId(i + 255), Signature(i + 255));
		}

		assert!(candidate.can_be_included(validity_threshold, availability_threshold));

		candidate.indicated_bad_by.push(AuthorityId(1024));

		assert!(!candidate.can_be_included(validity_threshold, availability_threshold));
	}

	#[test]
	fn includability_counter() {
		let context = TestContext {
			authorities: {
				let mut map = HashMap::new();
				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
				map.insert(AuthorityId(2), (GroupId(2), GroupId(455)));
				map.insert(AuthorityId(3), (GroupId(2), GroupId(455)));
				map.insert(AuthorityId(4), (GroupId(455), GroupId(2)));
				map
			}
		};

		// have 2/3 validity guarantors note validity.
		let mut table = create();
		let statement = SignedStatement {
			statement: Statement::Candidate(Candidate(2, 100)),
			signature: Signature(1),
			sender: AuthorityId(1),
		};
		let candidate_digest = Digest(100);

		table.import_statement(&context, statement);
		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));
		assert!(!table.candidate_includable(&candidate_digest, &context));
		assert!(table.includable_count.is_empty());

		let vote = SignedStatement {
			statement: Statement::Valid(candidate_digest.clone()),
			signature: Signature(2),
			sender: AuthorityId(2),
		};

		table.import_statement(&context, vote);
		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2)));
		assert!(!table.candidate_includable(&candidate_digest, &context));
		assert!(table.includable_count.is_empty());

		// have the availability guarantor note validity.
		let vote = SignedStatement {
			statement: Statement::Available(candidate_digest.clone()),
			signature: Signature(4),
			sender: AuthorityId(4),
		};

		table.import_statement(&context, vote);
		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(4)));
		assert!(table.candidate_includable(&candidate_digest, &context));
		assert!(table.includable_count.get(&GroupId(2)).is_some());

		// have the last validity guarantor note invalidity. now it is unincludable.
		let vote = SignedStatement {
			statement: Statement::Invalid(candidate_digest.clone()),
			signature: Signature(3),
			sender: AuthorityId(3),
		};

		table.import_statement(&context, vote);
		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2)));
		assert!(!table.candidate_includable(&candidate_digest, &context));
		assert!(table.includable_count.is_empty());
	}

	#[test]
	fn candidate_import_gives_summary() {
		let context = TestContext {
			authorities: {
				let mut map = HashMap::new();
				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
				map
			}
		};

		let mut table = create();
		let statement = SignedStatement {
			statement: Statement::Candidate(Candidate(2, 100)),
			signature: Signature(1),
			sender: AuthorityId(1),
		};

		let summary = table.import_statement(&context, statement)
			.expect("candidate import to give summary");

		assert_eq!(summary.candidate, Digest(100));
		assert_eq!(summary.group_id, GroupId(2));
		assert_eq!(summary.validity_votes, 1);
		assert_eq!(summary.availability_votes, 0);
	}

	#[test]
	fn candidate_vote_gives_summary() {
		let context = TestContext {
			authorities: {
				let mut map = HashMap::new();
				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
				map.insert(AuthorityId(2), (GroupId(2), GroupId(455)));
				map
			}
		};

		let mut table = create();
		let statement = SignedStatement {
			statement: Statement::Candidate(Candidate(2, 100)),
			signature: Signature(1),
			sender: AuthorityId(1),
		};
		let candidate_digest = Digest(100);

		table.import_statement(&context, statement);
		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));

		let vote = SignedStatement {
			statement: Statement::Valid(candidate_digest.clone()),
			signature: Signature(2),
			sender: AuthorityId(2),
		};

		let summary = table.import_statement(&context, vote)
			.expect("candidate vote to give summary");

		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2)));

		assert_eq!(summary.candidate, Digest(100));
		assert_eq!(summary.group_id, GroupId(2));
		assert_eq!(summary.validity_votes, 2);
		assert_eq!(summary.availability_votes, 0);
	}

	#[test]
	fn availability_vote_gives_summary() {
		let context = TestContext {
			authorities: {
				let mut map = HashMap::new();
				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
				map.insert(AuthorityId(2), (GroupId(5), GroupId(2)));
				map
			}
		};

		let mut table = create();
		let statement = SignedStatement {
			statement: Statement::Candidate(Candidate(2, 100)),
			signature: Signature(1),
			sender: AuthorityId(1),
		};
		let candidate_digest = Digest(100);

		table.import_statement(&context, statement);
		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));

		let vote = SignedStatement {
			statement: Statement::Available(candidate_digest.clone()),
			signature: Signature(2),
			sender: AuthorityId(2),
		};

		let summary = table.import_statement(&context, vote)
			.expect("candidate vote to give summary");

		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2)));

		assert_eq!(summary.candidate, Digest(100));
		assert_eq!(summary.group_id, GroupId(2));
		assert_eq!(summary.validity_votes, 1);
		assert_eq!(summary.availability_votes, 1);
	}
}