diff --git a/crates/sc-consensus-subspace/Cargo.toml b/crates/sc-consensus-subspace/Cargo.toml
index c8706efc84..1987de8ad5 100644
--- a/crates/sc-consensus-subspace/Cargo.toml
+++ b/crates/sc-consensus-subspace/Cargo.toml
@@ -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"]
diff --git a/crates/sc-consensus-subspace/README.md b/crates/sc-consensus-subspace/README.md
deleted file mode 100644
index e73516d8df..0000000000
--- a/crates/sc-consensus-subspace/README.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Subspace Proof-of-Archival-Storage consensus
-
-Subspace is a slot-based block production mechanism which uses a Proof-of-Archival-Storage to randomly perform the slot
-allocation. On every slot, all the farmers evaluate their disk-based plot. If they have a tag (reflecting a commitment
-to a valid encoding) that it is lower than a given threshold (which is proportional to the total space pledged by the
-network) they may produce a new block.
-
-Core inputs to the Proof-of-Archival-Storage, such as global randomness and solution range come from the runtime,
-see `pallet-subspace` for details.
-
-The fork choice rule is weight-based, where weight is derived from the distance between solution proposed in a block and
-the local challenge for particular farmer. The heaviest chain (represents a chain with more storage pledged to it)
-will be preferred over alternatives or longest chain is in case of a tie.
-
-For a more in-depth analysis of Subspace consensus can be found in our
-[consensus whitepaper](https://subspace.network/news/subspace-network-whitepaper).
-
-This crate contains following major components:
-* worker (`sc-consensus-slots`) for claiming slots (block production)
-* block verifier that stateless verification of signature and Proof-of-Space
-* block import that verifies Proof-of-Archival-Storage and triggers archiving of the history
-* archiver worker triggered by block import that ensures history is archived and segment headers are produced at precisely
- the right time before finishing block import
-
-License: GPL-3.0-or-later WITH Classpath-exception-2.0
diff --git a/crates/sc-consensus-subspace/src/archiver.rs b/crates/sc-consensus-subspace/src/archiver.rs
index 31580cd92e..988ec94969 100644
--- a/crates/sc-consensus-subspace/src/archiver.rs
+++ b/crates/sc-consensus-subspace/src/archiver.rs
@@ -14,10 +14,37 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-//! 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;
@@ -74,7 +101,16 @@ struct SegmentHeadersStoreInner {
cache: Mutex>,
}
-/// 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 {
inner: Arc>,
@@ -335,7 +371,10 @@ where
best_archived_block: (Block::Hash, NumberFor),
}
-/// 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(mut signed_block: SignedBlock) -> Vec
where
Block: BlockT,
@@ -664,6 +703,24 @@ fn finalize_block(
/// `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(
segment_headers_store: SegmentHeadersStore,
subspace_link: &SubspaceLink,
diff --git a/crates/sc-consensus-subspace/src/block_import.rs b/crates/sc-consensus-subspace/src/block_import.rs
index b3c66d7d6a..eeb48a84b0 100644
--- a/crates/sc-consensus-subspace/src/block_import.rs
+++ b/crates/sc-consensus-subspace/src/block_import.rs
@@ -14,9 +14,18 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-//! 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;
diff --git a/crates/sc-consensus-subspace/src/lib.rs b/crates/sc-consensus-subspace/src/lib.rs
index b66360076d..4a8b2adad3 100644
--- a/crates/sc-consensus-subspace/src/lib.rs
+++ b/crates/sc-consensus-subspace/src/lib.rs
@@ -14,7 +14,14 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-#![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)]
@@ -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 {
new_slot_notification_sender: SubspaceNotificationSender,
diff --git a/crates/sc-consensus-subspace/src/slot_worker.rs b/crates/sc-consensus-subspace/src/slot_worker.rs
index aabc1cb7e4..47e5594dde 100644
--- a/crates/sc-consensus-subspace/src/slot_worker.rs
+++ b/crates/sc-consensus-subspace/src/slot_worker.rs
@@ -14,9 +14,22 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-//! 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;
diff --git a/crates/sc-consensus-subspace/src/verifier.rs b/crates/sc-consensus-subspace/src/verifier.rs
index 1df226cdb3..308aae11ac 100644
--- a/crates/sc-consensus-subspace/src/verifier.rs
+++ b/crates/sc-consensus-subspace/src/verifier.rs
@@ -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::*;