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

Commit

Permalink
pvf-precheck: update rustdoc for paras module
Browse files Browse the repository at this point in the history
Basically updates the docs for the paras module.
  • Loading branch information
pepyakin committed Dec 10, 2021
1 parent 63b82d7 commit 92fff9c
Showing 1 changed file with 100 additions and 12 deletions.
112 changes: 100 additions & 12 deletions runtime/parachains/src/paras.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,97 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

//! The paras pallet is responsible for storing data on parachains and parathreads.
//! The paras pallet acts as the main registry of paras.
//!
//! It tracks which paras are parachains, what their current head data is in
//! this fork of the relay chain, what their validation code is, and what their past and upcoming
//! validation code is.
//! # Tracking State of Paras
//!
//! The most important responsibility of this module is to track which parachains and parathreads
//! are active and what their current state is. The current state of a para consists of the current
//! head data and the current validation code (AKA Parachain Validation Function (PVF)).
//!
//! A para is not considered live until it is registered and activated in this pallet.
//!
//! The set of parachains and parathreads cannot change except at session boundaries. This is
//! primarily to ensure that the number and meaning of bits required for the availability bitfields
//! does not change except at session boundaries.
//!
//! # Validation Code Upgrades
//!
//! When a para signals the validation code upgrade it will be processed by this module. This can
//! be in turn split into more fine grained items:
//!
//! - Part of the acceptance criteria checks if the para can indeed signal an upgrade,
//!
//! - When the candidate is enacted, this module schedules code upgrade, storing the prospective
//! validation code.
//!
//! - Actually assign the prospective validation code to be the current one after all conditions are
//! fulfilled.
//!
//! The conditions that must be met before the para can use the new validation code are:
//!
//! 1. The validation code should have been "soaked" in the storage for a given number of blocks. That
//! is, the validation code should have been stored in on-chain storage for some time, so that in
//! case of a revert with a non-extreme height difference, that validation code can still be
//! found on-chain.
//!
//! 2. The validation code was vetted by the validators and declared as non-malicious in a processes
//! known as PVF pre-checking.
//!
//! # Validation Code Management
//!
//! Potentially, one validation code can be used by several different paras. For example, during
//! initial stages of deployment several paras can use the same "shell" validation code, or
//! there can be shards of the same para that use the same validation code.
//!
//! In case a validation code ceases to have any users it must be pruned from the on-chain storage.
//!
//! # Para Lifecycle Management
//!
//! A para can be in one of the two stable states: it is either a parachain or a parathread.
//!
//! However, in order to get into one of those two states, it must first be onboarded. Onboarding
//! can be only enacted at session boundaries. Onboarding must take at least one full session.
//! Moreover, a brand new validation code should go through the PVF pre-checking process.
//!
//! Once the para is in one of the two stable states, it can switch to the other stable state or to
//! initiate offboarding process. The result of offboarding is removal of all data related to that
//! para.
//!
//! # PVF Pre-checking
//!
//! As was mentioned above, a brand new validation code should go through a process of approval.
//! As part of this process, validators from the active set will take the validation code and
//! check if it is malicious. Once they did that and have their judgement, either accept or reject,
//! they issue a statement in a form of an unsigned extrinsic. This extrinsic is processed by this
//! pallet. Once supermajority is gained for accept, then the process that initiated the check
//! is resumed (as mentioned before this can be either upgrading of validation code or onboarding).
//! If supermajority is gained for reject, then the process is canceled.
//!
//! Below is a state diagram that depicts states of a single PVF pre-checking vote.
//!
//! ```text
//! ┌──────────┐
//! supermajority │ │
//! ┌────────for───────────▶│ accepted │
//! vote────┐ │ │ │
//! │ │ │ └──────────┘
//! │ │ │
//! │ ┌───────┐
//! │ │ │
//! └─▶│ init │────supermajority ┌──────────┐
//! │ │ against │ │
//! └───────┘ └──────────▶│ rejected │
//! ▲ │ │ │
//! │ │ session └──────────┘
//! │ └──change
//! │ │
//! │ ▼
//! ┌─────┐
//! start──────▶│reset│
//! └─────┘
//! ```
//!
//! A para is not considered live until it is registered and activated in this pallet. Activation can
//! only occur at session boundaries.
use crate::{configuration, initializer::SessionChangeNotification, shared};
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
Expand Down Expand Up @@ -289,10 +372,11 @@ impl<BlockNumber> PvfCheckActiveVoteState<BlockNumber> {
/// Returns `None` if the quorum is not reached, or the direction of the decision.
fn quorum(&self, n_validators: usize) -> Option<PvfCheckOutcome> {
let q_threshold = primitives::v1::supermajority_threshold(n_validators);
if self.votes_accept.count_ones() >= q_threshold {
Some(PvfCheckOutcome::Accepted)
} else if self.votes_reject.count_ones() >= q_threshold {
// NOTE: counting the reject votes is deliberately placed first. This is to err on the safe.
if self.votes_reject.count_ones() >= q_threshold {
Some(PvfCheckOutcome::Rejected)
} else if self.votes_accept.count_ones() >= q_threshold {
Some(PvfCheckOutcome::Accepted)
} else {
None
}
Expand Down Expand Up @@ -706,6 +790,7 @@ pub mod pallet {
let mut active_vote = PvfActiveVoteMap::<T>::get(&stmt.subject)
.ok_or(Error::<T>::PvfCheckSubjectInvalid)?;

// Ensure that the validator submitting this statement hasn't voted already.
ensure!(
!active_vote
.has_vote(validator_index)
Expand Down Expand Up @@ -1463,7 +1548,9 @@ impl<T: Config> Pallet<T> {
//
// Any candidate that attempts to do that should be rejected by
// `can_upgrade_validation_code`.
UpgradeGoAheadSignal::<T>::insert(&id, UpgradeGoAhead::Abort);
//
// NOTE: we cannot set `UpgradeGoAheadSignal` signal here since this will be reset by
// the following call `note_new_head`
log::warn!(
target: "runtime::paras",
"ended up scheduling an upgrade while one is pending",
Expand All @@ -1477,11 +1564,12 @@ impl<T: Config> Pallet<T> {
// process right away.
weight += T::DbWeight::get().reads(1);
if CurrentCodeHash::<T>::get(&id) == Some(code_hash) {
log::info!(
// NOTE: we cannot set `UpgradeGoAheadSignal` signal here since this will be reset by
// the following call `note_new_head`
log::warn!(
target: "runtime::paras",
"para tried to upgrade to the same code. Abort the upgrade",
);
UpgradeGoAheadSignal::<T>::insert(&id, UpgradeGoAhead::Abort);
return weight
}

Expand Down

0 comments on commit 92fff9c

Please sign in to comment.