Running frost-node
frost-node run --config node.yamlOne process is one node: a consensus authority (validator or follower), an execution driver, and an ingress. The execution layer runs as a separate process alongside it, reached over the Engine API.
What the process does
Section titled “What the process does”For a validator, continuously:
- Participates in the consensus DAG, proposing and signing blocks.
- Receives the committed transaction order.
- Drives the execution layer over the forced-transaction Engine API profile: pass the committed list, get the payload, deliver it as the new head.
- Accepts user submissions on the ingress, validates them, and forwards them to consensus.
For a follower, the same minus consensus participation: it streams the committed order from a validator’s observer endpoint and drives its own execution layer to the identical chain.
Configuration
Section titled “Configuration”The node config is local to the machine:
# key paths — presence of protocol_key makes this a validatorprotocol_key: keys/protocol.keypq_network_key: keys/network-pq.keycheckpoint_key: keys/checkpoint.keycheckpoint_slh_key: keys/checkpoint-slh.key
db_path: /var/lib/frost/consensusjournal_path: /var/lib/frost/driver-journal.jsonl
engine_url: http://127.0.0.1:8551engine_jwt: /var/lib/frost/jwt.hex
ingress_listen: 0.0.0.0:8645metrics_listen: 127.0.0.1:9184The chain-defining manifest is separate and identical on every node. See Keys and committee.
Startup checks
Section titled “Startup checks”frost-node run refuses to start rather than joining a chain it cannot verify:
- Genesis cross-check. The execution layer’s genesis
extraDatamust carry the manifest’s committee digest. - Journal reconciliation. The write-ahead commit journal is reconciled against the execution layer’s head before anything is driven.
- Fresh-chain guard. A node expecting genesis refuses a non-genesis execution layer.
Each of these is a case where continuing would mean building a different chain than the network. Refusing to start is the correct outcome.
Fail-stop
Section titled “Fail-stop”The node halts loudly on any execution-layer error. This is deliberate and it is part of the execution/consensus contract.
The sharpest case is the journal assertion. Every rebuild during recovery is checked against the block hash the journal recorded. A mismatch means nondeterministic execution, and the node halts rather than continuing. A node that quietly proceeds past a determinism failure is exactly how a chain splits; halting is a bad outcome, forking is a worse one.
Configure your supervisor to restart on exit, but alert on repeated restarts rather than treating them as routine — a node halting repeatedly is telling you something.
Shutdown
Section titled “Shutdown”SIGTERM or SIGINT stops gracefully. Let it finish; a clean shutdown lets the
journal and the consensus database close consistently, which makes the next
start a resume rather than a recovery.
Restart safety
Section titled “Restart safety”The driver appends every block-producing commit to a write-ahead journal before the committing Engine API call. On startup:
- Clean restart → resume after the last journaled commit.
- Execution layer lost blocks (crash, SIGKILL, recovered at an earlier state) → those blocks are re-driven from replayed consensus commits, each rebuild asserted against the journaled hash.
- Irreconcilable disagreement → the node refuses to start.
This has been verified by fault injection in the exact crash window between journal append and commit.
Containerised deployment
Section titled “Containerised deployment”The reference deployment ships digest-pinned images and a generated Compose file:
docker compose up -ddocker compose logs -f frost-nodedocker compose stop # graceful; expect clean exit codesRun with a restart policy. Node data lives on volumes; keys should not live in the image.
Verify image digests against the recorded values before running — see Requirements. Consensus-critical parameters are compiled in, so running an unverified build risks splitting from the network rather than joining it.
Expose the ingress (8645) if you serve users. Keep the execution layer RPC (8545), the Engine API (8551), and metrics (9184) on localhost. See Requirements.
Checking it works
Section titled “Checking it works”# the node is following the chaincurl -s http://127.0.0.1:8645 -H 'content-type: application/json' \ --data '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'
# and agrees with the public network on block hashescurl -s https://rpc.frostfi.net -H 'content-type: application/json' \ --data '{"jsonrpc":"2.0","id":1,"method":"eth_getBlockByNumber","params":["0xdb703",false]}'Comparing a block hash against another node is the real test. Identical hashes mean your node is reproducing the network’s chain exactly, which is the whole point.