Blocks in Cardano SL

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

The block-related types are defined in Pos.Types.Block.Types module. The logic is defined in Pos.Block.Logic module.

Design

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

Main Block

A main block consists of header and body. A header contains meta-information about the block, like a block signature. A body contains 4 primary components:

  1. Transactions (with separate witnesses for them)
  2. SSC
  3. Delegation
  4. Update system

Transactions are stored in the Merkle tree. The list of witnesses for each transaction is stored in the block separately. Please read about Transactions in Cardano SL for more info about transaction and witnesses.

SSC (Shared Seed Computation) is used for the Follow-the-Satoshi algorithm. 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 in the ledger. So we use SSC as a source of randomness for the leader election process.

Delegation is a mechanism that allows a node to be a delegate of some other node. For example, let’s say the node D is a delegate of the node I. Then:

  • if I is a leader, D has a right to issue a new block.
  • if I has some money, we can think that D owns this money.

A delegate can prove its rights with a special certificate. Please note that only heavyweight delegation data is stored in the block.

The special payload is used for the update system mechanism. It contains:

  1. Proposal for software update (update for the nodes and update of the protocol itself).
  2. List of votes for the particular update (stakeholders can approve or reject one).
  3. Attributes for future extensions (we can use an attributes to add some new features).

Proposal is optional. Please read about Update System Model for more info.

Genesis Block

A genesis block doesn’t contain transactions, and there us 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 associated with.
  2. The list of slot-leaders for this epoch.
  3. Chain difficulty.

Please note that the list of slot-leaders (actually list of leaders’ addressHashes) cannot be empty, because every epoch must have exactly N slot-leaders, where N is a number of slots inside one epoch (and this number must be bigger than 0).

Chain difficulty represents efforts necessary to generate a chain, it is a number of the 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: a main block and a genesis block. 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 protocol paper.

First of all, we have to check whether our software can create a block according to current global state. If it can not, we report that this software is obsolete. If it can, we have to check slot ID: it shouldn’t be too large, but should be larger than the slot ID from the last known block. Then, if this condition is met, we can actually create the new block.

Genesis Block Creation

We create a genesis block 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.

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 rollbacked.
  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:

Of course, sometimes we cannot rollback blocks. For example, it’s impossible to rollback 0-th genesis block.

Block Headers Classification

A header can be classified as:

  1. Valid,
  2. Invalid,
  3. Useless.

The function classifyHeaders is used for it.

A header is treated as useless if the following conditions are met:

A header is treated as invalid if there are any errors in the chain of headers or if the last block of the passed chain wasn’t found locally.