Skip to content

raylsnetwork/rbft

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

RBFT - Rayls Byzantine Fault Tolerant Consensus

CI/CD License Rust

A high-performance Byzantine Fault Tolerant (BFT) consensus implementation based on QBFT, built on top of Reth. This implementation includes a native ETH-wrapping ERC20 contract and comprehensive testing infrastructure.

Features

  • QBFT Consensus: Standards-compliant QBFT implementation with RLPx peer-to-peer networking
  • Reth Integration: Built on Reth for high-performance block execution
  • Native ERC20: QBFTErc20 contract that wraps native ETH balances
  • Dynamic Validators: Add/remove validators through smart contract interactions
  • Comprehensive Testing: Automated testnet with transaction load testing and contract verification

Quick Start

Prerequisites

  • Rust 1.93 or later (with nightly for formatting)
  • Git
  • Make
  • Linux or macOS (Windows via WSL)

Installation

  1. Clone the repository:
git clone https://github.com/raylsnetwork/rbft.git
cd rbft
  1. Build the project:
cargo build --release

Running a Local Testnet

Start a 4-node testnet with a single command:

make testnet_start

This will:

  • Generate validator keys and genesis configuration
  • Start 4 validator nodes (HTTP ports 8545-8548)
  • Deploy the QBFTValidatorSet contract
  • Begin producing blocks every 500ms

The nodes will log to ~/.rbft/testnet/logs/ and store data in ~/.rbft/testnet/db/.

Running a Follower Node

A follower node connects to an existing validator network, receives blocks, and keeps a full copy of the chain. It does not participate in consensus (no --validator-key), so it can be added to or removed from the network at any time without affecting liveness.

Before running a follower you need:

  • A running RBFT testnet (e.g. started with make testnet_start)
  • The genesis.json and nodes.csv from the testnet assets directory (default: ~/.rbft/testnet/assets/)

Extract the validator enode URLs from nodes.csv (column 5):

ENODES=$(awk -F',' 'NR>1{printf "%s%s",sep,$5; sep=","}' ~/.rbft/testnet/assets/nodes.csv)

Then start the follower:

target/release/rbft-node node \
  --chain ~/.rbft/testnet/assets/genesis.json \
  --datadir /tmp/rbft-follower \
  --port 12345 \
  --authrpc.port 8651 \
  --http --http.port 8600 \
  --disable-discovery \
  --trusted-peers "$ENODES"

Key flags:

  • --chain — path to the shared genesis.json (must match the running network)
  • --datadir — a fresh directory for the follower's database; must not be shared with a validator
  • --port — P2P listen port; pick one that does not conflict with the validator nodes (default validator ports start at 30303)
  • --authrpc.port — engine API port; also must not conflict (validator default: 8551+)
  • --disable-discovery — prevents unwanted discv4/discv5 discovery; peers are supplied explicitly via --trusted-peers
  • --trusted-peers — comma-separated enode URLs of the validators to connect to
  • --validator-key is intentionally omitted — its absence is what makes this a follower

Adding a Validator Node

To add a new validator to a running testnet you need a validator key (for signing QBFT messages), a P2P secret key (for RLPx networking), and the enode URL derived from it.

1. Generate keys

target/release/rbft-utils validator keygen --ip <YOUR_IP> --port 30305

This prints JSON with all four values:

{
  "validator_address":     "0xABCD...",
  "validator_private_key": "0x1234...",
  "p2p_secret_key":        "abcd...",
  "enode":                 "enode://<pubkey>@<YOUR_IP>:30305"
}

Save the keys and capture the enode:

echo "0x1234..." > validator-key-new.txt
echo "abcd..."   > p2p-secret-key-new.txt
ENODE="enode://<pubkey>@<YOUR_IP>:30305"

2. Start the node

target/release/rbft-node node \
  --chain ~/.rbft/testnet/assets/genesis.json \
  --datadir /tmp/rbft-new-validator \
  --port 30305 \
  --authrpc.port 8652 \
  --http --http.port 8601 \
  --disable-discovery \
  --p2p-secret-key p2p-secret-key-new.txt \
  --validator-key validator-key-new.txt \
  --trusted-peers "$ENODES"   # enodes of existing validators

3. Register the validator in the contract

The admin key is taken from the RBFT_ADMIN_KEY environment variable, which must match the key used when the genesis was generated. For a fresh local testnet started without setting RBFT_ADMIN_KEY, the default is 0x000...0001:

target/release/rbft-utils validator add \
  --validator-address 0xABCD... \
  --enode "$ENODE" \
  --rpc-url http://localhost:8545

If RBFT_ADMIN_KEY is not set, pass it explicitly:

target/release/rbft-utils validator add \
  --admin-key <ADMIN_PRIVATE_KEY> \
  --validator-address 0xABCD... \
  --enode "$ENODE" \
  --rpc-url http://localhost:8545

The new validator becomes active at the next epoch boundary.

Installing Cast (Foundry)

Cast is a useful tool for interacting with the blockchain:

curl -L https://foundry.paradigm.xyz | bash
foundryup

Verify installation:

cast --version

Interacting with the Testnet

The testnet command will show the block heights of the nodes in the validator set and should increase at a rate of around two blocks a second.

Switch to another terminal to interact with the chain via commands.

Check Current Block Height

Using cast

cast bn

Using curl:

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

Submit a Transaction

For local testing, provide a dev-only key via environment variable:

export RBFT_ADMIN_KEY=0x<dev-private-key>

To derive the corresponding address:

cast wallet address --private-key "$RBFT_ADMIN_KEY"

Send ETH using cast:

cast send 0x1234567890123456789012345678901234567890 \
  --value 1ether \
  --private-key "$RBFT_ADMIN_KEY" \
  --rpc-url http://localhost:8545

Check Account Balance

cast balance 0x<address-derived-from-RBFT_ADMIN_KEY>

Or with curl:

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

Available Make Targets

Run make help to see all available commands:

  • testnet_start - Start a local testnet (default: 4 nodes)
  • testnet_load_test - Start testnet with transaction load testing and auto-exit
  • test-erc20-contract - Test ERC20 contract (funds, mints, verifies balanceOf)
  • genesis - Generate a genesis file
  • validator_status - Display QBFTValidatorSet contract status
  • add-validator - Add a test validator to the contract

Smart Contracts

QBFTValidatorSet

Manages the validator set with features:

  • Add/remove validators (admin only)
  • Query active validators
  • Epoch-based validator set updates

Contract address: 0x0000000000000000000000000000000000001001

Testing

Run Unit Tests

cargo test

Run Load Tests

make testnet_load_test

This starts a testnet with automated transaction generation and exits after reaching a target block height.

Test ERC20 Contract

make test-erc20-contract

This runs automated tests that:

  1. Fund the ERC20 contract
  2. Mint tokens to a test address
  3. Verify balanceOf() matches native balance
  4. Exit with success/failure status

Code Quality

  • Rust formatting is enforced with cargo +nightly fmt (100 column width via rustfmt.toml)
  • CI runs scripts/check_line_length.py to cap code/config lines at 100 characters
  • Pre-commit hooks available for local validation:
    pip install pre-commit
    pre-commit install

Architecture

┌─────────────────┐
│  RPC Interface  │ (HTTP on ports 8545+)
└────────┬────────┘
         │
┌────────▼────────┐
│  Reth Engine    │ (Block execution, state management)
└────────┬────────┘
         │
┌────────▼────────┐
│ RBFT Consensus  │ (QBFT protocol, validator rotation)
└────────┬────────┘
         │
┌────────▼────────┐
│  RLPx Network   │ (P2P messaging between validators)
└─────────────────┘

Environment Variables

Configure the testnet with environment variables:

  • RBFT_NUM_NODES - Number of validators (default: 4)
  • RBFT_EXIT_AFTER_BLOCK - Exit testnet after reaching this block
  • RBFT_TEST_ERC20 - Enable ERC20 contract testing at block 10
  • RBFT_RUN_MEGATX - Run transaction load generator
  • RBFT_ADD_AT_BLOCKS - Add validators at specific blocks (e.g., "10,20,30")
  • RBFT_REGISTRY - Container registry for Docker images (required for make docker-push)

Example:

RBFT_NUM_NODES=7 RBFT_EXIT_AFTER_BLOCK=100 make testnet_start

Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines on:

  • Code style and formatting
  • Testing requirements
  • Pull request process
  • Development workflow

License

This project is licensed under the Apache License, Version 2.0. See LICENSE.md for details.

Third-Party Licenses

This project incorporates or derives from the following third-party works:

Dependency License Copyright
reth Apache-2.0 OR MIT Copyright (c) 2022–2024 Paradigm
OpenZeppelin Contracts MIT Copyright (c) 2016–2024 OpenZeppelin

Full license texts for these dependencies are available in their respective repositories or in the target/forge_dependencies/ directory.

Resources

Support


Note: This is a development build. Do not use in production without thorough security auditing.

About

Rayls Byzantine Fault Tolerant consensus built on Reth

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors