mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 14:31:02 +00:00
Some late short-term fixes for dispute slashing (#6249)
* disputes/slashing: slash only backers for ForInvalid * add an assertion in mock impl * fix tests * do not slash backers on onconcluded disputes * slash an intersection of backers and losers * zombienet/disputes: check for offence only for invalid disputes * add backing votes to disputes bench builder * Update runtime/parachains/src/builder.rs * Brad implementers guide revisions 2 (#6239) * Add disputes subsystems fix * Updated dispute approval vote import reasoning * Improved wording of my changes * Resolving issues brought up in comments * Update disputes prioritisation in `dispute-coordinator` (#6130) * Scraper processes CandidateBacked events * Change definition of best-effort * Fix `dispute-coordinator` tests * Unit test for dispute filtering * Clarification comment * Add tests * Fix logic If a dispute is not backed, not included and not confirmed we don't participate but we do import votes. * Add metrics for refrained participations * Revert "Add tests" This reverts commit 7b8391a087922ced942cde9cd2b50ff3f633efc0. * Revert "Unit test for dispute filtering" This reverts commit 92ba5fe678214ab360306313a33c781338e600a0. * fix dispute-coordinator tests * Fix scraping * new tests * Small fixes in guide * Apply suggestions from code review Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> * Fix some comments and remove a pointless test * Code review feedback * Clarification comment in tests * Some tests * Reference counted `CandidateHash` in scraper * Proper handling for Backed and Included candidates in scraper Backed candidates which are not included should be kept for a predetermined window of finalized blocks. E.g. if a candidate is backed but not included in block 2, and the window size is 2, the same candidate should be cleaned after block 4 is finalized. Add reference counting for candidates in scraper. A candidate can be added on multiple block heights so we have to make sure we don't clean it prematurely from the scraper. Add tests. * Update comments in tests * Guide update * Fix cleanup logic for `backed_candidates_by_block_number` * Simplify cleanup * Make spellcheck happy * Update tests * Extract candidate backing logic in separate struct * Code review feedback * Treat backed and included candidates in the same fashion * Update some comments * Small improvements in test * spell check * Fix some more comments * clean -> prune * Code review feedback * Reword comment * spelling Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> * approval-voting: remove redundant validation check (#6266) * approval-voting: remove a redundant check * candidate-validation: remove unreachable check * remove fill_block (#6200) Co-authored-by: parity-processbot <> * fix a compilation warning (#6279) Fixes #6277. * Only report concluded if there is an actual dispute. (#6270) * Only report concluded if there is an actual dispute. Hence no "non"-disputes will be added to disputes anymore. * Fix redundant check. * Test for no onesided disputes. Co-authored-by: eskimor <eskimor@no-such-url.com> * [ci] fix buildah image (#6281) * Revert special casing of Kusama for grandpa rounds. (#6217) Co-authored-by: eskimor <eskimor@no-such-url.com> * Fixes "for loop over an `Option`" warnings (#6291) Was seeing these warnings when running `cargo check --all`: ``` warning: for loop over an `Option`. This is more readably written as an `if let` statement --> node/core/approval-voting/src/lib.rs:1147:21 | 1147 | for activated in update.activated { | ^^^^^^^^^^^^^^^^ | = note: `#[warn(for_loops_over_fallibles)]` on by default help: to check pattern in a loop use `while let` | 1147 | while let Some(activated) = update.activated { | ~~~~~~~~~~~~~~~ ~~~ help: consider using `if let` to clear intent | 1147 | if let Some(activated) = update.activated { | ~~~~~~~~~~~~ ~~~ ``` My guess is that `activated` used to be a SmallVec or similar, as is `deactivated`. It was changed to an `Option`, the `for` still compiled (it's technically correct, just weird), and the compiler didn't catch it until now. * companion for #12599 (#6290) * companion for #12599 * update Cargo.lock * use cargo path instead of diener * update lockfile for {"substrate"} Co-authored-by: parity-processbot <> * remove the runtime check and test * append keys on past-session slashing * runtime/disputes: allow importing backing votes after explicit for * explicit MaliciousBacker error and a test * update an outdated comment * Revert "update an outdated comment" This reverts commit 7c4c3f5a848f16e2b61435e981d814f00333ed41. * Revert "remove the runtime check and test" This reverts commit a5bff0c75e77effb5b7d3a1691de1b14bcdbd648. * incremental punishment post conclusion + test * punish backers post FOR vote * remove unnecessary lifetime annotation * add a comment to zombinet test * typo * fmt * post merge test fixes * fix test after changes in master * address review nits --------- Co-authored-by: Bradley Olson <34992650+BradleyOlson64@users.noreply.github.com> Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Co-authored-by: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Co-authored-by: eskimor <eskimor@users.noreply.github.com> Co-authored-by: eskimor <eskimor@no-such-url.com> Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Co-authored-by: Marcin S <marcin@bytedude.com> Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com>
This commit is contained in:
@@ -20,7 +20,8 @@ use crate::{
|
||||
disputes::DisputesHandler,
|
||||
mock::{
|
||||
new_test_ext, AccountId, AllPalletsWithSystem, Initializer, MockGenesisConfig, System,
|
||||
Test, PUNISH_VALIDATORS_AGAINST, PUNISH_VALIDATORS_FOR, REWARD_VALIDATORS,
|
||||
Test, PUNISH_BACKERS_FOR, PUNISH_VALIDATORS_AGAINST, PUNISH_VALIDATORS_FOR,
|
||||
REWARD_VALIDATORS,
|
||||
},
|
||||
};
|
||||
use frame_support::{
|
||||
@@ -30,6 +31,10 @@ use frame_support::{
|
||||
use primitives::BlockNumber;
|
||||
use sp_core::{crypto::CryptoType, Pair};
|
||||
|
||||
const VOTE_FOR: VoteKind = VoteKind::ExplicitValid;
|
||||
const VOTE_AGAINST: VoteKind = VoteKind::Invalid;
|
||||
const VOTE_BACKING: VoteKind = VoteKind::Backing;
|
||||
|
||||
fn filter_dispute_set(stmts: MultiDisputeStatementSet) -> CheckedMultiDisputeStatementSet {
|
||||
let config = <configuration::Pallet<Test>>::config();
|
||||
let post_conclusion_acceptance_period = config.dispute_post_conclusion_acceptance_period;
|
||||
@@ -138,22 +143,26 @@ fn test_import_new_participant() {
|
||||
start: 0,
|
||||
concluded_at: None,
|
||||
},
|
||||
BTreeSet::new(),
|
||||
0,
|
||||
);
|
||||
|
||||
assert_err!(
|
||||
importer.import(ValidatorIndex(9), true),
|
||||
importer.import(ValidatorIndex(9), VOTE_FOR),
|
||||
VoteImportError::ValidatorIndexOutOfBounds,
|
||||
);
|
||||
|
||||
assert_err!(importer.import(ValidatorIndex(0), true), VoteImportError::DuplicateStatement);
|
||||
assert_ok!(importer.import(ValidatorIndex(0), false));
|
||||
assert_err!(importer.import(ValidatorIndex(0), VOTE_FOR), VoteImportError::DuplicateStatement);
|
||||
assert_ok!(importer.import(ValidatorIndex(0), VOTE_AGAINST));
|
||||
|
||||
assert_ok!(importer.import(ValidatorIndex(2), true));
|
||||
assert_err!(importer.import(ValidatorIndex(2), true), VoteImportError::DuplicateStatement);
|
||||
assert_ok!(importer.import(ValidatorIndex(2), VOTE_FOR));
|
||||
assert_err!(importer.import(ValidatorIndex(2), VOTE_FOR), VoteImportError::DuplicateStatement);
|
||||
|
||||
assert_ok!(importer.import(ValidatorIndex(2), false));
|
||||
assert_err!(importer.import(ValidatorIndex(2), false), VoteImportError::DuplicateStatement);
|
||||
assert_ok!(importer.import(ValidatorIndex(2), VOTE_AGAINST));
|
||||
assert_err!(
|
||||
importer.import(ValidatorIndex(2), VOTE_AGAINST),
|
||||
VoteImportError::DuplicateStatement
|
||||
);
|
||||
|
||||
let summary = importer.finish();
|
||||
assert_eq!(summary.new_flags, DisputeStateFlags::default());
|
||||
@@ -180,10 +189,11 @@ fn test_import_prev_participant_confirmed() {
|
||||
start: 0,
|
||||
concluded_at: None,
|
||||
},
|
||||
BTreeSet::new(),
|
||||
0,
|
||||
);
|
||||
|
||||
assert_ok!(importer.import(ValidatorIndex(2), true));
|
||||
assert_ok!(importer.import(ValidatorIndex(2), VOTE_FOR));
|
||||
|
||||
let summary = importer.finish();
|
||||
assert_eq!(
|
||||
@@ -211,15 +221,16 @@ fn test_import_prev_participant_confirmed_slash_for() {
|
||||
start: 0,
|
||||
concluded_at: None,
|
||||
},
|
||||
BTreeSet::new(),
|
||||
0,
|
||||
);
|
||||
|
||||
assert_ok!(importer.import(ValidatorIndex(2), true));
|
||||
assert_ok!(importer.import(ValidatorIndex(2), false));
|
||||
assert_ok!(importer.import(ValidatorIndex(3), false));
|
||||
assert_ok!(importer.import(ValidatorIndex(4), false));
|
||||
assert_ok!(importer.import(ValidatorIndex(5), false));
|
||||
assert_ok!(importer.import(ValidatorIndex(6), false));
|
||||
assert_ok!(importer.import(ValidatorIndex(2), VOTE_FOR));
|
||||
assert_ok!(importer.import(ValidatorIndex(2), VOTE_AGAINST));
|
||||
assert_ok!(importer.import(ValidatorIndex(3), VOTE_AGAINST));
|
||||
assert_ok!(importer.import(ValidatorIndex(4), VOTE_AGAINST));
|
||||
assert_ok!(importer.import(ValidatorIndex(5), VOTE_AGAINST));
|
||||
assert_ok!(importer.import(ValidatorIndex(6), VOTE_AGAINST));
|
||||
|
||||
let summary = importer.finish();
|
||||
assert_eq!(
|
||||
@@ -250,14 +261,15 @@ fn test_import_slash_against() {
|
||||
start: 0,
|
||||
concluded_at: None,
|
||||
},
|
||||
BTreeSet::new(),
|
||||
0,
|
||||
);
|
||||
|
||||
assert_ok!(importer.import(ValidatorIndex(3), true));
|
||||
assert_ok!(importer.import(ValidatorIndex(4), true));
|
||||
assert_ok!(importer.import(ValidatorIndex(5), false));
|
||||
assert_ok!(importer.import(ValidatorIndex(6), true));
|
||||
assert_ok!(importer.import(ValidatorIndex(7), true));
|
||||
assert_ok!(importer.import(ValidatorIndex(3), VOTE_FOR));
|
||||
assert_ok!(importer.import(ValidatorIndex(4), VOTE_FOR));
|
||||
assert_ok!(importer.import(ValidatorIndex(5), VOTE_AGAINST));
|
||||
assert_ok!(importer.import(ValidatorIndex(6), VOTE_FOR));
|
||||
assert_ok!(importer.import(ValidatorIndex(7), VOTE_FOR));
|
||||
|
||||
let summary = importer.finish();
|
||||
assert_eq!(
|
||||
@@ -275,6 +287,48 @@ fn test_import_slash_against() {
|
||||
assert_eq!(summary.new_flags, DisputeStateFlags::FOR_SUPERMAJORITY);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_import_backing_votes() {
|
||||
let mut importer = DisputeStateImporter::new(
|
||||
DisputeState {
|
||||
validators_for: bitvec![u8, BitOrderLsb0; 1, 0, 1, 0, 0, 0, 0, 0],
|
||||
validators_against: bitvec![u8, BitOrderLsb0; 0, 1, 0, 0, 0, 0, 0, 0],
|
||||
start: 0,
|
||||
concluded_at: None,
|
||||
},
|
||||
BTreeSet::from_iter([ValidatorIndex(0)]),
|
||||
0,
|
||||
);
|
||||
|
||||
assert_ok!(importer.import(ValidatorIndex(3), VOTE_FOR));
|
||||
assert_ok!(importer.import(ValidatorIndex(3), VOTE_BACKING));
|
||||
assert_ok!(importer.import(ValidatorIndex(3), VOTE_AGAINST));
|
||||
assert_ok!(importer.import(ValidatorIndex(6), VOTE_FOR));
|
||||
assert_ok!(importer.import(ValidatorIndex(7), VOTE_BACKING));
|
||||
// Don't import backing vote twice
|
||||
assert_err!(
|
||||
importer.import(ValidatorIndex(0), VOTE_BACKING),
|
||||
VoteImportError::DuplicateStatement,
|
||||
);
|
||||
// Don't import explicit votes after backing
|
||||
assert_err!(importer.import(ValidatorIndex(7), VOTE_FOR), VoteImportError::MaliciousBacker,);
|
||||
|
||||
let summary = importer.finish();
|
||||
assert_eq!(
|
||||
summary.state,
|
||||
DisputeState {
|
||||
validators_for: bitvec![u8, BitOrderLsb0; 1, 0, 1, 1, 0, 0, 1, 1],
|
||||
validators_against: bitvec![u8, BitOrderLsb0; 0, 1, 0, 1, 0, 0, 0, 0],
|
||||
start: 0,
|
||||
concluded_at: None,
|
||||
},
|
||||
);
|
||||
assert_eq!(
|
||||
summary.backers,
|
||||
BTreeSet::from_iter([ValidatorIndex(0), ValidatorIndex(3), ValidatorIndex(7),]),
|
||||
);
|
||||
}
|
||||
|
||||
// Test that dispute timeout is handled correctly.
|
||||
#[test]
|
||||
fn test_dispute_timeout() {
|
||||
@@ -329,6 +383,7 @@ fn test_dispute_timeout() {
|
||||
});
|
||||
|
||||
let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1));
|
||||
let inclusion_parent = sp_core::H256::repeat_byte(0xff);
|
||||
|
||||
// v0 and v1 vote for 3, v2 against. We need f+1 votes (3) so that the dispute is
|
||||
// confirmed. Otherwise It will be filtered out.
|
||||
@@ -338,16 +393,13 @@ fn test_dispute_timeout() {
|
||||
session,
|
||||
statements: vec![
|
||||
(
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::Explicit),
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(
|
||||
inclusion_parent,
|
||||
)),
|
||||
ValidatorIndex(0),
|
||||
v0.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: true,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session: start - 1,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
v0.sign(&CompactStatement::Valid(candidate_hash).signing_payload(
|
||||
&SigningContext { session_index: start - 1, parent_hash: inclusion_parent },
|
||||
)),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::Explicit),
|
||||
@@ -495,21 +547,20 @@ fn test_provide_multi_dispute_is_providing() {
|
||||
});
|
||||
|
||||
let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1));
|
||||
let inclusion_parent = sp_core::H256::repeat_byte(0xff);
|
||||
let session = 1;
|
||||
let stmts = vec![DisputeStatementSet {
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session: 1,
|
||||
session,
|
||||
statements: vec![
|
||||
(
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::Explicit),
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(
|
||||
inclusion_parent,
|
||||
)),
|
||||
ValidatorIndex(0),
|
||||
v0.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: true,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session: 1,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
v0.sign(&CompactStatement::Valid(candidate_hash).signing_payload(
|
||||
&SigningContext { session_index: session, parent_hash: inclusion_parent },
|
||||
)),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit),
|
||||
@@ -518,7 +569,7 @@ fn test_provide_multi_dispute_is_providing() {
|
||||
&ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session: 1,
|
||||
session,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
@@ -538,6 +589,70 @@ fn test_provide_multi_dispute_is_providing() {
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_disputes_with_missing_backing_votes_are_rejected() {
|
||||
new_test_ext(Default::default()).execute_with(|| {
|
||||
let v0 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
let v1 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
|
||||
run_to_block(3, |b| {
|
||||
// a new session at each block
|
||||
if b == 1 {
|
||||
Some((
|
||||
true,
|
||||
b,
|
||||
vec![(&0, v0.public()), (&1, v1.public())],
|
||||
Some(vec![(&0, v0.public()), (&1, v1.public())]),
|
||||
))
|
||||
} else {
|
||||
Some((true, b, vec![(&1, v1.public())], Some(vec![(&1, v1.public())])))
|
||||
}
|
||||
});
|
||||
|
||||
let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1));
|
||||
let session = 1;
|
||||
|
||||
let stmts = vec![DisputeStatementSet {
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session,
|
||||
statements: vec![
|
||||
(
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::Explicit),
|
||||
ValidatorIndex(0),
|
||||
v0.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: true,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit),
|
||||
ValidatorIndex(1),
|
||||
v1.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
),
|
||||
],
|
||||
}];
|
||||
|
||||
assert!(Pallet::<Test>::process_checked_multi_dispute_data(
|
||||
stmts
|
||||
.into_iter()
|
||||
.map(CheckedDisputeStatementSet::unchecked_from_unchecked)
|
||||
.collect()
|
||||
)
|
||||
.is_err(),);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_freeze_on_note_included() {
|
||||
new_test_ext(Default::default()).execute_with(|| {
|
||||
@@ -555,6 +670,8 @@ fn test_freeze_on_note_included() {
|
||||
});
|
||||
|
||||
let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1));
|
||||
let inclusion_parent = sp_core::H256::repeat_byte(0xff);
|
||||
let session = 3;
|
||||
|
||||
// v0 votes for 3
|
||||
let stmts = vec![DisputeStatementSet {
|
||||
@@ -586,16 +703,13 @@ fn test_freeze_on_note_included() {
|
||||
),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::Explicit),
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(
|
||||
inclusion_parent,
|
||||
)),
|
||||
ValidatorIndex(1),
|
||||
v1.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: true,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session: 3,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
v0.sign(&CompactStatement::Valid(candidate_hash).signing_payload(
|
||||
&SigningContext { session_index: session, parent_hash: inclusion_parent },
|
||||
)),
|
||||
),
|
||||
],
|
||||
}];
|
||||
@@ -629,11 +743,13 @@ fn test_freeze_provided_against_supermajority_for_included() {
|
||||
});
|
||||
|
||||
let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1));
|
||||
let inclusion_parent = sp_core::H256::repeat_byte(0xff);
|
||||
let session = 3;
|
||||
|
||||
// v0 votes for 3
|
||||
let stmts = vec![DisputeStatementSet {
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session: 3,
|
||||
session,
|
||||
statements: vec![
|
||||
(
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit),
|
||||
@@ -642,7 +758,7 @@ fn test_freeze_provided_against_supermajority_for_included() {
|
||||
&ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session: 3,
|
||||
session,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
@@ -654,22 +770,19 @@ fn test_freeze_provided_against_supermajority_for_included() {
|
||||
&ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session: 3,
|
||||
session,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::Explicit),
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(
|
||||
inclusion_parent,
|
||||
)),
|
||||
ValidatorIndex(1),
|
||||
v1.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: true,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session: 3,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
v0.sign(&CompactStatement::Valid(candidate_hash).signing_payload(
|
||||
&SigningContext { session_index: session, parent_hash: inclusion_parent },
|
||||
)),
|
||||
),
|
||||
],
|
||||
}];
|
||||
@@ -851,23 +964,22 @@ fn test_provide_multi_dispute_success_and_other() {
|
||||
});
|
||||
|
||||
let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1));
|
||||
let inclusion_parent = sp_core::H256::repeat_byte(0xff);
|
||||
let session = 3;
|
||||
|
||||
// v0 and v1 vote for 3, v6 votes against
|
||||
let stmts = vec![DisputeStatementSet {
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session: 3,
|
||||
session,
|
||||
statements: vec![
|
||||
(
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::Explicit),
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(
|
||||
inclusion_parent,
|
||||
)),
|
||||
ValidatorIndex(0),
|
||||
v0.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: true,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session: 3,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
v0.sign(&CompactStatement::Valid(candidate_hash).signing_payload(
|
||||
&SigningContext { session_index: session, parent_hash: inclusion_parent },
|
||||
)),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit),
|
||||
@@ -876,7 +988,7 @@ fn test_provide_multi_dispute_success_and_other() {
|
||||
&ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session: 3,
|
||||
session,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
@@ -926,16 +1038,13 @@ fn test_provide_multi_dispute_success_and_other() {
|
||||
session: 5,
|
||||
statements: vec![
|
||||
(
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::Explicit),
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(
|
||||
inclusion_parent,
|
||||
)),
|
||||
ValidatorIndex(5),
|
||||
v3.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: true,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session: 5,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
v3.sign(&CompactStatement::Valid(candidate_hash).signing_payload(
|
||||
&SigningContext { session_index: 5, parent_hash: inclusion_parent },
|
||||
)),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit),
|
||||
@@ -1141,6 +1250,211 @@ fn test_provide_multi_dispute_success_and_other() {
|
||||
})
|
||||
}
|
||||
|
||||
/// In this setup we have only one dispute concluding AGAINST.
|
||||
/// There are some votes imported post dispute conclusion.
|
||||
/// We make sure these votes are accounted for in punishment.
|
||||
#[test]
|
||||
fn test_punish_post_conclusion() {
|
||||
new_test_ext(Default::default()).execute_with(|| {
|
||||
// supermajority threshold is 5
|
||||
let v0 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
let v1 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
let v2 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
let v3 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
let v4 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
let v5 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
let v6 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
// Mapping between key pair and `ValidatorIndex`
|
||||
// v0 -> 0
|
||||
// v1 -> 3
|
||||
// v2 -> 6
|
||||
// v3 -> 5
|
||||
// v4 -> 1
|
||||
// v5 -> 4
|
||||
// v6 -> 2
|
||||
|
||||
run_to_block(6, |b| {
|
||||
// a new session at each block
|
||||
Some((
|
||||
true,
|
||||
b,
|
||||
vec![
|
||||
(&0, v0.public()),
|
||||
(&1, v1.public()),
|
||||
(&2, v2.public()),
|
||||
(&3, v3.public()),
|
||||
(&4, v4.public()),
|
||||
(&5, v5.public()),
|
||||
(&6, v6.public()),
|
||||
],
|
||||
Some(vec![
|
||||
(&0, v0.public()),
|
||||
(&1, v1.public()),
|
||||
(&2, v2.public()),
|
||||
(&3, v3.public()),
|
||||
(&4, v4.public()),
|
||||
(&5, v5.public()),
|
||||
(&6, v6.public()),
|
||||
]),
|
||||
))
|
||||
});
|
||||
|
||||
let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1));
|
||||
let inclusion_parent = sp_core::H256::repeat_byte(0xff);
|
||||
let session = 3;
|
||||
|
||||
let stmts = vec![DisputeStatementSet {
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session,
|
||||
statements: vec![
|
||||
(
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(
|
||||
inclusion_parent,
|
||||
)),
|
||||
ValidatorIndex(0),
|
||||
v0.sign(&CompactStatement::Valid(candidate_hash).signing_payload(
|
||||
&SigningContext { session_index: session, parent_hash: inclusion_parent },
|
||||
)),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit),
|
||||
ValidatorIndex(1),
|
||||
v4.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit),
|
||||
ValidatorIndex(2),
|
||||
v6.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit),
|
||||
ValidatorIndex(6),
|
||||
v2.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit),
|
||||
ValidatorIndex(4),
|
||||
v5.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit),
|
||||
ValidatorIndex(5),
|
||||
v3.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking),
|
||||
ValidatorIndex(3),
|
||||
v1.sign(&ApprovalVote(candidate_hash).signing_payload(session)),
|
||||
),
|
||||
],
|
||||
}];
|
||||
|
||||
let stmts = filter_dispute_set(stmts);
|
||||
assert_ok!(
|
||||
Pallet::<Test>::process_checked_multi_dispute_data(stmts),
|
||||
vec![(session, candidate_hash)],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PUNISH_VALIDATORS_FOR.with(|r| r.borrow().clone()),
|
||||
vec![(session, vec![ValidatorIndex(0), ValidatorIndex(3)]),],
|
||||
);
|
||||
assert_eq!(
|
||||
PUNISH_BACKERS_FOR.with(|r| r.borrow().clone()),
|
||||
vec![(session, vec![ValidatorIndex(0)]),],
|
||||
);
|
||||
|
||||
// someone reveals 3 backing vote, 6 votes against
|
||||
let stmts = vec![DisputeStatementSet {
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session,
|
||||
statements: vec![
|
||||
(
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(
|
||||
inclusion_parent,
|
||||
)),
|
||||
ValidatorIndex(3),
|
||||
v1.sign(&CompactStatement::Valid(candidate_hash).signing_payload(
|
||||
&SigningContext { session_index: session, parent_hash: inclusion_parent },
|
||||
)),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit),
|
||||
ValidatorIndex(6),
|
||||
v2.sign(
|
||||
&ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash: candidate_hash.clone(),
|
||||
session,
|
||||
}
|
||||
.signing_payload(),
|
||||
),
|
||||
),
|
||||
],
|
||||
}];
|
||||
|
||||
let stmts = filter_dispute_set(stmts);
|
||||
assert_ok!(Pallet::<Test>::process_checked_multi_dispute_data(stmts), vec![],);
|
||||
|
||||
// Ensure punishment for is called
|
||||
assert_eq!(
|
||||
PUNISH_VALIDATORS_FOR.with(|r| r.borrow().clone()),
|
||||
vec![
|
||||
(session, vec![ValidatorIndex(0), ValidatorIndex(3)]),
|
||||
(session, vec![ValidatorIndex(3)]),
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PUNISH_BACKERS_FOR.with(|r| r.borrow().clone()),
|
||||
vec![
|
||||
(session, vec![ValidatorIndex(0)]),
|
||||
(session, vec![ValidatorIndex(0), ValidatorIndex(3)])
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PUNISH_VALIDATORS_AGAINST.with(|r| r.borrow().clone()),
|
||||
vec![(session, vec![]), (session, vec![]),],
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_revert_and_freeze() {
|
||||
new_test_ext(Default::default()).execute_with(|| {
|
||||
|
||||
Reference in New Issue
Block a user