Skip to content

PBFT Consensus

Introduction

One of the most important aspects of a blockchain is group consensus. All network members form an agreement to provide data verifiability and reliability. There is never one party in control of how data gets inserted or modified on the blockchain. Members form an agreement on any new data by attesting to the validity and correctness of the data.

See Blockchain Key Concepts for an overview on Blockchain consensus algorithms.

PBFT

STRATO uses the Practical Byzantine Fault Tolerance Consensus Algorithm to achieve network consensus. PBFT requires a ⅔ majority of members to reach consensus. It also is ideal for synchronous networks or possible failures as it allows up to ⅓ of members to temporarily disconnect, be out of sync with each other, or even attest to bad blocks (the member is said to be "byzantine").

PBFT uses a multi-stage communication strategy to allow for a strong network confidence. When a new block is proposed, it is broadcast to the other nodes. After a node receives a proposal for a new block, it validates the contents of the block. A node checks that the block contains valid data. After this is done, the node broadcasts its initial decision to the network. This decision, called the prepare message does not finalize the block. A node then receives incoming prepare messages from the network. After it has received ⅔ votes in agreement, it broadcasts a "commit" message with this decision. Once the initial proposer node receives ⅔ commit messages, the block is confirmed and inserted into chain. At this point the transactions in the block are executed and their results are recorded in the state.

Block Creation

Block creation in the STRATO PBFT system is very simple. A proposer node collects the necessary signatures, nonces, and transactions, and forms a block. It is then broadcast to the network.

Note

Since STRATO networks are formed with trusted parties, there is no need use Proof of Work or Proof of Stake algorithms. Therefore block creation can be done in an efficient manner without needing to worry about token values or mistrusting other members. This allows for several benefits:

  • Vastly less power and resources consumption.
  • Extremely high transaction throughput (time from transaction creation to transaction being inserted into a block) in a STRATO blockchain network, with a typical block time being < 1s.

STRATO PBFT Implementation

In order to facilitate rapid block creation, STRATO enables nodes in a network to Validator and Non-Validator nodes. Typically only a subset of nodes within a network are assigned as validator nodes. This allows for fewer messages sent between nodes, resulting in faster transaction validation and shorter block times. Since a node must communicate with every other validator node, the number of messages within the network that must be sent does not scale linearly with the number of nodes on the network. If every new node on the network were a validator nodes, validation would quickly be an expensive operation. By keeping the number of validator nodes relatively constant despite the growing network size, it ensures the network always performs at an optimal speed.

Validator Nodes

A Validator Node verifies that the data within a block is correct and subsequently inserts into the Blockchain. It participates in the consensus algorithm with other Validator Nodes to make an agreement on the blockchain state. The Root Node (initial node) of a network is automatically assigned as a validator.

Validation Process

A validator checks the following fields in a block to ensure the proposed block is valid:

  • Transaction Root
    • Confirms the hash of the transaction root is the same as the hash that this node arrives at after creating its own transaction root from the transactions contained within this block.
  • Parent Hash
    • The Parent Hash of block N must be the hash of block N-1.
  • Block Proposer
    • The Block Proposer must be the same as the proposer recorded in the this node.
  • Current Validators
    • A block contains the list of current validators on the network; the block's list must be the same as this node's list of proposers.

Proposer Node

At any given moment, a single validator node acts as the Proposer Node of the network. The proposer node receives new transactions and creates a block out of that data. Once a full block has been created, it is broadcasted to the rest of the validator nodes for validation. STRATO uses "rounds" to choose new proposers. A round is simply a 10 second period of time for which a given node is the proposer. The current round is recorded by storing the current round number in a node. In each new round, a new proposer node is selected automatically by the network. Like other mechanisms on the blockchain, the round number and new proposer node must be agreed upon by at least ⅔ of the network's validator nodes to be a valid change.

Non-Validator Nodes

A Non-Validator Node does not participate in the verification or creation of new blocks. It may send transactions and complete all other normal operations.

Managing Validator Nodes

Important

In STRATO v9.0, validator voting was changed in two ways:

  • Validators are represented as X.509 Identities, instead of node addresses.
  • Voting happens in a "Validator Governance" Contract in the Genesis block of the network.

All Validator management is done through a "Validator Governance contract that resides at the address 0x100 on the Main Chain of the network. This is where users can call functions to add/remove validator nodes, or admin users that are allowed to vote on validator nodes. This contract is contained in the state of the Genesis Block and therefore is always present on the network.

A Validator Node is defined as the X.509 Identity Credentials (Organization, Organizational Unit, and Common Name) of the Node Key of a specific node. So a Node cannot be a validator unless it has been issued an Identity associated with the address derived from its Node Key.

A "Validator Admin" is a user elected to be able to vote for validators on the network. The first Validator Admins are defined in the Genesis Block. Admins are managed by a ⅔ consensus vote, just like the PBFT and Validator Node voting mechanisms.

An Admin can propose to add or remove another validator node. This is accomplished by the Admin voting to administer that specified action. A two-thirds majority consensus is required for the vote's action to be administered. Once a ⅔ majority is met for the vote, than the network will execute the action of that vote, either adding the new node as a validator, or removing it as one.

Example

An Admin wants to add a new node as a validator. There are currently 10 Validator Nodes on the network. This node issues an "add" vote for the new node. Then each Admin within the network casts their vote (or chooses to abstain). If at any point the tally of "add" votes for the new node reaches 7 (⅔ of 10), the new node will be added as a validator, resulting in 11 validator nodes in the network.

Issuing a Vote from a Node

Validator voting happens as a simple function call to the Validator Governance Contract.

To cast a vote for a validator node, you must be an Admin in the Validator Governance Contract. First retrieve you must know the Identity of the node. If you do not have this on-hand, you can first fetch the node's address using the get-address tool from the node being voted on:

./strato --get-address

Returns

The address of the current node.

841de5684asde7592ac3be11a3845cedaa096f2f

Once you have the address, query the Identity database in Cirrus to retrieve the node's identity:

GET https://<strato_address>/cirrus/search/CertificateRegistry-Certificate?userAddress=eq.<nodeAddress>

Finally, send the following transaction function call:

curl -X POST \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "txs": [
      {
        "payload": {  
          "contractName": "MercataGovernance",
          "contractAddress": "0000000000000000000000000000000000000100",
          "method": "voteToAddValidator",
          "args": {
            _org : "<nodeOrg>",
            _orgUnit : "<nodeOrgUnit>",
            _commonName : "<nodeCommonName>"
          }
        },
        "type": "FUNCTION"
      }
    ],
    "txParams": {
      "gasLimit": 32100000000,
      "gasPrice": 1
    }
  }' \
  "https://<strato_address>/strato/v2.3/transaction?resolve=true"

You may confirm that a validator was added after a deciding vote by querying the node's /metadata endpoint or executing the command get-validators from the node's terminal:

GET https://<strato_address>/metadata

Response

{
    "validators": [
        {
            "orgName": "<nodeOrg>",
            "orgUnit": "<nodeOrgUnit>",
            "commonName": "<nodeCommonName>",
            "access": true,
        },
    ],
    ...,
}

CLI Command

./strato --get-validators

Note

In STRATO Getting Started versions prior to 3.2.0, the following command could be used to obtain the list of validators: docker exec -i strato_strato_1 bash -c "tail -n 100 logs/strato-sequencer | grep showctx/validators | tail -n 1 | cut -d '|' -f 4"

Fun Fact

BlockApps uses the term "Blockstanbul" as a play on words of the Istanbul BFT Consensus Algorithm. Blockstanbul is BlockApps implementation of the same algorithm.

Manage Validator Admin Users

Since Validators are added via function calls, the votes must be protected so that not just any user can vote in a new validator node. For this reason the Validator Governance Contract keeps a list of authorized "Validator Admin" users. This is the list of user addresses that are allowed to vote for Validators. Admins are controlled by a ⅔ vote of all existing admins, just like voting in validators. Since there must be at least one Admin to start the network, it is declared in the genesis block at the network's boot time.

To add a validator Admin, follow these steps:

  1. Retrieve Identity information of the user you want to vote in.

  2. Call the voteToAddAdmin function on the Validator Governance Contract at address 0x100.

    curl -X POST \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{
        "txs": [
        {
            "payload": {  
            "contractName": "MercataGovernance",
            "contractAddress": "0000000000000000000000000000000000000100",
            "method": "voteToAddAdmin",
            "args": {
                _org : "<userOrg>",
                _orgUnit : "<userOrgUnit>",
                _commonName : "<userCommonName>"
            }
            },
            "type": "FUNCTION"
        }
        ],
        "txParams": {
        "gasLimit": 32100000000,
        "gasPrice": 1
        }
    }' \
    "https://<strato_address>/strato/v2.3/transaction?resolve=true"
    
  3. If you are the only Validator Administrator, then the vote will automatically meet the ⅔ consensus requirement, and the user will be added as an Admin. That user will now be able to vote for validator nodes and other validator admins.

Upgrading Validator Nodes

When upgrading a STRATO node, any private chains that exclusively exist on the node will be lost. In order to retain this data, administrators must create a mirror node before upgrading the node to the latest version. For validator nodes, this upgrade process requires that the validator behavior be temporarily disabled for the mirror node so it does not create duplicate PBFT messages in the network. Contact BlockApps technical support for more information on the mirror node upgrade approach.

Node Administrator Reference:

The queryStrato validatorBehavior <use-validator-behavior> tool can be used within the STRATO docker container:

1. Enter the STRATO container of the mirror node:

sudo docker exec -it strato_strato_1 bash

2. Temporarily disable validator behavior

var/lib/strato> queryStrato validatorBehavior false 

3. Complete mirror node upgrade process.

Validator behavior can be re-enabled by executing the command with the true argument.

This CLI tool will not do anything when done on a non-validator node.

Further Reading

  1. Practical Byzantine Fault Tolerance

Check out our VS Code extension! Signup for STRATO Mercata