Blocks in Cardano SL
This guide describes block design and the logic of the block handling.
A block is a fundamental part of the ledger. There are two types of blocks: main blocks and genesis blocks.
A main block consists of a header and a body. The header contains meta-information about the block, for example, a block signature. The body contains 4 primary components:
- Transactions (with separate witnesses for them)
- 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. 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.
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
Iis a leader,
Dhas a right to issue a new block.
Ihas some money, we can think that
Downs 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:
- A proposal for software update (update for the nodes and update of the protocol itself).
- A list of votes for the particular update (stakeholders can approve or reject one).
- Attributes for future extensions (we can use an attributes to add some new features).
The proposal is optional. Please read about Update System Model for more info.
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:
- An index of the epoch this block is associated with.
- The list of slot-leaders for this epoch.
- Chain difficulty.
Please note that the list of slot-leaders (actually, the 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
- get block headers by different criteria
- classify block headers
As mentioned above, there are two kinds of blocks: main blocks and genesis blocks.
A main block is created with the
function, and a genesis block is created with the
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
slotSecurityParamblocks away from given slot ID.
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
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.
We apply blocks using the
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
function for it. If some error occurred during application, there are two options:
- All blocks applied inside this function will be rollbacked.
- This function will try to apply as many blocks as possible.
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
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:
is used for it.
A header is treated as useless if the following conditions are met:
- The newest hash is the same as our tip,
- The newest hash difficulty is not greater than our tip’s,
- LCA couldn’t be found, maybe the state of the database was updated during the process,
- The difference between the tip and LCA is too large.
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.