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

Commit

Permalink
runtime: past session slashing runtime API (#6667)
Browse files Browse the repository at this point in the history
* runtime/vstaging: unapplied_slashes runtime API

* runtime/vstaging: key_ownership_proof runtime API

* runtime/ParachainHost: submit_report_dispute_lost

* fix key_ownership_proof API

* runtime: submit_report_dispute_lost runtime API

* nits

* Update node/subsystem-types/src/messages.rs

Co-authored-by: Marcin S. <marcin@bytedude.com>

* revert unrelated fmt changes

* post merge fixes

* fix compilation

---------

Co-authored-by: Marcin S. <marcin@bytedude.com>
  • Loading branch information
ordian and mrcnski authored May 26, 2023
1 parent 3e93b4c commit 7104195
Show file tree
Hide file tree
Showing 12 changed files with 441 additions and 96 deletions.
64 changes: 59 additions & 5 deletions node/core/runtime-api/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ use lru::LruCache;
use sp_consensus_babe::Epoch;

use polkadot_primitives::{
AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash,
CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash,
Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption,
PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo,
ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature,
vstaging, AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent,
CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams,
GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage,
OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes,
SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex,
ValidatorSignature,
};

/// For consistency we have the same capacity for all caches. We use 128 as we'll only need that
Expand Down Expand Up @@ -63,6 +64,10 @@ pub(crate) struct RequestResultCache {
LruCache<(Hash, ParaId, OccupiedCoreAssumption), Option<ValidationCodeHash>>,
version: LruCache<Hash, u32>,
disputes: LruCache<Hash, Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>>,
unapplied_slashes:
LruCache<Hash, Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>>,
key_ownership_proof:
LruCache<(Hash, ValidatorId), Option<vstaging::slashing::OpaqueKeyOwnershipProof>>,
}

impl Default for RequestResultCache {
Expand Down Expand Up @@ -90,6 +95,8 @@ impl Default for RequestResultCache {
validation_code_hash: LruCache::new(DEFAULT_CACHE_CAP),
version: LruCache::new(DEFAULT_CACHE_CAP),
disputes: LruCache::new(DEFAULT_CACHE_CAP),
unapplied_slashes: LruCache::new(DEFAULT_CACHE_CAP),
key_ownership_proof: LruCache::new(DEFAULT_CACHE_CAP),
}
}
}
Expand Down Expand Up @@ -385,6 +392,44 @@ impl RequestResultCache {
) {
self.disputes.put(relay_parent, value);
}

pub(crate) fn unapplied_slashes(
&mut self,
relay_parent: &Hash,
) -> Option<&Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>> {
self.unapplied_slashes.get(relay_parent)
}

pub(crate) fn cache_unapplied_slashes(
&mut self,
relay_parent: Hash,
value: Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>,
) {
self.unapplied_slashes.put(relay_parent, value);
}

pub(crate) fn key_ownership_proof(
&mut self,
key: (Hash, ValidatorId),
) -> Option<&Option<vstaging::slashing::OpaqueKeyOwnershipProof>> {
self.key_ownership_proof.get(&key)
}

pub(crate) fn cache_key_ownership_proof(
&mut self,
key: (Hash, ValidatorId),
value: Option<vstaging::slashing::OpaqueKeyOwnershipProof>,
) {
self.key_ownership_proof.put(key, value);
}

// This request is never cached, hence always returns `None`.
pub(crate) fn submit_report_dispute_lost(
&mut self,
_key: (Hash, vstaging::slashing::DisputeProof, vstaging::slashing::OpaqueKeyOwnershipProof),
) -> Option<&Option<()>> {
None
}
}

pub(crate) enum RequestResult {
Expand Down Expand Up @@ -422,4 +467,13 @@ pub(crate) enum RequestResult {
ValidationCodeHash(Hash, ParaId, OccupiedCoreAssumption, Option<ValidationCodeHash>),
Version(Hash, u32),
Disputes(Hash, Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>),
UnappliedSlashes(Hash, Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>),
KeyOwnershipProof(Hash, ValidatorId, Option<vstaging::slashing::OpaqueKeyOwnershipProof>),
// This is a request with side-effects.
SubmitReportDisputeLost(
Hash,
vstaging::slashing::DisputeProof,
vstaging::slashing::OpaqueKeyOwnershipProof,
Option<()>,
),
}
95 changes: 71 additions & 24 deletions node/core/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ where
self.requests_cache.cache_version(relay_parent, version),
Disputes(relay_parent, disputes) =>
self.requests_cache.cache_disputes(relay_parent, disputes),
UnappliedSlashes(relay_parent, unapplied_slashes) =>
self.requests_cache.cache_unapplied_slashes(relay_parent, unapplied_slashes),
KeyOwnershipProof(relay_parent, validator_id, key_ownership_proof) => self
.requests_cache
.cache_key_ownership_proof((relay_parent, validator_id), key_ownership_proof),
SubmitReportDisputeLost(_, _, _, _) => {},
}
}

Expand Down Expand Up @@ -271,6 +277,17 @@ where
.map(|sender| Request::ValidationCodeHash(para, assumption, sender)),
Request::Disputes(sender) =>
query!(disputes(), sender).map(|sender| Request::Disputes(sender)),
Request::UnappliedSlashes(sender) =>
query!(unapplied_slashes(), sender).map(|sender| Request::UnappliedSlashes(sender)),
Request::KeyOwnershipProof(validator_id, sender) =>
query!(key_ownership_proof(validator_id), sender)
.map(|sender| Request::KeyOwnershipProof(validator_id, sender)),
Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, sender) =>
query!(submit_report_dispute_lost(dispute_proof, key_ownership_proof), sender).map(
|sender| {
Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, sender)
},
),
}
}

Expand Down Expand Up @@ -419,33 +436,38 @@ where

Request::Authorities(sender) => query!(Authorities, authorities(), ver = 1, sender),
Request::Validators(sender) => query!(Validators, validators(), ver = 1, sender),
Request::ValidatorGroups(sender) =>
query!(ValidatorGroups, validator_groups(), ver = 1, sender),
Request::AvailabilityCores(sender) =>
query!(AvailabilityCores, availability_cores(), ver = 1, sender),
Request::ValidatorGroups(sender) => {
query!(ValidatorGroups, validator_groups(), ver = 1, sender)
},
Request::AvailabilityCores(sender) => {
query!(AvailabilityCores, availability_cores(), ver = 1, sender)
},
Request::PersistedValidationData(para, assumption, sender) => query!(
PersistedValidationData,
persisted_validation_data(para, assumption),
ver = 1,
sender
),
Request::AssumedValidationData(para, expected_persisted_validation_data_hash, sender) =>
Request::AssumedValidationData(para, expected_persisted_validation_data_hash, sender) => {
query!(
AssumedValidationData,
assumed_validation_data(para, expected_persisted_validation_data_hash),
ver = 1,
sender
),
)
},
Request::CheckValidationOutputs(para, commitments, sender) => query!(
CheckValidationOutputs,
check_validation_outputs(para, commitments),
ver = 1,
sender
),
Request::SessionIndexForChild(sender) =>
query!(SessionIndexForChild, session_index_for_child(), ver = 1, sender),
Request::ValidationCode(para, assumption, sender) =>
query!(ValidationCode, validation_code(para, assumption), ver = 1, sender),
Request::SessionIndexForChild(sender) => {
query!(SessionIndexForChild, session_index_for_child(), ver = 1, sender)
},
Request::ValidationCode(para, assumption, sender) => {
query!(ValidationCode, validation_code(para, assumption), ver = 1, sender)
},
Request::ValidationCodeByHash(validation_code_hash, sender) => query!(
ValidationCodeByHash,
validation_code_by_hash(validation_code_hash),
Expand All @@ -458,23 +480,28 @@ where
ver = 1,
sender
),
Request::CandidateEvents(sender) =>
query!(CandidateEvents, candidate_events(), ver = 1, sender),
Request::SessionInfo(index, sender) =>
query!(SessionInfo, session_info(index), ver = 2, sender),
Request::CandidateEvents(sender) => {
query!(CandidateEvents, candidate_events(), ver = 1, sender)
},
Request::SessionInfo(index, sender) => {
query!(SessionInfo, session_info(index), ver = 2, sender)
},
Request::SessionExecutorParams(session_index, sender) => query!(
SessionExecutorParams,
session_executor_params(session_index),
ver = Request::EXECUTOR_PARAMS_RUNTIME_REQUIREMENT,
sender
),
Request::DmqContents(id, sender) => query!(DmqContents, dmq_contents(id), ver = 1, sender),
Request::InboundHrmpChannelsContents(id, sender) =>
query!(InboundHrmpChannelsContents, inbound_hrmp_channels_contents(id), ver = 1, sender),
Request::CurrentBabeEpoch(sender) =>
query!(CurrentBabeEpoch, current_epoch(), ver = 1, sender),
Request::FetchOnChainVotes(sender) =>
query!(FetchOnChainVotes, on_chain_votes(), ver = 1, sender),
Request::InboundHrmpChannelsContents(id, sender) => {
query!(InboundHrmpChannelsContents, inbound_hrmp_channels_contents(id), ver = 1, sender)
},
Request::CurrentBabeEpoch(sender) => {
query!(CurrentBabeEpoch, current_epoch(), ver = 1, sender)
},
Request::FetchOnChainVotes(sender) => {
query!(FetchOnChainVotes, on_chain_votes(), ver = 1, sender)
},
Request::SubmitPvfCheckStatement(stmt, signature, sender) => {
query!(
SubmitPvfCheckStatement,
Expand All @@ -486,9 +513,29 @@ where
Request::PvfsRequirePrecheck(sender) => {
query!(PvfsRequirePrecheck, pvfs_require_precheck(), ver = 2, sender)
},
Request::ValidationCodeHash(para, assumption, sender) =>
query!(ValidationCodeHash, validation_code_hash(para, assumption), ver = 2, sender),
Request::Disputes(sender) =>
query!(Disputes, disputes(), ver = Request::DISPUTES_RUNTIME_REQUIREMENT, sender),
Request::ValidationCodeHash(para, assumption, sender) => {
query!(ValidationCodeHash, validation_code_hash(para, assumption), ver = 2, sender)
},
Request::Disputes(sender) => {
query!(Disputes, disputes(), ver = Request::DISPUTES_RUNTIME_REQUIREMENT, sender)
},
Request::UnappliedSlashes(sender) => query!(
UnappliedSlashes,
unapplied_slashes(),
ver = Request::UNAPPLIED_SLASHES_RUNTIME_REQUIREMENT,
sender
),
Request::KeyOwnershipProof(validator_id, sender) => query!(
KeyOwnershipProof,
key_ownership_proof(validator_id),
ver = Request::KEY_OWNERSHIP_PROOF_RUNTIME_REQUIREMENT,
sender
),
Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, sender) => query!(
SubmitReportDisputeLost,
submit_report_dispute_lost(dispute_proof, key_ownership_proof),
ver = Request::SUBMIT_REPORT_DISPUTE_LOST_RUNTIME_REQUIREMENT,
sender
),
}
}
29 changes: 28 additions & 1 deletion node/subsystem-types/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use polkadot_node_primitives::{
SignedDisputeStatement, SignedFullStatement, ValidationResult,
};
use polkadot_primitives::{
AuthorityDiscoveryId, BackedCandidate, BlockNumber, CandidateEvent, CandidateHash,
vstaging, AuthorityDiscoveryId, BackedCandidate, BlockNumber, CandidateEvent, CandidateHash,
CandidateIndex, CandidateReceipt, CollatorId, CommittedCandidateReceipt, CoreState,
DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, Header as BlockHeader,
Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, MultiDisputeStatementSet,
Expand Down Expand Up @@ -606,6 +606,24 @@ pub enum RuntimeApiRequest {
),
/// Returns all on-chain disputes at given block number. Available in `v3`.
Disputes(RuntimeApiSender<Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>>),
/// Returns a list of validators that lost a past session dispute and need to be slashed.
/// `VStaging`
UnappliedSlashes(
RuntimeApiSender<Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>>,
),
/// Returns a merkle proof of a validator session key.
/// `VStaging`
KeyOwnershipProof(
ValidatorId,
RuntimeApiSender<Option<vstaging::slashing::OpaqueKeyOwnershipProof>>,
),
/// Submits an unsigned extrinsic to slash validator who lost a past session dispute.
/// `VStaging`
SubmitReportDisputeLost(
vstaging::slashing::DisputeProof,
vstaging::slashing::OpaqueKeyOwnershipProof,
RuntimeApiSender<Option<()>>,
),
}

impl RuntimeApiRequest {
Expand All @@ -614,8 +632,17 @@ impl RuntimeApiRequest {
/// `Disputes`
pub const DISPUTES_RUNTIME_REQUIREMENT: u32 = 3;

/// `UnappliedSlashes`
pub const UNAPPLIED_SLASHES_RUNTIME_REQUIREMENT: u32 = 4;

/// `ExecutorParams`
pub const EXECUTOR_PARAMS_RUNTIME_REQUIREMENT: u32 = 4;

/// `KeyOwnershipProof`
pub const KEY_OWNERSHIP_PROOF_RUNTIME_REQUIREMENT: u32 = 4;

/// `SubmitReportDisputeLost`
pub const SUBMIT_REPORT_DISPUTE_LOST_RUNTIME_REQUIREMENT: u32 = 4;
}

/// A message to the Runtime API subsystem.
Expand Down
55 changes: 54 additions & 1 deletion node/subsystem-types/src/runtime_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

use async_trait::async_trait;
use polkadot_primitives::{
runtime_api::ParachainHost, Block, BlockNumber, CandidateCommitments, CandidateEvent,
runtime_api::ParachainHost, vstaging, Block, BlockNumber, CandidateCommitments, CandidateEvent,
CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams,
GroupRotationInfo, Hash, Id, InboundDownwardMessage, InboundHrmpMessage,
OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes,
Expand Down Expand Up @@ -182,6 +182,34 @@ pub trait RuntimeApiSubsystemClient {
at: Hash,
) -> Result<Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>, ApiError>;

/// Returns a list of validators that lost a past session dispute and need to be slashed.
///
/// WARNING: This is a staging method! Do not use on production runtimes!
async fn unapplied_slashes(
&self,
at: Hash,
) -> Result<Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>, ApiError>;

/// Returns a merkle proof of a validator session key in a past session.
///
/// WARNING: This is a staging method! Do not use on production runtimes!
async fn key_ownership_proof(
&self,
at: Hash,
validator_id: ValidatorId,
) -> Result<Option<vstaging::slashing::OpaqueKeyOwnershipProof>, ApiError>;

/// Submits an unsigned extrinsic to slash validators who lost a dispute about
/// a candidate of a past session.
///
/// WARNING: This is a staging method! Do not use on production runtimes!
async fn submit_report_dispute_lost(
&self,
at: Hash,
dispute_proof: vstaging::slashing::DisputeProof,
key_ownership_proof: vstaging::slashing::OpaqueKeyOwnershipProof,
) -> Result<Option<()>, ApiError>;

/// Get the execution environment parameter set by parent hash, if stored
async fn session_executor_params(
&self,
Expand Down Expand Up @@ -374,4 +402,29 @@ where
) -> Result<Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>, ApiError> {
self.runtime_api().disputes(at)
}

async fn unapplied_slashes(
&self,
at: Hash,
) -> Result<Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>, ApiError> {
self.runtime_api().unapplied_slashes(at)
}

async fn key_ownership_proof(
&self,
at: Hash,
validator_id: ValidatorId,
) -> Result<Option<vstaging::slashing::OpaqueKeyOwnershipProof>, ApiError> {
self.runtime_api().key_ownership_proof(at, validator_id)
}

async fn submit_report_dispute_lost(
&self,
at: Hash,
dispute_proof: vstaging::slashing::DisputeProof,
key_ownership_proof: vstaging::slashing::OpaqueKeyOwnershipProof,
) -> Result<Option<()>, ApiError> {
self.runtime_api()
.submit_report_dispute_lost(at, dispute_proof, key_ownership_proof)
}
}
Loading

0 comments on commit 7104195

Please sign in to comment.