Blocks in Cardano SL

This guide describes block design and the logic of the block handling.

The block-related types are defined in Pos.Block.Core.Main.Types module and Pos.Block.Core.Genesis.Types. The logic of work with blocks is defined in Pos.Block.Logic.* modules.

Design

A block is a fundamental part of the ledger. There are two types of blocks: main blocks and genesis blocks.

Main Block

A main block consists of a header and a body. The header contains meta-information about the block:

  1. A pointer to the header of previous block block signature.
  2. Proof of body.
  3. Consensus data to verify consensus algorithm.
  4. Some extra-data.

The block’s body contains payloads and some extra-data as well. Payloads include:

  1. Transactions payload. This payload is the main one. Transactions are stored in the Merkle tree. This payload includes list of witnesses as well. Please read about Transactions in Cardano SL for more info about transaction and witnesses.
  2. SSC payload. SSC (Shared Seed Computation) is used for the Follow-the-Satoshi algorithm. Within every epoch, slot-leaders for the next epoch must be elected. These slot-leaders will be able to generate new main blocks and add them to the ledger. So SSC is used as a source of randomness for the leader election process.
  3. Delegation payload. This payload consists of a list of heavyweight proxy signing keys. Please read about Stake Delegation in Cardano SL for more info.
  4. Update payload. It contains a proposal for software update and a list of votes for the particular update. Please read about Update System Model for more info.

Genesis Block

A genesis block doesn’t contain transactions, and there is just one genesis block for each epoch. Genesis blocks have a header and a body, just like main blocks. The body of the block contains:

  1. An index of the epoch this block is associated with.
  2. The list of slot-leaders for this epoch. This list cannot be empty.
  3. Chain difficulty. It represents efforts necessary to generate a chain, it’s the number of main blocks in the chain.

Block Handling Logic

We work with blocks and block headers. Fundamentally, we can:

  • create a block,
  • verify a block,
  • apply a block,
  • rollback a block,

and:

  • get block headers by different criteria,
  • classify block headers.

Block Creation

As mentioned above, there are two kinds of blocks: main blocks and genesis blocks. A main block is created with the createMainBlock function, and a genesis block is created with the createGenesisBlock function.

Main Block Creation

We try to create a new main block on top of the best chain if possible. A new block can be created if the following conditions are met:

  • We know the genesis block for the epoch from the given slot ID,
  • The last known block is not more than slotSecurityParam blocks away from given slot ID.

The value of slotSecurityParam (which actually is a number of slots) depends on maximum number of blocks which can be rolled back. This maximum number is a security parameter from the paper.

First of all, we have to check whether our software can create a block according to current global state. If it can’t, we report about it. If it can, we create and apply block.

Genesis Block Creation

A genesis block is created for the current epoch when the head of currently known best chain is MainBlock corresponding to one of the last slotSecurityParam slots of (i - 1)-th epoch.

First of all, we try to get the slot-leaders. If there’s no leaders or not enough blocks for LRC (Leaders and Richmen Computation), an error is reported. Otherwise we’re trying to actually create a new genesis block. However, sometimes we shouldn’t create one. For example, we shouldn’t do it for the 0th epoch because genesis block for 0th epoch is hardcoded.

Block Application

We apply blocks using the applyBlocks function. The sequence of blocks should be definitely valid: we must verify all predicates and data checks regarding blocks.

Important: all blocks in that sequence must be of the same epoch!

If all conditions are met, we actually apply blocks:

Moreover, we can verify blocks before application (i.e. apply blocks only if they’re valid). We use verifyAndApplyBlocks function for it. If some error occurred during application, there are two options:

  1. All blocks applied inside this function will be rolled back.
  2. This function will try to apply as many blocks as possible.

Block Rollback

You can think about a rollback as the opposite of application: when a rollback is performed, all changes made by the application are cancelled. To do this, the rollbackBlocks function is used.

We get the tip and the first block to rollback. If they do not match, an error is reported. If they match, we actually rollback the sequence of blocks:

Block Headers Classification

A header can be classified as:

  1. Continues,
  2. Alternative,
  3. Invalid,
  4. Useless.

A header is treated as continues if verification is succeed: header is a direct continuation of the main chain (i.e. its parent is our tip).

A header is treated as alternative if header’s parent is not our tip and it’s more difficult than our main chain.

A header is treated as invalid if there are any errors in the chain of headers or if there is no block corresponding to parent of oldest element in chain (should be one of checkpoints).

A header is treated as useless in different conditions (e.g. if header’s slot is less or equal than our tip’s slot, or header doesn’t continue main chain and is not more difficult).