Consensus Chain
Unless specified otherwise below, consensus chain primitives are inherited from Substrate.
Public Parameters
These parameters are fixed at the beginning of the protocol and used by all clients.
- Genesis block (derived from Substrate chain specification)
Consensus Block Structure
A block on the consensus chain largely follows standard Substrate block structure:
- Header,
- Body,
- Justifications
Header
The block header carries a set of consensus items necessary for integrity and continuity of the consensus chain:
number: block numberextrinsics_root: Merkle root hash of extrinsics trie included in the block body.state_root: Merkle root hash of state trie, used to verify the state of the consensus chain.parent_hash: hash of the parent blockdigest: set of Subspace-specific auxiliary data
Digest Items
PreRuntime items:
Slot: the slot claimed by this blockSolution: the PoS solution as defined in ProvingPreDigestPotInfo: information about PoT chain, includesproof_of_timeoutput for the claimed slot andfuture_proof_of_timefor a future slot as defined in PoT specification.
Consensus log items:
PotSlotIterationsnumber of iterations for proof-of-time evaluation per slot, corresponds to slot that directly follows parent block's slot and can change before slot for which block is produced.SolutionRangesolution range for this block/era.PotParametersChangechange of parameters to apply to PoT chain, including at which slot change of parameters takes effectslot, new number of slot iterationsslot_iterationsand entropy (entropy) that should be injected at theslot.NextSolutionRangenew solution range for next block/era.- (
SegmentIndex,SegmentCommitment) index and KZG commitment of the new segments archived right before this block that were not yet included in previous blocks. EnableSolutionRangeAdjustmentAndOverride: enable solution range adjustment and override solution range to a given value. Can only be set if solution range adjustment is currently disabled (network early days).RootPlotPublicKeyUpdatewhether the root plot public key was updated and its new value.
Seal: farmer (block proposer) signature
Body
The body consists of a set of Extrinsic, including:
Normal(e.g. transfers, domain bundles, staking)Operational(e.g. votes, fraud proofs)Mandatory(e.g. runtime upgrades)
such that total size and weight fit within block storage and compute limits. The limits currently are 5 MiB and equivalent of 2 sec compute time, out of which Normal extrinsics can take up to 75%.
Justifications
Justifications contain a set of all PoT checkpoints since the parent block up to future_proof_of_time. See more in PoT specification.
Synchronization
Sync from DSN implementation
-
Connect node to Kademlia DHT and get 20 peers closest to random key (using disjoint query path) that support the segment-header request response protocol.
Fall back to fewer number of nodes on each attempt if not enough nodes found, which might be the case in small dev networks and similar circumstances.
-
Ask the peers about their latest
segment_headersIn case the number of obtained
segment_headers doesn’t change twice in a row, we may have gotten a response from all available nodes that support the segment-header request response protocol. -
Find the
segment_headerthat largest subset of peers agree on as their newest (mode) from their last 2 segment headers. -
Download the chain of archived
segment_headersbackwards from newest to oldest, checking that every older segment header is part of the next (by hash, as described in Archiving) -
Download full segments in forward direction, verifying each piece against
segment_commitmentin from correspondingsegment_headeralong the way:- Split piece into
record,record_commitmentandrecord_witness - Hash the
record_commitmentto obtain therecord_commitment_hash - Verify the
record_witnessfor thepiece_index,record_commitment_hashandsegment_commitment - In case verification fails, the peer that returns an invalid piece must be banned.
- Split piece into
-
Reconstruct blocks from headers.
-
Verify and import blocks into the chain. PoT is verified probabilistically according to Major Sync
-
Blocks that are close to the tip and were not archived yet are handled by Substrate Sync
When and how to use sync from DSN
- Sync from DSN should be attempted first thing on node startup, before Substrate node is fully started
- Sync from DSN should be attempted during normal operations when any of the following events (triggers) happen:
- When node has not imported blocks for a long time (currently 10 minutes)
- When Substrate and/or Subspace networking identified that node was offline network-wise and then became online, meaning there could have been some blocks it missed in the meantime
- Implementation must only run one DSN sync at a time and not try to run multiple concurrently
- DSN sync must be able to terminate early if local chain already contains imported blocks that DSN sync was about to download (doesn’t happen often, but possible)
- Node blocks that are finalized and pruned must be much higher than archiving point such that block available through DSN sync and regular Substrate sync have significant overall (5 archived segments worth of blocks right now)
Fast sync
- Obtain segment headers from DSN as described in steps 1 to 4 of sync from DSN implementation
- Download and reconstruct all blocks from the last segment of archived history
- Note: In most cases it'll be necessary to download second last segment as well due to the first block being partially included in latest segment
- Download state that corresponds to the first block received in the previous step using Substrate State Sync
- Import the first block of the last segment with its state into the blockchain DB bypassing the blockchain checks of missing parent block, it is important for this to be an atomic operation
- Import and execute other remaining blocks from the last segment as they would normally
- Pass the control to sync from DSN implementation. It will either download the new archived segment if any or pass the control to Substrate Sync.
Substrate Sync
Default sync in Substrate
- Given the connected synced peers (with the
is_syncing: falsestatus) and their best blocks and find the tip. - Download blocks from the last archived block to tip from the peers in batches in parallel.
- Import and verify blocks. Ban bad peers.
- When you are close to tip (~18 blocks) switch to keep-up sync
- When get to tip start participate in consensus
Block Reward Address
In a basic blockchain farming setup, a farmer’s identity would be used for plot creation, block signing, and receiving block rewards, posing risks like plot invalidation on testnet when used across multiple nodes and incompatibility with cold wallets. To address these, the farmer's identity is decoupled from the reward address by introducing a --reward-address argument in the farmer app, allowing the specification of a separate address for block rewards. This additional reward_address block header field, enhances security, supports multi-replica farming, and aligns farming operations with practices in PoW mining where reward addresses are independent of operational identities.
pub struct Solution<PublicKey, RewardAddress> {
/// Public key of the farmer that created the solution
pub public_key: PublicKey,
/// Address for receiving block reward
pub reward_address: RewardAddress,
/// Index of the sector where solution was found
pub sector_index: SectorIndex,
/// Size of the blockchain history at time of sector creation
pub history_size: HistorySize,
/// Pieces offset within sector
pub piece_offset: PieceOffset,
/// Record commitment that can use used to verify that piece was included in blockchain history
pub record_commitment: RecordCommitment,
/// Witness for above record commitment
pub record_witness: RecordWitness,
/// Chunk at above offset
pub chunk: Scalar,
/// Witness for above chunk
pub chunk_witness: ChunkWitness,
/// Proof of space for piece offset
pub proof_of_space: PosProof,
}