mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-17 21:51:06 +00:00
Dispute distribution implementation (#3282)
* Dispute protocol. * Dispute distribution protocol. * Get network requests routed. * WIP: Basic dispute sender logic. * Basic validator determination logic. * WIP: Getting things to typecheck. * Slightly larger timeout. * More typechecking stuff. * Cleanup. * Finished most of the sending logic. * Handle active leaves updates - Cleanup dead disputes - Update sends for new sessions - Retry on errors * Pass sessions in already. * Startup dispute sending. * Provide incoming decoding facilities and use them in statement-distribution. * Relaxed runtime util requirements. We only need a `SubsystemSender` not a full `SubsystemContext`. * Better usability of incoming requests. Make it possible to consume stuff without clones. * Add basic receiver functionality. * Cleanup + fixes for sender. * One more sender fix. * Start receiver. * Make sure to send responses back. * WIP: Exposed authority discovery * Make tests pass. * Fully featured receiver. * Decrease cost of `NotAValidator`. * Make `RuntimeInfo` LRU cache size configurable. * Cache more sessions. * Fix collator protocol. * Disable metrics for now. * Make dispute-distribution a proper subsystem. * Fix naming. * Code style fixes. * Factored out 4x copied mock function. * WIP: Tests. * Whitespace cleanup. * Accessor functions. * More testing. * More Debug instances. * Fix busy loop. * Working tests. * More tests. * Cleanup. * Fix build. * Basic receiving test. * Non validator message gets dropped. * More receiving tests. * Test nested and subsequent imports. * Fix spaces. * Better formatted imports. * Import cleanup. * Metrics. * Message -> MuxedMessage * Message -> MuxedMessage * More review remarks. * Add missing metrics.rs. * Fix flaky test. * Dispute coordinator - deliver confirmations. * Send out `DisputeMessage` on issue local statement. * Unwire dispute distribution. * Review remarks. * Review remarks. * Better docs.
This commit is contained in:
@@ -28,22 +28,21 @@
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
use polkadot_node_primitives::{CandidateVotes, SignedDisputeStatement};
|
||||
use polkadot_node_primitives::{CandidateVotes, DISPUTE_WINDOW, DisputeMessage, SignedDisputeStatement, DisputeMessageCheckError};
|
||||
use polkadot_node_subsystem::{
|
||||
overseer,
|
||||
messages::{
|
||||
DisputeCoordinatorMessage, ChainApiMessage, DisputeParticipationMessage,
|
||||
},
|
||||
SubsystemContext, FromOverseer, OverseerSignal, SpawnedSubsystem,
|
||||
SubsystemError,
|
||||
overseer, SubsystemContext, FromOverseer, OverseerSignal, SpawnedSubsystem, SubsystemError,
|
||||
errors::{ChainApiError, RuntimeApiError},
|
||||
messages::{
|
||||
ChainApiMessage, DisputeCoordinatorMessage, DisputeDistributionMessage,
|
||||
DisputeParticipationMessage, ImportStatementsResult
|
||||
}
|
||||
};
|
||||
use polkadot_node_subsystem_util::rolling_session_window::{
|
||||
RollingSessionWindow, SessionWindowUpdate,
|
||||
};
|
||||
use polkadot_primitives::v1::{
|
||||
SessionIndex, CandidateHash, Hash, CandidateReceipt, DisputeStatement, ValidatorIndex,
|
||||
ValidatorSignature, BlockNumber, ValidatorPair,
|
||||
BlockNumber, CandidateHash, CandidateReceipt, DisputeStatement, Hash,
|
||||
SessionIndex, SessionInfo, ValidatorIndex, ValidatorPair, ValidatorSignature
|
||||
};
|
||||
|
||||
use futures::prelude::*;
|
||||
@@ -61,10 +60,6 @@ mod tests;
|
||||
|
||||
const LOG_TARGET: &str = "parachain::dispute-coordinator";
|
||||
|
||||
// It would be nice to draw this from the chain state, but we have no tools for it right now.
|
||||
// On Polkadot this is 1 day, and on Kusama it's 6 hours.
|
||||
const DISPUTE_WINDOW: SessionIndex = 6;
|
||||
|
||||
struct State {
|
||||
keystore: Arc<LocalKeystore>,
|
||||
highest_session: Option<SessionIndex>,
|
||||
@@ -134,6 +129,9 @@ pub enum Error {
|
||||
#[error(transparent)]
|
||||
Oneshot(#[from] oneshot::Canceled),
|
||||
|
||||
#[error("Oneshot send failed")]
|
||||
OneshotSend,
|
||||
|
||||
#[error(transparent)]
|
||||
Subsystem(#[from] SubsystemError),
|
||||
|
||||
@@ -308,6 +306,7 @@ async fn handle_incoming(
|
||||
candidate_receipt,
|
||||
session,
|
||||
statements,
|
||||
pending_confirmation,
|
||||
} => {
|
||||
handle_import_statements(
|
||||
ctx,
|
||||
@@ -318,6 +317,7 @@ async fn handle_incoming(
|
||||
candidate_receipt,
|
||||
session,
|
||||
statements,
|
||||
pending_confirmation,
|
||||
).await?;
|
||||
}
|
||||
DisputeCoordinatorMessage::ActiveDisputes(rx) => {
|
||||
@@ -400,8 +400,13 @@ async fn handle_import_statements(
|
||||
candidate_receipt: CandidateReceipt,
|
||||
session: SessionIndex,
|
||||
statements: Vec<(SignedDisputeStatement, ValidatorIndex)>,
|
||||
pending_confirmation: oneshot::Sender<ImportStatementsResult>,
|
||||
) -> Result<(), Error> {
|
||||
if state.highest_session.map_or(true, |h| session + DISPUTE_WINDOW < h) {
|
||||
|
||||
// It is not valid to participate in an ancient dispute (spam?).
|
||||
pending_confirmation.send(ImportStatementsResult::InvalidImport).map_err(|_| Error::OneshotSend)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -479,37 +484,54 @@ async fn handle_import_statements(
|
||||
let already_disputed = is_disputed && !was_undisputed;
|
||||
let concluded_valid = votes.valid.len() >= supermajority_threshold;
|
||||
|
||||
let mut tx = db::v1::Transaction::default();
|
||||
{ // Scope so we will only confirm valid import after the import got actually persisted.
|
||||
let mut tx = db::v1::Transaction::default();
|
||||
|
||||
if freshly_disputed && !concluded_valid {
|
||||
// add to active disputes and begin local participation.
|
||||
update_active_disputes(
|
||||
store,
|
||||
config,
|
||||
&mut tx,
|
||||
|active| active.insert(session, candidate_hash),
|
||||
)?;
|
||||
if freshly_disputed && !concluded_valid {
|
||||
|
||||
ctx.send_message(DisputeParticipationMessage::Participate {
|
||||
candidate_hash,
|
||||
candidate_receipt,
|
||||
session,
|
||||
n_validators: n_validators as u32,
|
||||
}).await;
|
||||
let (report_availability, receive_availability) = oneshot::channel();
|
||||
ctx.send_message(DisputeParticipationMessage::Participate {
|
||||
candidate_hash,
|
||||
candidate_receipt,
|
||||
session,
|
||||
n_validators: n_validators as u32,
|
||||
report_availability,
|
||||
}).await;
|
||||
|
||||
if !receive_availability.await.map_err(Error::Oneshot)? {
|
||||
pending_confirmation.send(ImportStatementsResult::InvalidImport).map_err(|_| Error::OneshotSend)?;
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
"Recovering availability failed - invalid import."
|
||||
);
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
// add to active disputes and begin local participation.
|
||||
update_active_disputes(
|
||||
store,
|
||||
config,
|
||||
&mut tx,
|
||||
|active| active.insert(session, candidate_hash),
|
||||
)?;
|
||||
|
||||
}
|
||||
|
||||
if concluded_valid && already_disputed {
|
||||
// remove from active disputes.
|
||||
update_active_disputes(
|
||||
store,
|
||||
config,
|
||||
&mut tx,
|
||||
|active| active.delete(session, candidate_hash),
|
||||
)?;
|
||||
}
|
||||
|
||||
tx.put_candidate_votes(session, candidate_hash, votes.into());
|
||||
tx.write(store, &config.column_config())?;
|
||||
}
|
||||
|
||||
if concluded_valid && already_disputed {
|
||||
// remove from active disputes.
|
||||
update_active_disputes(
|
||||
store,
|
||||
config,
|
||||
&mut tx,
|
||||
|active| active.delete(session, candidate_hash),
|
||||
)?;
|
||||
}
|
||||
|
||||
tx.put_candidate_votes(session, candidate_hash, votes.into());
|
||||
tx.write(store, &config.column_config())?;
|
||||
pending_confirmation.send(ImportStatementsResult::ValidImport).map_err(|_| Error::OneshotSend)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -541,7 +563,7 @@ async fn issue_local_statement(
|
||||
valid: bool,
|
||||
) -> Result<(), Error> {
|
||||
// Load session info.
|
||||
let validators = match state.rolling_session_window.session_info(session) {
|
||||
let info = match state.rolling_session_window.session_info(session) {
|
||||
None => {
|
||||
tracing::warn!(
|
||||
target: LOG_TARGET,
|
||||
@@ -551,9 +573,11 @@ async fn issue_local_statement(
|
||||
|
||||
return Ok(())
|
||||
}
|
||||
Some(info) => info.validators.clone(),
|
||||
Some(info) => info,
|
||||
};
|
||||
|
||||
let validators = info.validators.clone();
|
||||
|
||||
let votes = db::v1::load_candidate_votes(
|
||||
store,
|
||||
&config.column_config(),
|
||||
@@ -604,8 +628,27 @@ async fn issue_local_statement(
|
||||
}
|
||||
}
|
||||
|
||||
// Get our message out:
|
||||
for (statement, index) in &statements {
|
||||
let dispute_message = match make_dispute_message(info, &votes, statement.clone(), *index) {
|
||||
Err(err) => {
|
||||
tracing::debug!(
|
||||
target: LOG_TARGET,
|
||||
?err,
|
||||
"Creating dispute message failed."
|
||||
);
|
||||
continue
|
||||
}
|
||||
Ok(dispute_message) => dispute_message,
|
||||
};
|
||||
|
||||
ctx.send_message(DisputeDistributionMessage::SendDispute(dispute_message)).await;
|
||||
}
|
||||
|
||||
|
||||
// Do import
|
||||
if !statements.is_empty() {
|
||||
let (pending_confirmation, _rx) = oneshot::channel();
|
||||
handle_import_statements(
|
||||
ctx,
|
||||
store,
|
||||
@@ -615,12 +658,67 @@ async fn issue_local_statement(
|
||||
candidate_receipt,
|
||||
session,
|
||||
statements,
|
||||
pending_confirmation,
|
||||
).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
enum MakeDisputeMessageError {
|
||||
#[error("There was no opposite vote available")]
|
||||
NoOppositeVote,
|
||||
#[error("Found vote had an invalid validator index that could not be found")]
|
||||
InvalidValidatorIndex,
|
||||
#[error("Statement found in votes had invalid signature.")]
|
||||
InvalidStoredStatement,
|
||||
#[error(transparent)]
|
||||
InvalidStatementCombination(DisputeMessageCheckError),
|
||||
}
|
||||
|
||||
fn make_dispute_message(
|
||||
info: &SessionInfo,
|
||||
votes: &CandidateVotes,
|
||||
our_vote: SignedDisputeStatement,
|
||||
our_index: ValidatorIndex
|
||||
) -> Result<DisputeMessage, MakeDisputeMessageError> {
|
||||
|
||||
let validators = &info.validators;
|
||||
|
||||
let (valid_statement, valid_index, invalid_statement, invalid_index) =
|
||||
if let DisputeStatement::Valid(_) = our_vote.statement() {
|
||||
let (statement_kind, validator_index, validator_signature)
|
||||
= votes.invalid.get(0).ok_or(MakeDisputeMessageError::NoOppositeVote)?.clone();
|
||||
let other_vote = SignedDisputeStatement::new_checked(
|
||||
DisputeStatement::Invalid(statement_kind),
|
||||
our_vote.candidate_hash().clone(),
|
||||
our_vote.session_index(),
|
||||
validators.get(validator_index.0 as usize).ok_or(MakeDisputeMessageError::InvalidValidatorIndex)?.clone(),
|
||||
validator_signature,
|
||||
).map_err(|()| MakeDisputeMessageError::InvalidStoredStatement)?;
|
||||
(our_vote, our_index, other_vote, validator_index)
|
||||
} else {
|
||||
let (statement_kind, validator_index, validator_signature)
|
||||
= votes.valid.get(0).ok_or(MakeDisputeMessageError::NoOppositeVote)?.clone();
|
||||
let other_vote = SignedDisputeStatement::new_checked(
|
||||
DisputeStatement::Valid(statement_kind),
|
||||
our_vote.candidate_hash().clone(),
|
||||
our_vote.session_index(),
|
||||
validators.get(validator_index.0 as usize).ok_or(MakeDisputeMessageError::InvalidValidatorIndex)?.clone(),
|
||||
validator_signature,
|
||||
).map_err(|()| MakeDisputeMessageError::InvalidStoredStatement)?;
|
||||
(other_vote, validator_index, our_vote, our_index)
|
||||
};
|
||||
|
||||
DisputeMessage::from_signed_statements(
|
||||
valid_statement, valid_index,
|
||||
invalid_statement, invalid_index,
|
||||
votes.candidate_receipt.clone(),
|
||||
info,
|
||||
).map_err(MakeDisputeMessageError::InvalidStatementCombination)
|
||||
}
|
||||
|
||||
fn determine_undisputed_chain(
|
||||
store: &dyn KeyValueDB,
|
||||
config: &Config,
|
||||
|
||||
@@ -25,7 +25,10 @@ use polkadot_node_subsystem_test_helpers::{make_subsystem_context, TestSubsystem
|
||||
use sp_core::testing::TaskExecutor;
|
||||
use sp_keyring::Sr25519Keyring;
|
||||
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
|
||||
use futures::future::{self, BoxFuture};
|
||||
use futures::{
|
||||
channel::oneshot,
|
||||
future::{self, BoxFuture},
|
||||
};
|
||||
use parity_scale_codec::Encode;
|
||||
use assert_matches::assert_matches;
|
||||
|
||||
@@ -261,6 +264,7 @@ fn conflicting_votes_lead_to_dispute_participation() {
|
||||
false,
|
||||
).await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash,
|
||||
@@ -270,9 +274,9 @@ fn conflicting_votes_lead_to_dispute_participation() {
|
||||
(valid_vote, ValidatorIndex(0)),
|
||||
(invalid_vote, ValidatorIndex(1)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
}).await;
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeParticipation(DisputeParticipationMessage::Participate {
|
||||
@@ -280,11 +284,13 @@ fn conflicting_votes_lead_to_dispute_participation() {
|
||||
candidate_receipt: c_receipt,
|
||||
session: s,
|
||||
n_validators,
|
||||
report_availability,
|
||||
}) => {
|
||||
assert_eq!(c_hash, candidate_hash);
|
||||
assert_eq!(c_receipt, candidate_receipt);
|
||||
assert_eq!(s, session);
|
||||
assert_eq!(n_validators, test_state.validators.len() as u32);
|
||||
report_availability.send(true).unwrap();
|
||||
}
|
||||
);
|
||||
|
||||
@@ -310,6 +316,7 @@ fn conflicting_votes_lead_to_dispute_participation() {
|
||||
assert_eq!(votes.invalid.len(), 1);
|
||||
}
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash,
|
||||
@@ -318,6 +325,7 @@ fn conflicting_votes_lead_to_dispute_participation() {
|
||||
statements: vec![
|
||||
(invalid_vote_2, ValidatorIndex(2)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
}).await;
|
||||
|
||||
@@ -371,6 +379,7 @@ fn positive_votes_dont_trigger_participation() {
|
||||
true,
|
||||
).await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash,
|
||||
@@ -379,6 +388,7 @@ fn positive_votes_dont_trigger_participation() {
|
||||
statements: vec![
|
||||
(valid_vote, ValidatorIndex(0)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
}).await;
|
||||
|
||||
@@ -404,6 +414,7 @@ fn positive_votes_dont_trigger_participation() {
|
||||
assert!(votes.invalid.is_empty());
|
||||
}
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash,
|
||||
@@ -412,6 +423,7 @@ fn positive_votes_dont_trigger_participation() {
|
||||
statements: vec![
|
||||
(valid_vote_2, ValidatorIndex(1)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
}).await;
|
||||
|
||||
@@ -472,6 +484,7 @@ fn wrong_validator_index_is_ignored() {
|
||||
false,
|
||||
).await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash,
|
||||
@@ -481,6 +494,7 @@ fn wrong_validator_index_is_ignored() {
|
||||
(valid_vote, ValidatorIndex(1)),
|
||||
(invalid_vote, ValidatorIndex(0)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
}).await;
|
||||
|
||||
@@ -541,6 +555,7 @@ fn finality_votes_ignore_disputed_candidates() {
|
||||
false,
|
||||
).await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash,
|
||||
@@ -550,9 +565,21 @@ fn finality_votes_ignore_disputed_candidates() {
|
||||
(valid_vote, ValidatorIndex(0)),
|
||||
(invalid_vote, ValidatorIndex(1)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
}).await;
|
||||
let _ = virtual_overseer.recv().await;
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeParticipation(
|
||||
DisputeParticipationMessage::Participate {
|
||||
report_availability,
|
||||
..
|
||||
}
|
||||
) => {
|
||||
report_availability.send(true).unwrap();
|
||||
}
|
||||
);
|
||||
|
||||
{
|
||||
let (tx, rx) = oneshot::channel();
|
||||
@@ -624,6 +651,7 @@ fn supermajority_valid_dispute_may_be_finalized() {
|
||||
false,
|
||||
).await;
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash,
|
||||
@@ -633,6 +661,7 @@ fn supermajority_valid_dispute_may_be_finalized() {
|
||||
(valid_vote, ValidatorIndex(0)),
|
||||
(invalid_vote, ValidatorIndex(1)),
|
||||
],
|
||||
pending_confirmation,
|
||||
},
|
||||
}).await;
|
||||
|
||||
@@ -650,12 +679,14 @@ fn supermajority_valid_dispute_may_be_finalized() {
|
||||
statements.push((vote, ValidatorIndex(i as _)));
|
||||
};
|
||||
|
||||
let (pending_confirmation, _confirmation_rx) = oneshot::channel();
|
||||
virtual_overseer.send(FromOverseer::Communication {
|
||||
msg: DisputeCoordinatorMessage::ImportStatements {
|
||||
candidate_hash,
|
||||
candidate_receipt: candidate_receipt.clone(),
|
||||
session,
|
||||
statements,
|
||||
pending_confirmation,
|
||||
},
|
||||
}).await;
|
||||
|
||||
|
||||
@@ -83,6 +83,9 @@ pub enum Error {
|
||||
#[error(transparent)]
|
||||
Oneshot(#[from] oneshot::Canceled),
|
||||
|
||||
#[error("Oneshot receiver died")]
|
||||
OneshotSendFailed,
|
||||
|
||||
#[error(transparent)]
|
||||
Participation(#[from] ParticipationError),
|
||||
}
|
||||
@@ -159,6 +162,7 @@ async fn handle_incoming(
|
||||
candidate_receipt,
|
||||
session,
|
||||
n_validators,
|
||||
report_availability,
|
||||
} => {
|
||||
if let Some((_, block_hash)) = state.recent_block {
|
||||
participate(
|
||||
@@ -168,6 +172,7 @@ async fn handle_incoming(
|
||||
candidate_receipt,
|
||||
session,
|
||||
n_validators,
|
||||
report_availability,
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
@@ -184,6 +189,7 @@ async fn participate(
|
||||
candidate_receipt: CandidateReceipt,
|
||||
session: SessionIndex,
|
||||
n_validators: u32,
|
||||
report_availability: oneshot::Sender<bool>,
|
||||
) -> Result<(), Error> {
|
||||
let (recover_available_data_tx, recover_available_data_rx) = oneshot::channel();
|
||||
let (code_tx, code_rx) = oneshot::channel();
|
||||
@@ -203,14 +209,21 @@ async fn participate(
|
||||
.await;
|
||||
|
||||
let available_data = match recover_available_data_rx.await? {
|
||||
Ok(data) => data,
|
||||
Ok(data) => {
|
||||
report_availability.send(true).map_err(|_| Error::OneshotSendFailed)?;
|
||||
data
|
||||
}
|
||||
Err(RecoveryError::Invalid) => {
|
||||
report_availability.send(true).map_err(|_| Error::OneshotSendFailed)?;
|
||||
|
||||
// the available data was recovered but it is invalid, therefore we'll
|
||||
// vote negatively for the candidate dispute
|
||||
cast_invalid_vote(ctx, candidate_hash, candidate_receipt, session).await;
|
||||
return Ok(());
|
||||
}
|
||||
Err(RecoveryError::Unavailable) => {
|
||||
report_availability.send(false).map_err(|_| Error::OneshotSendFailed)?;
|
||||
|
||||
return Err(ParticipationError::MissingAvailableData(candidate_hash).into());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -80,7 +80,7 @@ async fn activate_leaf(virtual_overseer: &mut VirtualOverseer, block_number: Blo
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn participate(virtual_overseer: &mut VirtualOverseer) {
|
||||
async fn participate(virtual_overseer: &mut VirtualOverseer) -> oneshot::Receiver<bool> {
|
||||
let commitments = CandidateCommitments::default();
|
||||
let candidate_receipt = {
|
||||
let mut receipt = CandidateReceipt::default();
|
||||
@@ -91,6 +91,8 @@ async fn participate(virtual_overseer: &mut VirtualOverseer) {
|
||||
let session = 1;
|
||||
let n_validators = 10;
|
||||
|
||||
let (report_availability, receive_availability) = oneshot::channel();
|
||||
|
||||
virtual_overseer
|
||||
.send(FromOverseer::Communication {
|
||||
msg: DisputeParticipationMessage::Participate {
|
||||
@@ -98,12 +100,14 @@ async fn participate(virtual_overseer: &mut VirtualOverseer) {
|
||||
candidate_receipt: candidate_receipt.clone(),
|
||||
session,
|
||||
n_validators,
|
||||
report_availability,
|
||||
},
|
||||
})
|
||||
.await;
|
||||
})
|
||||
.await;
|
||||
receive_availability
|
||||
}
|
||||
|
||||
async fn recover_available_data(virtual_overseer: &mut VirtualOverseer) {
|
||||
async fn recover_available_data(virtual_overseer: &mut VirtualOverseer, receive_availability: oneshot::Receiver<bool>) {
|
||||
let pov_block = PoV {
|
||||
block_data: BlockData(Vec::new()),
|
||||
};
|
||||
@@ -122,6 +126,8 @@ async fn recover_available_data(virtual_overseer: &mut VirtualOverseer) {
|
||||
},
|
||||
"overseer did not receive recover available data message",
|
||||
);
|
||||
|
||||
assert_eq!(receive_availability.await.expect("Availability should get reported"), true);
|
||||
}
|
||||
|
||||
async fn fetch_validation_code(virtual_overseer: &mut VirtualOverseer) {
|
||||
@@ -166,7 +172,7 @@ async fn store_available_data(virtual_overseer: &mut VirtualOverseer, success: b
|
||||
fn cannot_participate_when_recent_block_state_is_missing() {
|
||||
test_harness(|mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
participate(&mut virtual_overseer).await;
|
||||
let _ = participate(&mut virtual_overseer).await;
|
||||
|
||||
virtual_overseer
|
||||
})
|
||||
@@ -175,7 +181,7 @@ fn cannot_participate_when_recent_block_state_is_missing() {
|
||||
test_harness(|mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
activate_leaf(&mut virtual_overseer, 10).await;
|
||||
participate(&mut virtual_overseer).await;
|
||||
let _ = participate(&mut virtual_overseer).await;
|
||||
|
||||
// after activating at least one leaf the recent block
|
||||
// state should be available which should lead to trying
|
||||
@@ -199,7 +205,7 @@ fn cannot_participate_if_cannot_recover_available_data() {
|
||||
test_harness(|mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
activate_leaf(&mut virtual_overseer, 10).await;
|
||||
participate(&mut virtual_overseer).await;
|
||||
let receive_availability = participate(&mut virtual_overseer).await;
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
@@ -211,6 +217,8 @@ fn cannot_participate_if_cannot_recover_available_data() {
|
||||
"overseer did not receive recover available data message",
|
||||
);
|
||||
|
||||
assert_eq!(receive_availability.await.expect("Availability should get reported"), false);
|
||||
|
||||
virtual_overseer
|
||||
})
|
||||
});
|
||||
@@ -221,8 +229,8 @@ fn cannot_participate_if_cannot_recover_validation_code() {
|
||||
test_harness(|mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
activate_leaf(&mut virtual_overseer, 10).await;
|
||||
participate(&mut virtual_overseer).await;
|
||||
recover_available_data(&mut virtual_overseer).await;
|
||||
let receive_availability = participate(&mut virtual_overseer).await;
|
||||
recover_available_data(&mut virtual_overseer, receive_availability).await;
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
@@ -248,7 +256,7 @@ fn cast_invalid_vote_if_available_data_is_invalid() {
|
||||
test_harness(|mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
activate_leaf(&mut virtual_overseer, 10).await;
|
||||
participate(&mut virtual_overseer).await;
|
||||
let receive_availability = participate(&mut virtual_overseer).await;
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
@@ -260,6 +268,8 @@ fn cast_invalid_vote_if_available_data_is_invalid() {
|
||||
"overseer did not receive recover available data message",
|
||||
);
|
||||
|
||||
assert_eq!(receive_availability.await.expect("Availability should get reported"), true);
|
||||
|
||||
assert_matches!(
|
||||
virtual_overseer.recv().await,
|
||||
AllMessages::DisputeCoordinator(DisputeCoordinatorMessage::IssueLocalStatement(
|
||||
@@ -281,8 +291,8 @@ fn cast_invalid_vote_if_validation_fails_or_is_invalid() {
|
||||
test_harness(|mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
activate_leaf(&mut virtual_overseer, 10).await;
|
||||
participate(&mut virtual_overseer).await;
|
||||
recover_available_data(&mut virtual_overseer).await;
|
||||
let receive_availability = participate(&mut virtual_overseer).await;
|
||||
recover_available_data(&mut virtual_overseer, receive_availability).await;
|
||||
fetch_validation_code(&mut virtual_overseer).await;
|
||||
store_available_data(&mut virtual_overseer, true).await;
|
||||
|
||||
@@ -317,8 +327,8 @@ fn cast_invalid_vote_if_validation_passes_but_commitments_dont_match() {
|
||||
test_harness(|mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
activate_leaf(&mut virtual_overseer, 10).await;
|
||||
participate(&mut virtual_overseer).await;
|
||||
recover_available_data(&mut virtual_overseer).await;
|
||||
let receive_availability = participate(&mut virtual_overseer).await;
|
||||
recover_available_data(&mut virtual_overseer, receive_availability).await;
|
||||
fetch_validation_code(&mut virtual_overseer).await;
|
||||
store_available_data(&mut virtual_overseer, true).await;
|
||||
|
||||
@@ -357,8 +367,8 @@ fn cast_valid_vote_if_validation_passes() {
|
||||
test_harness(|mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
activate_leaf(&mut virtual_overseer, 10).await;
|
||||
participate(&mut virtual_overseer).await;
|
||||
recover_available_data(&mut virtual_overseer).await;
|
||||
let receive_availability = participate(&mut virtual_overseer).await;
|
||||
recover_available_data(&mut virtual_overseer, receive_availability).await;
|
||||
fetch_validation_code(&mut virtual_overseer).await;
|
||||
store_available_data(&mut virtual_overseer, true).await;
|
||||
|
||||
@@ -393,8 +403,8 @@ fn failure_to_store_available_data_does_not_preclude_participation() {
|
||||
test_harness(|mut virtual_overseer| {
|
||||
Box::pin(async move {
|
||||
activate_leaf(&mut virtual_overseer, 10).await;
|
||||
participate(&mut virtual_overseer).await;
|
||||
recover_available_data(&mut virtual_overseer).await;
|
||||
let receive_availability = participate(&mut virtual_overseer).await;
|
||||
recover_available_data(&mut virtual_overseer, receive_availability).await;
|
||||
fetch_validation_code(&mut virtual_overseer).await;
|
||||
// the store available data request should fail
|
||||
store_available_data(&mut virtual_overseer, false).await;
|
||||
|
||||
Reference in New Issue
Block a user