ChainLaunch

Manage Validators

This guide covers adding, removing, and monitoring validators in a running QBFT/IBFT 2.0 Besu network.

This guide covers adding, removing, and monitoring validators in a running QBFT/IBFT 2.0 Besu network.

How Validator Voting Works

In QBFT and IBFT 2.0, validator changes happen through on-chain voting:

  1. An existing validator proposes to add or remove a validator
  2. Other validators vote on the proposal
  3. When the proposal reaches a majority (>50% of current validators), the change takes effect at the next epoch boundary

No downtime is required. The network continues producing blocks during the voting process.

View Current Validators

Via JSON-RPC

curl -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "qbft_getValidatorsByBlockNumber",
    "params": ["latest"],
    "id": 1
  }'

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0xaa36a7d6fb3e7f6ff89a4ecef5e27d28b37b74e3",
    "0xbb36a7d6fb3e7f6ff89a4ecef5e27d28b37b74e4",
    "0xcc36a7d6fb3e7f6ff89a4ecef5e27d28b37b74e5",
    "0xdd36a7d6fb3e7f6ff89a4ecef5e27d28b37b74e6"
  ]
}

Via ChainLaunch API

curl http://localhost:8100/api/v1/networks/{networkId}/validators | jq

Add a Validator

Step 1: Create the Node

First, create a new Besu node and wait for it to sync with the network.

Step 2: Propose the Addition

Each existing validator must vote to add the new validator. Connect to each validator's RPC endpoint:

# Vote from validator 1
curl -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "qbft_proposeValidatorVote",
    "params": ["0xnew_validator_address", true],
    "id": 1
  }'
 
# Vote from validator 2
curl -X POST http://localhost:8546 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "qbft_proposeValidatorVote",
    "params": ["0xnew_validator_address", true],
    "id": 1
  }'

Step 3: Verify

Once a majority of validators have voted, the new validator is added at the next epoch:

curl -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "qbft_getValidatorsByBlockNumber",
    "params": ["latest"],
    "id": 1
  }'

Remove a Validator

Same process, but with false as the vote:

curl -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "qbft_proposeValidatorVote",
    "params": ["0xvalidator_to_remove", false],
    "id": 1
  }'

Warning

Never remove so many validators that fewer than 2f + 1 remain, where f is the Byzantine fault tolerance. For example, if you have 4 validators (tolerates 1 fault), do not remove 2 validators at once.

Check Pending Votes

curl -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "qbft_getPendingVotes",
    "params": [],
    "id": 1
  }'

Discard a Vote

To cancel a pending vote:

curl -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "qbft_discardValidatorVote",
    "params": ["0xvalidator_address"],
    "id": 1
  }'

Validator Fault Tolerance

Validators Byzantine Fault Tolerance Can lose
4 1 1 node
5 1 1 node
7 2 2 nodes
10 3 3 nodes

Formula: f = floor((n - 1) / 3) where n is the number of validators.

Monitoring Validator Health

Key metrics to watch:

# Check if a validator is producing blocks
curl -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "qbft_getSignerMetrics",
    "params": [],
    "id": 1
  }'

This returns the number of blocks proposed and sealed by each validator, helping identify underperforming nodes.

Next Steps