Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Disputes runtime #2947

Merged
74 commits merged into from
Jul 19, 2021
Merged
Changes from 1 commit
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
8bd80d3
disputes module skeleton and storage
rphmeier Apr 28, 2021
101fde9
implement dispute module initialization logic
rphmeier Apr 28, 2021
4198797
implement disputes session change logic
rphmeier Apr 28, 2021
7dac193
provide dispute skeletons
rphmeier May 4, 2021
dd01c06
deduplication & ancient check
rphmeier May 4, 2021
ef153dc
fix a couple of warnings
rphmeier May 4, 2021
8dea7e6
begin provide_dispute_data impl
rphmeier May 5, 2021
f70f6e2
flesh out statement set import somewhat
rphmeier May 5, 2021
0451139
move ApprovalVote to shared primitives
rphmeier May 5, 2021
6748578
add a signing-payload API to explicit dispute statements
rphmeier May 5, 2021
95d6c19
implement statement signature checking
rphmeier May 5, 2021
ce5906b
Merge branch 'master' into rh-disputes-runtime
rphmeier May 5, 2021
01e948e
some bitflags glue for observing changes in disputes
rphmeier May 6, 2021
8e25b48
implement dispute vote import logic
rphmeier May 7, 2021
271434b
flesh out everything except slashing
rphmeier May 8, 2021
310ee52
guide: tweaks
rphmeier May 10, 2021
37c3c3a
declare and use punishment trait
rphmeier May 10, 2021
8180eae
punish validators for inconclusive disputes
rphmeier May 10, 2021
2ed7fe5
guide: tiny fix
rphmeier May 10, 2021
31c27c0
guide: update docs
rphmeier May 10, 2021
cfdbebd
add disputes getter fn
rphmeier May 10, 2021
dcd410c
guide: small change to spam slots handling
rphmeier May 10, 2021
ebd8b18
improve spam slots handling and fix some bugs
rphmeier May 10, 2021
da2d43a
finish API of disputes runtime
rphmeier May 10, 2021
d09c851
define and deposit `RevertTo` log
rphmeier May 11, 2021
cfe3241
begin integrating disputes into para_inherent
rphmeier May 11, 2021
d14e904
use precomputed slash_for/against
rphmeier May 11, 2021
7ffe889
return candidate hash from process_bitfields
rphmeier May 11, 2021
3638877
implement inclusion::collect_disputed
rphmeier May 11, 2021
82e86da
finish integration into rest of runtime
rphmeier May 11, 2021
955e0c4
add Disputes to initializer
rphmeier May 11, 2021
83e7b62
address suggestions
gui1117 May 21, 2021
fc3ab87
use pallet macro
gui1117 May 21, 2021
6fa374c
fix typo
gui1117 May 21, 2021
1b4838d
Update runtime/parachains/src/disputes.rs
gui1117 May 27, 2021
c0d15be
Merge branch 'rh-disputes-runtime' of https://github.com/paritytech/p…
rphmeier May 28, 2021
7ef44b5
add test: fix pruning
gui1117 May 28, 2021
7570236
document specific behavior
gui1117 May 28, 2021
6dd0ad6
deposit events on dispute changes
rphmeier May 31, 2021
040cc17
add an allow(unused) on fn disputes
rphmeier May 31, 2021
4a3eeba
add a dummy PunishValidators implementation
rphmeier May 31, 2021
6f5b27f
add disputes module to Rococo
rphmeier May 31, 2021
aacc3de
add disputes module to westend runtime
rphmeier May 31, 2021
993709b
add disputes module to test runtime
rphmeier May 31, 2021
5b7928a
add disputes module to kusama runtime
rphmeier May 31, 2021
14bd62d
Merge branch 'master' into rh-disputes-runtime
rphmeier May 31, 2021
776b3b6
guide: prepare for runtime API for checking frozenness
rphmeier Jun 2, 2021
a4ee80f
remove revert digests in favor of state variable
rphmeier Jun 2, 2021
b0d579c
merge reversions
rphmeier Jun 3, 2021
9430d3c
Update runtime/parachains/src/disputes.rs
rphmeier Jun 3, 2021
0680641
Update runtime/parachains/src/disputes.rs
rphmeier Jun 3, 2021
a715d61
Update runtime/parachains/src/disputes.rs
rphmeier Jun 3, 2021
3f6ce32
Merge branch 'master' into rh-disputes-runtime
rphmeier Jun 7, 2021
8ebc635
add byzantine_threshold and supermajority_threshold utilities to prim…
rphmeier Jun 10, 2021
f3e22c0
use primitive helpers
rphmeier Jun 10, 2021
53e2ccb
deposit revert event when freezing chain
andresilva Jun 23, 2021
4f4b84b
deposit revert log when freezing chain
andresilva Jun 23, 2021
a7ad191
test revert event and log are generated when freezing
andresilva Jun 23, 2021
7b04be6
add trait to decouple disputes handling from paras inherent handling
andresilva Jun 23, 2021
c6cf3f7
runtime: fix compilation and setup dispute handler
andresilva Jun 23, 2021
3acf2c1
Merge branch 'master' into rh-disputes-runtime
andresilva Jun 23, 2021
9aa95b4
disputes: add hook for filtering out dispute statements
andresilva Jun 23, 2021
ff06d0f
disputes: add initializer hooks to DisputesHandler
andresilva Jun 23, 2021
dd35e7f
runtime: remove disputes pallet from all runtimes
andresilva Jun 23, 2021
df6bfa8
Merge branch 'master' into rh-disputes-runtime
rphmeier Jul 15, 2021
9214a99
Merge branch 'rh-disputes-runtime' of https://github.com/paritytech/p…
rphmeier Jul 15, 2021
eb81811
tag TODOs
rphmeier Jul 15, 2021
c7afa0c
don't import any dispute statements just yet...
rphmeier Jul 15, 2021
4378b5c
address grumbles
rphmeier Jul 17, 2021
8a7abdb
fix spellcheck, hopefully
rphmeier Jul 17, 2021
663b5cc
maybe now?
rphmeier Jul 17, 2021
3be97bb
last spellcheck round
rphmeier Jul 17, 2021
bb47ed4
fix runtime tests
rphmeier Jul 19, 2021
5ecf237
fix test-runtime
rphmeier Jul 19, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
use pallet macro
  • Loading branch information
gui1117 committed May 21, 2021
commit fc3ab87c1be122f05158a883614f506c8f2f6cc4
149 changes: 80 additions & 69 deletions runtime/parachains/src/disputes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,44 +17,35 @@
//! Runtime component for handling disputes of parachain candidates.

use sp_std::prelude::*;
use sp_std::result;
#[cfg(feature = "std")]
use sp_std::marker::PhantomData;
use primitives::v1::{
Id as ParaId, ValidationCode, HeadData, SessionIndex, Hash, BlockNumber, CandidateHash,
Id as ParaId, SessionIndex, CandidateHash,
DisputeState, DisputeStatementSet, MultiDisputeStatementSet, ValidatorId, ValidatorSignature,
DisputeStatement, ValidDisputeStatementKind, InvalidDisputeStatementKind,
ExplicitDisputeStatement, CompactStatement, SigningContext, ApprovalVote, ValidatorIndex,
ConsensusLog,
};
use sp_runtime::{
traits::{One, Zero, Saturating, AppVerify},
DispatchResult, DispatchError, SaturatedConversion,
};
use frame_system::ensure_root;
use frame_support::{
decl_storage, decl_module, decl_error, decl_event, ensure,
traits::Get,
weights::Weight,
DispatchError, SaturatedConversion, RuntimeDebug,
};
use frame_support::{ensure, traits::Get, weights::Weight};
use parity_scale_codec::{Encode, Decode};
use bitvec::{bitvec, order::Lsb0 as BitOrderLsb0};
use crate::{
configuration::{self, HostConfiguration},
initializer::SessionChangeNotification,
shared,
session_info,
};

/// Whereas the dispute is local or remote.
rphmeier marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Encode, Decode, Clone, PartialEq, Eq)]
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub enum DisputeLocation {
Local,
Remote,
}

/// The result of a dispute, whether the candidate is deemed valid (for) or invalid (against).
#[derive(Encode, Decode, Clone, PartialEq, Eq)]
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub enum DisputeResult {
Valid,
Invalid,
Expand Down Expand Up @@ -85,46 +76,68 @@ pub trait PunishValidators {
fn punish_inconclusive(session: SessionIndex, validators: impl IntoIterator<Item=ValidatorIndex>);
}

pub trait Config:
frame_system::Config +
configuration::Config +
session_info::Config
{
type Event: From<Event> + Into<<Self as frame_system::Config>::Event>;
type RewardValidators: RewardValidators;
type PunishValidators: PunishValidators;
}

decl_storage! {
trait Store for Module<T: Config> as ParaDisputes {
/// The last pruneed session, if any. All data stored by this module
/// references sessions.
LastPrunedSession: Option<SessionIndex>;
// All ongoing or concluded disputes for the last several sessions.
Disputes: double_map
hasher(twox_64_concat) SessionIndex,
hasher(blake2_128_concat) CandidateHash
=> Option<DisputeState<T::BlockNumber>>;
// All included blocks on the chain, as well as the block number in this chain that
// should be reverted back to if the candidate is disputed and determined to be invalid.
Included: double_map
hasher(twox_64_concat) SessionIndex,
hasher(blake2_128_concat) CandidateHash
=> Option<T::BlockNumber>;
// Maps session indices to a vector indicating the number of potentially-spam disputes
// each validator is participating in. Potentially-spam disputes are remote disputes which have
// fewer than `byzantine_threshold + 1` validators.
//
// The i'th entry of the vector corresponds to the i'th validator in the session.
SpamSlots: map hasher(twox_64_concat) SessionIndex => Option<Vec<u32>>;
// Whether the chain is frozen or not. Starts as `false`. When this is `true`,
// the chain will not accept any new parachain blocks for backing or inclusion.
// It can only be set back to `false` by governance intervention.
Frozen get(fn is_frozen): bool;
pub use pallet::*;
#[frame_support::pallet]
pub mod pallet {
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use super::*;

#[pallet::config]
pub trait Config:
frame_system::Config +
configuration::Config +
session_info::Config
{
type Event: From<Event> + IsType<<Self as frame_system::Config>::Event>;
type RewardValidators: RewardValidators;
type PunishValidators: PunishValidators;
}
}

decl_event! {
#[pallet::pallet]
pub struct Pallet<T>(_);

/// The last pruneed session, if any. All data stored by this module
rphmeier marked this conversation as resolved.
Show resolved Hide resolved
/// references sessions.
#[pallet::storage]
pub(crate) type LastPrunedSession<T> = StorageValue<_, SessionIndex>;

/// All ongoing or concluded disputes for the last several sessions.
#[pallet::storage]
pub(crate) type Disputes<T: Config> = StorageDoubleMap<
_,
Twox64Concat, SessionIndex,
Blake2_128Concat, CandidateHash,
DisputeState<T::BlockNumber>,
>;

/// All included blocks on the chain, as well as the block number in this chain that
/// should be reverted back to if the candidate is disputed and determined to be invalid.
#[pallet::storage]
pub(crate) type Included<T: Config> = StorageDoubleMap<
_,
Twox64Concat, SessionIndex,
Blake2_128Concat, CandidateHash,
T::BlockNumber,
>;

/// Maps session indices to a vector indicating the number of potentially-spam disputes
/// each validator is participating in. Potentially-spam disputes are remote disputes which have
/// fewer than `byzantine_threshold + 1` validators.
///
/// The i'th entry of the vector corresponds to the i'th validator in the session.
#[pallet::storage]
pub(crate) type SpamSlots<T> = StorageMap<_, Twox64Concat, SessionIndex, Vec<u32>>;

/// Whether the chain is frozen or not. Starts as `false`. When this is `true`,
/// the chain will not accept any new parachain blocks for backing or inclusion.
/// It can only be set back to `false` by governance intervention.
#[pallet::storage]
#[pallet::getter(fn is_frozen)]
pub(crate) type Frozen<T> = StorageValue<_, bool, ValueQuery>;

#[pallet::event]
#[pallet::generate_deposit(fn deposit_event)]
pub enum Event {
/// A dispute has been initiated. \[para_id, candidate hash, dispute location\]
DisputeInitiated(ParaId, CandidateHash, DisputeLocation),
Expand All @@ -135,17 +148,15 @@ decl_event! {
/// \[para_id, candidate hash\]
DisputeTimedOut(ParaId, CandidateHash),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe I read it somewhere, but forgot. What do we do on timeout? Governance intervention, roll back just to be sure?

Copy link
Contributor

@drahnr drahnr May 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since one can not say for sure what should be done (that was the point of the dispute votes in the first place), so do nothing and let governance decide the action.

Copy link
Contributor

@burdges burdges May 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll slash everyone who should've participated in availability a tiny amount. Interestingly, if we worried about disputes spam slots preventing real disputes, then we'll want correlated timeouts to increase up to 100%, but..

Afaik, If we're confident the disputes spam slots blocking cannot obstruct real disputes: We do not care if adversarial nodes consume all their disputes spam slots. If honest parties votes in a dispute, then we should slash someone adversarial. If we've fill an honest nodes's disputes spam slot then we've so many of these the adversary should be slashed 100% by giving correlated wrong invalid votes.

We'd ideally spell this reasoning out more clearly elsewhere I guess, but so far I felt Rob's spam design aligns nicely.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a dispute times out, it means that the nodes are unable to participate and recover availability. A dispute initiation is a claim that the data is available, so we apply a minor punishment to all nodes which participated in the dispute.

}
}

decl_module! {
/// The parachains configuration module.
pub struct Module<T: Config> for enum Call where origin: <T as frame_system::Config>::Origin {
fn deposit_event() = default;
}
}
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}

#[pallet::call]
impl<T: Config> Pallet<T> {}
shawntabrizi marked this conversation as resolved.
Show resolved Hide resolved

decl_error! {
pub enum Error for Module<T: Config> {
#[pallet::error]
pub enum Error<T> {
/// Duplicate dispute statement sets provided.
DuplicateDisputeStatementSets,
/// Ancient dispute statement provided.
Expand Down Expand Up @@ -379,7 +390,7 @@ impl<BlockNumber: Clone> DisputeStateImporter<BlockNumber> {
}
}

impl<T: Config> Module<T> {
impl<T: Config> Pallet<T> {
/// Called by the initalizer to initialize the disputes module.
pub(crate) fn initializer_initialize(now: T::BlockNumber) -> Weight {
let config = <configuration::Module<T>>::config();
Expand All @@ -403,7 +414,7 @@ impl<T: Config> Module<T> {

// mildly punish all validators involved. they've failed to make
// data available to others, so this is most likely spam.
SpamSlots::mutate(session_index, |spam_slots| {
SpamSlots::<T>::mutate(session_index, |spam_slots| {
let spam_slots = match spam_slots {
Some(ref mut s) => s,
None => return,
Expand Down Expand Up @@ -446,12 +457,12 @@ impl<T: Config> Module<T> {

let pruning_target = notification.session_index - config.dispute_period - 1;

LastPrunedSession::mutate(|last_pruned| {
LastPrunedSession::<T>::mutate(|last_pruned| {
if let Some(last_pruned) = last_pruned {
for to_prune in *last_pruned + 1 ..= pruning_target {
<Disputes<T>>::remove_prefix(to_prune);
<Included<T>>::remove_prefix(to_prune);
SpamSlots::remove(to_prune);
SpamSlots::<T>::remove(to_prune);
}
}

Expand Down Expand Up @@ -561,7 +572,7 @@ impl<T: Config> Module<T> {

// Apply spam slot changes. Bail early if too many occupied.
if !<Included<T>>::contains_key(&set.session, &set.candidate_hash) {
let mut spam_slots: Vec<u32> = SpamSlots::get(&set.session)
let mut spam_slots: Vec<u32> = SpamSlots::<T>::get(&set.session)
.unwrap_or_else(|| vec![0; n_validators]);

for (validator_index, spam_slot_change) in summary.spam_slot_changes {
Expand All @@ -583,7 +594,7 @@ impl<T: Config> Module<T> {
}
}

SpamSlots::insert(&set.session, spam_slots);
SpamSlots::<T>::insert(&set.session, spam_slots);
}

// Reward statements.
Expand Down Expand Up @@ -637,7 +648,7 @@ impl<T: Config> Module<T> {
// If we just included a block locally which has a live dispute, decrement spam slots
andresilva marked this conversation as resolved.
Show resolved Hide resolved
// for any involved validators, if the dispute is not already confirmed by f + 1.
if let Some(state) = <Disputes<T>>::get(&session, candidate_hash) {
SpamSlots::mutate(&session, |spam_slots| {
SpamSlots::<T>::mutate(&session, |spam_slots| {
if let Some(ref mut spam_slots) = *spam_slots {
decrement_spam(spam_slots, &state);
}
Expand All @@ -662,7 +673,7 @@ impl<T: Config> Module<T> {
let revert_to = revert_to.saturated_into();
<frame_system::Pallet<T>>::deposit_log(ConsensusLog::RevertTo(revert_to).into());

Frozen::set(true);
Frozen::<T>::set(true);
}
}

Expand Down