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_time
output for the claimed slot andfuture_proof_of_time
for a future slot as defined in PoT specification.
Consensus log items:
PotSlotIterations
number 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.SolutionRange
solution range for this block/era.PotParametersChange
change of parameters to apply to PoT chain, including at which slot change of parameters takes effectslot
, new number of slot iterationsslot_iterations
and entropy (entropy
) that should be injected at theslot
.NextSolutionRange
new 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).RootPlotPublicKeyUpdate
whether 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_header
sIn case the number of obtained
segment_header
s 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_header
that largest subset of peers agree on as their newest (mode) from their last 2 segment headers. -
Download the chain of archived
segment_headers
backwards 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_commitment
in from correspondingsegment_header
along the way:- Split piece into
record
,record_commitment
andrecord_witness
- Hash the
record_commitment
to obtain therecord_commitment_hash
- Verify the
record_witness
for thepiece_index
,record_commitment_hash
andsegment_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: false
status) 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,
}