Skip to main content

Node Configuration

Node configs live in config/node/node1.toml, node2.toml, node3.toml. Each file configures one validator.

Full example​

# Identity / network
blockchain_name = "clutch-node-test-1"
libp2p_topic_name = "test-net"

# Validator keys (keep secret_key secure — never commit)
author_public_key = "0x9b6e8af0c70..."
author_secret_key = "0x<validator-private-key>"

# All validator public keys — must match across every node
authorities = [
"0x9b6e8af0c70...",
"0x<validator-2-pubkey>",
"0x<validator-3-pubkey>",
]

# Networking
websocket_addr = "0.0.0.0:8081"
listen_addrs = ["/ip4/0.0.0.0/tcp/4001"]
bootstrap_nodes = [] # node1 is the bootstrap; node2/3 set ["..."]

# Consensus parameters — committed to state by the genesis ChainInit transaction.
# Must be byte-for-byte identical across every node (see below).
chain_id = 2077
is_testnet = true
tx_fee = 1000
mint_authority = "0x9b6e8af0c70..."
faucet_address = "0xdeb4cfb63db134698e1879ea24904df074726cc0"
faucet_allocation = 0
ride_request_referrer_fee_bps = 200
ride_offer_referrer_fee_bps = 200
ride_auto_release_secs = 300 # 0 turns the rule off
# mint_cosigners = ["0x...", "0x..."] # optional, for multi-signature minting
# mint_threshold = 2

# Observability
serve_metric_addr = "0.0.0.0:3001"
seq_url = "http://seq:80"

Key settings​

SettingDescriptionExample
libp2p_topic_nameNetwork gossip topictest-net
blockchain_nameChain identifierclutch-node-test-1
author_public_keyValidator public key0x9b6e8af...
author_secret_keyValidator secret (keep secure)—
developer_modeDeletes the on-disk database on every graceful shutdown — see the danger note belowtrue in clutch-node's own configs; false in every clutch-deploy config
websocket_addrWebSocket JSON-RPC bind0.0.0.0:8081
listen_addrslibp2p listen addresses["/ip4/0.0.0.0/tcp/4001"]
bootstrap_nodesPeers to dial on startup["/ip4/127.0.0.1/tcp/4001"] (node2/3)
authoritiesOrdered list of validator public keysMust match across nodes
block_authoring_enabledWhether this node runs the block-authoring job (participates as an active validator)true
chain_idNetwork identifier, signed into every transaction2077
is_testnetGates the genesis faucet allocation, and node startup with one configuredtrue
tx_feeFlat CLT fee per non-exempt transaction, paid to the block author1000 (= $0.001)
mint_authorityThe only address permitted to sign a Mint transactionvalidator or dedicated treasury key
faucet_addressAddress the genesis faucet allocation is credited to0xdeb4cfb6...
faucet_allocationCLT credited to faucet_address at genesis, only if is_testnet = true0 — genesis pre-mints nothing
ride_request_referrer_fee_bpsRequest referrer fee on each RidePay, in basis points200 (2%)
ride_offer_referrer_fee_bpsOffer referrer fee on each RidePay, in basis points200 (2%)
ride_auto_release_secsSeconds after a RideAcceptance after which a cancel pays the held fare to the driver instead of refunding the rider. 0 turns the rule off. See Ride Lifecycle300 on the testnet, 7200 on the mainnet
mint_cosignersFurther addresses allowed to sign or approve a Mint, on top of mint_authorityempty: one signer
mint_thresholdDistinct authority signatures a Mint needs. 0 and 1 both mean one0
wallet_chain_idThe EIP-155 chain id wallets sign with; with the next setting it turns on wallet transfers. Must equal the Hub API's wallet_chain_id20771 on the testnet; unset (off) by default
wallet_transfers_from_blockThe first block that may carry a wallet transfer. Set both or neither: the node refuses to start with one0 on the testnet
sync_enabledWhether this node runs the peer-sync job (pulls blocks from peers)true
serve_metric_enabledWhether the Prometheus /metrics endpoint is served at alltrue
serve_metric_addrPrometheus metrics bind0.0.0.0:3001
log_levelTracing log verbosityinfo
seq_urlSeq logging URLhttp://seq:80
developer_mode deletes the database

developer_mode = true — the value in clutch-node's own configs, including default.toml, and in none of clutch-deploy's — makes the node delete its entire on-disk database on every graceful shutdown (shutdown_blockchain → cleanup_db in blockchain.rs). That's the intended behavior for a scratch chain that starts fresh each run, and catastrophic for one whose data is meant to survive a restart: a month of stage outages were mistakenly blamed on volumes and the deploy script before anyone traced the actual cause to this flag.

The escape hatch is the DB_PATH environment variable: if it's set, the node treats that as a sign the data is meant to outlive the process, logs a warning, and refuses to delete rather than honoring developer_mode. Set DB_PATH (or developer_mode = false) before running against any volume whose contents you care about.

block_reward_amount is removed

There is no block_reward_amount key anymore, and no CLT is minted per block. Validators are compensated from tx_fee revenue instead — see CLT Economics. A config file left over from before this release that still sets block_reward_amount will simply have that key ignored; the node no longer reads it.

JSON-RPC exposure​

Open by design, not a bug to patch

websocket_addr binds 0.0.0.0 in every shipped config, and the WebSocket JSON-RPC server performs no authentication and no Origin check: any caller that can reach the port can call send_raw_transaction, every read method, and everything else on the RPC surface with no credential at all. It also never inspects the request path before completing the WebSocket handshake — /ws in this doc and in JSON-RPC Reference is a convention the examples follow, not a route the server enforces; any path completes the same handshake.

That is the right default for a testnet whose entire purpose is letting anyone submit transactions freely. It stops being safe the moment the port is reachable from anywhere untrusted — at that point it needs a reverse proxy or a firewall in front of it, because the node itself enforces nothing at this layer. See Security — Threat model.

Consensus parameters must match across every node​

chain_id, is_testnet, tx_fee, mint_authority, mint_cosigners, mint_threshold, faucet_address, faucet_allocation, ride_auto_release_secs, and the two referrer-fee bps rates are not just per-node preferences — they are written into the chain's state by a single ChainInit transaction (RLP tag 9) at block 0, and that transaction's hash feeds the genesis block hash. Peers compare genesis hashes during the p2p handshake: a node whose config produces a different genesis hash is refused outright, not silently allowed to fork.

Practically, this means:

  • All three node TOMLs (node1.toml, node2.toml, node3.toml, and their -docker variants) must carry identical values for every consensus-parameter key above.
  • Changing any of these values on an existing chain is equivalent to starting a new chain — the new genesis hash will not match any existing peer's, and no amount of retrying will make them sync.
  • This is a deliberate fix: these parameters used to be per-node local config with no cross-node consistency check, which meant two misconfigured nodes could silently diverge instead of failing to connect. Now the failure is loud and immediate — a mismatched node simply never syncs.

Wallet transfers: same rule on every validator, set before its block​

wallet_chain_id and wallet_transfers_from_block are not in genesis, so changing them does not start a new chain, but they decide whether a block is valid. A validator without them refuses a block that carries a wallet transfer, so all validators of a chain must carry the same two values before wallet_transfers_from_block is reached. On a running chain with real balances, switch it on as a rolling upgrade: pick a block comfortably ahead of the current height, restart each validator with the new image and the two settings, one at a time, and check all of them carry the setting before that block arrives. On a chain where every validator restarts at once, 0 is enough, because no earlier block can hold a wallet transfer.

Key settings​

  • Node 1 (bootstrap): leave bootstrap_nodes = []. It is the seed other nodes dial.
  • Node 2 / Node 3: point bootstrap_nodes at node1. The checked-in node2.toml / node3.toml use ["/ip4/127.0.0.1/tcp/4001"] for all three nodes on one host; the container variants node2-docker.toml / node3-docker.toml use ["/dns4/node1/tcp/4001"] so Docker DNS resolves the peer.
  • authorities must be identical on every node, in the same order. Aura schedules block authors by position in this list.
  • Validator keys: generate a secp256k1 keypair per node. author_public_key goes in authorities for every node; author_secret_key stays on the node that authors.
  • mint_authority does not need to be a validator key — a production deployment should use a dedicated treasury key from a proper key ceremony, never a validator's author_secret_key. The checked-in testnet config reuses node1's dev key purely for local convenience.
  • Genesis: testnet genesis allocates faucet_allocation CLT to faucet_address, but only when is_testnet = true — on any other chain, faucet allocation is forced to zero regardless of what faucet_allocation says, and the node refuses to boot at all if is_testnet = false with a nonzero faucet_allocation configured. This deployment sets it to 0 anyway, so genesis pre-mints nothing on any chain: see CLT Economics — Testnet notes for why an unbacked genesis balance stopped being acceptable once redemptions went live. Do not change blockchain_name on a running chain — it would fork.
  • Secret management: store author_secret_key via environment or a secret manager in production; never commit it to git.

Multi-node checklist​

  • Same authorities list (same order) on all nodes
  • Same libp2p_topic_name and blockchain_name
  • Same chain_id, is_testnet, tx_fee, mint_authority, mint_cosigners, mint_threshold, faucet_address, faucet_allocation, ride_auto_release_secs, and both referrer-fee bps rates on all nodes — a mismatch here prevents peering entirely
  • Same wallet_chain_id and wallet_transfers_from_block on all validators, or both unset everywhere
  • Node 1 has empty bootstrap_nodes; others point to node 1
  • Distinct ports per node (8081/8082/8083, 4001/4002/4003, 3001/3002/3003)
  • Validator secret keys kept out of source control