QuorumChain Consensus [Quorum v1.x ONLY]
*Note: QuorumChain was removed in Quorum 2.0. The information on this page only applies to Quorum v1.x
Whilst the overall goal is to ensure pluggability of consensus mechanisms, the initial consensus mechanism that Quorum supports is a new mechanism dubbed QuorumChain, a time-based, majority-voting algorithm that utilises:
- A Smart Contract to govern consensus and manage who can partake in consensus
- Ethereum Transactions to propagate
votesthrough the network
- Ethereum's signature validation to validate signatures received from
Nodes within a Quorum network can be given the
Voter role which allows them to
vote on which block should be the canonical head at a particular height. The most recent block with the most votes is considered the canonical head of the chain. A block is only considered valid once a given threshold of
votes has been received from valid
Block creation is only allowed by nodes that have been given the
Maker role. A node with this role can create a block and sign it by setting their signature in the
ExtraData field of the block. On block import, as part of the block header validation, nodes verify that the block was signed by one of the nodes that have the
Maker role by looking up the signer's address in the list of valid
Makers in the voting contract.
Nodes can be given no role, one of the roles or both roles through command line arguments.
Voting Smart Contract
QuorumChain is implemented in the
BlockVoting contract (found here) which is set at address
0x0000000000000000000000000000000000000020 within the Genesis block. That address, the pre-compiled byte code for the
BlockVoting contract and its associated ABI are hard coded into the Quorum client. If the consensus rules within the
BlockVoting contract need to be updated then the new code needs to be compiled and the Quorum client needs to be updated to reflect the new code.
Through predefined functions on the contract,
Makers can be added or removed, and the minimum number of
votes before a block is selected as the winner can be configured.
BlockVoting contract tracks whether the
votes received are from valid
Voters, and whether the number of
votes received for a particular block is greater than the
voteThreshold that is defined within the contract.
As part of block validation, the contract is called to determine the latest block which meets the required number of
votes (the canonical height of the chain) - it is this block that the proposed block should be attempting to build upon (i.e. should be the parent of the proposed block).
Maker Nodes are responsible for making blocks and their Ethereum addresses are registered in the
BlockVoting contract. There must be at least 1
Maker Node configured in the contract. The initial set of
Maker Nodes is pre-configured in the genesis block via the
genesis.json file, however once the network is established,
Maker Nodes can add and remove other
Maker Nodes by sending a Transaction with the appropriate function call to the
Maker Nodes can also be setup as
Voter nodes are also registered in the
BlockVoting contract and are responsible for voting on the validity of blocks. The voting role allows a node to
vote on which block should be the canonical hash at a particular height. The block with the most
votes will win and is considered the canonical head of the chain. Like
Makers, the initial set of
Voter Nodes is pre-configured in the genesis block via the
genesis.json file, however once the network is established,
Voter Nodes can add and remove other
Voter Nodes by sending a Transaction with the appropriate function call to the
Voter Nodes can also set the
voteThreshold that must be met before a block will be accepted into the chain.
Note: The current implementation does not dynamically update the
voteThreshold when the number of
Voter Nodes on the network changes, and also does not specifically track or limit the number of
Voter has made in a given
Period. These items are on the Product Roadmap.
If a Node is neither a
Voter then it is simply considered to be an Observer and will naturally not take part in block making nor voting but instead will simply receive and validate blocks.
Multiple Nodes on a Quorum network can be configured as
Maker Nodes, however to reduce the likelihood of 2 (or more)
Makers creating a block at the same time, each
Maker generates a random duration (a timeout) that it has to wait before it can create a block. If a
Maker reaches its timeout before any other
Maker does it will create a block, after which it will generate a new random timeout for itself and wait for that to elapse before attempting to create another block. Note that once a
Maker begins the block creation process, the other
Maker Nodes will reset their current timeout, generate a new random timeout, and wait until that expires before attempting to creating a block.
The timeout duration randomly falls within a
max time (in seconds) that are defined in the
BlockMakerStrategy and that can be set at Node start up via the CLI flags
--maxblocktime. If these are not explicitly set at startup then default values will be used.
After a block is successfully imported as chain head a new pending block is prepared on top of that block. All processable transactions are selected and applied to the pending state in the new block. If the node is configured with the
Maker role and is ordered to create a block, it will first validate that the parent block hash is a valid canonical hash (latest block with required number of votes). If this block differs from the current local head the block creation fails. If the block was built on top of the correct block then the new block is inserted into the block chain and broadcast to other nodes.
Note: in the current implementation, in order to avoid chain-halting due to limited online
Voter Nodes, the
Maker node will cast
votes (if it is configured to be a
Voter) for the parent block in order to meet the
voteThreshold and allow the chain to progress. This naturally has control implications and should be managed by ensuring
Voter Nodes meet their obligations to the network by remaining up.
Block voting occurs within a
Period, the duration of which is linked to the block creation duration described above. After successfully validating a block,
Voters will cast a
vote for the block by calling the
Although block creation is governed by the
BlockMakerStrategy described in the Block Creation section above, it is possible (although unlikely) that two
Maker nodes simultaneously reach their timeouts and both create a block.
Voters will vote on both blocks, but the one that has the most
votes at the end of the voting
Period will be the one that is selected to be the canonical head of the chain.
Consensus Process Flow
Within a Period:
MakerNode that reaches the timeout first creates a block and signs it. The block includes the
votesfor its parent block, which were cast in the previous
- The block is published to the network using the standard Ethereum P2P protocol - all nodes, regardless of role, receive the block.
VoterNodes validate the block. This includes:
- Calling the
BlockVotingcontract to check whether the
Makeris allowed to create blocks.
- Calling the
BlockVotingcontract to check whether the block's parent block received enough
- Executing all processable Transactions in the block, i.e. the Public Transactions and the Private Transactions the node is party to (after retrieving the Transaction payload from its Transaction Manager, as defined in the Transaction Processing & Privacy page).
- Validate the public state by comparing the public state root hash with the state root within the block.
- Hashing all Transactions in the block (Public & Private) and comparing that hash to the Transaction Hash on the block. This is not a state check but ensures that all
VoterNodes agree on the list of Transactions in the block.
- Once successfully validated,
VoterNodes send their
BlockVotingcontract using a standard Ethereum Transaction that is distributed to all Nodes. Since
votesfor a given block are cast via standard Transactions, they can only be processed when the next block is created.
MakerNode reaches its timeout, determines if the minimum number of votes have been received for the previous block, and then the block creation - > validation -> voting process is repeated.
A Note on Consensus on Private Transactions
Whilst consensus on private state is implicit through a combination of provably synchronized contract inputs (global Transaction Hash validation check), a provably deterministic EVM (public state validation check), and provable chain synchronization (new blocks only added to the canonical chain), private state consensus can be further validated via a new rpc command,
eth_storageRoot. This command returns the private state root hash of a contract account at a given block number. This can then be validated against a counterparty's
storageRoot result off-chain or at the application layer.
Quorum Block Structure
Quorum blocks include:
- A Global Transaction Hash, which is the hash of all Transactions in a block (both private and public)
- The Public State root hash (as opposed to a Global State root hash in standard Ethereum)
Maker's signature in the