Chain Management

This article describes implementation details of chain management in the Aergo server. It is aimed at blockchain server developers.

The chain service is responsible for managing the chain. It performs the following tasks in large part:

  1. Validation
  2. Insert block to chain
  3. Reorganization
  4. Syncronization

Block validation

The blocks received in the network may not be valid, so a number of checks are made.

Pre-execution execution

The validator module ensures that the block was generated from a valid BP and the transaction contained in the block was not forged.

  • Consensus validation

    Validate the block generated by the valid BP through block creation time and signature.

  • Transaction merkle validation

    Validate that the transactions were not forged. The verifier module generates a merkle tree with the transactions and checks if it is the same as the transaction merkle root stored in the block header.

Post-execution validation

These checks ensure that the results of the transaction contained in the block are the same as the results of the BP node that generated the block.

  • State root validation

    Checks if the changed state root node hash is the same as the blocksRootHash stored in the block head.

  • Receipt merkle validation

    Generates a merkle tree with the receipts generated as a result of the transactions and checks if they are identical to the receipts stored in the block header.

Insert block into chain

There are two cases in which the chain service adds blocks:

  1. Block generated by block factory

When it is a BP node’s turn, it generates new blocks in the block factory.

The block factory performs all transactions and forwards the block to the chain service. The execution results are included with the block.

The execution results include the results of the transaction, receipt, and state changed entry indicating the change to the account.

The chain service stores information related to blocks in the ChainDB and information about accounts in the StateDB.

  1. Block received from another peer node

For blocks received from other peer nodes, there are three main cases:

  • Orphan block

    This is the case if the parent block has not yet been stored in the DB. Orphan blocks are stored in the orphan block cache on memory. Then, when the parent block is received, it is removed from the organ block cache and reprocessed.

  • Side branch block

    In case the parent block is stored but is not part of the main branch. In this case, the block is not performed and only the block info{hash, block} is stored.

  • Main branch block

    In case the head of the main branch is the next block. In this case, the blocks are stored after performing the transactions.

The process for storing blocks in the main branch is as follows:

  1. Validation before execution
  2. Execute transactions
  3. Apply changed account entries state merkle tree
  4. Validate after execution
  5. Save state merkle tree to StateDB
  6. Save chain meta data to ChainDB

Reorganization

The chain service selects and maintains the longest chain as the main branch. The side branches are not executed and only the block info is stored in the DB. If the side branch received from another peer is longer than the main branch held by the node, the side branch is changed to the main branch. This is called the reorgnize process.

The reorgnization is performed as follows.

  1. Find common ancestor
Syncer finds the last common ancestor block of the main branch and side branch.
  1. Rollback master branch
State is reset to the point at which the common ancestor block was executed
  1. Rollforward side branch
Syncer runs from the next number of the common ancestor block to the head block of the side branch. At this time, only StateDB is changed and Chain info and Tx info are not changed.
  1. Swap chain meta

Syncer do not change the chain info during rollback and rollforward to atomically change the chain. Change the chain meta information after the previous process has been successfully completed. At this time, chain info and transaction info are deleted for the rollbacked block, and new chain info and transaction info are added for the rollforwarded block.

Transactions belonging to rollbacked blocks but not included in rollforwarded blocks are returned to mempool. This is to prevent transaction loss.

Syncronization

When you add a new node or restart a node that was temporarily stopped, you need to get the latest chain information from existing nodes. This is called the synchonization process.

The situation that causes sync is as follows:

  • When the peer goes through a handshake process to connect, the height of the chain of the remote peer is higher than the current node
  • If the height of the block notified in the peer is higher than the head of the current main branch

The syncer specifies the node that sent the block that caused the sync to the target node and synchronizes with the chain of that node.

To synchronize a long chain, a large amount of block information must be received from the peer node. This is likely to cause a performance degrade at the peer node. Therefore, it gets information from as many peers as possible to distribute the load.

Synchronize step

  1. Find common ancestor: Syncer finds the last common ancestor of the current node chain and the target node chain.
  2. Get hashes: It gets the hashes of the block after the common ancestor from the target node.
  3. Get blocks: N blocks are requested from all valid peers connected to the current node.
  4. Insert blocks to chain: The received block is added to the chain using the chain service.

2, 3, and 4 are performed in parallel. Most of the time is spent in the insert part of the chain.