feat: initialize Kurdistan SDK - independent fork of Polkadot SDK
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Pezkuwi types shared between the runtime and the Node-side code.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
// `v13` is currently the latest stable version of the runtime API, the number below
|
||||
// should be incremented when a new version is released and is independent of the
|
||||
// released version of the Pezkuwi runtime.
|
||||
pub mod v9;
|
||||
|
||||
// The 'staging' version is special - it contains primitives which are
|
||||
// still in development. Once they are considered stable, they will be
|
||||
// moved to a new versioned module.
|
||||
pub mod vstaging;
|
||||
|
||||
// `runtime_api` contains the actual API implementation. It contains stable and
|
||||
// unstable functions.
|
||||
pub mod runtime_api;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
// Current primitives not requiring versioning are exported here.
|
||||
// Primitives requiring versioning must not be exported and must be referred by an exact version.
|
||||
pub use v9::{
|
||||
async_backing, byzantine_threshold, check_candidate_backing, effective_minimum_backing_votes,
|
||||
executor_params, metric_definitions, node_features, skip_ump_signals, slashing,
|
||||
supermajority_threshold, transpose_claim_queue, well_known_keys, AbridgedHostConfiguration,
|
||||
AbridgedHrmpChannel, AccountId, AccountIndex, AccountPublic, ApprovalVote,
|
||||
ApprovalVoteMultipleCandidates, ApprovalVotingParams, ApprovedPeerId, AssignmentId,
|
||||
AsyncBackingParams, AuthorityDiscoveryId, AvailabilityBitfield, BackedCandidate, Balance,
|
||||
BlakeTwo256, Block, BlockId, BlockNumber, CandidateCommitments, CandidateDescriptorV2,
|
||||
CandidateDescriptorVersion, CandidateEvent, CandidateHash, CandidateIndex, CandidateReceiptV2,
|
||||
CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, ChunkIndex, ClaimQueueOffset,
|
||||
CollatorId, CollatorSignature, CommittedCandidateReceiptError, CommittedCandidateReceiptV2,
|
||||
CompactStatement, ConsensusLog, CoreIndex, CoreSelector, CoreState, DisputeOffenceKind,
|
||||
DisputeState, DisputeStatement, DisputeStatementSet, DownwardMessage, EncodeAs, ExecutorParam,
|
||||
ExecutorParamError, ExecutorParams, ExecutorParamsHash, ExecutorParamsPrepHash,
|
||||
ExplicitDisputeStatement, GroupIndex, GroupRotationInfo, Hash, HashT, HeadData, Header,
|
||||
HorizontalMessages, HrmpChannelId, Id, InboundDownwardMessage, InboundHrmpMessage, IndexedVec,
|
||||
InherentData, InternalVersion, InvalidDisputeStatementKind, Moment, MultiDisputeStatementSet,
|
||||
NodeFeatures, Nonce, OccupiedCore, OccupiedCoreAssumption, OutboundHrmpMessage,
|
||||
ParathreadClaim, ParathreadEntry, PersistedValidationData, PvfCheckStatement, PvfExecKind,
|
||||
PvfPrepKind, RuntimeMetricLabel, RuntimeMetricLabelValue, RuntimeMetricLabelValues,
|
||||
RuntimeMetricLabels, RuntimeMetricOp, RuntimeMetricUpdate, ScheduledCore, SchedulerParams,
|
||||
ScrapedOnChainVotes, SessionIndex, SessionInfo, Signature, Signed, SignedAvailabilityBitfield,
|
||||
SignedAvailabilityBitfields, SignedStatement, SigningContext, Slot, TransposedClaimQueue,
|
||||
UMPSignal, UncheckedSigned, UncheckedSignedAvailabilityBitfield,
|
||||
UncheckedSignedAvailabilityBitfields, UncheckedSignedStatement, UpgradeGoAhead,
|
||||
UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode,
|
||||
ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation,
|
||||
ValidityError, ASSIGNMENT_KEY_TYPE_ID, DEFAULT_CLAIM_QUEUE_OFFSET,
|
||||
DEFAULT_SCHEDULING_LOOKAHEAD, LEGACY_MIN_BACKING_VOTES, LOWEST_PUBLIC_ID, MAX_CODE_SIZE,
|
||||
MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, MIN_CODE_SIZE, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE,
|
||||
ON_DEMAND_MAX_QUEUE_MAX_SIZE, TEYRCHAINS_INHERENT_IDENTIFIER, TEYRCHAIN_KEY_TYPE_ID,
|
||||
UMP_SEPARATOR,
|
||||
};
|
||||
|
||||
#[cfg(feature = "test")]
|
||||
pub use v9::{AppVerify, MutateDescriptorV2};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use v9::{AssignmentPair, CollatorPair, ValidatorPair};
|
||||
@@ -0,0 +1,325 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Runtime API module declares the `trait TeyrchainHost` which is part
|
||||
//! of the Runtime API exposed from the Runtime to the Host.
|
||||
//!
|
||||
//! The functions in trait TeyrchainHost` can be part of the stable API
|
||||
//! (which is versioned) or they can be staging (aka unstable/testing
|
||||
//! functions).
|
||||
//!
|
||||
//! The separation outlined above is achieved with the versioned API feature
|
||||
//! of `decl_runtime_apis!` and `impl_runtime_apis!`. Before moving on let's
|
||||
//! see a quick example about how API versioning works.
|
||||
//!
|
||||
//! # Runtime API versioning crash course
|
||||
//!
|
||||
//! The versioning is achieved with the `api_version` attribute. It can be
|
||||
//! placed on:
|
||||
//! * trait declaration - represents the base version of the API.
|
||||
//! * method declaration (inside a trait declaration) - represents a versioned method, which is not
|
||||
//! available in the base version.
|
||||
//! * trait implementation - represents which version of the API is being implemented.
|
||||
//!
|
||||
//! Let's see a quick example:
|
||||
//!
|
||||
//! ```nocompile
|
||||
//! sp_api::decl_runtime_apis! {
|
||||
//! #[api_version(2)]
|
||||
//! pub trait MyApi {
|
||||
//! fn fn1();
|
||||
//! fn fn2();
|
||||
//! #[api_version(3)]
|
||||
//! fn fn3();
|
||||
//! #[api_version(4)]
|
||||
//! fn fn4();
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! struct Runtime {}
|
||||
//!
|
||||
//! sp_api::impl_runtime_apis! {
|
||||
//! #[api_version(3)]
|
||||
//! impl self::MyApi<Block> for Runtime {
|
||||
//! fn fn1() {}
|
||||
//! fn fn2() {}
|
||||
//! fn fn3() {}
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//! A new API named `MyApi` is declared with `decl_runtime_apis!`. The trait declaration
|
||||
//! has got an `api_version` attribute which represents its base version - 2 in this case.
|
||||
//!
|
||||
//! The API has got three methods - `fn1`, `fn2`, `fn3` and `fn4`. `fn3` and `fn4` has got
|
||||
//! an `api_version` attribute which makes them versioned methods. These methods do not exist
|
||||
//! in the base version of the API. Behind the scenes the declaration above creates three
|
||||
//! runtime APIs:
|
||||
//! * `MyApiV2` with `fn1` and `fn2`
|
||||
//! * `MyApiV3` with `fn1`, `fn2` and `fn3`.
|
||||
//! * `MyApiV4` with `fn1`, `fn2`, `fn3` and `fn4`.
|
||||
//!
|
||||
//! Please note that `v4` contains all methods from `v3`, `v3` all methods from `v2` and so on.
|
||||
//!
|
||||
//! Back to our example. At the end runtime API is implemented for `struct Runtime` with
|
||||
//! `impl_runtime_apis` macro. `api_version` attribute is attached to the `impl` block which
|
||||
//! means that a version different from the base one is being implemented - in our case this
|
||||
//! is `v3`.
|
||||
//!
|
||||
//! This version of the API contains three methods so the `impl` block has got definitions
|
||||
//! for them. Note that `fn4` is not implemented as it is not part of this version of the API.
|
||||
//! `impl_runtime_apis` generates a default implementation for it calling `unimplemented!()`.
|
||||
//!
|
||||
//! Hopefully this should be all you need to know in order to use versioned methods in the node.
|
||||
//! For more details about how the API versioning works refer to `spi_api`
|
||||
//! documentation [here](https://docs.pezkuwichain.io/rustdocs/latest/sp_api/macro.decl_runtime_apis.html).
|
||||
//!
|
||||
//! # How versioned methods are used for `TeyrchainHost`
|
||||
//!
|
||||
//! Let's introduce two types of `TeyrchainHost` API implementation:
|
||||
//! * stable - used on stable production networks like Pezkuwi and Kusama. There is only one stable
|
||||
//! API at a single point in time.
|
||||
//! * staging - methods that are ready for production, but will be released on Pezkuwichain first.
|
||||
//! We can batch together multiple changes and then release all of them to production, by making
|
||||
//! staging production (bump base version). We can not change or remove any method in staging
|
||||
//! after a release, as this would break Pezkuwichain. It should be ok to keep adding methods to
|
||||
//! staging across several releases. For experimental methods, you have to keep them on a separate
|
||||
//! branch until ready.
|
||||
//!
|
||||
//! The stable version of `TeyrchainHost` is indicated by the base version of the API. Any staging
|
||||
//! method must use `api_version` attribute so that it is assigned to a specific version of a
|
||||
//! staging API. This way in a single declaration one can see what's the stable version of
|
||||
//! `TeyrchainHost` and what staging versions/functions are available.
|
||||
//!
|
||||
//! All stable API functions should use primitives from the latest version.
|
||||
//! In the time of writing of this document - this is `v2`. So for example:
|
||||
//! ```ignore
|
||||
//! fn validators() -> Vec<v2::ValidatorId>;
|
||||
//! ```
|
||||
//! indicates a function from the stable `v2` API.
|
||||
//!
|
||||
//! All staging API functions should use primitives from `vstaging`. They should be clearly
|
||||
//! separated from the stable primitives.
|
||||
|
||||
use crate::{
|
||||
async_backing::{BackingState, Constraints},
|
||||
slashing, ApprovalVotingParams, AsyncBackingParams, BlockNumber, CandidateCommitments,
|
||||
CandidateEvent, CandidateHash, CommittedCandidateReceiptV2 as CommittedCandidateReceipt,
|
||||
CoreIndex, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, NodeFeatures,
|
||||
OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes,
|
||||
SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, ValidatorSignature,
|
||||
};
|
||||
|
||||
use alloc::{
|
||||
collections::{btree_map::BTreeMap, vec_deque::VecDeque},
|
||||
vec::Vec,
|
||||
};
|
||||
use pezkuwi_core_primitives as pcp;
|
||||
use pezkuwi_teyrchain_primitives::primitives as ppp;
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// The API for querying the state of teyrchains on-chain.
|
||||
#[api_version(5)]
|
||||
pub trait TeyrchainHost {
|
||||
/// Get the current validators.
|
||||
fn validators() -> Vec<ValidatorId>;
|
||||
|
||||
/// Returns the validator groups and rotation info localized based on the hypothetical child
|
||||
/// of a block whose state this is invoked on. Note that `now` in the `GroupRotationInfo`
|
||||
/// should be the successor of the number of the block.
|
||||
fn validator_groups() -> (Vec<Vec<ValidatorIndex>>, GroupRotationInfo<BlockNumber>);
|
||||
|
||||
/// Yields information on all availability cores as relevant to the child block.
|
||||
/// Cores are either free or occupied. Free cores can have paras assigned to them.
|
||||
fn availability_cores() -> Vec<CoreState<Hash, BlockNumber>>;
|
||||
|
||||
/// Yields the persisted validation data for the given `ParaId` along with an assumption that
|
||||
/// should be used if the para currently occupies a core.
|
||||
///
|
||||
/// Returns `None` if either the para is not registered or the assumption is `Freed`
|
||||
/// and the para already occupies a core.
|
||||
fn persisted_validation_data(para_id: ppp::Id, assumption: OccupiedCoreAssumption)
|
||||
-> Option<PersistedValidationData<Hash, BlockNumber>>;
|
||||
|
||||
/// Returns the persisted validation data for the given `ParaId` along with the corresponding
|
||||
/// validation code hash. Instead of accepting assumption about the para, matches the validation
|
||||
/// data hash against an expected one and yields `None` if they're not equal.
|
||||
fn assumed_validation_data(
|
||||
para_id: ppp::Id,
|
||||
expected_persisted_validation_data_hash: Hash,
|
||||
) -> Option<(PersistedValidationData<Hash, BlockNumber>, ppp::ValidationCodeHash)>;
|
||||
|
||||
/// Checks if the given validation outputs pass the acceptance criteria.
|
||||
fn check_validation_outputs(para_id: ppp::Id, outputs: CandidateCommitments) -> bool;
|
||||
|
||||
/// Returns the session index expected at a child of the block.
|
||||
///
|
||||
/// This can be used to instantiate a `SigningContext`.
|
||||
fn session_index_for_child() -> SessionIndex;
|
||||
|
||||
/// Fetch the validation code used by a para, making the given `OccupiedCoreAssumption`.
|
||||
///
|
||||
/// Returns `None` if either the para is not registered or the assumption is `Freed`
|
||||
/// and the para already occupies a core.
|
||||
fn validation_code(
|
||||
para_id: ppp::Id,
|
||||
assumption: OccupiedCoreAssumption,
|
||||
) -> Option<ppp::ValidationCode>;
|
||||
|
||||
/// Get the receipt of a candidate pending availability. This returns `Some` for any paras
|
||||
/// assigned to occupied cores in `availability_cores` and `None` otherwise.
|
||||
fn candidate_pending_availability(para_id: ppp::Id) -> Option<CommittedCandidateReceipt<Hash>>;
|
||||
|
||||
/// Get a vector of events concerning candidates that occurred within a block.
|
||||
fn candidate_events() -> Vec<CandidateEvent<Hash>>;
|
||||
|
||||
/// Get all the pending inbound messages in the downward message queue for a para.
|
||||
fn dmq_contents(
|
||||
recipient: ppp::Id,
|
||||
) -> Vec<pcp::v2::InboundDownwardMessage<BlockNumber>>;
|
||||
|
||||
/// Get the contents of all channels addressed to the given recipient. Channels that have no
|
||||
/// messages in them are also included.
|
||||
fn inbound_hrmp_channels_contents(
|
||||
recipient: ppp::Id,
|
||||
) -> BTreeMap<ppp::Id, Vec<pcp::v2::InboundHrmpMessage<BlockNumber>>>;
|
||||
|
||||
/// Get the validation code from its hash.
|
||||
fn validation_code_by_hash(hash: ppp::ValidationCodeHash) -> Option<ppp::ValidationCode>;
|
||||
|
||||
/// Scrape dispute relevant from on-chain, backing votes and resolved disputes.
|
||||
fn on_chain_votes() -> Option<ScrapedOnChainVotes<Hash>>;
|
||||
|
||||
/***** Added in v2 *****/
|
||||
|
||||
/// Get the session info for the given session, if stored.
|
||||
///
|
||||
/// NOTE: This function is only available since teyrchain host version 2.
|
||||
fn session_info(index: SessionIndex) -> Option<SessionInfo>;
|
||||
|
||||
/// Submits a PVF pre-checking statement into the transaction pool.
|
||||
///
|
||||
/// NOTE: This function is only available since teyrchain host version 2.
|
||||
fn submit_pvf_check_statement(stmt: PvfCheckStatement, signature: ValidatorSignature);
|
||||
|
||||
/// Returns code hashes of PVFs that require pre-checking by validators in the active set.
|
||||
///
|
||||
/// NOTE: This function is only available since teyrchain host version 2.
|
||||
fn pvfs_require_precheck() -> Vec<ppp::ValidationCodeHash>;
|
||||
|
||||
/// Fetch the hash of the validation code used by a para, making the given `OccupiedCoreAssumption`.
|
||||
///
|
||||
/// NOTE: This function is only available since teyrchain host version 2.
|
||||
fn validation_code_hash(para_id: ppp::Id, assumption: OccupiedCoreAssumption)
|
||||
-> Option<ppp::ValidationCodeHash>;
|
||||
|
||||
/// Returns all onchain disputes.
|
||||
fn disputes() -> Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)>;
|
||||
|
||||
/// Returns execution parameters for the session.
|
||||
fn session_executor_params(session_index: SessionIndex) -> Option<ExecutorParams>;
|
||||
|
||||
/// Returns a list of validators that lost a past session dispute and need to be slashed.
|
||||
///
|
||||
/// Deprecated. Use `unapplied_slashes_v2` instead.
|
||||
fn unapplied_slashes() -> Vec<(SessionIndex, CandidateHash, slashing::LegacyPendingSlashes)>;
|
||||
|
||||
/// Returns a merkle proof of a validator session key.
|
||||
/// NOTE: This function is only available since teyrchain host version 5.
|
||||
fn key_ownership_proof(
|
||||
validator_id: ValidatorId,
|
||||
) -> Option<slashing::OpaqueKeyOwnershipProof>;
|
||||
|
||||
/// Submit an unsigned extrinsic to slash validators who lost a dispute about
|
||||
/// a candidate of a past session.
|
||||
/// NOTE: This function is only available since teyrchain host version 5.
|
||||
fn submit_report_dispute_lost(
|
||||
dispute_proof: slashing::DisputeProof,
|
||||
key_ownership_proof: slashing::OpaqueKeyOwnershipProof,
|
||||
) -> Option<()>;
|
||||
|
||||
/***** Added in v6 *****/
|
||||
|
||||
/// Get the minimum number of backing votes for a teyrchain candidate.
|
||||
/// This is a staging method! Do not use on production runtimes!
|
||||
#[api_version(6)]
|
||||
fn minimum_backing_votes() -> u32;
|
||||
|
||||
|
||||
/***** Added in v7: Asynchronous backing *****/
|
||||
|
||||
/// Returns the state of teyrchain backing for a given para.
|
||||
#[api_version(7)]
|
||||
fn para_backing_state(_: ppp::Id) -> Option<BackingState<Hash, BlockNumber>>;
|
||||
|
||||
/// Returns candidate's acceptance limitations for asynchronous backing for a relay parent.
|
||||
#[api_version(7)]
|
||||
fn async_backing_params() -> AsyncBackingParams;
|
||||
|
||||
/***** Added in v8 *****/
|
||||
|
||||
/// Returns a list of all disabled validators at the given block.
|
||||
#[api_version(8)]
|
||||
fn disabled_validators() -> Vec<ValidatorIndex>;
|
||||
|
||||
/***** Added in v9 *****/
|
||||
|
||||
/// Get node features.
|
||||
/// This is a staging method! Do not use on production runtimes!
|
||||
#[api_version(9)]
|
||||
fn node_features() -> NodeFeatures;
|
||||
|
||||
/***** Added in v10 *****/
|
||||
/// Approval voting configuration parameters
|
||||
#[api_version(10)]
|
||||
fn approval_voting_params() -> ApprovalVotingParams;
|
||||
|
||||
/***** Added in v11 *****/
|
||||
/// Claim queue
|
||||
#[api_version(11)]
|
||||
fn claim_queue() -> BTreeMap<CoreIndex, VecDeque<ppp::Id>>;
|
||||
|
||||
/***** Added in v11 *****/
|
||||
/// Elastic scaling support
|
||||
#[api_version(11)]
|
||||
fn candidates_pending_availability(para_id: ppp::Id) -> Vec<CommittedCandidateReceipt<Hash>>;
|
||||
|
||||
/***** Added in v12 *****/
|
||||
/// Retrieve the maximum uncompressed code size.
|
||||
#[api_version(12)]
|
||||
fn validation_code_bomb_limit() -> u32;
|
||||
|
||||
/***** Added in v13 *****/
|
||||
/// Returns the constraints on the actions that can be taken by a new teyrchain
|
||||
/// block.
|
||||
#[api_version(13)]
|
||||
fn backing_constraints(para_id: ppp::Id) -> Option<Constraints>;
|
||||
|
||||
/***** Added in v13 *****/
|
||||
/// Retrieve the scheduling lookahead
|
||||
#[api_version(13)]
|
||||
fn scheduling_lookahead() -> u32;
|
||||
|
||||
/***** Added in v14 *****/
|
||||
/// Retrieve paraids at relay parent
|
||||
#[api_version(14)]
|
||||
fn para_ids() -> Vec<ppp::Id>;
|
||||
|
||||
/***** Added in v15 *****/
|
||||
/// Returns a list of validators that lost a past session dispute and need to be slashed.
|
||||
#[api_version(15)]
|
||||
fn unapplied_slashes_v2() -> Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// pezkuwi/primitives/src/traits.rs
|
||||
#![cfg_attr(not(feature = "std"), no_no_std)]
|
||||
|
||||
use frame_support::pallet_prelude::*;
|
||||
use sp_runtime::traits::BlockNumber as BlockNumberT;
|
||||
use sp_std::prelude::*;
|
||||
use codec::{Encode, Decode};
|
||||
use scale_info::TypeInfo;
|
||||
// `pallet-staking-score`'dan StakingDetails'ı doğrudan kullanabilmek için
|
||||
// StakingDetails'ı burada yeniden tanımlıyoruz. Bu struct, pallet-staking-score'daki ile BİREBİR AYNI olmalı.
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo, Debug)]
|
||||
pub struct StakingDetails<Balance> {
|
||||
pub staked_amount: Balance,
|
||||
pub nominations_count: u32,
|
||||
pub unlocking_chunks_count: u32,
|
||||
}
|
||||
|
||||
/// Puanlamada kullanılacak ham skor tipi.
|
||||
pub type RawScore = u32;
|
||||
|
||||
/// Staking skorunu sağlayan arayüz.
|
||||
pub trait StakingScoreProvider<AccountId, B: BlockNumber> { // B ismini veriyoruz
|
||||
/// Belirtilen hesabın staking puanını ve hesaplamada kullanılan süreyi döndürür.
|
||||
/// (score, duration_in_blocks)
|
||||
fn get_staking_score(who: &AccountId) -> (RawScore, B); // B'yi kullanıyoruz
|
||||
}
|
||||
|
||||
/// Referans skorunu sağlayan arayüz.
|
||||
pub trait ReferralScoreProvider<AccountId> {
|
||||
/// Belirtilen hesabın referans puanını döndürür.
|
||||
fn get_referral_score(who: &AccountId) -> RawScore;
|
||||
}
|
||||
|
||||
/// Vatandaşlık durumunu sağlayan arayüz.
|
||||
pub trait CitizenshipStatusProvider<AccountId> {
|
||||
/// Belirtilen hesabın vatandaş olup olmadığını döndürür (Approved KYC).
|
||||
fn is_citizen(who: &AccountId) -> bool;
|
||||
}
|
||||
|
||||
/// Eğitim/Perwerde skorunu sağlayan arayüz.
|
||||
pub trait PerwerdeScoreProvider<AccountId> {
|
||||
/// Belirtilen hesabın eğitim puanını döndürür.
|
||||
fn get_perwerde_score(who: &AccountId) -> RawScore;
|
||||
}
|
||||
|
||||
/// Tiki (Rol) skorunu sağlayan arayüz.
|
||||
pub trait TikiScoreProvider<AccountId> {
|
||||
/// Belirtilen hesabın sahip olduğu Tiki'lerden gelen toplam bileşen puanını döndürür.
|
||||
fn get_tiki_score(who: &AccountId) -> RawScore;
|
||||
}
|
||||
|
||||
// Trust skorunun güncellenmesi için bir arayüz.
|
||||
// Bu trait'i Trust paleti implemente edecektir.
|
||||
pub trait TrustScoreUpdater<AccountId> {
|
||||
/// Belirli bir hesabın Trust Puanını yeniden hesaplar ve günceller.
|
||||
fn update_trust_score(who: &AccountId);
|
||||
/// Tüm aktif hesapların Trust Puanlarını günceller (uzun sürebilir, batch işlenmelidir).
|
||||
fn update_all_trust_scores();
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Asynchronous backing primitives.
|
||||
|
||||
use super::*;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use codec::{Decode, DecodeWithMemTracking, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_core::RuntimeDebug;
|
||||
|
||||
/// Candidate's acceptance limitations for asynchronous backing per relay parent.
|
||||
#[derive(
|
||||
RuntimeDebug,
|
||||
Copy,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Encode,
|
||||
Decode,
|
||||
DecodeWithMemTracking,
|
||||
TypeInfo,
|
||||
serde::Serialize,
|
||||
serde::Deserialize,
|
||||
)]
|
||||
|
||||
pub struct AsyncBackingParams {
|
||||
/// The maximum number of para blocks between the para head in a relay parent
|
||||
/// and a new candidate. Restricts nodes from building arbitrary long chains
|
||||
/// and spamming other validators.
|
||||
///
|
||||
/// When async backing is disabled, the only valid value is 0.
|
||||
pub max_candidate_depth: u32,
|
||||
/// How many ancestors of a relay parent are allowed to build candidates on top
|
||||
/// of.
|
||||
///
|
||||
/// When async backing is disabled, the only valid value is 0.
|
||||
pub allowed_ancestry_len: u32,
|
||||
}
|
||||
|
||||
/// Constraints on inbound HRMP channels.
|
||||
#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct InboundHrmpLimitations<N = BlockNumber> {
|
||||
/// An exhaustive set of all valid watermarks, sorted ascending.
|
||||
///
|
||||
/// It's only expected to contain block numbers at which messages were
|
||||
/// previously sent to a para, excluding most recent head.
|
||||
pub valid_watermarks: Vec<N>,
|
||||
}
|
||||
|
||||
/// Constraints on outbound HRMP channels.
|
||||
#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct OutboundHrmpChannelLimitations {
|
||||
/// The maximum bytes that can be written to the channel.
|
||||
pub bytes_remaining: u32,
|
||||
/// The maximum messages that can be written to the channel.
|
||||
pub messages_remaining: u32,
|
||||
}
|
||||
|
||||
/// Constraints on the actions that can be taken by a new parachain
|
||||
/// block. These limitations are implicitly associated with some particular
|
||||
/// parachain, which should be apparent from usage.
|
||||
#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct Constraints<N = BlockNumber> {
|
||||
/// The minimum relay-parent number accepted under these constraints.
|
||||
pub min_relay_parent_number: N,
|
||||
/// The maximum Proof-of-Validity size allowed, in bytes.
|
||||
pub max_pov_size: u32,
|
||||
/// The maximum new validation code size allowed, in bytes.
|
||||
pub max_code_size: u32,
|
||||
/// The amount of UMP messages remaining.
|
||||
pub ump_remaining: u32,
|
||||
/// The amount of UMP bytes remaining.
|
||||
pub ump_remaining_bytes: u32,
|
||||
/// The maximum number of UMP messages allowed per candidate.
|
||||
pub max_ump_num_per_candidate: u32,
|
||||
/// Remaining DMP queue. Only includes sent-at block numbers.
|
||||
pub dmp_remaining_messages: Vec<N>,
|
||||
/// The limitations of all registered inbound HRMP channels.
|
||||
pub hrmp_inbound: InboundHrmpLimitations<N>,
|
||||
/// The limitations of all registered outbound HRMP channels.
|
||||
pub hrmp_channels_out: Vec<(Id, OutboundHrmpChannelLimitations)>,
|
||||
/// The maximum number of HRMP messages allowed per candidate.
|
||||
pub max_hrmp_num_per_candidate: u32,
|
||||
/// The required parent head-data of the parachain.
|
||||
pub required_parent: HeadData,
|
||||
/// The expected validation-code-hash of this parachain.
|
||||
pub validation_code_hash: ValidationCodeHash,
|
||||
/// The code upgrade restriction signal as-of this parachain.
|
||||
pub upgrade_restriction: Option<UpgradeRestriction>,
|
||||
/// The future validation code hash, if any, and at what relay-parent
|
||||
/// number the upgrade would be minimally applied.
|
||||
pub future_validation_code: Option<(N, ValidationCodeHash)>,
|
||||
}
|
||||
|
||||
/// A candidate pending availability.
|
||||
#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct CandidatePendingAvailability<H = Hash, N = BlockNumber> {
|
||||
/// The hash of the candidate.
|
||||
pub candidate_hash: CandidateHash,
|
||||
/// The candidate's descriptor.
|
||||
pub descriptor: CandidateDescriptor<H>,
|
||||
/// The commitments of the candidate.
|
||||
pub commitments: CandidateCommitments,
|
||||
/// The candidate's relay parent's number.
|
||||
pub relay_parent_number: N,
|
||||
/// The maximum Proof-of-Validity size allowed, in bytes.
|
||||
pub max_pov_size: u32,
|
||||
}
|
||||
|
||||
/// The per-parachain state of the backing system, including
|
||||
/// state-machine constraints and candidates pending availability.
|
||||
#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct BackingState<H = Hash, N = BlockNumber> {
|
||||
/// The state-machine constraints of the parachain.
|
||||
pub constraints: Constraints<N>,
|
||||
/// The candidates pending availability. These should be ordered, i.e. they should form
|
||||
/// a sub-chain, where the first candidate builds on top of the required parent of the
|
||||
/// constraints and each subsequent builds on top of the previous head-data.
|
||||
pub pending_availability: Vec<CandidatePendingAvailability<H, N>>,
|
||||
}
|
||||
@@ -0,0 +1,459 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. 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 `pezkuwi-node-core-pvf`.
|
||||
|
||||
use crate::{BlakeTwo256, HashT as _, PvfExecKind, PvfPrepKind};
|
||||
use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec};
|
||||
use codec::{Decode, DecodeWithMemTracking, Encode};
|
||||
use core::{ops::Deref, time::Duration};
|
||||
use pezkuwi_core_primitives::Hash;
|
||||
use scale_info::TypeInfo;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Default maximum number of wasm values allowed for the stack during execution of a PVF.
|
||||
pub const DEFAULT_LOGICAL_STACK_MAX: u32 = 65536;
|
||||
/// Default maximum number of bytes devoted for the stack during execution of a PVF.
|
||||
pub const DEFAULT_NATIVE_STACK_MAX: u32 = 256 * 1024 * 1024;
|
||||
|
||||
/// The limit of [`ExecutorParam::MaxMemoryPages`].
|
||||
pub const MEMORY_PAGES_MAX: u32 = 65536;
|
||||
/// The lower bound of [`ExecutorParam::StackLogicalMax`].
|
||||
pub const LOGICAL_MAX_LO: u32 = 1024;
|
||||
/// The upper bound of [`ExecutorParam::StackLogicalMax`].
|
||||
pub const LOGICAL_MAX_HI: u32 = 2 * 65536;
|
||||
/// The lower bound of [`ExecutorParam::PrecheckingMaxMemory`].
|
||||
pub const PRECHECK_MEM_MAX_LO: u64 = 256 * 1024 * 1024;
|
||||
/// The upper bound of [`ExecutorParam::PrecheckingMaxMemory`].
|
||||
pub const PRECHECK_MEM_MAX_HI: u64 = 16 * 1024 * 1024 * 1024;
|
||||
|
||||
// Default PVF timeouts. Must never be changed! Use executor environment parameters to adjust them.
|
||||
// See also `PvfPrepKind` and `PvfExecKind` docs.
|
||||
|
||||
/// Default PVF preparation timeout for prechecking requests.
|
||||
pub const DEFAULT_PRECHECK_PREPARATION_TIMEOUT: Duration = Duration::from_secs(60);
|
||||
/// Default PVF preparation timeout for execution requests.
|
||||
pub const DEFAULT_LENIENT_PREPARATION_TIMEOUT: Duration = Duration::from_secs(360);
|
||||
/// Default PVF execution timeout for backing.
|
||||
pub const DEFAULT_BACKING_EXECUTION_TIMEOUT: Duration = Duration::from_secs(2);
|
||||
/// Default PVF execution timeout for approval or disputes.
|
||||
pub const DEFAULT_APPROVAL_EXECUTION_TIMEOUT: Duration = Duration::from_secs(12);
|
||||
|
||||
const DEFAULT_PRECHECK_PREPARATION_TIMEOUT_MS: u64 =
|
||||
DEFAULT_PRECHECK_PREPARATION_TIMEOUT.as_millis() as u64;
|
||||
const DEFAULT_LENIENT_PREPARATION_TIMEOUT_MS: u64 =
|
||||
DEFAULT_LENIENT_PREPARATION_TIMEOUT.as_millis() as u64;
|
||||
const DEFAULT_BACKING_EXECUTION_TIMEOUT_MS: u64 =
|
||||
DEFAULT_BACKING_EXECUTION_TIMEOUT.as_millis() as u64;
|
||||
const DEFAULT_APPROVAL_EXECUTION_TIMEOUT_MS: u64 =
|
||||
DEFAULT_APPROVAL_EXECUTION_TIMEOUT.as_millis() as u64;
|
||||
|
||||
/// The different executor parameters for changing the execution environment semantics.
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
Encode,
|
||||
Decode,
|
||||
DecodeWithMemTracking,
|
||||
PartialEq,
|
||||
Eq,
|
||||
TypeInfo,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
pub enum ExecutorParam {
|
||||
/// Maximum number of memory pages (64KiB bytes per page) the executor can allocate.
|
||||
/// A valid value lies within (0, 65536].
|
||||
#[codec(index = 1)]
|
||||
MaxMemoryPages(u32),
|
||||
/// Wasm logical stack size limit (max. number of Wasm values on stack).
|
||||
/// A valid value lies within [[`LOGICAL_MAX_LO`], [`LOGICAL_MAX_HI`]].
|
||||
///
|
||||
/// For WebAssembly, the stack limit is subject to implementations, meaning that it may vary on
|
||||
/// different platforms. However, we want execution to be deterministic across machines of
|
||||
/// different architectures, including failures like stack overflow. For deterministic
|
||||
/// overflow, we rely on a **logical** limit, the maximum number of values allowed to be pushed
|
||||
/// on the stack.
|
||||
#[codec(index = 2)]
|
||||
StackLogicalMax(u32),
|
||||
/// Executor machine stack size limit, in bytes.
|
||||
/// If `StackLogicalMax` is also present, a valid value should not fall below
|
||||
/// 128 * `StackLogicalMax`.
|
||||
///
|
||||
/// For deterministic overflow, `StackLogicalMax` should be reached before the native stack is
|
||||
/// exhausted.
|
||||
#[codec(index = 3)]
|
||||
StackNativeMax(u32),
|
||||
/// Max. amount of memory the preparation worker is allowed to use during
|
||||
/// pre-checking, in bytes.
|
||||
/// Valid max. memory ranges from [`PRECHECK_MEM_MAX_LO`] to [`PRECHECK_MEM_MAX_HI`].
|
||||
#[codec(index = 4)]
|
||||
PrecheckingMaxMemory(u64),
|
||||
/// PVF preparation timeouts, in millisecond.
|
||||
/// Always ensure that `precheck_timeout` < `lenient_timeout`.
|
||||
/// When absent, the default values will be used.
|
||||
#[codec(index = 5)]
|
||||
PvfPrepTimeout(PvfPrepKind, u64),
|
||||
/// PVF execution timeouts, in millisecond.
|
||||
/// Always ensure that `backing_timeout` < `approval_timeout`.
|
||||
/// When absent, the default values will be used.
|
||||
#[codec(index = 6)]
|
||||
PvfExecTimeout(PvfExecKind, u64),
|
||||
/// Enables WASM bulk memory proposal
|
||||
#[codec(index = 7)]
|
||||
WasmExtBulkMemory,
|
||||
}
|
||||
|
||||
/// Possible inconsistencies of executor params.
|
||||
#[derive(Debug)]
|
||||
pub enum ExecutorParamError {
|
||||
/// A param is duplicated.
|
||||
DuplicatedParam(&'static str),
|
||||
/// A param value exceeds its limitation.
|
||||
OutsideLimit(&'static str),
|
||||
/// Two param values are incompatible or senseless when put together.
|
||||
IncompatibleValues(&'static str, &'static str),
|
||||
}
|
||||
|
||||
/// 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 core::fmt::Display for ExecutorParamsHash {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for ExecutorParamsHash {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::LowerHex for ExecutorParamsHash {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
core::fmt::LowerHex::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Unit type wrapper around [`type@Hash`] that represents a hash of preparation-related
|
||||
/// executor parameters.
|
||||
///
|
||||
/// This type is produced by [`ExecutorParams::prep_hash`].
|
||||
#[derive(Clone, Copy, Encode, Decode, Hash, Eq, PartialEq, PartialOrd, Ord, TypeInfo)]
|
||||
pub struct ExecutorParamsPrepHash(Hash);
|
||||
|
||||
impl core::fmt::Display for ExecutorParamsPrepHash {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for ExecutorParamsPrepHash {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::LowerHex for ExecutorParamsPrepHash {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
core::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.
|
||||
//
|
||||
// !!! Any new parameter that does not affect the prepared artifact must be added to the exclusion
|
||||
// !!! list in `prep_hash()` to avoid unneccessary artifact rebuilds.
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
Default,
|
||||
Encode,
|
||||
Decode,
|
||||
DecodeWithMemTracking,
|
||||
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 hash of preparation-related executor parameters
|
||||
pub fn prep_hash(&self) -> ExecutorParamsPrepHash {
|
||||
use ExecutorParam::*;
|
||||
|
||||
let mut enc = b"prep".to_vec();
|
||||
|
||||
self.0
|
||||
.iter()
|
||||
.flat_map(|param| match param {
|
||||
MaxMemoryPages(..) => None,
|
||||
StackLogicalMax(..) => Some(param),
|
||||
StackNativeMax(..) => None,
|
||||
PrecheckingMaxMemory(..) => None,
|
||||
PvfPrepTimeout(..) => Some(param),
|
||||
PvfExecTimeout(..) => None,
|
||||
WasmExtBulkMemory => Some(param),
|
||||
})
|
||||
.for_each(|p| enc.extend(p.encode()));
|
||||
|
||||
ExecutorParamsPrepHash(BlakeTwo256::hash(&enc))
|
||||
}
|
||||
|
||||
/// Returns a PVF preparation timeout, if any
|
||||
pub fn pvf_prep_timeout(&self, kind: PvfPrepKind) -> 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: PvfExecKind) -> Option<Duration> {
|
||||
for param in &self.0 {
|
||||
if let ExecutorParam::PvfExecTimeout(k, timeout) = param {
|
||||
if kind == *k {
|
||||
return Some(Duration::from_millis(*timeout))
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns pre-checking memory limit, if any
|
||||
pub fn prechecking_max_memory(&self) -> Option<u64> {
|
||||
for param in &self.0 {
|
||||
if let ExecutorParam::PrecheckingMaxMemory(limit) = param {
|
||||
return Some(*limit)
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Check params coherence.
|
||||
pub fn check_consistency(&self) -> Result<(), ExecutorParamError> {
|
||||
use ExecutorParam::*;
|
||||
use ExecutorParamError::*;
|
||||
|
||||
let mut seen = BTreeMap::<&str, u64>::new();
|
||||
|
||||
macro_rules! check {
|
||||
($param:ident, $val:expr $(,)?) => {
|
||||
if seen.contains_key($param) {
|
||||
return Err(DuplicatedParam($param))
|
||||
}
|
||||
seen.insert($param, $val as u64);
|
||||
};
|
||||
|
||||
// should check existence before range
|
||||
($param:ident, $val:expr, $out_of_limit:expr $(,)?) => {
|
||||
if seen.contains_key($param) {
|
||||
return Err(DuplicatedParam($param))
|
||||
}
|
||||
if $out_of_limit {
|
||||
return Err(OutsideLimit($param))
|
||||
}
|
||||
seen.insert($param, $val as u64);
|
||||
};
|
||||
}
|
||||
|
||||
for param in &self.0 {
|
||||
// should ensure to be unique
|
||||
let param_ident = match *param {
|
||||
MaxMemoryPages(_) => "MaxMemoryPages",
|
||||
StackLogicalMax(_) => "StackLogicalMax",
|
||||
StackNativeMax(_) => "StackNativeMax",
|
||||
PrecheckingMaxMemory(_) => "PrecheckingMaxMemory",
|
||||
PvfPrepTimeout(kind, _) => match kind {
|
||||
PvfPrepKind::Precheck => "PvfPrepKind::Precheck",
|
||||
PvfPrepKind::Prepare => "PvfPrepKind::Prepare",
|
||||
},
|
||||
PvfExecTimeout(kind, _) => match kind {
|
||||
PvfExecKind::Backing => "PvfExecKind::Backing",
|
||||
PvfExecKind::Approval => "PvfExecKind::Approval",
|
||||
},
|
||||
WasmExtBulkMemory => "WasmExtBulkMemory",
|
||||
};
|
||||
|
||||
match *param {
|
||||
MaxMemoryPages(val) => {
|
||||
check!(param_ident, val, val == 0 || val > MEMORY_PAGES_MAX,);
|
||||
},
|
||||
|
||||
StackLogicalMax(val) => {
|
||||
check!(param_ident, val, val < LOGICAL_MAX_LO || val > LOGICAL_MAX_HI,);
|
||||
},
|
||||
|
||||
StackNativeMax(val) => {
|
||||
check!(param_ident, val);
|
||||
},
|
||||
|
||||
PrecheckingMaxMemory(val) => {
|
||||
check!(
|
||||
param_ident,
|
||||
val,
|
||||
val < PRECHECK_MEM_MAX_LO || val > PRECHECK_MEM_MAX_HI,
|
||||
);
|
||||
},
|
||||
|
||||
PvfPrepTimeout(_, val) => {
|
||||
check!(param_ident, val);
|
||||
},
|
||||
|
||||
PvfExecTimeout(_, val) => {
|
||||
check!(param_ident, val);
|
||||
},
|
||||
|
||||
WasmExtBulkMemory => {
|
||||
check!(param_ident, 1);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(lm), Some(nm)) = (
|
||||
seen.get("StackLogicalMax").or(Some(&(DEFAULT_LOGICAL_STACK_MAX as u64))),
|
||||
seen.get("StackNativeMax").or(Some(&(DEFAULT_NATIVE_STACK_MAX as u64))),
|
||||
) {
|
||||
if *nm < 128 * *lm {
|
||||
return Err(IncompatibleValues("StackLogicalMax", "StackNativeMax"))
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(precheck), Some(lenient)) = (
|
||||
seen.get("PvfPrepKind::Precheck")
|
||||
.or(Some(&DEFAULT_PRECHECK_PREPARATION_TIMEOUT_MS)),
|
||||
seen.get("PvfPrepKind::Prepare")
|
||||
.or(Some(&DEFAULT_LENIENT_PREPARATION_TIMEOUT_MS)),
|
||||
) {
|
||||
if *precheck >= *lenient {
|
||||
return Err(IncompatibleValues("PvfPrepKind::Precheck", "PvfPrepKind::Prepare"))
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(backing), Some(approval)) = (
|
||||
seen.get("PvfExecKind::Backing").or(Some(&DEFAULT_BACKING_EXECUTION_TIMEOUT_MS)),
|
||||
seen.get("PvfExecKind::Approval")
|
||||
.or(Some(&DEFAULT_APPROVAL_EXECUTION_TIMEOUT_MS)),
|
||||
) {
|
||||
if *backing >= *approval {
|
||||
return Err(IncompatibleValues("PvfExecKind::Backing", "PvfExecKind::Approval"))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
// This test ensures the hash generated by `prep_hash()` changes if any preparation-related
|
||||
// executor parameter changes. If you're adding a new executor parameter, you must add it into
|
||||
// this test, and if changing that parameter may not affect the artifact produced on the
|
||||
// preparation step, it must be added to the list of exlusions in `pre_hash()` as well.
|
||||
// See also `prep_hash()` comments.
|
||||
#[test]
|
||||
fn ensure_prep_hash_changes() {
|
||||
use ExecutorParam::*;
|
||||
let ep = ExecutorParams::from(
|
||||
&[
|
||||
MaxMemoryPages(0),
|
||||
StackLogicalMax(0),
|
||||
StackNativeMax(0),
|
||||
PrecheckingMaxMemory(0),
|
||||
PvfPrepTimeout(PvfPrepKind::Precheck, 0),
|
||||
PvfPrepTimeout(PvfPrepKind::Prepare, 0),
|
||||
PvfExecTimeout(PvfExecKind::Backing, 0),
|
||||
PvfExecTimeout(PvfExecKind::Approval, 0),
|
||||
WasmExtBulkMemory,
|
||||
][..],
|
||||
);
|
||||
|
||||
for p in ep.iter() {
|
||||
let (ep1, ep2) = match p {
|
||||
MaxMemoryPages(_) => continue,
|
||||
StackLogicalMax(_) => (
|
||||
ExecutorParams::from(&[StackLogicalMax(1)][..]),
|
||||
ExecutorParams::from(&[StackLogicalMax(2)][..]),
|
||||
),
|
||||
StackNativeMax(_) => continue,
|
||||
PrecheckingMaxMemory(_) => continue,
|
||||
PvfPrepTimeout(PvfPrepKind::Precheck, _) => (
|
||||
ExecutorParams::from(&[PvfPrepTimeout(PvfPrepKind::Precheck, 1)][..]),
|
||||
ExecutorParams::from(&[PvfPrepTimeout(PvfPrepKind::Precheck, 2)][..]),
|
||||
),
|
||||
PvfPrepTimeout(PvfPrepKind::Prepare, _) => (
|
||||
ExecutorParams::from(&[PvfPrepTimeout(PvfPrepKind::Prepare, 1)][..]),
|
||||
ExecutorParams::from(&[PvfPrepTimeout(PvfPrepKind::Prepare, 2)][..]),
|
||||
),
|
||||
PvfExecTimeout(_, _) => continue,
|
||||
WasmExtBulkMemory =>
|
||||
(ExecutorParams::default(), ExecutorParams::from(&[WasmExtBulkMemory][..])),
|
||||
};
|
||||
|
||||
assert_ne!(ep1.prep_hash(), ep2.prep_hash());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Runtime metric primitives.
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use codec::{Decode, Encode};
|
||||
|
||||
/// 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 alloc::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;
|
||||
|
||||
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: "pezkuwi_parachain_inherent_data_weight",
|
||||
description: "Inherent data weight before and after filtering",
|
||||
labels: &["when"],
|
||||
};
|
||||
|
||||
/// Counts the number of bitfields processed in `process_inherent_data`.
|
||||
pub const PARACHAIN_INHERENT_DATA_BITFIELDS_PROCESSED: CounterDefinition = CounterDefinition {
|
||||
name: "pezkuwi_parachain_inherent_data_bitfields_processed",
|
||||
description: "Counts the number of bitfields processed in `process_inherent_data`.",
|
||||
};
|
||||
|
||||
/// Counts the `total`, `sanitized` and `included` number of parachain block candidates
|
||||
/// in `process_inherent_data`.
|
||||
pub const PARACHAIN_INHERENT_DATA_CANDIDATES_PROCESSED: CounterVecDefinition =
|
||||
CounterVecDefinition {
|
||||
name: "pezkuwi_parachain_inherent_data_candidates_processed",
|
||||
description:
|
||||
"Counts the number of parachain block candidates processed in `process_inherent_data`.",
|
||||
labels: &["category"],
|
||||
};
|
||||
|
||||
/// Counts the number of `imported`, `current` and `concluded_invalid` dispute statements sets
|
||||
/// processed in `process_inherent_data`. The `current` label refers to the disputes statement
|
||||
/// sets of the current session.
|
||||
pub const PARACHAIN_INHERENT_DATA_DISPUTE_SETS_PROCESSED: CounterVecDefinition =
|
||||
CounterVecDefinition {
|
||||
name: "pezkuwi_parachain_inherent_data_dispute_sets_processed",
|
||||
description:
|
||||
"Counts the number of dispute statements sets processed in `process_inherent_data`.",
|
||||
labels: &["category"],
|
||||
};
|
||||
|
||||
/// Counts the number of `valid` and `invalid` bitfields signature checked in
|
||||
/// `process_inherent_data`.
|
||||
pub const PARACHAIN_CREATE_INHERENT_BITFIELDS_SIGNATURE_CHECKS: CounterVecDefinition =
|
||||
CounterVecDefinition {
|
||||
name: "pezkuwi_parachain_create_inherent_bitfields_signature_checks",
|
||||
description:
|
||||
"Counts the number of bitfields signature checked in `process_inherent_data`.",
|
||||
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: "pezkuwi_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,367 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use codec::{Decode, DecodeWithMemTracking, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
#[cfg(feature = "std")]
|
||||
use sp_application_crypto::AppCrypto;
|
||||
#[cfg(feature = "std")]
|
||||
use sp_keystore::{Error as KeystoreError, KeystorePtr};
|
||||
|
||||
use sp_core::RuntimeDebug;
|
||||
use sp_runtime::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, DecodeWithMemTracking, 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: core::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>,
|
||||
{
|
||||
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: core::marker::PhantomData,
|
||||
}))
|
||||
} else {
|
||||
Err((self, claimed))
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert `Payload` into some converted `SuperPayload` if the encoding matches.
|
||||
///
|
||||
/// This invokes the closure on the current payload, which is irreversible.
|
||||
///
|
||||
/// Succeeds if and only if the super-payload provided actually encodes as
|
||||
/// the expected payload.
|
||||
pub fn convert_to_superpayload_with<F, SuperPayload>(
|
||||
self,
|
||||
convert: F,
|
||||
) -> Result<Signed<SuperPayload, RealPayload>, SuperPayload>
|
||||
where
|
||||
F: FnOnce(Payload) -> SuperPayload,
|
||||
SuperPayload: EncodeAs<RealPayload>,
|
||||
{
|
||||
let expected_encode_as = self.0.payload.encode_as();
|
||||
let converted = convert(self.0.payload);
|
||||
if converted.encode_as() == expected_encode_as {
|
||||
Ok(Signed(UncheckedSigned {
|
||||
payload: converted,
|
||||
validator_index: self.0.validator_index,
|
||||
signature: self.0.signature,
|
||||
real_payload: core::marker::PhantomData,
|
||||
}))
|
||||
} else {
|
||||
Err(converted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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: core::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 sp_application_crypto::RuntimeAppPublic;
|
||||
let data = Self::payload_data(&payload, context);
|
||||
let signature = public.sign(&data).unwrap();
|
||||
|
||||
Self { payload, validator_index, signature, real_payload: core::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 `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,106 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Primitives types used for dispute slashing.
|
||||
|
||||
use crate::{CandidateHash, SessionIndex, ValidatorId, ValidatorIndex};
|
||||
use alloc::{collections::btree_map::BTreeMap, vec::Vec};
|
||||
use codec::{Decode, DecodeWithMemTracking, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
/// The kind of the dispute offence.
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, DecodeWithMemTracking, 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, DecodeWithMemTracking, 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, DecodeWithMemTracking, TypeInfo, Debug)]
|
||||
pub struct DisputeProof {
|
||||
/// Time slot when the dispute occurred.
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Asynchronous backing primitives.
|
||||
|
||||
use super::*;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use codec::{Decode, DecodeWithMemTracking, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_core::RuntimeDebug;
|
||||
|
||||
use crate::CandidateDescriptorV2;
|
||||
|
||||
/// Candidate's acceptance limitations for asynchronous backing per relay parent.
|
||||
#[derive(
|
||||
RuntimeDebug,
|
||||
Copy,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Encode,
|
||||
Decode,
|
||||
DecodeWithMemTracking,
|
||||
TypeInfo,
|
||||
serde::Serialize,
|
||||
serde::Deserialize,
|
||||
)]
|
||||
|
||||
pub struct AsyncBackingParams {
|
||||
/// The maximum number of para blocks between the para head in a relay parent
|
||||
/// and a new candidate. Restricts nodes from building arbitrary long chains
|
||||
/// and spamming other validators.
|
||||
///
|
||||
/// When async backing is disabled, the only valid value is 0.
|
||||
pub max_candidate_depth: u32,
|
||||
/// How many ancestors of a relay parent are allowed to build candidates on top
|
||||
/// of.
|
||||
///
|
||||
/// When async backing is disabled, the only valid value is 0.
|
||||
pub allowed_ancestry_len: u32,
|
||||
}
|
||||
|
||||
/// Constraints on inbound HRMP channels.
|
||||
#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct InboundHrmpLimitations<N = BlockNumber> {
|
||||
/// An exhaustive set of all valid watermarks, sorted ascending.
|
||||
///
|
||||
/// It's only expected to contain block numbers at which messages were
|
||||
/// previously sent to a para, excluding most recent head.
|
||||
pub valid_watermarks: Vec<N>,
|
||||
}
|
||||
|
||||
/// Constraints on outbound HRMP channels.
|
||||
#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct OutboundHrmpChannelLimitations {
|
||||
/// The maximum bytes that can be written to the channel.
|
||||
pub bytes_remaining: u32,
|
||||
/// The maximum messages that can be written to the channel.
|
||||
pub messages_remaining: u32,
|
||||
}
|
||||
|
||||
/// Constraints on the actions that can be taken by a new teyrchain
|
||||
/// block. These limitations are implicitly associated with some particular
|
||||
/// teyrchain, which should be apparent from usage.
|
||||
#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct Constraints<N = BlockNumber> {
|
||||
/// The minimum relay-parent number accepted under these constraints.
|
||||
pub min_relay_parent_number: N,
|
||||
/// The maximum Proof-of-Validity size allowed, in bytes.
|
||||
pub max_pov_size: u32,
|
||||
/// The maximum new validation code size allowed, in bytes.
|
||||
pub max_code_size: u32,
|
||||
/// The maximum head-data size, in bytes.
|
||||
pub max_head_data_size: u32,
|
||||
/// The amount of UMP messages remaining.
|
||||
pub ump_remaining: u32,
|
||||
/// The amount of UMP bytes remaining.
|
||||
pub ump_remaining_bytes: u32,
|
||||
/// The maximum number of UMP messages allowed per candidate.
|
||||
pub max_ump_num_per_candidate: u32,
|
||||
/// Remaining DMP queue. Only includes sent-at block numbers.
|
||||
pub dmp_remaining_messages: Vec<N>,
|
||||
/// The limitations of all registered inbound HRMP channels.
|
||||
pub hrmp_inbound: InboundHrmpLimitations<N>,
|
||||
/// The limitations of all registered outbound HRMP channels.
|
||||
pub hrmp_channels_out: Vec<(Id, OutboundHrmpChannelLimitations)>,
|
||||
/// The maximum number of HRMP messages allowed per candidate.
|
||||
pub max_hrmp_num_per_candidate: u32,
|
||||
/// The required parent head-data of the teyrchain.
|
||||
pub required_parent: HeadData,
|
||||
/// The expected validation-code-hash of this teyrchain.
|
||||
pub validation_code_hash: ValidationCodeHash,
|
||||
/// The code upgrade restriction signal as-of this teyrchain.
|
||||
pub upgrade_restriction: Option<UpgradeRestriction>,
|
||||
/// The future validation code hash, if any, and at what relay-parent
|
||||
/// number the upgrade would be minimally applied.
|
||||
pub future_validation_code: Option<(N, ValidationCodeHash)>,
|
||||
}
|
||||
|
||||
impl<N> Constraints<N> {
|
||||
/// Equal to Pezkuwi/Kusama config.
|
||||
pub const DEFAULT_MAX_HEAD_DATA_SIZE: u32 = 20480;
|
||||
}
|
||||
|
||||
/// A candidate pending availability.
|
||||
#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct CandidatePendingAvailability<H = Hash, N = BlockNumber> {
|
||||
/// The hash of the candidate.
|
||||
pub candidate_hash: CandidateHash,
|
||||
/// The candidate's descriptor.
|
||||
pub descriptor: CandidateDescriptorV2<H>,
|
||||
/// The commitments of the candidate.
|
||||
pub commitments: CandidateCommitments,
|
||||
/// The candidate's relay parent's number.
|
||||
pub relay_parent_number: N,
|
||||
/// The maximum Proof-of-Validity size allowed, in bytes.
|
||||
pub max_pov_size: u32,
|
||||
}
|
||||
|
||||
/// The per-teyrchain state of the backing system, including
|
||||
/// state-machine constraints and candidates pending availability.
|
||||
#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct BackingState<H = Hash, N = BlockNumber> {
|
||||
/// The state-machine constraints of the teyrchain.
|
||||
pub constraints: crate::async_backing::Constraints<N>,
|
||||
/// The candidates pending availability. These should be ordered, i.e. they should form
|
||||
/// a sub-chain, where the first candidate builds on top of the required parent of the
|
||||
/// constraints and each subsequent builds on top of the previous head-data.
|
||||
pub pending_availability: Vec<CandidatePendingAvailability<H, N>>,
|
||||
}
|
||||
@@ -0,0 +1,456 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. 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 `pezkuwi-node-core-pvf`.
|
||||
|
||||
use crate::{BlakeTwo256, HashT as _, PvfExecKind, PvfPrepKind};
|
||||
use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec};
|
||||
use codec::{Decode, DecodeWithMemTracking, Encode};
|
||||
use core::{ops::Deref, time::Duration};
|
||||
use pezkuwi_core_primitives::Hash;
|
||||
use scale_info::TypeInfo;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Default maximum number of wasm values allowed for the stack during execution of a PVF.
|
||||
pub const DEFAULT_LOGICAL_STACK_MAX: u32 = 65536;
|
||||
/// Default maximum number of bytes devoted for the stack during execution of a PVF.
|
||||
pub const DEFAULT_NATIVE_STACK_MAX: u32 = 256 * 1024 * 1024;
|
||||
|
||||
/// The limit of [`ExecutorParam::MaxMemoryPages`].
|
||||
pub const MEMORY_PAGES_MAX: u32 = 65536;
|
||||
/// The lower bound of [`ExecutorParam::StackLogicalMax`].
|
||||
pub const LOGICAL_MAX_LO: u32 = 1024;
|
||||
/// The upper bound of [`ExecutorParam::StackLogicalMax`].
|
||||
pub const LOGICAL_MAX_HI: u32 = 2 * 65536;
|
||||
/// The lower bound of [`ExecutorParam::PrecheckingMaxMemory`].
|
||||
pub const PRECHECK_MEM_MAX_LO: u64 = 256 * 1024 * 1024;
|
||||
/// The upper bound of [`ExecutorParam::PrecheckingMaxMemory`].
|
||||
pub const PRECHECK_MEM_MAX_HI: u64 = 16 * 1024 * 1024 * 1024;
|
||||
|
||||
// Default PVF timeouts. Must never be changed! Use executor environment parameters to adjust them.
|
||||
// See also `PvfPrepKind` and `PvfExecKind` docs.
|
||||
|
||||
/// Default PVF preparation timeout for prechecking requests.
|
||||
pub const DEFAULT_PRECHECK_PREPARATION_TIMEOUT: Duration = Duration::from_secs(60);
|
||||
/// Default PVF preparation timeout for execution requests.
|
||||
pub const DEFAULT_LENIENT_PREPARATION_TIMEOUT: Duration = Duration::from_secs(360);
|
||||
/// Default PVF execution timeout for backing.
|
||||
pub const DEFAULT_BACKING_EXECUTION_TIMEOUT: Duration = Duration::from_secs(2);
|
||||
/// Default PVF execution timeout for approval or disputes.
|
||||
pub const DEFAULT_APPROVAL_EXECUTION_TIMEOUT: Duration = Duration::from_secs(12);
|
||||
|
||||
const DEFAULT_PRECHECK_PREPARATION_TIMEOUT_MS: u64 =
|
||||
DEFAULT_PRECHECK_PREPARATION_TIMEOUT.as_millis() as u64;
|
||||
const DEFAULT_LENIENT_PREPARATION_TIMEOUT_MS: u64 =
|
||||
DEFAULT_LENIENT_PREPARATION_TIMEOUT.as_millis() as u64;
|
||||
const DEFAULT_BACKING_EXECUTION_TIMEOUT_MS: u64 =
|
||||
DEFAULT_BACKING_EXECUTION_TIMEOUT.as_millis() as u64;
|
||||
const DEFAULT_APPROVAL_EXECUTION_TIMEOUT_MS: u64 =
|
||||
DEFAULT_APPROVAL_EXECUTION_TIMEOUT.as_millis() as u64;
|
||||
|
||||
/// The different executor parameters for changing the execution environment semantics.
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
Encode,
|
||||
Decode,
|
||||
DecodeWithMemTracking,
|
||||
PartialEq,
|
||||
Eq,
|
||||
TypeInfo,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
pub enum ExecutorParam {
|
||||
/// Maximum number of memory pages (64KiB bytes per page) the executor can allocate.
|
||||
/// A valid value lies within (0, 65536].
|
||||
#[codec(index = 1)]
|
||||
MaxMemoryPages(u32),
|
||||
/// Wasm logical stack size limit (max. number of Wasm values on stack).
|
||||
/// A valid value lies within [[`LOGICAL_MAX_LO`], [`LOGICAL_MAX_HI`]].
|
||||
///
|
||||
/// For WebAssembly, the stack limit is subject to implementations, meaning that it may vary on
|
||||
/// different platforms. However, we want execution to be deterministic across machines of
|
||||
/// different architectures, including failures like stack overflow. For deterministic
|
||||
/// overflow, we rely on a **logical** limit, the maximum number of values allowed to be pushed
|
||||
/// on the stack.
|
||||
#[codec(index = 2)]
|
||||
StackLogicalMax(u32),
|
||||
/// Executor machine stack size limit, in bytes.
|
||||
/// If `StackLogicalMax` is also present, a valid value should not fall below
|
||||
/// 128 * `StackLogicalMax`.
|
||||
///
|
||||
/// For deterministic overflow, `StackLogicalMax` should be reached before the native stack is
|
||||
/// exhausted.
|
||||
#[codec(index = 3)]
|
||||
StackNativeMax(u32),
|
||||
/// Max. amount of memory the preparation worker is allowed to use during
|
||||
/// pre-checking, in bytes.
|
||||
/// Valid max. memory ranges from [`PRECHECK_MEM_MAX_LO`] to [`PRECHECK_MEM_MAX_HI`].
|
||||
#[codec(index = 4)]
|
||||
PrecheckingMaxMemory(u64),
|
||||
/// PVF preparation timeouts, in millisecond.
|
||||
/// Always ensure that `precheck_timeout` < `lenient_timeout`.
|
||||
/// When absent, the default values will be used.
|
||||
#[codec(index = 5)]
|
||||
PvfPrepTimeout(PvfPrepKind, u64),
|
||||
/// PVF execution timeouts, in millisecond.
|
||||
/// Always ensure that `backing_timeout` < `approval_timeout`.
|
||||
/// When absent, the default values will be used.
|
||||
#[codec(index = 6)]
|
||||
PvfExecTimeout(PvfExecKind, u64),
|
||||
/// Enables WASM bulk memory proposal
|
||||
#[codec(index = 7)]
|
||||
WasmExtBulkMemory,
|
||||
}
|
||||
|
||||
/// Possible inconsistencies of executor params.
|
||||
#[derive(Debug)]
|
||||
pub enum ExecutorParamError {
|
||||
/// A param is duplicated.
|
||||
DuplicatedParam(&'static str),
|
||||
/// A param value exceeds its limitation.
|
||||
OutsideLimit(&'static str),
|
||||
/// Two param values are incompatible or senseless when put together.
|
||||
IncompatibleValues(&'static str, &'static str),
|
||||
}
|
||||
|
||||
/// 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 core::fmt::Display for ExecutorParamsHash {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for ExecutorParamsHash {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::LowerHex for ExecutorParamsHash {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
core::fmt::LowerHex::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Unit type wrapper around [`type@Hash`] that represents a hash of preparation-related
|
||||
/// executor parameters.
|
||||
///
|
||||
/// This type is produced by [`ExecutorParams::prep_hash`].
|
||||
#[derive(Clone, Copy, Encode, Decode, Hash, Eq, PartialEq, PartialOrd, Ord, TypeInfo)]
|
||||
pub struct ExecutorParamsPrepHash(Hash);
|
||||
|
||||
impl core::fmt::Display for ExecutorParamsPrepHash {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for ExecutorParamsPrepHash {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::LowerHex for ExecutorParamsPrepHash {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
core::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.
|
||||
//
|
||||
// !!! Any new parameter that does not affect the prepared artifact must be added to the exclusion
|
||||
// !!! list in `prep_hash()` to avoid unnecessary artifact rebuilds.
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
Default,
|
||||
Encode,
|
||||
Decode,
|
||||
DecodeWithMemTracking,
|
||||
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 hash of preparation-related executor parameters (those affecting the artifact
|
||||
/// produced on the preparation step).
|
||||
pub fn prep_hash(&self) -> ExecutorParamsPrepHash {
|
||||
use ExecutorParam::*;
|
||||
|
||||
let mut enc = b"prep".to_vec();
|
||||
|
||||
self.0
|
||||
.iter()
|
||||
.flat_map(|param| match param {
|
||||
MaxMemoryPages(..) => Some(param),
|
||||
StackLogicalMax(..) => Some(param),
|
||||
StackNativeMax(..) => None,
|
||||
PrecheckingMaxMemory(..) => None,
|
||||
PvfPrepTimeout(..) => None,
|
||||
PvfExecTimeout(..) => None,
|
||||
WasmExtBulkMemory => Some(param),
|
||||
})
|
||||
.for_each(|p| enc.extend(p.encode()));
|
||||
|
||||
ExecutorParamsPrepHash(BlakeTwo256::hash(&enc))
|
||||
}
|
||||
|
||||
/// Returns a PVF preparation timeout, if any
|
||||
pub fn pvf_prep_timeout(&self, kind: PvfPrepKind) -> 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: PvfExecKind) -> Option<Duration> {
|
||||
for param in &self.0 {
|
||||
if let ExecutorParam::PvfExecTimeout(k, timeout) = param {
|
||||
if kind == *k {
|
||||
return Some(Duration::from_millis(*timeout));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns pre-checking memory limit, if any
|
||||
pub fn prechecking_max_memory(&self) -> Option<u64> {
|
||||
for param in &self.0 {
|
||||
if let ExecutorParam::PrecheckingMaxMemory(limit) = param {
|
||||
return Some(*limit);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Check params coherence.
|
||||
pub fn check_consistency(&self) -> Result<(), ExecutorParamError> {
|
||||
use ExecutorParam::*;
|
||||
use ExecutorParamError::*;
|
||||
|
||||
let mut seen = BTreeMap::<&str, u64>::new();
|
||||
|
||||
macro_rules! check {
|
||||
($param:ident, $val:expr $(,)?) => {
|
||||
if seen.contains_key($param) {
|
||||
return Err(DuplicatedParam($param));
|
||||
}
|
||||
seen.insert($param, $val as u64);
|
||||
};
|
||||
|
||||
// should check existence before range
|
||||
($param:ident, $val:expr, $out_of_limit:expr $(,)?) => {
|
||||
if seen.contains_key($param) {
|
||||
return Err(DuplicatedParam($param));
|
||||
}
|
||||
if $out_of_limit {
|
||||
return Err(OutsideLimit($param));
|
||||
}
|
||||
seen.insert($param, $val as u64);
|
||||
};
|
||||
}
|
||||
|
||||
for param in &self.0 {
|
||||
// should ensure to be unique
|
||||
let param_ident = match *param {
|
||||
MaxMemoryPages(_) => "MaxMemoryPages",
|
||||
StackLogicalMax(_) => "StackLogicalMax",
|
||||
StackNativeMax(_) => "StackNativeMax",
|
||||
PrecheckingMaxMemory(_) => "PrecheckingMaxMemory",
|
||||
PvfPrepTimeout(kind, _) => match kind {
|
||||
PvfPrepKind::Precheck => "PvfPrepKind::Precheck",
|
||||
PvfPrepKind::Prepare => "PvfPrepKind::Prepare",
|
||||
},
|
||||
PvfExecTimeout(kind, _) => match kind {
|
||||
PvfExecKind::Backing => "PvfExecKind::Backing",
|
||||
PvfExecKind::Approval => "PvfExecKind::Approval",
|
||||
},
|
||||
WasmExtBulkMemory => "WasmExtBulkMemory",
|
||||
};
|
||||
|
||||
match *param {
|
||||
MaxMemoryPages(val) => {
|
||||
check!(param_ident, val, val == 0 || val > MEMORY_PAGES_MAX,);
|
||||
},
|
||||
|
||||
StackLogicalMax(val) => {
|
||||
check!(param_ident, val, val < LOGICAL_MAX_LO || val > LOGICAL_MAX_HI,);
|
||||
},
|
||||
|
||||
StackNativeMax(val) => {
|
||||
check!(param_ident, val);
|
||||
},
|
||||
|
||||
PrecheckingMaxMemory(val) => {
|
||||
check!(
|
||||
param_ident,
|
||||
val,
|
||||
val < PRECHECK_MEM_MAX_LO || val > PRECHECK_MEM_MAX_HI,
|
||||
);
|
||||
},
|
||||
|
||||
PvfPrepTimeout(_, val) => {
|
||||
check!(param_ident, val);
|
||||
},
|
||||
|
||||
PvfExecTimeout(_, val) => {
|
||||
check!(param_ident, val);
|
||||
},
|
||||
|
||||
WasmExtBulkMemory => {
|
||||
check!(param_ident, 1);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(lm), Some(nm)) = (
|
||||
seen.get("StackLogicalMax").or(Some(&(DEFAULT_LOGICAL_STACK_MAX as u64))),
|
||||
seen.get("StackNativeMax").or(Some(&(DEFAULT_NATIVE_STACK_MAX as u64))),
|
||||
) {
|
||||
if *nm < 128 * *lm {
|
||||
return Err(IncompatibleValues("StackLogicalMax", "StackNativeMax"));
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(precheck), Some(lenient)) = (
|
||||
seen.get("PvfPrepKind::Precheck")
|
||||
.or(Some(&DEFAULT_PRECHECK_PREPARATION_TIMEOUT_MS)),
|
||||
seen.get("PvfPrepKind::Prepare")
|
||||
.or(Some(&DEFAULT_LENIENT_PREPARATION_TIMEOUT_MS)),
|
||||
) {
|
||||
if *precheck >= *lenient {
|
||||
return Err(IncompatibleValues("PvfPrepKind::Precheck", "PvfPrepKind::Prepare"));
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(backing), Some(approval)) = (
|
||||
seen.get("PvfExecKind::Backing").or(Some(&DEFAULT_BACKING_EXECUTION_TIMEOUT_MS)),
|
||||
seen.get("PvfExecKind::Approval")
|
||||
.or(Some(&DEFAULT_APPROVAL_EXECUTION_TIMEOUT_MS)),
|
||||
) {
|
||||
if *backing >= *approval {
|
||||
return Err(IncompatibleValues("PvfExecKind::Backing", "PvfExecKind::Approval"));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
// This test ensures the hash generated by `prep_hash()` changes if any preparation-related
|
||||
// executor parameter changes. If you're adding a new executor parameter, you must add it into
|
||||
// this test, and if changing that parameter may not affect the artifact produced on the
|
||||
// preparation step, it must be added to the list of exclusions in `pre_hash()` as well.
|
||||
// See also `prep_hash()` comments.
|
||||
#[test]
|
||||
fn ensure_prep_hash_changes() {
|
||||
use ExecutorParam::*;
|
||||
let ep = ExecutorParams::from(
|
||||
&[
|
||||
MaxMemoryPages(0),
|
||||
StackLogicalMax(0),
|
||||
StackNativeMax(0),
|
||||
PrecheckingMaxMemory(0),
|
||||
PvfPrepTimeout(PvfPrepKind::Precheck, 0),
|
||||
PvfPrepTimeout(PvfPrepKind::Prepare, 0),
|
||||
PvfExecTimeout(PvfExecKind::Backing, 0),
|
||||
PvfExecTimeout(PvfExecKind::Approval, 0),
|
||||
WasmExtBulkMemory,
|
||||
][..],
|
||||
);
|
||||
|
||||
for p in ep.iter() {
|
||||
let (ep1, ep2) = match p {
|
||||
MaxMemoryPages(_) => (
|
||||
ExecutorParams::from(&[MaxMemoryPages(1)][..]),
|
||||
ExecutorParams::from(&[MaxMemoryPages(2)][..]),
|
||||
),
|
||||
StackLogicalMax(_) => (
|
||||
ExecutorParams::from(&[StackLogicalMax(1)][..]),
|
||||
ExecutorParams::from(&[StackLogicalMax(2)][..]),
|
||||
),
|
||||
StackNativeMax(_) => continue,
|
||||
PrecheckingMaxMemory(_) => continue,
|
||||
PvfPrepTimeout(_, _) => continue,
|
||||
PvfExecTimeout(_, _) => continue,
|
||||
WasmExtBulkMemory =>
|
||||
(ExecutorParams::default(), ExecutorParams::from(&[WasmExtBulkMemory][..])),
|
||||
};
|
||||
|
||||
assert_ne!(ep1.prep_hash(), ep2.prep_hash());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Runtime metric primitives.
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use codec::{Decode, Encode};
|
||||
|
||||
/// 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 alloc::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;
|
||||
|
||||
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 teyrchain inherent data weights. Use `before` and `after` labels to differentiate
|
||||
/// between the weight before and after filtering.
|
||||
pub const TEYRCHAIN_INHERENT_DATA_WEIGHT: CounterVecDefinition = CounterVecDefinition {
|
||||
name: "pezkuwi_teyrchain_inherent_data_weight",
|
||||
description: "Inherent data weight before and after filtering",
|
||||
labels: &["when"],
|
||||
};
|
||||
|
||||
/// Counts the number of bitfields processed in `process_inherent_data`.
|
||||
pub const TEYRCHAIN_INHERENT_DATA_BITFIELDS_PROCESSED: CounterDefinition = CounterDefinition {
|
||||
name: "pezkuwi_teyrchain_inherent_data_bitfields_processed",
|
||||
description: "Counts the number of bitfields processed in `process_inherent_data`.",
|
||||
};
|
||||
|
||||
/// Counts the `total`, `sanitized` and `included` number of teyrchain block candidates
|
||||
/// in `process_inherent_data`.
|
||||
pub const TEYRCHAIN_INHERENT_DATA_CANDIDATES_PROCESSED: CounterVecDefinition =
|
||||
CounterVecDefinition {
|
||||
name: "pezkuwi_teyrchain_inherent_data_candidates_processed",
|
||||
description:
|
||||
"Counts the number of teyrchain block candidates processed in `process_inherent_data`.",
|
||||
labels: &["category"],
|
||||
};
|
||||
|
||||
/// Counts the number of `imported`, `current` and `concluded_invalid` dispute statements sets
|
||||
/// processed in `process_inherent_data`. The `current` label refers to the disputes statement
|
||||
/// sets of the current session.
|
||||
pub const TEYRCHAIN_INHERENT_DATA_DISPUTE_SETS_PROCESSED: CounterVecDefinition =
|
||||
CounterVecDefinition {
|
||||
name: "pezkuwi_teyrchain_inherent_data_dispute_sets_processed",
|
||||
description:
|
||||
"Counts the number of dispute statements sets processed in `process_inherent_data`.",
|
||||
labels: &["category"],
|
||||
};
|
||||
|
||||
/// Counts the number of `valid` and `invalid` bitfields signature checked in
|
||||
/// `process_inherent_data`.
|
||||
pub const TEYRCHAIN_CREATE_INHERENT_BITFIELDS_SIGNATURE_CHECKS: CounterVecDefinition =
|
||||
CounterVecDefinition {
|
||||
name: "pezkuwi_teyrchain_create_inherent_bitfields_signature_checks",
|
||||
description:
|
||||
"Counts the number of bitfields signature checked in `process_inherent_data`.",
|
||||
labels: &["validity"],
|
||||
};
|
||||
|
||||
/// Measures how much time does it take to verify a single validator signature of a dispute
|
||||
/// statement
|
||||
pub const TEYRCHAIN_VERIFY_DISPUTE_SIGNATURE: HistogramDefinition =
|
||||
HistogramDefinition {
|
||||
name: "pezkuwi_teyrchain_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,367 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use codec::{Decode, DecodeWithMemTracking, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
#[cfg(feature = "std")]
|
||||
use sp_application_crypto::AppCrypto;
|
||||
#[cfg(feature = "std")]
|
||||
use sp_keystore::{Error as KeystoreError, KeystorePtr};
|
||||
|
||||
use sp_core::RuntimeDebug;
|
||||
use sp_runtime::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, DecodeWithMemTracking, 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: core::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>,
|
||||
{
|
||||
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: core::marker::PhantomData,
|
||||
}))
|
||||
} else {
|
||||
Err((self, claimed))
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert `Payload` into some converted `SuperPayload` if the encoding matches.
|
||||
///
|
||||
/// This invokes the closure on the current payload, which is irreversible.
|
||||
///
|
||||
/// Succeeds if and only if the super-payload provided actually encodes as
|
||||
/// the expected payload.
|
||||
pub fn convert_to_superpayload_with<F, SuperPayload>(
|
||||
self,
|
||||
convert: F,
|
||||
) -> Result<Signed<SuperPayload, RealPayload>, SuperPayload>
|
||||
where
|
||||
F: FnOnce(Payload) -> SuperPayload,
|
||||
SuperPayload: EncodeAs<RealPayload>,
|
||||
{
|
||||
let expected_encode_as = self.0.payload.encode_as();
|
||||
let converted = convert(self.0.payload);
|
||||
if converted.encode_as() == expected_encode_as {
|
||||
Ok(Signed(UncheckedSigned {
|
||||
payload: converted,
|
||||
validator_index: self.0.validator_index,
|
||||
signature: self.0.signature,
|
||||
real_payload: core::marker::PhantomData,
|
||||
}))
|
||||
} else {
|
||||
Err(converted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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: core::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 sp_application_crypto::RuntimeAppPublic;
|
||||
let data = Self::payload_data(&payload, context);
|
||||
let signature = public.sign(&data).unwrap();
|
||||
|
||||
Self { payload, validator_index, signature, real_payload: core::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 `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,125 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Primitives types used for dispute slashing.
|
||||
|
||||
use crate::{CandidateHash, DisputeOffenceKind, SessionIndex, ValidatorId, ValidatorIndex};
|
||||
use alloc::{collections::btree_map::BTreeMap, vec::Vec};
|
||||
use codec::{Decode, DecodeWithMemTracking, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
/// The kind of the slashing offence (those come from disputes).
|
||||
///
|
||||
/// Notes:
|
||||
/// Will soon be fully eclipsed by the expanded `DisputeOffenceKind` enum.
|
||||
/// Only kept for backwards compatibility through old runtime apis.
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, DecodeWithMemTracking, 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, DecodeWithMemTracking, 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, DecodeWithMemTracking, TypeInfo, Debug)]
|
||||
pub struct DisputeProof {
|
||||
/// Time slot when the dispute occurred.
|
||||
pub time_slot: DisputesTimeSlot,
|
||||
/// The dispute outcome.
|
||||
pub kind: DisputeOffenceKind,
|
||||
/// The index of the validator who lost a dispute.
|
||||
pub validator_index: ValidatorIndex,
|
||||
/// The teyrchain session key of the validator.
|
||||
pub validator_id: ValidatorId,
|
||||
}
|
||||
|
||||
/// Slashes that are waiting to be applied once we have validator key
|
||||
/// identification.
|
||||
///
|
||||
/// Legacy version. We need to keep this around for backwards compatibility.
|
||||
/// Once old nodes are no longer supported, we can remove it along with the
|
||||
/// `UnappliedSlashes` runtime API.
|
||||
#[derive(Encode, Decode, TypeInfo, Debug, Clone)]
|
||||
pub struct LegacyPendingSlashes {
|
||||
/// 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,
|
||||
}
|
||||
|
||||
/// 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: DisputeOffenceKind,
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use codec::{Decode, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_core::RuntimeDebug;
|
||||
|
||||
/// A candidate pending availability.
|
||||
#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct CandidatePendingAvailability<H = Hash, N = BlockNumber> {
|
||||
/// The hash of the candidate.
|
||||
pub candidate_hash: CandidateHash,
|
||||
/// The candidate's descriptor.
|
||||
pub descriptor: CandidateDescriptorV2<H>,
|
||||
/// The commitments of the candidate.
|
||||
pub commitments: CandidateCommitments,
|
||||
/// The candidate's relay parent's number.
|
||||
pub relay_parent_number: N,
|
||||
/// The maximum Proof-of-Validity size allowed, in bytes.
|
||||
pub max_pov_size: u32,
|
||||
}
|
||||
|
||||
impl<H: Copy> From<CandidatePendingAvailability<H>>
|
||||
for crate::v8::async_backing::CandidatePendingAvailability<H>
|
||||
{
|
||||
fn from(value: CandidatePendingAvailability<H>) -> Self {
|
||||
Self {
|
||||
candidate_hash: value.candidate_hash,
|
||||
descriptor: value.descriptor.into(),
|
||||
commitments: value.commitments,
|
||||
relay_parent_number: value.relay_parent_number,
|
||||
max_pov_size: value.max_pov_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Constraints on the actions that can be taken by a new parachain
|
||||
/// block. These limitations are implicitly associated with some particular
|
||||
/// parachain, which should be apparent from usage.
|
||||
#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct Constraints<N = BlockNumber> {
|
||||
/// The minimum relay-parent number accepted under these constraints.
|
||||
pub min_relay_parent_number: N,
|
||||
/// The maximum Proof-of-Validity size allowed, in bytes.
|
||||
pub max_pov_size: u32,
|
||||
/// The maximum new validation code size allowed, in bytes.
|
||||
pub max_code_size: u32,
|
||||
/// The maximum head-data size, in bytes.
|
||||
pub max_head_data_size: u32,
|
||||
/// The amount of UMP messages remaining.
|
||||
pub ump_remaining: u32,
|
||||
/// The amount of UMP bytes remaining.
|
||||
pub ump_remaining_bytes: u32,
|
||||
/// The maximum number of UMP messages allowed per candidate.
|
||||
pub max_ump_num_per_candidate: u32,
|
||||
/// Remaining DMP queue. Only includes sent-at block numbers.
|
||||
pub dmp_remaining_messages: Vec<N>,
|
||||
/// The limitations of all registered inbound HRMP channels.
|
||||
pub hrmp_inbound: InboundHrmpLimitations<N>,
|
||||
/// The limitations of all registered outbound HRMP channels.
|
||||
pub hrmp_channels_out: Vec<(Id, OutboundHrmpChannelLimitations)>,
|
||||
/// The maximum number of HRMP messages allowed per candidate.
|
||||
pub max_hrmp_num_per_candidate: u32,
|
||||
/// The required parent head-data of the parachain.
|
||||
pub required_parent: HeadData,
|
||||
/// The expected validation-code-hash of this parachain.
|
||||
pub validation_code_hash: ValidationCodeHash,
|
||||
/// The code upgrade restriction signal as-of this parachain.
|
||||
pub upgrade_restriction: Option<UpgradeRestriction>,
|
||||
/// The future validation code hash, if any, and at what relay-parent
|
||||
/// number the upgrade would be minimally applied.
|
||||
pub future_validation_code: Option<(N, ValidationCodeHash)>,
|
||||
}
|
||||
|
||||
/// The per-parachain state of the backing system, including
|
||||
/// state-machine constraints and candidates pending availability.
|
||||
#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)]
|
||||
pub struct BackingState<H = Hash, N = BlockNumber> {
|
||||
/// The state-machine constraints of the parachain.
|
||||
pub constraints: crate::async_backing::Constraints<N>,
|
||||
/// The candidates pending availability. These should be ordered, i.e. they should form
|
||||
/// a sub-chain, where the first candidate builds on top of the required parent of the
|
||||
/// constraints and each subsequent builds on top of the previous head-data.
|
||||
pub pending_availability: Vec<CandidatePendingAvailability<H, N>>,
|
||||
}
|
||||
|
||||
impl<H: Copy> From<BackingState<H>> for crate::v8::async_backing::BackingState<H> {
|
||||
fn from(value: BackingState<H>) -> Self {
|
||||
Self {
|
||||
constraints: value.constraints,
|
||||
pending_availability: value
|
||||
.pending_availability
|
||||
.into_iter()
|
||||
.map(|candidate| candidate.into())
|
||||
.collect::<Vec<_>>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Pezkuwi.
|
||||
|
||||
// Pezkuwi 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.
|
||||
|
||||
// Pezkuwi 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 Pezkuwi. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Staging Primitives.
|
||||
Reference in New Issue
Block a user