diff --git a/runtime/parachains/src/disputes.rs b/runtime/parachains/src/disputes.rs index b5e9d2540045..3c1f1a334c9f 100644 --- a/runtime/parachains/src/disputes.rs +++ b/runtime/parachains/src/disputes.rs @@ -521,6 +521,8 @@ pub mod pallet { PotentialSpam, /// A dispute where there are only votes on one side. SingleSidedDispute, + /// Unconfirmed dispute statement sets provided + UnconfirmedDispute, } #[pallet::call] @@ -937,6 +939,7 @@ impl Pallet { // // Votes which are duplicate or already known by the chain are filtered out. // The entire set is removed if the dispute is both, ancient and concluded. + // Disputes without enough votes to get confirmed are also filtered out. fn filter_dispute_data( set: &DisputeStatementSet, post_conclusion_acceptance_period: ::BlockNumber, @@ -1038,6 +1041,13 @@ impl Pallet { return StatementSetFilter::RemoveAll } + // Reject disputes containing less votes than needed for confirmation. + if (summary.state.validators_for.clone() | &summary.state.validators_against).count_ones() <= + byzantine_threshold(summary.state.validators_for.len()) + { + return StatementSetFilter::RemoveAll + } + // Apply spam slot changes. Bail early if too many occupied. let is_local = >::contains_key(&set.session, &set.candidate_hash); if !is_local { @@ -1200,6 +1210,13 @@ impl Pallet { Error::::SingleSidedDispute, ); + // Reject disputes containing less votes than needed for confirmation. + ensure!( + (summary.state.validators_for.clone() | &summary.state.validators_against).count_ones() > + byzantine_threshold(summary.state.validators_for.len()), + Error::::UnconfirmedDispute, + ); + let DisputeStatementSet { ref session, ref candidate_hash, .. } = set; let session = *session; let candidate_hash = *candidate_hash;