Skip to content

Commit

Permalink
Slash bad validators (#468)
Browse files Browse the repository at this point in the history
* implement general design

* add slashing

* bug fixes

* fix pr comments

* misc fixes

* fix grandpa abi call type

* Correct rebase artifacts I introduced

* Cleanups and corrections

1) Uses vec![] for the OpaqueKeyProof as there's no value to passing it around
2) Remove usage of Babe/Grandpa Offences for tracking if an offence is known
   for checking if can slash. If can slash, no prior offence must have been
   known.
3) Rename DisabledIndices to SeraiDisabledIndices, drop historical data for
   current session only.
4) Doesn't remove from the pre-declared upcoming Serai set upon slash due to
   breaking light clients.
5) Into/From instead of AsRef for KeyOwnerProofSystem's generic to ensure
   safety of the conversion.

* Correct deduction from TotalAllocatedStake on slash

It should only be done if in set and only with allocations contributing to
TotalAllocatedStake (Allocation + latest session's PendingDeallocation).

* Changes meant for prior commit

---------

Co-authored-by: Luke Parker <[email protected]>
  • Loading branch information
akildemir and kayabaNerve authored Dec 16, 2023
1 parent 74a68c6 commit c40ce00
Show file tree
Hide file tree
Showing 7 changed files with 334 additions and 77 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions substrate/abi/src/babe.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use sp_consensus_babe::EquivocationProof;

use serai_primitives::Header;
use serai_primitives::{Header, SeraiAddress};

#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
pub struct ReportEquivocation {
pub equivocation_proof: Box<EquivocationProof<Header>>,
pub key_owner_proof: (),
pub key_owner_proof: SeraiAddress,
}

// We could define a Babe Config here and use the literal pallet_babe::Call
Expand Down
2 changes: 1 addition & 1 deletion substrate/abi/src/grandpa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use serai_primitives::{BlockNumber, SeraiAddress};
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
pub struct ReportEquivocation {
pub equivocation_proof: Box<EquivocationProof<[u8; 32], BlockNumber>>,
pub key_owner_proof: (),
pub key_owner_proof: SeraiAddress,
}

#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
Expand Down
2 changes: 2 additions & 0 deletions substrate/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ frame-benchmarking = { git = "https://github.com/serai-dex/substrate", default-f
serai-primitives = { path = "../primitives", default-features = false }

pallet-timestamp = { git = "https://github.com/serai-dex/substrate", default-features = false }
pallet-authorship = { git = "https://github.com/serai-dex/substrate", default-features = false }

pallet-transaction-payment = { git = "https://github.com/serai-dex/substrate", default-features = false }

Expand Down Expand Up @@ -98,6 +99,7 @@ std = [
"serai-primitives/std",

"pallet-timestamp/std",
"pallet-authorship/std",

"pallet-transaction-payment/std",

Expand Down
78 changes: 54 additions & 24 deletions substrate/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));

use core::marker::PhantomData;

// Re-export all components
pub use serai_primitives as primitives;
pub use primitives::{BlockNumber, Header};
Expand Down Expand Up @@ -55,9 +57,11 @@ use support::{
parameter_types, construct_runtime,
};

use validator_sets::MembershipProof;

use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use babe::AuthorityId as BabeId;
use grandpa::AuthorityId as GrandpaId;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;

/// Nonce of a transaction in the chain, for a given account.
pub type Nonce = u32;
Expand Down Expand Up @@ -141,8 +145,6 @@ parameter_types! {
Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX),
NORMAL_DISPATCH_RATIO,
);

pub const MaxAuthorities: u32 = validator_sets::primitives::MAX_KEY_SHARES_PER_SET;
}

pub struct CallFilter;
Expand Down Expand Up @@ -275,20 +277,43 @@ impl in_instructions::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
}

// for publishing equivocation evidences.
impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime
where
RuntimeCall: From<C>,
{
type Extrinsic = Transaction;
type OverarchingCall = RuntimeCall;
}

// for validating equivocation evidences.
// The following runtime construction doesn't actually implement the pallet as doing so is
// unnecessary
// TODO: Replace the requirement on Config for a requirement on FindAuthor directly
impl pallet_authorship::Config for Runtime {
type FindAuthor = ValidatorSets;
type EventHandler = ();
}

// Maximum number of authorities per session.
pub type MaxAuthorities = ConstU32<{ validator_sets::primitives::MAX_KEY_SHARES_PER_SET }>;

/// Longevity of an offence report.
pub type ReportLongevity = <Runtime as pallet_babe::Config>::EpochDuration;

impl babe::Config for Runtime {
#[allow(clippy::identity_op)]
type EpochDuration = ConstU64<{ 1 * DAYS }>;
type ExpectedBlockTime = ConstU64<{ TARGET_BLOCK_TIME * 1000 }>;
type EpochChangeTrigger = pallet_babe::ExternalTrigger;
type EpochChangeTrigger = babe::ExternalTrigger;
type DisabledValidators = ValidatorSets;

type WeightInfo = ();

type MaxAuthorities = MaxAuthorities;

// TODO: Handle equivocation reports
type KeyOwnerProof = sp_core::Void;
type EquivocationReportSystem = ();
type KeyOwnerProof = MembershipProof<Self>;
type EquivocationReportSystem =
babe::EquivocationReportSystem<Self, ValidatorSets, ValidatorSets, ReportLongevity>;
}

impl grandpa::Config for Runtime {
Expand All @@ -297,10 +322,10 @@ impl grandpa::Config for Runtime {
type WeightInfo = ();
type MaxAuthorities = MaxAuthorities;

// TODO: Handle equivocation reports
type MaxSetIdSessionEntries = ConstU64<0>;
type KeyOwnerProof = sp_core::Void;
type EquivocationReportSystem = ();
type KeyOwnerProof = MembershipProof<Self>;
type EquivocationReportSystem =
grandpa::EquivocationReportSystem<Self, ValidatorSets, ValidatorSets, ReportLongevity>;
}

pub type Executive = frame_executive::Executive<
Expand Down Expand Up @@ -459,18 +484,22 @@ sp_api::impl_runtime_apis! {
Babe::next_epoch()
}

// This refers to a key being 'owned' by an authority in a system with multiple keys per
// validator
// Since we do not have such an infrastructure, we do not need this
fn generate_key_ownership_proof(
_: sp_consensus_babe::Slot,
_: BabeId,
_slot: sp_consensus_babe::Slot,
_authority_id: BabeId,
) -> Option<sp_consensus_babe::OpaqueKeyOwnershipProof> {
None
Some(sp_consensus_babe::OpaqueKeyOwnershipProof::new(vec![]))
}

fn submit_report_equivocation_unsigned_extrinsic(
_: sp_consensus_babe::EquivocationProof<Header>,
equivocation_proof: sp_consensus_babe::EquivocationProof<Header>,
_: sp_consensus_babe::OpaqueKeyOwnershipProof,
) -> Option<()> {
None
let proof = MembershipProof(equivocation_proof.offender.clone().into(), PhantomData);
Babe::submit_unsigned_equivocation_report(equivocation_proof, proof)
}
}

Expand All @@ -483,18 +512,19 @@ sp_api::impl_runtime_apis! {
Grandpa::current_set_id()
}

fn submit_report_equivocation_unsigned_extrinsic(
_: sp_consensus_grandpa::EquivocationProof<<Block as BlockT>::Hash, u64>,
_: sp_consensus_grandpa::OpaqueKeyOwnershipProof,
) -> Option<()> {
None
}

fn generate_key_ownership_proof(
_set_id: sp_consensus_grandpa::SetId,
_authority_id: GrandpaId,
) -> Option<sp_consensus_grandpa::OpaqueKeyOwnershipProof> {
None
Some(sp_consensus_grandpa::OpaqueKeyOwnershipProof::new(vec![]))
}

fn submit_report_equivocation_unsigned_extrinsic(
equivocation_proof: sp_consensus_grandpa::EquivocationProof<<Block as BlockT>::Hash, u64>,
_: sp_consensus_grandpa::OpaqueKeyOwnershipProof,
) -> Option<()> {
let proof = MembershipProof(equivocation_proof.offender().clone().into(), PhantomData);
Grandpa::submit_unsigned_equivocation_report(equivocation_proof, proof)
}
}

Expand Down
2 changes: 2 additions & 0 deletions substrate/validator-sets/pallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ sp-std = { git = "https://github.com/serai-dex/substrate", default-features = fa
sp-application-crypto = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-session = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-staking = { git = "https://github.com/serai-dex/substrate", default-features = false }

frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false }
frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false }
Expand All @@ -51,6 +52,7 @@ std = [
"sp-application-crypto/std",
"sp-runtime/std",
"sp-session/std",
"sp-staking/std",

"frame-system/std",
"frame-support/std",
Expand Down
Loading

0 comments on commit c40ce00

Please sign in to comment.