Run a Validator
Install
- Install Rust and Cargo.
- Clone scl-node and build the release binary with
cargo build --release. The binary lands attarget/release/scl-node. - Keep it alongside a writable data directory for state and logs.
You do not need a local Bitcoin node: chain data is read from an Esplora endpoint over HTTP.
Configure
Configuration comes from a config.toml next to the binary, from environment variables, or both; environment variables override the file. All fields have working defaults.
Example config.toml:
node_id = "my-node"
rest_address = "0.0.0.0:8080" # client-facing REST API
bind_address = "0.0.0.0:50051" # gRPC: peer sync and gossip
url = "http://my-node.example:50051" # public gRPC URL advertised to peers
peers = ["http://node1.example:50051", "http://node2.example:50051"]
esplora = "https://blockstream.info/api"
db_path = "./data/scl-node"
data_dir = "./data"
peer_limit = 10
# Optional: stable Ed25519 identity for signing gossip (64 hex chars).
# Omit for an ephemeral identity.
gossip_private_key = ""
# Optional: bearer token protecting private endpoints
# (confirmed-call log, admin operations). Omit to leave them locked.
api_token = ""
The equivalent environment variables:
| Variable | Default | Purpose |
|---|---|---|
SCL_NODE_ID |
scl-node-1 |
Node identifier |
SCL_REST_ADDRESS |
0.0.0.0:8080 |
REST API bind |
SCL_BIND_ADDRESS |
0.0.0.0:50051 |
gRPC bind |
SCL_PUBLIC_URL |
http://localhost:50051 |
Public gRPC URL advertised to peers |
SCL_PEERS |
empty | Comma-separated peer gRPC URLs |
SCL_PEER_LIMIT |
10 |
Max peers for gossip forwarding |
SCL_ESPLORA_URL |
https://blockstream.info/api |
Esplora API base (set a testnet URL for testnet) |
SCL_DB_PATH |
data/scl-node |
Database path |
SCL_GOSSIP_PRIVATE_KEY |
empty | Ed25519 seed for a stable gossip identity |
SCL_API_TOKEN |
empty | Bearer token for private endpoints |
RUST_LOG |
info |
Log filter |
Start
./scl-node
There are no subcommands; configuration fully determines behavior. A docker-compose.yml in the repository runs a single node with persistent data if you prefer containers.
On startup your node:
- Initializes local storage.
- Fetches the current Bitcoin height from Esplora and anchors its block journal.
- Reloads the contract registry.
- Syncs with peers using Merkle-based diffing.
- Then serves requests, gossips payloads, and watches Bitcoin for new blocks (checking every 60 seconds, with a full peer sync every 5 minutes).
Health check:
curl -i http://localhost:8080/health
# Expect: HTTP/1.1 200 OK
curl http://localhost:8080/node_status
Verify you're in sync
Compare state roots with another node; matching roots at the same height prove matching state:
curl http://localhost:8080/v2/state_root
For the full REST and gRPC surface, see the Node API Reference. Treat the REST surface as current implementation, not a stable public API.
Earning XRB
Validators stake XRB to participate in validation rounds and earn from the validator emission pool, released per Bitcoin block, plus fee flows from network activity. See Fuel and Emissions for the mechanism and numbers.