Skip to content

Commit

Permalink
Merge pull request #2350 from subspace/sc-consensus-subspace-docs
Browse files Browse the repository at this point in the history
Documentation in `sc-consensus-subspace`
  • Loading branch information
nazar-pc authored Dec 21, 2023
2 parents 0a51f37 + 7573b71 commit f76fb31
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 38 deletions.
1 change: 0 additions & 1 deletion crates/sc-consensus-subspace/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
homepage = "https://subspace.network"
repository = "https://github.com/subspace/subspace"
documentation = "https://docs.rs/sc-consensus-subspace"
readme = "README.md"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
Expand Down
25 changes: 0 additions & 25 deletions crates/sc-consensus-subspace/README.md

This file was deleted.

67 changes: 62 additions & 5 deletions crates/sc-consensus-subspace/src/archiver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,37 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! Consensus archiver module.
//! Consensus archiver responsible for archival of blockchain history, it is driven by block import
//! pipeline.
//!
//! Contains implementation of archiving process in Subspace blockchain that converts blockchain
//! history (blocks) into archived history (pieces).
//! Implements archiving process in Subspace blockchain that converts blockchain history (blocks)
//! into archived history (pieces).
//!
//! The main entry point here is [`create_subspace_archiver`] that will create a task, which while
//! driven will perform the archiving itself.
//!
//! Archiving is triggered by block importing notification ([`SubspaceLink::block_importing_notification_stream`])
//! and tries to archive the block at [`ChainConstants::confirmation_depth_k`](sp_consensus_subspace::ChainConstants::confirmation_depth_k)
//! depth from the block being imported. Block import will then wait for archiver to acknowledge
//! processing, which is necessary for ensuring that when the next block is imported, inherents will
//! contain segment header of newly archived block (must happen exactly in the next block).
//!
//! Archiving itself will also wait for acknowledgement by various subscribers before proceeding,
//! which includes farmer subscription, in case of reference implementation via RPC
//! (`sc-consensus-subspace-rpc`), but could also be in other ways.
//!
//! [`SegmentHeadersStore`] is maintained as a data structure containing all known (including future
//! in case of syncing) segment headers. This data structure contents is then made available to
//! other parts of the protocol that need to know what correct archival history of the blockchain
//! looks like. For example, it is used during node sync and farmer plotting in order to verify
//! pieces of archival history received from other network participants.
//!
//! [`recreate_genesis_segment`] is a bit of a hack and is useful for deriving of the genesis
//! segment that is special case since we don't have enough data in the blockchain history itself
//! during genesis in order to do the archiving.
//!
//! [`encode_block`] and [`decode_block`] are symmetric encoding/decoding functions turning
//! [`SignedBlock`]s into bytes and back.
use crate::block_import::BlockImportingNotification;
use crate::slot_worker::SubspaceSyncOracle;
Expand Down Expand Up @@ -74,7 +101,16 @@ struct SegmentHeadersStoreInner<AS> {
cache: Mutex<Vec<SegmentHeader>>,
}

/// Persistent storage of segment headers
/// Persistent storage of segment headers.
///
/// It maintains all known segment headers. During sync from DSN it is possible that this data structure contains
/// segment headers that from the point of view of the tip of the current chain are "in the future". This is expected
/// and must be accounted for in the archiver and other places.
///
/// Segment headers are stored in batches (which is more efficient to store and retrieve). Each next batch contains
/// distinct segment headers with monotonically increasing segment indices. During instantiation all previously stored
/// batches will be read and in-memory representation of the whole contents will be created such that queries to this
/// data structure are quick and not involving any disk I/O.
#[derive(Debug)]
pub struct SegmentHeadersStore<AS> {
inner: Arc<SegmentHeadersStoreInner<AS>>,
Expand Down Expand Up @@ -335,7 +371,10 @@ where
best_archived_block: (Block::Hash, NumberFor<Block>),
}

/// Encode block for archiving purposes
/// Encode block for archiving purposes.
///
/// Only specific Subspace justifications are included in the encoding, determined by result of
/// [`SubspaceJustification::must_be_archived`], other justifications are filtered-out.
pub fn encode_block<Block>(mut signed_block: SignedBlock<Block>) -> Vec<u8>
where
Block: BlockT,
Expand Down Expand Up @@ -664,6 +703,24 @@ fn finalize_block<Block, Backend, Client>(
/// `store_segment_header` extrinsic).
///
/// NOTE: Archiver is doing blocking operations and must run in a dedicated task.
///
/// Archiver is only able to move forward and doesn't support reorgs. Upon restart it will check
/// [`SegmentHeadersStore`] and chain history to reconstruct "current" state it was in before last
/// shutdown and continue incrementally archiving blockchain history from there.
///
/// Archiving is triggered by block importing notification ([`SubspaceLink::block_importing_notification_stream`])
/// and tries to archive the block at [`ChainConstants::confirmation_depth_k`](sp_consensus_subspace::ChainConstants::confirmation_depth_k)
/// depth from the block being imported. Block import will then wait for archiver to acknowledge
/// processing, which is necessary for ensuring that when the next block is imported, inherents will
/// contain segment header of newly archived block (must happen exactly in the next block).
///
/// Once segment header is archived, notification ([`SubspaceLink::archived_segment_notification_stream`])
/// will be sent and archiver will be paused until all receivers have provided an acknowledgement
/// for it.
///
/// Archiving will be incremental during normal operation to decrease impact on block import and
/// non-incremental heavily parallel during sync process since parallel implementation is more
/// efficient overall and during sync only total sync time matters.
pub fn create_subspace_archiver<Block, Backend, Client, AS, SO>(
segment_headers_store: SegmentHeadersStore<AS>,
subspace_link: &SubspaceLink<Block>,
Expand Down
13 changes: 11 additions & 2 deletions crates/sc-consensus-subspace/src/block_import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,18 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! Block import module.
//! Block import for Subspace, which includes stateful verification and corresponding notifications.
//!
//! Contains implementation of block import with corresponding checks and notifications.
//! In most cases block import happens after stateless block verification using [`verifier`](crate::verifier),
//! the only exception to that is locally authored blocks.
//!
//! Since [`verifier`](crate::verifier) is stateless, the remaining checks in block import are those
//! that require presence of the parent block or its state in the database. Specifically for Proof
//! of Time individual checkpoints are assumed to be checked already and only PoT inputs need to be
//! checked to correspond to the state of the parent block.
//!
//! After all checks and right before importing the block notification ([`SubspaceLink::block_importing_notification_stream`])
//! will be sent that [`archiver`](crate::archiver) among other things is subscribed to.
use crate::archiver::SegmentHeadersStore;
use crate::verifier::VerificationError;
Expand Down
11 changes: 9 additions & 2 deletions crates/sc-consensus-subspace/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

#![doc = include_str!("../README.md")]
//! `sc-consensus-subspace` is the core of Subspace consensus implementation.
//!
//! You should familiarize yourself with [Subnomicon](https://subnomicon.subspace.network/) and, ideally, protocol
//! specifications. Documentation here assumes decent prior knowledge of the protocol on conceptual level and will not
//! explain how the protocol works, it will instead explain how the protocol is implemented.
//!
//! All of the modules here are crucial for consensus, open each module for specific details.
#![feature(const_option, let_chains, try_blocks)]
#![forbid(unsafe_code)]
#![warn(missing_docs)]
Expand All @@ -40,7 +47,7 @@ use std::sync::Arc;
use subspace_core_primitives::crypto::kzg::Kzg;
use subspace_core_primitives::SegmentHeader;

/// State that must be shared between the import queue and the authoring logic.
/// State that must be shared between various consensus components.
#[derive(Clone)]
pub struct SubspaceLink<Block: BlockT> {
new_slot_notification_sender: SubspaceNotificationSender<NewSlotNotification>,
Expand Down
17 changes: 15 additions & 2 deletions crates/sc-consensus-subspace/src/slot_worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,22 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! Slot worker module.
//! Slot worker drives block and vote production based on slots produced in [`sc_proof_of_time`].
//!
//! Contains implementation of Subspace slot worker that produces block and votes.
//! While slot worker uses [`sc_consensus_slots`], it is not driven by time, but instead by Proof of
//! Time that is produced by [`PotSourceWorker`](sc_proof_of_time::source::PotSourceWorker).
//!
//! Each time a new proof is found, [`PotSlotWorker::on_proof`] is called and corresponding
//! [`SlotInfo`] notification is sent ([`SubspaceLink::new_slot_notification_stream`]) to farmers to
//! do the audit and try to prove they have a solution without actually waiting for the response.
//! [`ChainConstants::block_authoring_delay`](sp_consensus_subspace::ChainConstants::block_authoring_delay)
//! slots later (when corresponding future proof arrives) all the solutions produced by farmers so
//! far are collected and corresponding block and/or votes are produced. In case PoT chain reorg
//! happens, outdated solutions (they are tied to proofs of time) are thrown away.
//!
//! Custom [`SubspaceSyncOracle`] wrapper is introduced due to Subspace-specific changes comparing
//! to the base Substrate behavior where major syncing is assumed to not happen in case authoring is
//! forced.
use crate::archiver::SegmentHeadersStore;
use crate::SubspaceLink;
Expand Down
15 changes: 14 additions & 1 deletion crates/sc-consensus-subspace/src/verifier.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
//! Subspace block import implementation
//! Stateless and parallelized block verification that happens before block is imported (except for locally produced
//! blocks that are imported directly).
//!
//! The goal of verifier is to check internal consistency of the block, which includes things like
//! solution according to claimed inputs, signature, Proof of Time checkpoints in justifications,
//! etc.
//!
//! This should be the majority of the block verification computation such that all that is left for
//! [`block_import`](crate::block_import) to check is that information in the block corresponds to
//! the state of the parent block, which for the most part is comparing bytes against known good
//! values.
//!
//! This is a significant tradeoff in the protocol: having a smaller header vs being able to verify
//! a lot of things stateless and in parallel.
use futures::lock::Mutex;
use rand::prelude::*;
Expand Down

0 comments on commit f76fb31

Please sign in to comment.