mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 07:01:03 +00:00
Move vstaging to production (#7341)
* Move vstaging to production (and thus past session slashing). WIP: test-runtime still needs to be fixed. * Fix test-runtime. --------- Co-authored-by: eskimor <eskimor@no-such-url.com>
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Abstract execution environment parameter set.
|
||||
//!
|
||||
//! Parameter set is encoded as an opaque vector which structure depends on the execution
|
||||
//! environment itself (except for environment type/version which is always represented
|
||||
//! by the first element of the vector). Decoding to a usable semantics structure is
|
||||
//! done in `polkadot-node-core-pvf`.
|
||||
|
||||
use crate::{BlakeTwo256, HashT as _, PvfExecTimeoutKind, PvfPrepTimeoutKind};
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use polkadot_core_primitives::Hash;
|
||||
use scale_info::TypeInfo;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sp_std::{ops::Deref, time::Duration, vec, vec::Vec};
|
||||
|
||||
/// The different executor parameters for changing the execution environment semantics.
|
||||
#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, Serialize, Deserialize)]
|
||||
pub enum ExecutorParam {
|
||||
/// Maximum number of memory pages (64KiB bytes per page) the executor can allocate.
|
||||
#[codec(index = 1)]
|
||||
MaxMemoryPages(u32),
|
||||
/// Wasm logical stack size limit (max. number of Wasm values on stack)
|
||||
#[codec(index = 2)]
|
||||
StackLogicalMax(u32),
|
||||
/// Executor machine stack size limit, in bytes
|
||||
#[codec(index = 3)]
|
||||
StackNativeMax(u32),
|
||||
/// Max. amount of memory the preparation worker is allowed to use during
|
||||
/// pre-checking, in bytes
|
||||
#[codec(index = 4)]
|
||||
PrecheckingMaxMemory(u64),
|
||||
/// PVF preparation timeouts, millisec
|
||||
#[codec(index = 5)]
|
||||
PvfPrepTimeout(PvfPrepTimeoutKind, u64),
|
||||
/// PVF execution timeouts, millisec
|
||||
#[codec(index = 6)]
|
||||
PvfExecTimeout(PvfExecTimeoutKind, u64),
|
||||
/// Enables WASM bulk memory proposal
|
||||
#[codec(index = 7)]
|
||||
WasmExtBulkMemory,
|
||||
}
|
||||
|
||||
/// Unit type wrapper around [`type@Hash`] that represents an execution parameter set hash.
|
||||
///
|
||||
/// This type is produced by [`ExecutorParams::hash`].
|
||||
#[derive(Clone, Copy, Encode, Decode, Hash, Eq, PartialEq, PartialOrd, Ord, TypeInfo)]
|
||||
pub struct ExecutorParamsHash(Hash);
|
||||
|
||||
impl ExecutorParamsHash {
|
||||
/// Create a new executor parameter hash from `H256` hash
|
||||
pub fn from_hash(hash: Hash) -> Self {
|
||||
Self(hash)
|
||||
}
|
||||
}
|
||||
|
||||
impl sp_std::fmt::Display for ExecutorParamsHash {
|
||||
fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl sp_std::fmt::Debug for ExecutorParamsHash {
|
||||
fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result {
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl sp_std::fmt::LowerHex for ExecutorParamsHash {
|
||||
fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result {
|
||||
sp_std::fmt::LowerHex::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// # Deterministically serialized execution environment semantics
|
||||
/// Represents an arbitrary semantics of an arbitrary execution environment, so should be kept as
|
||||
/// abstract as possible.
|
||||
// ADR: For mandatory entries, mandatoriness should be enforced in code rather than separating them
|
||||
// into individual fields of the structure. Thus, complex migrations shall be avoided when adding
|
||||
// new entries and removing old ones. At the moment, there's no mandatory parameters defined. If
|
||||
// they show up, they must be clearly documented as mandatory ones.
|
||||
#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq, TypeInfo, Serialize, Deserialize)]
|
||||
pub struct ExecutorParams(Vec<ExecutorParam>);
|
||||
|
||||
impl ExecutorParams {
|
||||
/// Creates a new, empty executor parameter set
|
||||
pub fn new() -> Self {
|
||||
ExecutorParams(vec![])
|
||||
}
|
||||
|
||||
/// Returns hash of the set of execution environment parameters
|
||||
pub fn hash(&self) -> ExecutorParamsHash {
|
||||
ExecutorParamsHash(BlakeTwo256::hash(&self.encode()))
|
||||
}
|
||||
|
||||
/// Returns a PVF preparation timeout, if any
|
||||
pub fn pvf_prep_timeout(&self, kind: PvfPrepTimeoutKind) -> Option<Duration> {
|
||||
for param in &self.0 {
|
||||
if let ExecutorParam::PvfPrepTimeout(k, timeout) = param {
|
||||
if kind == *k {
|
||||
return Some(Duration::from_millis(*timeout))
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns a PVF execution timeout, if any
|
||||
pub fn pvf_exec_timeout(&self, kind: PvfExecTimeoutKind) -> Option<Duration> {
|
||||
for param in &self.0 {
|
||||
if let ExecutorParam::PvfExecTimeout(k, timeout) = param {
|
||||
if kind == *k {
|
||||
return Some(Duration::from_millis(*timeout))
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ExecutorParams {
|
||||
type Target = Vec<ExecutorParam>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[ExecutorParam]> for ExecutorParams {
|
||||
fn from(arr: &[ExecutorParam]) -> Self {
|
||||
ExecutorParams(arr.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ExecutorParams {
|
||||
fn default() -> Self {
|
||||
ExecutorParams(vec![])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Runtime metric primitives.
|
||||
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
/// Runtime metric operations.
|
||||
#[derive(Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
pub enum RuntimeMetricOp {
|
||||
/// Increment a counter metric with labels by value.
|
||||
IncrementCounterVec(u64, RuntimeMetricLabelValues),
|
||||
/// Increment a counter metric by value.
|
||||
IncrementCounter(u64),
|
||||
/// Observe histogram value
|
||||
ObserveHistogram(u128),
|
||||
}
|
||||
|
||||
/// Runtime metric update event.
|
||||
#[derive(Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
pub struct RuntimeMetricUpdate {
|
||||
/// The name of the metric.
|
||||
pub metric_name: Vec<u8>,
|
||||
/// The operation applied to the metric.
|
||||
pub op: RuntimeMetricOp,
|
||||
}
|
||||
|
||||
fn vec_to_str<'a>(v: &'a Vec<u8>, default: &'static str) -> &'a str {
|
||||
return sp_std::str::from_utf8(v).unwrap_or(default)
|
||||
}
|
||||
|
||||
impl RuntimeMetricLabels {
|
||||
/// Returns a labels as `Vec<&str>`.
|
||||
pub fn as_str_vec(&self) -> Vec<&str> {
|
||||
self.0
|
||||
.iter()
|
||||
.map(|label_vec| vec_to_str(&label_vec.0, "invalid_label"))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Return the inner values as vec.
|
||||
pub fn clear(&mut self) {
|
||||
self.0.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[&'static str]> for RuntimeMetricLabels {
|
||||
fn from(v: &[&'static str]) -> RuntimeMetricLabels {
|
||||
RuntimeMetricLabels(
|
||||
v.iter().map(|label| RuntimeMetricLabel(label.as_bytes().to_vec())).collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl RuntimeMetricUpdate {
|
||||
/// Returns the metric name.
|
||||
pub fn metric_name(&self) -> &str {
|
||||
vec_to_str(&self.metric_name, "invalid_metric_name")
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of metric labels.
|
||||
#[derive(Clone, Default, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
pub struct RuntimeMetricLabels(Vec<RuntimeMetricLabel>);
|
||||
|
||||
/// A metric label.
|
||||
#[derive(Clone, Default, Encode, Decode)]
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
pub struct RuntimeMetricLabel(Vec<u8>);
|
||||
|
||||
/// A metric label value.
|
||||
pub type RuntimeMetricLabelValue = RuntimeMetricLabel;
|
||||
|
||||
/// A set of metric label values.
|
||||
pub type RuntimeMetricLabelValues = RuntimeMetricLabels;
|
||||
|
||||
/// Trait for converting Vec<u8> to `&str`.
|
||||
pub trait AsStr {
|
||||
/// Return a str reference.
|
||||
fn as_str(&self) -> Option<&str>;
|
||||
}
|
||||
|
||||
impl AsStr for RuntimeMetricLabel {
|
||||
fn as_str(&self) -> Option<&str> {
|
||||
sp_std::str::from_utf8(&self.0).ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for RuntimeMetricLabel {
|
||||
fn from(s: &'static str) -> Self {
|
||||
Self(s.as_bytes().to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains all runtime metrics defined as constants.
|
||||
pub mod metric_definitions {
|
||||
/// `Counter` metric definition.
|
||||
pub struct CounterDefinition {
|
||||
/// The name of the metric.
|
||||
pub name: &'static str,
|
||||
/// The description of the metric.
|
||||
pub description: &'static str,
|
||||
}
|
||||
|
||||
/// `CounterVec` metric definition.
|
||||
pub struct CounterVecDefinition<'a> {
|
||||
/// The name of the metric.
|
||||
pub name: &'static str,
|
||||
/// The description of the metric.
|
||||
pub description: &'static str,
|
||||
/// The label names of the metric.
|
||||
pub labels: &'a [&'static str],
|
||||
}
|
||||
|
||||
/// `Histogram` metric definition
|
||||
pub struct HistogramDefinition<'a> {
|
||||
/// The name of the metric.
|
||||
pub name: &'static str,
|
||||
/// The description of the metric.
|
||||
pub description: &'static str,
|
||||
/// The buckets for the histogram
|
||||
pub buckets: &'a [f64],
|
||||
}
|
||||
|
||||
/// Counts parachain inherent data weights. Use `before` and `after` labels to differentiate
|
||||
/// between the weight before and after filtering.
|
||||
pub const PARACHAIN_INHERENT_DATA_WEIGHT: CounterVecDefinition = CounterVecDefinition {
|
||||
name: "polkadot_parachain_inherent_data_weight",
|
||||
description: "Inherent data weight before and after filtering",
|
||||
labels: &["when"],
|
||||
};
|
||||
|
||||
/// Counts the number of bitfields processed in `enter_inner`.
|
||||
pub const PARACHAIN_INHERENT_DATA_BITFIELDS_PROCESSED: CounterDefinition = CounterDefinition {
|
||||
name: "polkadot_parachain_inherent_data_bitfields_processed",
|
||||
description: "Counts the number of bitfields processed in `enter_inner`.",
|
||||
};
|
||||
|
||||
/// Counts the `total`, `sanitized` and `included` number of parachain block candidates
|
||||
/// in `enter_inner`.
|
||||
pub const PARACHAIN_INHERENT_DATA_CANDIDATES_PROCESSED: CounterVecDefinition =
|
||||
CounterVecDefinition {
|
||||
name: "polkadot_parachain_inherent_data_candidates_processed",
|
||||
description:
|
||||
"Counts the number of parachain block candidates processed in `enter_inner`.",
|
||||
labels: &["category"],
|
||||
};
|
||||
|
||||
/// Counts the number of `imported`, `current` and `concluded_invalid` dispute statements sets
|
||||
/// processed in `enter_inner`. The `current` label refers to the disputes statement sets of
|
||||
/// the current session.
|
||||
pub const PARACHAIN_INHERENT_DATA_DISPUTE_SETS_PROCESSED: CounterVecDefinition =
|
||||
CounterVecDefinition {
|
||||
name: "polkadot_parachain_inherent_data_dispute_sets_processed",
|
||||
description: "Counts the number of dispute statements sets processed in `enter_inner`.",
|
||||
labels: &["category"],
|
||||
};
|
||||
|
||||
/// Counts the number of dispute statements sets included in a block in `enter_inner`.
|
||||
pub const PARACHAIN_INHERENT_DATA_DISPUTE_SETS_INCLUDED: CounterDefinition =
|
||||
CounterDefinition {
|
||||
name: "polkadot_parachain_inherent_data_dispute_sets_included",
|
||||
description:
|
||||
"Counts the number of dispute statements sets included in a block in `enter_inner`.",
|
||||
};
|
||||
|
||||
/// Counts the number of `valid` and `invalid` bitfields signature checked in `enter_inner`.
|
||||
pub const PARACHAIN_CREATE_INHERENT_BITFIELDS_SIGNATURE_CHECKS: CounterVecDefinition =
|
||||
CounterVecDefinition {
|
||||
name: "polkadot_parachain_create_inherent_bitfields_signature_checks",
|
||||
description: "Counts the number of bitfields signature checked in `enter_inner`.",
|
||||
labels: &["validity"],
|
||||
};
|
||||
|
||||
/// Measures how much time does it take to verify a single validator signature of a dispute statement
|
||||
pub const PARACHAIN_VERIFY_DISPUTE_SIGNATURE: HistogramDefinition =
|
||||
HistogramDefinition {
|
||||
name: "polkadot_parachain_verify_dispute_signature",
|
||||
description: "How much time does it take to verify a single validator signature of a dispute statement, in seconds",
|
||||
buckets: &[0.0, 0.00005, 0.00006, 0.0001, 0.0005, 0.001, 0.005, 0.01, 0.05, 0.1, 0.3, 0.5, 1.0],
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,340 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use application_crypto::AppCrypto;
|
||||
#[cfg(feature = "std")]
|
||||
use sp_keystore::{Error as KeystoreError, KeystorePtr};
|
||||
use sp_std::prelude::Vec;
|
||||
|
||||
use primitives::RuntimeDebug;
|
||||
use runtime_primitives::traits::AppVerify;
|
||||
|
||||
use super::{SigningContext, ValidatorId, ValidatorIndex, ValidatorSignature};
|
||||
|
||||
/// Signed data with signature already verified.
|
||||
///
|
||||
/// NOTE: This type does not have an Encode/Decode instance, as this would cancel out our
|
||||
/// valid signature guarantees. If you need to encode/decode you have to convert into an
|
||||
/// `UncheckedSigned` first.
|
||||
///
|
||||
/// `Signed` can easily be converted into `UncheckedSigned` and conversion back via `into_signed`
|
||||
/// enforces a valid signature again.
|
||||
#[derive(Clone, PartialEq, Eq, RuntimeDebug)]
|
||||
pub struct Signed<Payload, RealPayload = Payload>(UncheckedSigned<Payload, RealPayload>);
|
||||
|
||||
impl<Payload, RealPayload> Signed<Payload, RealPayload> {
|
||||
/// Convert back to an unchecked type.
|
||||
pub fn into_unchecked(self) -> UncheckedSigned<Payload, RealPayload> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Unchecked signed data, can be converted to `Signed` by checking the signature.
|
||||
#[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, TypeInfo)]
|
||||
pub struct UncheckedSigned<Payload, RealPayload = Payload> {
|
||||
/// The payload is part of the signed data. The rest is the signing context,
|
||||
/// which is known both at signing and at validation.
|
||||
payload: Payload,
|
||||
/// The index of the validator signing this statement.
|
||||
validator_index: ValidatorIndex,
|
||||
/// The signature by the validator of the signed payload.
|
||||
signature: ValidatorSignature,
|
||||
/// This ensures the real payload is tracked at the typesystem level.
|
||||
real_payload: sp_std::marker::PhantomData<RealPayload>,
|
||||
}
|
||||
|
||||
impl<Payload: EncodeAs<RealPayload>, RealPayload: Encode> Signed<Payload, RealPayload> {
|
||||
/// Used to create a `Signed` from already existing parts.
|
||||
///
|
||||
/// The signature is checked as part of the process.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn new<H: Encode>(
|
||||
payload: Payload,
|
||||
validator_index: ValidatorIndex,
|
||||
signature: ValidatorSignature,
|
||||
context: &SigningContext<H>,
|
||||
key: &ValidatorId,
|
||||
) -> Option<Self> {
|
||||
let s = UncheckedSigned {
|
||||
payload,
|
||||
validator_index,
|
||||
signature,
|
||||
real_payload: std::marker::PhantomData,
|
||||
};
|
||||
|
||||
s.check_signature(context, key).ok()?;
|
||||
|
||||
Some(Self(s))
|
||||
}
|
||||
|
||||
/// Create a new `Signed` by signing data.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn sign<H: Encode>(
|
||||
keystore: &KeystorePtr,
|
||||
payload: Payload,
|
||||
context: &SigningContext<H>,
|
||||
validator_index: ValidatorIndex,
|
||||
key: &ValidatorId,
|
||||
) -> Result<Option<Self>, KeystoreError> {
|
||||
let r = UncheckedSigned::sign(keystore, payload, context, validator_index, key)?;
|
||||
Ok(r.map(Self))
|
||||
}
|
||||
|
||||
/// Try to convert from `UncheckedSigned` by checking the signature.
|
||||
pub fn try_from_unchecked<H: Encode>(
|
||||
unchecked: UncheckedSigned<Payload, RealPayload>,
|
||||
context: &SigningContext<H>,
|
||||
key: &ValidatorId,
|
||||
) -> Result<Self, UncheckedSigned<Payload, RealPayload>> {
|
||||
if unchecked.check_signature(context, key).is_ok() {
|
||||
Ok(Self(unchecked))
|
||||
} else {
|
||||
Err(unchecked)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference to data as unchecked.
|
||||
pub fn as_unchecked(&self) -> &UncheckedSigned<Payload, RealPayload> {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Immutably access the payload.
|
||||
#[inline]
|
||||
pub fn payload(&self) -> &Payload {
|
||||
&self.0.payload
|
||||
}
|
||||
|
||||
/// Immutably access the validator index.
|
||||
#[inline]
|
||||
pub fn validator_index(&self) -> ValidatorIndex {
|
||||
self.0.validator_index
|
||||
}
|
||||
|
||||
/// Immutably access the signature.
|
||||
#[inline]
|
||||
pub fn signature(&self) -> &ValidatorSignature {
|
||||
&self.0.signature
|
||||
}
|
||||
|
||||
/// Discard signing data, get the payload
|
||||
#[inline]
|
||||
pub fn into_payload(self) -> Payload {
|
||||
self.0.payload
|
||||
}
|
||||
|
||||
/// Convert `Payload` into `RealPayload`.
|
||||
pub fn convert_payload(&self) -> Signed<RealPayload>
|
||||
where
|
||||
for<'a> &'a Payload: Into<RealPayload>,
|
||||
{
|
||||
Signed(self.0.unchecked_convert_payload())
|
||||
}
|
||||
|
||||
/// Convert `Payload` into some claimed `SuperPayload` if the encoding matches.
|
||||
///
|
||||
/// Succeeds if and only if the super-payload provided actually encodes as
|
||||
/// the expected payload.
|
||||
pub fn convert_to_superpayload<SuperPayload>(
|
||||
self,
|
||||
claimed: SuperPayload,
|
||||
) -> Result<Signed<SuperPayload, RealPayload>, (Self, SuperPayload)>
|
||||
where
|
||||
SuperPayload: EncodeAs<RealPayload>,
|
||||
Payload: Encode,
|
||||
{
|
||||
if claimed.encode_as() == self.0.payload.encode_as() {
|
||||
Ok(Signed(UncheckedSigned {
|
||||
payload: claimed,
|
||||
validator_index: self.0.validator_index,
|
||||
signature: self.0.signature,
|
||||
real_payload: sp_std::marker::PhantomData,
|
||||
}))
|
||||
} else {
|
||||
Err((self, claimed))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can't bound this on `Payload: Into<RealPayload>` because that conversion consumes
|
||||
// the payload, and we don't want that. We can't bound it on `Payload: AsRef<RealPayload>`
|
||||
// because there's no blanket impl of `AsRef<T> for T`. In the end, we just invent our
|
||||
// own trait which does what we need: EncodeAs.
|
||||
impl<Payload: EncodeAs<RealPayload>, RealPayload: Encode> UncheckedSigned<Payload, RealPayload> {
|
||||
/// Used to create a `UncheckedSigned` from already existing parts.
|
||||
///
|
||||
/// Signature is not checked here, hence `UncheckedSigned`.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn new(
|
||||
payload: Payload,
|
||||
validator_index: ValidatorIndex,
|
||||
signature: ValidatorSignature,
|
||||
) -> Self {
|
||||
Self { payload, validator_index, signature, real_payload: std::marker::PhantomData }
|
||||
}
|
||||
|
||||
/// Check signature and convert to `Signed` if successful.
|
||||
pub fn try_into_checked<H: Encode>(
|
||||
self,
|
||||
context: &SigningContext<H>,
|
||||
key: &ValidatorId,
|
||||
) -> Result<Signed<Payload, RealPayload>, Self> {
|
||||
Signed::try_from_unchecked(self, context, key)
|
||||
}
|
||||
|
||||
/// Immutably access the payload.
|
||||
#[inline]
|
||||
pub fn unchecked_payload(&self) -> &Payload {
|
||||
&self.payload
|
||||
}
|
||||
|
||||
/// Immutably access the validator index.
|
||||
#[inline]
|
||||
pub fn unchecked_validator_index(&self) -> ValidatorIndex {
|
||||
self.validator_index
|
||||
}
|
||||
|
||||
/// Immutably access the signature.
|
||||
#[inline]
|
||||
pub fn unchecked_signature(&self) -> &ValidatorSignature {
|
||||
&self.signature
|
||||
}
|
||||
|
||||
/// Discard signing data, get the payload
|
||||
#[inline]
|
||||
pub fn unchecked_into_payload(self) -> Payload {
|
||||
self.payload
|
||||
}
|
||||
|
||||
/// Convert `Payload` into `RealPayload`.
|
||||
pub fn unchecked_convert_payload(&self) -> UncheckedSigned<RealPayload>
|
||||
where
|
||||
for<'a> &'a Payload: Into<RealPayload>,
|
||||
{
|
||||
UncheckedSigned {
|
||||
signature: self.signature.clone(),
|
||||
validator_index: self.validator_index,
|
||||
payload: (&self.payload).into(),
|
||||
real_payload: sp_std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn payload_data<H: Encode>(payload: &Payload, context: &SigningContext<H>) -> Vec<u8> {
|
||||
// equivalent to (`real_payload`, context).encode()
|
||||
let mut out = payload.encode_as();
|
||||
out.extend(context.encode());
|
||||
out
|
||||
}
|
||||
|
||||
/// Sign this payload with the given context and key, storing the validator index.
|
||||
#[cfg(feature = "std")]
|
||||
fn sign<H: Encode>(
|
||||
keystore: &KeystorePtr,
|
||||
payload: Payload,
|
||||
context: &SigningContext<H>,
|
||||
validator_index: ValidatorIndex,
|
||||
key: &ValidatorId,
|
||||
) -> Result<Option<Self>, KeystoreError> {
|
||||
let data = Self::payload_data(&payload, context);
|
||||
let signature =
|
||||
keystore.sr25519_sign(ValidatorId::ID, key.as_ref(), &data)?.map(|sig| Self {
|
||||
payload,
|
||||
validator_index,
|
||||
signature: sig.into(),
|
||||
real_payload: std::marker::PhantomData,
|
||||
});
|
||||
Ok(signature)
|
||||
}
|
||||
|
||||
/// Validate the payload given the context and public key
|
||||
/// without creating a `Signed` type.
|
||||
pub fn check_signature<H: Encode>(
|
||||
&self,
|
||||
context: &SigningContext<H>,
|
||||
key: &ValidatorId,
|
||||
) -> Result<(), ()> {
|
||||
let data = Self::payload_data(&self.payload, context);
|
||||
if self.signature.verify(data.as_slice(), key) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sign this payload with the given context and pair.
|
||||
#[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
|
||||
pub fn benchmark_sign<H: Encode>(
|
||||
public: &super::ValidatorId,
|
||||
payload: Payload,
|
||||
context: &SigningContext<H>,
|
||||
validator_index: ValidatorIndex,
|
||||
) -> Self {
|
||||
use application_crypto::RuntimeAppPublic;
|
||||
let data = Self::payload_data(&payload, context);
|
||||
let signature = public.sign(&data).unwrap();
|
||||
|
||||
Self { payload, validator_index, signature, real_payload: sp_std::marker::PhantomData }
|
||||
}
|
||||
|
||||
/// Immutably access the signature.
|
||||
#[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
|
||||
pub fn benchmark_signature(&self) -> ValidatorSignature {
|
||||
self.signature.clone()
|
||||
}
|
||||
|
||||
/// Set the signature. Only should be used for creating testing mocks.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn set_signature(&mut self, signature: ValidatorSignature) {
|
||||
self.signature = signature
|
||||
}
|
||||
}
|
||||
|
||||
impl<Payload, RealPayload> From<Signed<Payload, RealPayload>>
|
||||
for UncheckedSigned<Payload, RealPayload>
|
||||
{
|
||||
fn from(signed: Signed<Payload, RealPayload>) -> Self {
|
||||
signed.0
|
||||
}
|
||||
}
|
||||
|
||||
/// This helper trait ensures that we can encode `Statement` as `CompactStatement`,
|
||||
/// and anything as itself.
|
||||
///
|
||||
/// This resembles `parity_scale_codec::EncodeLike`, but it's distinct:
|
||||
/// `EncodeLike` is a marker trait which asserts at the typesystem level that
|
||||
/// one type's encoding is a valid encoding for another type. It doesn't
|
||||
/// perform any type conversion when encoding.
|
||||
///
|
||||
/// This trait, on the other hand, provides a method which can be used to
|
||||
/// simultaneously convert and encode one type as another.
|
||||
pub trait EncodeAs<T> {
|
||||
/// Convert Self into T, then encode T.
|
||||
///
|
||||
/// This is useful when T is a subset of Self, reducing encoding costs;
|
||||
/// its signature also means that we do not need to clone Self in order
|
||||
/// to retain ownership, as we would if we were to do
|
||||
/// `self.clone().into().encode()`.
|
||||
fn encode_as(&self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
impl<T: Encode> EncodeAs<T> for T {
|
||||
fn encode_as(&self) -> Vec<u8> {
|
||||
self.encode()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright 2017-2023 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Primitives types used for dispute slashing.
|
||||
|
||||
use crate::{CandidateHash, SessionIndex, ValidatorId, ValidatorIndex};
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_std::{collections::btree_map::BTreeMap, vec::Vec};
|
||||
|
||||
/// The kind of the dispute offence.
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, TypeInfo, Debug)]
|
||||
pub enum SlashingOffenceKind {
|
||||
/// A severe offence when a validator backed an invalid block.
|
||||
#[codec(index = 0)]
|
||||
ForInvalid,
|
||||
/// A minor offence when a validator disputed a valid block.
|
||||
#[codec(index = 1)]
|
||||
AgainstValid,
|
||||
}
|
||||
|
||||
/// Timeslots should uniquely identify offences and are used for the offence
|
||||
/// deduplication.
|
||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Encode, Decode, TypeInfo, Debug)]
|
||||
pub struct DisputesTimeSlot {
|
||||
// The order of the fields matters for `derive(Ord)`.
|
||||
/// Session index when the candidate was backed/included.
|
||||
pub session_index: SessionIndex,
|
||||
/// Candidate hash of the disputed candidate.
|
||||
pub candidate_hash: CandidateHash,
|
||||
}
|
||||
|
||||
impl DisputesTimeSlot {
|
||||
/// Create a new instance of `Self`.
|
||||
pub fn new(session_index: SessionIndex, candidate_hash: CandidateHash) -> Self {
|
||||
Self { session_index, candidate_hash }
|
||||
}
|
||||
}
|
||||
|
||||
/// We store most of the information about a lost dispute on chain. This struct
|
||||
/// is required to identify and verify it.
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Debug)]
|
||||
pub struct DisputeProof {
|
||||
/// Time slot when the dispute occured.
|
||||
pub time_slot: DisputesTimeSlot,
|
||||
/// The dispute outcome.
|
||||
pub kind: SlashingOffenceKind,
|
||||
/// The index of the validator who lost a dispute.
|
||||
pub validator_index: ValidatorIndex,
|
||||
/// The parachain session key of the validator.
|
||||
pub validator_id: ValidatorId,
|
||||
}
|
||||
|
||||
/// Slashes that are waiting to be applied once we have validator key
|
||||
/// identification.
|
||||
#[derive(Encode, Decode, TypeInfo, Debug, Clone)]
|
||||
pub struct PendingSlashes {
|
||||
/// Indices and keys of the validators who lost a dispute and are pending
|
||||
/// slashes.
|
||||
pub keys: BTreeMap<ValidatorIndex, ValidatorId>,
|
||||
/// The dispute outcome.
|
||||
pub kind: SlashingOffenceKind,
|
||||
}
|
||||
|
||||
// TODO: can we reuse this type between BABE, GRANDPA and disputes?
|
||||
/// An opaque type used to represent the key ownership proof at the runtime API
|
||||
/// boundary. The inner value is an encoded representation of the actual key
|
||||
/// ownership proof which will be parameterized when defining the runtime. At
|
||||
/// the runtime API boundary this type is unknown and as such we keep this
|
||||
/// opaque representation, implementors of the runtime API will have to make
|
||||
/// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type.
|
||||
#[derive(Decode, Encode, PartialEq, Eq, Debug, Clone, TypeInfo)]
|
||||
pub struct OpaqueKeyOwnershipProof(Vec<u8>);
|
||||
impl OpaqueKeyOwnershipProof {
|
||||
/// Create a new `OpaqueKeyOwnershipProof` using the given encoded
|
||||
/// representation.
|
||||
pub fn new(inner: Vec<u8>) -> OpaqueKeyOwnershipProof {
|
||||
OpaqueKeyOwnershipProof(inner)
|
||||
}
|
||||
|
||||
/// Try to decode this `OpaqueKeyOwnershipProof` into the given concrete key
|
||||
/// ownership proof type.
|
||||
pub fn decode<T: Decode>(self) -> Option<T> {
|
||||
Decode::decode(&mut &self.0[..]).ok()
|
||||
}
|
||||
|
||||
/// Length of the encoded proof.
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user