mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 01:41:09 +00:00
Better spam slots handling (#4845)
* Only bypass spam slots on actualy approval/backing vote import. * Fix spam slot treatment. * More tests. * Make sure backing statements import works. * Aaaaaand the actual proper fix. * Better docs + spelling fixes. * Fix. * Typo Co-authored-by: Robert Habermeier <rphmeier@gmail.com> * Fix doc. * Update node/core/dispute-coordinator/src/real/initialized.rs * minor rewording, line wrap * fix test case * Fix obsolete comment. Co-authored-by: Robert Habermeier <rphmeier@gmail.com> Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>
This commit is contained in:
@@ -244,8 +244,10 @@ impl Initialized {
|
||||
if !overlay_db.is_empty() {
|
||||
let ops = overlay_db.into_write_ops();
|
||||
backend.write(ops)?;
|
||||
confirm_write()?;
|
||||
}
|
||||
// even if the changeset was empty,
|
||||
// otherwise the caller will error.
|
||||
confirm_write()?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -882,7 +884,8 @@ impl Initialized {
|
||||
|
||||
// Whether or not we know already that this is a good dispute:
|
||||
//
|
||||
// Note we can only know for sure whether we reached the `byzantine_threshold` after updating candidate votes above, therefore the spam checking is afterwards:
|
||||
// Note we can only know for sure whether we reached the `byzantine_threshold` after
|
||||
// updating candidate votes above, therefore the spam checking is afterwards:
|
||||
let is_confirmed = is_included ||
|
||||
was_confirmed ||
|
||||
is_local || votes.voted_indices().len() >
|
||||
@@ -890,13 +893,19 @@ impl Initialized {
|
||||
|
||||
// Potential spam:
|
||||
if !is_confirmed {
|
||||
let mut free_spam_slots = statements.is_empty();
|
||||
let mut free_spam_slots_available = true;
|
||||
// Only allow import if all validators voting invalid, have not exceeded
|
||||
// their spam slots:
|
||||
for (statement, index) in statements.iter() {
|
||||
free_spam_slots |= statement.statement().is_backing() ||
|
||||
// Disputes can only be triggered via an invalidity stating vote, thus we only
|
||||
// need to increase spam slots on invalid votes. (If we did not, we would also
|
||||
// increase spam slots for backing validators for example - as validators have to
|
||||
// provide some opposing vote for dispute-distribution).
|
||||
free_spam_slots_available &= statement.statement().indicates_validity() ||
|
||||
self.spam_slots.add_unconfirmed(session, candidate_hash, *index);
|
||||
}
|
||||
// No reporting validator had a free spam slot:
|
||||
if !free_spam_slots {
|
||||
// Only validity stating votes or validator had free spam slot?
|
||||
if !free_spam_slots_available {
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
?candidate_hash,
|
||||
|
||||
@@ -23,19 +23,24 @@ use crate::real::LOG_TARGET;
|
||||
/// Type used for counting potential spam votes.
|
||||
type SpamCount = u32;
|
||||
|
||||
/// How many unconfirmed disputes a validator is allowed to be a participant in (per session).
|
||||
/// How many unconfirmed disputes a validator is allowed to import (per session).
|
||||
///
|
||||
/// Unconfirmed means: Node has not seen the candidate be included on any chain, it has not cast a
|
||||
/// vote itself on that dispute, the dispute has not yet reached more than a third of
|
||||
/// validator's votes and the including relay chain block has not yet been finalized.
|
||||
///
|
||||
/// Exact number of `MAX_SPAM_VOTES` is not that important here. It is important that the number is
|
||||
/// low enough to not cause resource exhaustion, if multiple validators spend their limits. Also
|
||||
/// if things are working properly, this number cannot really be too low either, as all relevant
|
||||
/// disputes _should_ have been seen as included my enough validators. (Otherwise the candidate
|
||||
/// would not have been available in the first place and could not have been included.) So this is
|
||||
/// really just a fallback mechanism if things go terribly wrong.
|
||||
/// low enough to not cause resource exhaustion (disk & memory) on the importing validator, even if
|
||||
/// multiple validators fully make use of their assigned spam slots.
|
||||
///
|
||||
/// Also if things are working properly, this number cannot really be too low either, as all
|
||||
/// relevant disputes _should_ have been seen as included by enough validators. (Otherwise the
|
||||
/// candidate would not have been available in the first place and could not have been included.)
|
||||
/// So this is really just a fallback mechanism if things go terribly wrong.
|
||||
#[cfg(not(test))]
|
||||
const MAX_SPAM_VOTES: SpamCount = 50;
|
||||
#[cfg(test)]
|
||||
const MAX_SPAM_VOTES: SpamCount = 1;
|
||||
|
||||
/// Spam slots for raised disputes concerning unknown candidates.
|
||||
pub struct SpamSlots {
|
||||
@@ -76,7 +81,12 @@ impl SpamSlots {
|
||||
Self { slots, unconfirmed: unconfirmed_disputes }
|
||||
}
|
||||
|
||||
/// Add an unconfirmed dispute if free slots are available.
|
||||
/// Increase a "voting invalid" validator's spam slot.
|
||||
///
|
||||
/// This function should get called for any validator's invalidity vote for any not yet
|
||||
/// confirmed dispute.
|
||||
///
|
||||
/// Returns: `true` if validator still had vacant spam slots, `false` otherwise.
|
||||
pub fn add_unconfirmed(
|
||||
&mut self,
|
||||
session: SessionIndex,
|
||||
@@ -90,14 +100,16 @@ impl SpamSlots {
|
||||
let validators = self.unconfirmed.entry((session, candidate)).or_default();
|
||||
|
||||
if validators.insert(validator) {
|
||||
// We only increment spam slots once per candidate, as each validator has to provide an
|
||||
// opposing vote for sending out its own vote. Therefore, receiving multiple votes for
|
||||
// a single candidate is expected and should not get punished here.
|
||||
*c += 1;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Clear out spam slots for a given candiate in a session.
|
||||
/// Clear out spam slots for a given candidate in a session.
|
||||
///
|
||||
/// This effectively reduces the spam slot count for all validators participating in a dispute
|
||||
/// for that candidate. You should call this function once a dispute became obsolete or got
|
||||
|
||||
@@ -32,7 +32,7 @@ use futures::{
|
||||
use kvdb::KeyValueDB;
|
||||
use parity_scale_codec::Encode;
|
||||
|
||||
use polkadot_node_primitives::SignedDisputeStatement;
|
||||
use polkadot_node_primitives::{SignedDisputeStatement, SignedFullStatement, Statement};
|
||||
use polkadot_node_subsystem::{
|
||||
messages::{
|
||||
ChainApiMessage, DisputeCoordinatorMessage, DisputeDistributionMessage,
|
||||
@@ -43,7 +43,7 @@ use polkadot_node_subsystem::{
|
||||
};
|
||||
use polkadot_node_subsystem_util::TimeoutExt;
|
||||
use sc_keystore::LocalKeystore;
|
||||
use sp_core::testing::TaskExecutor;
|
||||
use sp_core::{sr25519::Pair, testing::TaskExecutor, Pair as PairT};
|
||||
use sp_keyring::Sr25519Keyring;
|
||||
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
|
||||
|
||||
@@ -57,8 +57,8 @@ use polkadot_node_subsystem_test_helpers::{make_subsystem_context, TestSubsystem
|
||||
use polkadot_primitives::{
|
||||
v1::{
|
||||
BlakeTwo256, BlockNumber, CandidateCommitments, CandidateHash, CandidateReceipt, Hash,
|
||||
HashT, Header, MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, ValidatorId,
|
||||
ValidatorIndex,
|
||||
HashT, Header, MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, SigningContext,
|
||||
ValidatorId, ValidatorIndex,
|
||||
},
|
||||
v2::SessionInfo,
|
||||
};
|
||||
@@ -78,12 +78,12 @@ use super::db::v1::DbBackend;
|
||||
const TEST_TIMEOUT: Duration = Duration::from_secs(2);
|
||||
|
||||
// sets up a keystore with the given keyring accounts.
|
||||
fn make_keystore(accounts: &[Sr25519Keyring]) -> LocalKeystore {
|
||||
fn make_keystore(seeds: impl Iterator<Item = String>) -> LocalKeystore {
|
||||
let store = LocalKeystore::in_memory();
|
||||
|
||||
for s in accounts.iter().copied().map(|k| k.to_seed()) {
|
||||
for s in seeds {
|
||||
store
|
||||
.sr25519_generate_new(polkadot_primitives::v1::PARACHAIN_KEY_TYPE_ID, Some(s.as_str()))
|
||||
.sr25519_generate_new(polkadot_primitives::v1::PARACHAIN_KEY_TYPE_ID, Some(&s))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ impl MockClock {
|
||||
}
|
||||
|
||||
struct TestState {
|
||||
validators: Vec<Sr25519Keyring>,
|
||||
validators: Vec<Pair>,
|
||||
validator_public: Vec<ValidatorId>,
|
||||
validator_groups: Vec<Vec<ValidatorIndex>>,
|
||||
master_keystore: Arc<sc_keystore::LocalKeystore>,
|
||||
@@ -133,17 +133,28 @@ struct TestState {
|
||||
|
||||
impl Default for TestState {
|
||||
fn default() -> TestState {
|
||||
let p1 = Pair::from_string("//Polka", None).unwrap();
|
||||
let p2 = Pair::from_string("//Dot", None).unwrap();
|
||||
let p3 = Pair::from_string("//Kusama", None).unwrap();
|
||||
let validators = vec![
|
||||
Sr25519Keyring::Alice,
|
||||
Sr25519Keyring::Bob,
|
||||
Sr25519Keyring::Charlie,
|
||||
Sr25519Keyring::Dave,
|
||||
Sr25519Keyring::Eve,
|
||||
Sr25519Keyring::One,
|
||||
Sr25519Keyring::Ferdie,
|
||||
(Sr25519Keyring::Alice.pair(), Sr25519Keyring::Alice.to_seed()),
|
||||
(Sr25519Keyring::Bob.pair(), Sr25519Keyring::Bob.to_seed()),
|
||||
(Sr25519Keyring::Charlie.pair(), Sr25519Keyring::Charlie.to_seed()),
|
||||
(Sr25519Keyring::Dave.pair(), Sr25519Keyring::Dave.to_seed()),
|
||||
(Sr25519Keyring::Eve.pair(), Sr25519Keyring::Eve.to_seed()),
|
||||
(Sr25519Keyring::One.pair(), Sr25519Keyring::One.to_seed()),
|
||||
(Sr25519Keyring::Ferdie.pair(), Sr25519Keyring::Ferdie.to_seed()),
|
||||
// Two more keys needed so disputes are not confirmed already with only 3 statements.
|
||||
(p1, "//Polka".into()),
|
||||
(p2, "//Dot".into()),
|
||||
(p3, "//Kusama".into()),
|
||||
];
|
||||
|
||||
let validator_public = validators.iter().map(|k| ValidatorId::from(k.public())).collect();
|
||||
let validator_public = validators
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|k| ValidatorId::from(k.0.public()))
|
||||
.collect();
|
||||
|
||||
let validator_groups = vec![
|
||||
vec![ValidatorIndex(0), ValidatorIndex(1)],
|
||||
@@ -151,14 +162,15 @@ impl Default for TestState {
|
||||
vec![ValidatorIndex(4), ValidatorIndex(5), ValidatorIndex(6)],
|
||||
];
|
||||
|
||||
let master_keystore = make_keystore(&validators).into();
|
||||
let subsystem_keystore = make_keystore(&[Sr25519Keyring::Alice]).into();
|
||||
let master_keystore = make_keystore(validators.iter().map(|v| v.1.clone())).into();
|
||||
let subsystem_keystore =
|
||||
make_keystore(vec![Sr25519Keyring::Alice.to_seed()].into_iter()).into();
|
||||
|
||||
let db = Arc::new(kvdb_memorydb::create(1));
|
||||
let config = Config { col_data: 0 };
|
||||
|
||||
TestState {
|
||||
validators,
|
||||
validators: validators.into_iter().map(|(pair, _)| pair).collect(),
|
||||
validator_public,
|
||||
validator_groups,
|
||||
master_keystore,
|
||||
@@ -322,7 +334,7 @@ impl TestState {
|
||||
}
|
||||
}
|
||||
|
||||
async fn issue_statement_with_index(
|
||||
async fn issue_explicit_statement_with_index(
|
||||
&self,
|
||||
index: usize,
|
||||
candidate_hash: CandidateHash,
|
||||
@@ -339,6 +351,32 @@ impl TestState {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
async fn issue_backing_statement_with_index(
|
||||
&self,
|
||||
index: usize,
|
||||
candidate_hash: CandidateHash,
|
||||
session: SessionIndex,
|
||||
) -> SignedDisputeStatement {
|
||||
let keystore = self.master_keystore.clone() as SyncCryptoStorePtr;
|
||||
let validator_id = self.validators[index].public().into();
|
||||
let context =
|
||||
SigningContext { session_index: session, parent_hash: Hash::repeat_byte(0xac) };
|
||||
|
||||
let statement = SignedFullStatement::sign(
|
||||
&keystore,
|
||||
Statement::Valid(candidate_hash),
|
||||
&context,
|
||||
ValidatorIndex(index as _),
|
||||
&validator_id,
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_unchecked();
|
||||
|
||||
SignedDisputeStatement::from_backing_statement(&statement, context, validator_id).unwrap()
|
||||
}
|
||||
|
||||
fn resume<F>(self, test: F) -> Self
|
||||
where
|
||||
F: FnOnce(TestState, VirtualOverseer) -> BoxFuture<'static, TestState>,
|
||||
@@ -393,6 +431,477 @@ fn make_invalid_candidate_receipt() -> CandidateReceipt {
|
||||
dummy_candidate_receipt_bad_sig(Default::default(), Some(Default::default()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn too_many_unconfirmed_statements_are_considered_spam() {
|
||||
test_harness(|mut test_state, mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
let session = 1;
|
||||
|
||||
test_state.handle_resume_sync(&mut virtual_overseer, session).await;
|
||||
|
||||
let candidate_receipt1 = make_valid_candidate_receipt();
|
||||
let candidate_hash1 = candidate_receipt1.hash();
|
||||
let candidate_receipt2 = make_invalid_candidate_receipt();
|
||||
let candidate_hash2 = candidate_receipt2.hash();
|
||||
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let valid_vote1 =
|
||||
test_state.issue_backing_statement_with_index(3, candidate_hash1, session).await;
|
||||
|
||||
let invalid_vote1 = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash1, session, false)
|
||||
.await;
|
||||
|
||||
let valid_vote2 =
|
||||
test_state.issue_backing_statement_with_index(3, candidate_hash1, session).await;
|
||||
|
||||
let invalid_vote2 = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash1, session, false)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash: candidate_hash1,
|
||||
candidate_receipt: candidate_receipt1.clone(),
|
||||
session,
|
||||
statements: vec![
|
||||
(valid_vote1, ValidatorIndex(3)),
|
||||
(invalid_vote1, ValidatorIndex(1)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
})
|
||||
.await;
|
||||
|
||||
// Participation has to fail, otherwise the dispute will be confirmed.
|
||||
participation_missing_availability(&mut virtual_overseer).await;
|
||||
|
||||
{
|
||||
let (tx, rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ActiveDisputes(tx),
|
||||
})
|
||||
.await;
|
||||
|
||||
assert_eq!(rx.await.unwrap(), vec![(session, candidate_hash1)]);
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::QueryCandidateVotes(
|
||||
vec![(session, candidate_hash1)],
|
||||
tx,
|
||||
),
|
||||
})
|
||||
.await;
|
||||
|
||||
let (_, _, votes) = rx.await.unwrap().get(0).unwrap().clone();
|
||||
assert_eq!(votes.valid.len(), 1);
|
||||
assert_eq!(votes.invalid.len(), 1);
|
||||
}
|
||||
|
||||
let (pending_confirmation, confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash: candidate_hash2,
|
||||
candidate_receipt: candidate_receipt2.clone(),
|
||||
session,
|
||||
statements: vec![
|
||||
(valid_vote2, ValidatorIndex(3)),
|
||||
(invalid_vote2, ValidatorIndex(1)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
})
|
||||
.await;
|
||||
|
||||
{
|
||||
let (tx, rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::QueryCandidateVotes(
|
||||
vec![(session, candidate_hash2)],
|
||||
tx,
|
||||
),
|
||||
})
|
||||
.await;
|
||||
|
||||
assert_matches!(rx.await.unwrap().get(0), None);
|
||||
}
|
||||
|
||||
// Result should be invalid, because it should be considered spam.
|
||||
assert_matches!(confirmation_rx.await, Ok(ImportStatementsResult::InvalidImport));
|
||||
|
||||
virtual_overseer.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
|
||||
|
||||
// No more messages expected:
|
||||
assert!(virtual_overseer.try_recv().await.is_none());
|
||||
|
||||
test_state
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dispute_gets_confirmed_via_participation() {
|
||||
test_harness(|mut test_state, mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
let session = 1;
|
||||
|
||||
test_state.handle_resume_sync(&mut virtual_overseer, session).await;
|
||||
|
||||
let candidate_receipt1 = make_valid_candidate_receipt();
|
||||
let candidate_hash1 = candidate_receipt1.hash();
|
||||
let candidate_receipt2 = make_invalid_candidate_receipt();
|
||||
let candidate_hash2 = candidate_receipt2.hash();
|
||||
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let valid_vote1 = test_state
|
||||
.issue_explicit_statement_with_index(3, candidate_hash1, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote1 = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash1, session, false)
|
||||
.await;
|
||||
|
||||
let valid_vote2 = test_state
|
||||
.issue_explicit_statement_with_index(3, candidate_hash1, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote2 = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash1, session, false)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash: candidate_hash1,
|
||||
candidate_receipt: candidate_receipt1.clone(),
|
||||
session,
|
||||
statements: vec![
|
||||
(valid_vote1, ValidatorIndex(3)),
|
||||
(invalid_vote1, ValidatorIndex(1)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
})
|
||||
.await;
|
||||
|
||||
participation_with_distribution(&mut virtual_overseer, &candidate_hash1).await;
|
||||
|
||||
{
|
||||
let (tx, rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ActiveDisputes(tx),
|
||||
})
|
||||
.await;
|
||||
|
||||
assert_eq!(rx.await.unwrap(), vec![(session, candidate_hash1)]);
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::QueryCandidateVotes(
|
||||
vec![(session, candidate_hash1)],
|
||||
tx,
|
||||
),
|
||||
})
|
||||
.await;
|
||||
|
||||
let (_, _, votes) = rx.await.unwrap().get(0).unwrap().clone();
|
||||
assert_eq!(votes.valid.len(), 2);
|
||||
assert_eq!(votes.invalid.len(), 1);
|
||||
}
|
||||
|
||||
let (pending_confirmation, confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash: candidate_hash2,
|
||||
candidate_receipt: candidate_receipt2.clone(),
|
||||
session,
|
||||
statements: vec![
|
||||
(valid_vote2, ValidatorIndex(3)),
|
||||
(invalid_vote2, ValidatorIndex(1)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
})
|
||||
.await;
|
||||
|
||||
participation_missing_availability(&mut virtual_overseer).await;
|
||||
|
||||
{
|
||||
let (tx, rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::QueryCandidateVotes(
|
||||
vec![(session, candidate_hash2)],
|
||||
tx,
|
||||
),
|
||||
})
|
||||
.await;
|
||||
|
||||
let (_, _, votes) = rx.await.unwrap().get(0).unwrap().clone();
|
||||
assert_eq!(votes.valid.len(), 1);
|
||||
assert_eq!(votes.invalid.len(), 1);
|
||||
}
|
||||
|
||||
// Result should be valid, because our node participated, so spam slots are cleared:
|
||||
assert_matches!(confirmation_rx.await, Ok(ImportStatementsResult::ValidImport));
|
||||
|
||||
virtual_overseer.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
|
||||
|
||||
// No more messages expected:
|
||||
assert!(virtual_overseer.try_recv().await.is_none());
|
||||
|
||||
test_state
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dispute_gets_confirmed_at_byzantine_threshold() {
|
||||
test_harness(|mut test_state, mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
let session = 1;
|
||||
|
||||
test_state.handle_resume_sync(&mut virtual_overseer, session).await;
|
||||
|
||||
let candidate_receipt1 = make_valid_candidate_receipt();
|
||||
let candidate_hash1 = candidate_receipt1.hash();
|
||||
let candidate_receipt2 = make_invalid_candidate_receipt();
|
||||
let candidate_hash2 = candidate_receipt2.hash();
|
||||
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let valid_vote1 = test_state
|
||||
.issue_explicit_statement_with_index(3, candidate_hash1, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote1 = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash1, session, false)
|
||||
.await;
|
||||
|
||||
let valid_vote1a = test_state
|
||||
.issue_explicit_statement_with_index(4, candidate_hash1, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote1a = test_state
|
||||
.issue_explicit_statement_with_index(5, candidate_hash1, session, false)
|
||||
.await;
|
||||
|
||||
let valid_vote2 = test_state
|
||||
.issue_explicit_statement_with_index(3, candidate_hash1, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote2 = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash1, session, false)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash: candidate_hash1,
|
||||
candidate_receipt: candidate_receipt1.clone(),
|
||||
session,
|
||||
statements: vec![
|
||||
(valid_vote1, ValidatorIndex(3)),
|
||||
(invalid_vote1, ValidatorIndex(1)),
|
||||
(valid_vote1a, ValidatorIndex(4)),
|
||||
(invalid_vote1a, ValidatorIndex(5)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
})
|
||||
.await;
|
||||
|
||||
participation_missing_availability(&mut virtual_overseer).await;
|
||||
|
||||
{
|
||||
let (tx, rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ActiveDisputes(tx),
|
||||
})
|
||||
.await;
|
||||
|
||||
assert_eq!(rx.await.unwrap(), vec![(session, candidate_hash1)]);
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::QueryCandidateVotes(
|
||||
vec![(session, candidate_hash1)],
|
||||
tx,
|
||||
),
|
||||
})
|
||||
.await;
|
||||
|
||||
let (_, _, votes) = rx.await.unwrap().get(0).unwrap().clone();
|
||||
assert_eq!(votes.valid.len(), 2);
|
||||
assert_eq!(votes.invalid.len(), 2);
|
||||
}
|
||||
|
||||
let (pending_confirmation, confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash: candidate_hash2,
|
||||
candidate_receipt: candidate_receipt2.clone(),
|
||||
session,
|
||||
statements: vec![
|
||||
(valid_vote2, ValidatorIndex(3)),
|
||||
(invalid_vote2, ValidatorIndex(1)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
})
|
||||
.await;
|
||||
|
||||
participation_missing_availability(&mut virtual_overseer).await;
|
||||
|
||||
{
|
||||
let (tx, rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::QueryCandidateVotes(
|
||||
vec![(session, candidate_hash2)],
|
||||
tx,
|
||||
),
|
||||
})
|
||||
.await;
|
||||
|
||||
let (_, _, votes) = rx.await.unwrap().get(0).unwrap().clone();
|
||||
assert_eq!(votes.valid.len(), 1);
|
||||
assert_eq!(votes.invalid.len(), 1);
|
||||
}
|
||||
|
||||
// Result should be valid, because byzantine threshold has been reached in first
|
||||
// import, so spam slots are cleared:
|
||||
assert_matches!(confirmation_rx.await, Ok(ImportStatementsResult::ValidImport));
|
||||
|
||||
virtual_overseer.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
|
||||
|
||||
// No more messages expected:
|
||||
assert!(virtual_overseer.try_recv().await.is_none());
|
||||
|
||||
test_state
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn backing_statements_import_works_and_no_spam() {
|
||||
test_harness(|mut test_state, mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
let session = 1;
|
||||
|
||||
test_state.handle_resume_sync(&mut virtual_overseer, session).await;
|
||||
|
||||
let candidate_receipt = make_valid_candidate_receipt();
|
||||
let candidate_hash = candidate_receipt.hash();
|
||||
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let valid_vote1 =
|
||||
test_state.issue_backing_statement_with_index(3, candidate_hash, session).await;
|
||||
|
||||
let valid_vote2 =
|
||||
test_state.issue_backing_statement_with_index(4, candidate_hash, session).await;
|
||||
|
||||
let (pending_confirmation, confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash,
|
||||
candidate_receipt: candidate_receipt.clone(),
|
||||
session,
|
||||
statements: vec![
|
||||
(valid_vote1, ValidatorIndex(3)),
|
||||
(valid_vote2, ValidatorIndex(4)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
})
|
||||
.await;
|
||||
assert_matches!(confirmation_rx.await, Ok(ImportStatementsResult::ValidImport));
|
||||
|
||||
{
|
||||
// Just backing votes - we should not have any active disputes now.
|
||||
let (tx, rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ActiveDisputes(tx),
|
||||
})
|
||||
.await;
|
||||
|
||||
assert!(rx.await.unwrap().is_empty());
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::QueryCandidateVotes(
|
||||
vec![(session, candidate_hash)],
|
||||
tx,
|
||||
),
|
||||
})
|
||||
.await;
|
||||
|
||||
let (_, _, votes) = rx.await.unwrap().get(0).unwrap().clone();
|
||||
assert_eq!(votes.valid.len(), 2);
|
||||
assert_eq!(votes.invalid.len(), 0);
|
||||
}
|
||||
|
||||
let candidate_receipt = make_invalid_candidate_receipt();
|
||||
let candidate_hash = candidate_receipt.hash();
|
||||
|
||||
let valid_vote1 =
|
||||
test_state.issue_backing_statement_with_index(3, candidate_hash, session).await;
|
||||
|
||||
let valid_vote2 =
|
||||
test_state.issue_backing_statement_with_index(4, candidate_hash, session).await;
|
||||
|
||||
let (pending_confirmation, confirmation_rx) = oneshot::channel();
|
||||
// Backing vote import should not have accounted to spam slots, so this should succeed
|
||||
// as well:
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash,
|
||||
candidate_receipt: candidate_receipt.clone(),
|
||||
session,
|
||||
statements: vec![
|
||||
(valid_vote1, ValidatorIndex(3)),
|
||||
(valid_vote2, ValidatorIndex(4)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
})
|
||||
.await;
|
||||
|
||||
// Result should be valid, because our node participated, so spam slots are cleared:
|
||||
assert_matches!(confirmation_rx.await, Ok(ImportStatementsResult::ValidImport));
|
||||
|
||||
virtual_overseer.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
|
||||
|
||||
// No more messages expected:
|
||||
assert!(virtual_overseer.try_recv().await.is_none());
|
||||
|
||||
test_state
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conflicting_votes_lead_to_dispute_participation() {
|
||||
test_harness(|mut test_state, mut virtual_overseer| {
|
||||
@@ -406,14 +915,17 @@ fn conflicting_votes_lead_to_dispute_participation() {
|
||||
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let valid_vote =
|
||||
test_state.issue_statement_with_index(3, candidate_hash, session, true).await;
|
||||
let valid_vote = test_state
|
||||
.issue_explicit_statement_with_index(3, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote =
|
||||
test_state.issue_statement_with_index(1, candidate_hash, session, false).await;
|
||||
let invalid_vote = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash, session, false)
|
||||
.await;
|
||||
|
||||
let invalid_vote_2 =
|
||||
test_state.issue_statement_with_index(2, candidate_hash, session, false).await;
|
||||
let invalid_vote_2 = test_state
|
||||
.issue_explicit_statement_with_index(2, candidate_hash, session, false)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
@@ -510,11 +1022,13 @@ fn positive_votes_dont_trigger_participation() {
|
||||
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let valid_vote =
|
||||
test_state.issue_statement_with_index(2, candidate_hash, session, true).await;
|
||||
let valid_vote = test_state
|
||||
.issue_explicit_statement_with_index(2, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let valid_vote_2 =
|
||||
test_state.issue_statement_with_index(1, candidate_hash, session, true).await;
|
||||
let valid_vote_2 = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
@@ -615,11 +1129,13 @@ fn wrong_validator_index_is_ignored() {
|
||||
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let valid_vote =
|
||||
test_state.issue_statement_with_index(2, candidate_hash, session, true).await;
|
||||
let valid_vote = test_state
|
||||
.issue_explicit_statement_with_index(2, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote =
|
||||
test_state.issue_statement_with_index(1, candidate_hash, session, false).await;
|
||||
let invalid_vote = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash, session, false)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
@@ -685,11 +1201,13 @@ fn finality_votes_ignore_disputed_candidates() {
|
||||
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let valid_vote =
|
||||
test_state.issue_statement_with_index(2, candidate_hash, session, true).await;
|
||||
let valid_vote = test_state
|
||||
.issue_explicit_statement_with_index(2, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote =
|
||||
test_state.issue_statement_with_index(1, candidate_hash, session, false).await;
|
||||
let invalid_vote = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash, session, false)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
@@ -781,11 +1299,13 @@ fn supermajority_valid_dispute_may_be_finalized() {
|
||||
let supermajority_threshold =
|
||||
polkadot_primitives::v1::supermajority_threshold(test_state.validators.len());
|
||||
|
||||
let valid_vote =
|
||||
test_state.issue_statement_with_index(2, candidate_hash, session, true).await;
|
||||
let valid_vote = test_state
|
||||
.issue_explicit_statement_with_index(2, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote =
|
||||
test_state.issue_statement_with_index(1, candidate_hash, session, false).await;
|
||||
let invalid_vote = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash, session, false)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
@@ -807,8 +1327,9 @@ fn supermajority_valid_dispute_may_be_finalized() {
|
||||
|
||||
let mut statements = Vec::new();
|
||||
for i in (0..supermajority_threshold - 1).map(|i| i + 3) {
|
||||
let vote =
|
||||
test_state.issue_statement_with_index(i, candidate_hash, session, true).await;
|
||||
let vote = test_state
|
||||
.issue_explicit_statement_with_index(i, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
statements.push((vote, ValidatorIndex(i as _)));
|
||||
}
|
||||
@@ -898,11 +1419,13 @@ fn concluded_supermajority_for_non_active_after_time() {
|
||||
let supermajority_threshold =
|
||||
polkadot_primitives::v1::supermajority_threshold(test_state.validators.len());
|
||||
|
||||
let valid_vote =
|
||||
test_state.issue_statement_with_index(2, candidate_hash, session, true).await;
|
||||
let valid_vote = test_state
|
||||
.issue_explicit_statement_with_index(2, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote =
|
||||
test_state.issue_statement_with_index(1, candidate_hash, session, false).await;
|
||||
let invalid_vote = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash, session, false)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
@@ -925,8 +1448,9 @@ fn concluded_supermajority_for_non_active_after_time() {
|
||||
let mut statements = Vec::new();
|
||||
// -2: 1 for already imported vote and one for local vote (which is valid).
|
||||
for i in (0..supermajority_threshold - 2).map(|i| i + 3) {
|
||||
let vote =
|
||||
test_state.issue_statement_with_index(i, candidate_hash, session, true).await;
|
||||
let vote = test_state
|
||||
.issue_explicit_statement_with_index(i, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
statements.push((vote, ValidatorIndex(i as _)));
|
||||
}
|
||||
@@ -993,11 +1517,13 @@ fn concluded_supermajority_against_non_active_after_time() {
|
||||
let supermajority_threshold =
|
||||
polkadot_primitives::v1::supermajority_threshold(test_state.validators.len());
|
||||
|
||||
let valid_vote =
|
||||
test_state.issue_statement_with_index(2, candidate_hash, session, true).await;
|
||||
let valid_vote = test_state
|
||||
.issue_explicit_statement_with_index(2, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote =
|
||||
test_state.issue_statement_with_index(1, candidate_hash, session, false).await;
|
||||
let invalid_vote = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash, session, false)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
@@ -1023,8 +1549,9 @@ fn concluded_supermajority_against_non_active_after_time() {
|
||||
let mut statements = Vec::new();
|
||||
// minus 2, because of local vote and one previously imported invalid vote.
|
||||
for i in (0..supermajority_threshold - 2).map(|i| i + 3) {
|
||||
let vote =
|
||||
test_state.issue_statement_with_index(i, candidate_hash, session, false).await;
|
||||
let vote = test_state
|
||||
.issue_explicit_statement_with_index(i, candidate_hash, session, false)
|
||||
.await;
|
||||
|
||||
statements.push((vote, ValidatorIndex(i as _)));
|
||||
}
|
||||
@@ -1090,11 +1617,13 @@ fn resume_dispute_without_local_statement() {
|
||||
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let valid_vote =
|
||||
test_state.issue_statement_with_index(1, candidate_hash, session, true).await;
|
||||
let valid_vote = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote =
|
||||
test_state.issue_statement_with_index(2, candidate_hash, session, false).await;
|
||||
let invalid_vote = test_state
|
||||
.issue_explicit_statement_with_index(2, candidate_hash, session, false)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
@@ -1146,14 +1675,24 @@ fn resume_dispute_without_local_statement() {
|
||||
|
||||
participation_with_distribution(&mut virtual_overseer, &candidate_hash).await;
|
||||
|
||||
let valid_vote0 =
|
||||
test_state.issue_statement_with_index(0, candidate_hash, session, true).await;
|
||||
let valid_vote3 =
|
||||
test_state.issue_statement_with_index(3, candidate_hash, session, true).await;
|
||||
let valid_vote4 =
|
||||
test_state.issue_statement_with_index(4, candidate_hash, session, true).await;
|
||||
let valid_vote5 =
|
||||
test_state.issue_statement_with_index(5, candidate_hash, session, true).await;
|
||||
let valid_vote0 = test_state
|
||||
.issue_explicit_statement_with_index(0, candidate_hash, session, true)
|
||||
.await;
|
||||
let valid_vote3 = test_state
|
||||
.issue_explicit_statement_with_index(3, candidate_hash, session, true)
|
||||
.await;
|
||||
let valid_vote4 = test_state
|
||||
.issue_explicit_statement_with_index(4, candidate_hash, session, true)
|
||||
.await;
|
||||
let valid_vote5 = test_state
|
||||
.issue_explicit_statement_with_index(5, candidate_hash, session, true)
|
||||
.await;
|
||||
let valid_vote6 = test_state
|
||||
.issue_explicit_statement_with_index(6, candidate_hash, session, true)
|
||||
.await;
|
||||
let valid_vote7 = test_state
|
||||
.issue_explicit_statement_with_index(7, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
@@ -1167,6 +1706,8 @@ fn resume_dispute_without_local_statement() {
|
||||
(valid_vote3, ValidatorIndex(3)),
|
||||
(valid_vote4, ValidatorIndex(4)),
|
||||
(valid_vote5, ValidatorIndex(5)),
|
||||
(valid_vote6, ValidatorIndex(6)),
|
||||
(valid_vote7, ValidatorIndex(7)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
@@ -1210,14 +1751,17 @@ fn resume_dispute_with_local_statement() {
|
||||
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let local_valid_vote =
|
||||
test_state.issue_statement_with_index(0, candidate_hash, session, true).await;
|
||||
let local_valid_vote = test_state
|
||||
.issue_explicit_statement_with_index(0, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let valid_vote =
|
||||
test_state.issue_statement_with_index(1, candidate_hash, session, true).await;
|
||||
let valid_vote = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote =
|
||||
test_state.issue_statement_with_index(2, candidate_hash, session, false).await;
|
||||
let invalid_vote = test_state
|
||||
.issue_explicit_statement_with_index(2, candidate_hash, session, false)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
@@ -1277,7 +1821,8 @@ fn resume_dispute_with_local_statement() {
|
||||
fn resume_dispute_without_local_statement_or_local_key() {
|
||||
let session = 1;
|
||||
let mut test_state = TestState::default();
|
||||
test_state.subsystem_keystore = make_keystore(&[Sr25519Keyring::Two]).into();
|
||||
test_state.subsystem_keystore =
|
||||
make_keystore(vec![Sr25519Keyring::Two.to_seed()].into_iter()).into();
|
||||
test_state
|
||||
.resume(|mut test_state, mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
@@ -1288,11 +1833,13 @@ fn resume_dispute_without_local_statement_or_local_key() {
|
||||
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let valid_vote =
|
||||
test_state.issue_statement_with_index(1, candidate_hash, session, true).await;
|
||||
let valid_vote = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote =
|
||||
test_state.issue_statement_with_index(2, candidate_hash, session, false).await;
|
||||
let invalid_vote = test_state
|
||||
.issue_explicit_statement_with_index(2, candidate_hash, session, false)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
@@ -1364,14 +1911,17 @@ fn resume_dispute_with_local_statement_without_local_key() {
|
||||
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let local_valid_vote =
|
||||
test_state.issue_statement_with_index(0, candidate_hash, session, true).await;
|
||||
let local_valid_vote = test_state
|
||||
.issue_explicit_statement_with_index(0, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let valid_vote =
|
||||
test_state.issue_statement_with_index(1, candidate_hash, session, true).await;
|
||||
let valid_vote = test_state
|
||||
.issue_explicit_statement_with_index(1, candidate_hash, session, true)
|
||||
.await;
|
||||
|
||||
let invalid_vote =
|
||||
test_state.issue_statement_with_index(2, candidate_hash, session, false).await;
|
||||
let invalid_vote = test_state
|
||||
.issue_explicit_statement_with_index(2, candidate_hash, session, false)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer
|
||||
@@ -1411,7 +1961,8 @@ fn resume_dispute_with_local_statement_without_local_key() {
|
||||
})
|
||||
});
|
||||
// No keys:
|
||||
test_state.subsystem_keystore = make_keystore(&[Sr25519Keyring::Two]).into();
|
||||
test_state.subsystem_keystore =
|
||||
make_keystore(vec![Sr25519Keyring::Two.to_seed()].into_iter()).into();
|
||||
// Two should not send a DisputeParticiationMessage::Participate on restart since we gave
|
||||
// her a non existing key.
|
||||
test_state.resume(|test_state, mut virtual_overseer| {
|
||||
@@ -1453,7 +2004,7 @@ fn issue_local_statement_does_cause_distribution_but_not_duplicate_participation
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let other_vote = test_state
|
||||
.issue_statement_with_index(1, candidate_hash, session, !validity)
|
||||
.issue_explicit_statement_with_index(1, candidate_hash, session, !validity)
|
||||
.await;
|
||||
|
||||
let (pending_confirmation, confirmation_rx) = oneshot::channel();
|
||||
@@ -1606,10 +2157,10 @@ fn redundant_votes_ignored() {
|
||||
test_state.activate_leaf_at_session(&mut virtual_overseer, session, 1).await;
|
||||
|
||||
let valid_vote =
|
||||
test_state.issue_statement_with_index(1, candidate_hash, session, true).await;
|
||||
test_state.issue_backing_statement_with_index(1, candidate_hash, session).await;
|
||||
|
||||
let valid_vote_2 =
|
||||
test_state.issue_statement_with_index(1, candidate_hash, session, true).await;
|
||||
test_state.issue_backing_statement_with_index(1, candidate_hash, session).await;
|
||||
|
||||
assert!(valid_vote.validator_signature() != valid_vote_2.validator_signature());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user