Add equivocation detector crate and implement clients (#2348) (#2353)

* Split FinalitySyncPipeline and SourceClient

* Move some logic to finality_base

* Add empty equivocation detection clients

* Add equivocation reporting logic to the source client

* Use convenience trait for SubstrateFinalitySyncPipeline

* Define JustificationVerificationContext for GRANDPA

* Equivocation source client: finality_verification_context()

* Equivocation source client: synced_headers_finality_info()

* reuse HeaderFinalityInfo

* Define EquivocationsFinder

* Fix spellcheck

* Address review comments

* Avoid equivocations lookup errors
This commit is contained in:
Serban Iorga
2023-08-16 08:20:09 +03:00
committed by Bastian Köcher
parent 9bfad80664
commit 48cae06a77
35 changed files with 931 additions and 375 deletions
@@ -25,19 +25,18 @@ type TestHeader = sp_runtime::testing::Header;
#[test]
fn duplicate_votes_are_not_considered_equivocations() {
let voter_set = voter_set();
let verification_context = verification_context(TEST_GRANDPA_SET_ID);
let base_justification = make_default_justification::<TestHeader>(&test_header(1));
let mut collector =
EquivocationsCollector::new(TEST_GRANDPA_SET_ID, &voter_set, &base_justification).unwrap();
collector.parse_justification(&base_justification.clone()).unwrap();
EquivocationsCollector::new(&verification_context, &base_justification).unwrap();
collector.parse_justifications(&[base_justification.clone()]);
assert_eq!(collector.into_equivocation_proofs().len(), 0);
}
#[test]
fn equivocations_are_detected_in_base_justification_redundant_votes() {
let voter_set = voter_set();
let mut base_justification = make_default_justification::<TestHeader>(&test_header(1));
let first_vote = base_justification.commit.precommits[0].clone();
@@ -49,8 +48,9 @@ fn equivocations_are_detected_in_base_justification_redundant_votes() {
);
base_justification.commit.precommits.push(equivocation.clone());
let verification_context = verification_context(TEST_GRANDPA_SET_ID);
let collector =
EquivocationsCollector::new(TEST_GRANDPA_SET_ID, &voter_set, &base_justification).unwrap();
EquivocationsCollector::new(&verification_context, &base_justification).unwrap();
assert_eq!(
collector.into_equivocation_proofs(),
@@ -80,7 +80,6 @@ fn equivocations_are_detected_in_base_justification_redundant_votes() {
#[test]
fn equivocations_are_detected_in_extra_justification_redundant_votes() {
let voter_set = voter_set();
let base_justification = make_default_justification::<TestHeader>(&test_header(1));
let first_vote = base_justification.commit.precommits[0].clone();
@@ -93,9 +92,10 @@ fn equivocations_are_detected_in_extra_justification_redundant_votes() {
);
extra_justification.commit.precommits.push(equivocation.clone());
let verification_context = verification_context(TEST_GRANDPA_SET_ID);
let mut collector =
EquivocationsCollector::new(TEST_GRANDPA_SET_ID, &voter_set, &base_justification).unwrap();
collector.parse_justification(&extra_justification).unwrap();
EquivocationsCollector::new(&verification_context, &base_justification).unwrap();
collector.parse_justifications(&[extra_justification]);
assert_eq!(
collector.into_equivocation_proofs(),
@@ -30,8 +30,7 @@ fn optimizer_does_noting_with_minimal_justification() {
let num_precommits_before = justification.commit.precommits.len();
verify_and_optimize_justification::<TestHeader>(
header_id::<TestHeader>(1),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&mut justification,
)
.unwrap();
@@ -53,8 +52,7 @@ fn unknown_authority_votes_are_removed_by_optimizer() {
let num_precommits_before = justification.commit.precommits.len();
verify_and_optimize_justification::<TestHeader>(
header_id::<TestHeader>(1),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&mut justification,
)
.unwrap();
@@ -74,8 +72,7 @@ fn duplicate_authority_votes_are_removed_by_optimizer() {
let num_precommits_before = justification.commit.precommits.len();
verify_and_optimize_justification::<TestHeader>(
header_id::<TestHeader>(1),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&mut justification,
)
.unwrap();
@@ -105,8 +102,7 @@ fn invalid_authority_signatures_are_removed_by_optimizer() {
let num_precommits_before = justification.commit.precommits.len();
verify_and_optimize_justification::<TestHeader>(
header_id::<TestHeader>(1),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&mut justification,
)
.unwrap();
@@ -128,8 +124,7 @@ fn redundant_authority_votes_are_removed_by_optimizer() {
let num_precommits_before = justification.commit.precommits.len();
verify_and_optimize_justification::<TestHeader>(
header_id::<TestHeader>(1),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&mut justification,
)
.unwrap();
@@ -154,8 +149,7 @@ fn unrelated_ancestry_votes_are_removed_by_optimizer() {
let num_precommits_before = justification.commit.precommits.len();
verify_and_optimize_justification::<TestHeader>(
header_id::<TestHeader>(2),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&mut justification,
)
.unwrap();
@@ -172,8 +166,7 @@ fn redundant_votes_ancestries_are_removed_by_optimizer() {
let num_votes_ancestries_before = justification.votes_ancestries.len();
verify_and_optimize_justification::<TestHeader>(
header_id::<TestHeader>(1),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&mut justification,
)
.unwrap();
@@ -17,8 +17,8 @@
//! Tests for Grandpa strict justification verifier code.
use bp_header_chain::justification::{
required_justification_precommits, verify_justification, JustificationVerificationError,
PrecommitError,
required_justification_precommits, verify_justification, JustificationVerificationContext,
JustificationVerificationError, PrecommitError,
};
use bp_test_utils::*;
@@ -40,8 +40,7 @@ fn valid_justification_accepted() {
assert_eq!(
verify_justification::<TestHeader>(
header_id::<TestHeader>(1),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&justification,
),
Ok(()),
@@ -65,8 +64,7 @@ fn valid_justification_accepted_with_single_fork() {
assert_eq!(
verify_justification::<TestHeader>(
header_id::<TestHeader>(1),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&make_justification_for_header::<TestHeader>(params)
),
Ok(()),
@@ -100,8 +98,7 @@ fn valid_justification_accepted_with_arbitrary_number_of_authorities() {
assert_eq!(
verify_justification::<TestHeader>(
header_id::<TestHeader>(1),
TEST_GRANDPA_SET_ID,
&voter_set,
&JustificationVerificationContext { voter_set, authority_set_id: TEST_GRANDPA_SET_ID },
&make_justification_for_header::<TestHeader>(params)
),
Ok(()),
@@ -113,8 +110,7 @@ fn justification_with_invalid_target_rejected() {
assert_eq!(
verify_justification::<TestHeader>(
header_id::<TestHeader>(2),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&make_default_justification::<TestHeader>(&test_header(1)),
),
Err(JustificationVerificationError::InvalidJustificationTarget),
@@ -129,8 +125,7 @@ fn justification_with_invalid_commit_rejected() {
assert_eq!(
verify_justification::<TestHeader>(
header_id::<TestHeader>(1),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&justification,
),
Err(JustificationVerificationError::TooLowCumulativeWeight),
@@ -146,8 +141,7 @@ fn justification_with_invalid_authority_signature_rejected() {
assert_eq!(
verify_justification::<TestHeader>(
header_id::<TestHeader>(1),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&justification,
),
Err(JustificationVerificationError::Precommit(PrecommitError::InvalidAuthoritySignature)),
@@ -162,8 +156,7 @@ fn justification_with_invalid_precommit_ancestry() {
assert_eq!(
verify_justification::<TestHeader>(
header_id::<TestHeader>(1),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&justification,
),
Err(JustificationVerificationError::RedundantVotesAncestries),
@@ -187,8 +180,7 @@ fn justification_is_invalid_if_we_dont_meet_threshold() {
assert_eq!(
verify_justification::<TestHeader>(
header_id::<TestHeader>(1),
TEST_GRANDPA_SET_ID,
&voter_set(),
&verification_context(TEST_GRANDPA_SET_ID),
&make_justification_for_header::<TestHeader>(params)
),
Err(JustificationVerificationError::TooLowCumulativeWeight),