Skip to main content

Running a Node

This guide covers running a node-only QoreChain deployment — a full or RPC node that syncs the chain and exposes endpoints for integration, without validator duties. It targets exchanges (CEX), wallet backends, indexers, and integrators who need reliable read/write access to the network but do not sign blocks.

note

For block production, staking, slashing, and pool classification, see Running a Validator instead. A node-only deployment never holds a validator consensus key and never appears in the active set.

warning

Binaries, genesis, and snapshots are published at download.qore.host with SHA-256 checksums. Always verify checksums before installing or extracting, and verify deposits only against your own synced node.

Source of truth: the live manifest

The current binary, genesis, peers, seeds, and a state-sync trust point are published as a JSON manifest, refreshed live — don't hardcode a binary version, checksum, or snapshot filename in your install scripts, since they go stale as soon as a new release ships:

  • Mainnet: https://download.qore.host/mainnet/latest.json
  • Testnet: https://download.qore.host/testnet/latest.json

The manifest's fields include binary (url + sha256), genesis (url + sha256 + sizeBytes), peers, seeds, p2pPort, stateSync (a trust point refreshed hourly), and minCompatible. The install and join steps below fetch this manifest and use its current values.

v3.1.94 or later required for a node joining fresh

A node that syncs from genesis or replays from an archive/snapshot needs to be on v3.1.94 or later, for two stacked reasons: v3.1.92 fixed a gas-metering bug that otherwise halts replay at the first block containing a transaction, and mainnet has since passed the v3.1.94 governance upgrade (a hard-cap on emission, applied at height 2,122,074) — a node without that upgrade's handler halts again trying to replay past that same height. v3.1.97 is the current recommended version (rolling, non-consensus-breaking security updates); minCompatible is 3.1.94. The manifest is promoted deliberately (testnet first, mainnet after a soak period) and has previously lagged behind this floor — check its "version" field before trusting binary.url, and fall back to the qorechain-core GitHub releases or building from source if it's behind.


Node vs Validator​

AspectNode-only (this guide)Validator
Consensus keyNoneed25519 consensus key (must be secured)
Block productionNoYes — proposes and signs blocks
Staking / slashingNot applicableSelf-delegation, slashing risk
Primary purposeServe RPC/REST/gRPC/EVM/SVM to integrationsSecure the network, earn rewards
Public exposureRPC/EVM endpoints typically exposedValidator hidden behind sentry nodes

Target Networks​

NetworkChain IDEVM chain IDNotes
Mainnetqorechain-vladi9801 (hex 0x2649)Primary — live since 7 Jun 2026
Testnetqorechain-diana9800Rehearse integrations here first

Substitute the appropriate --chain-id for your target network throughout this guide. The examples default to mainnet.


ProfileCPURAMDisk (NVMe SSD)Network
Pruned RPC node4 cores16 GB500 GB+100 Mbps+
Full/archive node8 cores32 GB2 TB+ (grows over time)1 Gbps
Exchange integration8 cores32 GB2 TB+ with headroom1 Gbps

NVMe SSD is strongly recommended — chain state and the EVM/SVM stores are I/O intensive. Archive nodes (no pruning, full tx indexing) grow continuously; provision disk with headroom and monitoring.


Deployment​

Docker Compose​

A node-only deployment with Docker Compose. There is no publicly published qorechaind image to pull yet — build one yourself from the repository's Dockerfile and tag it to the live chain version (v3.1.97 on mainnet), then mount a persistent volume for chain data:

git clone https://github.com/qorechain/qorechain-core.git
cd qorechain-core
docker build -t qorechain-node:v3.1.97 .
# docker-compose.yml
services:
qorechain-node:
image: qorechain-node:v3.1.97
container_name: qorechain-node
restart: unless-stopped
command: ["start", "--home", "/root/.qorechaind"]
volumes:
- qorechain-data:/root/.qorechaind
ports:
- "26657:26657" # RPC
- "26656:26656" # P2P
- "1317:1317" # REST
- "9090:9090" # gRPC
- "8545:8545" # EVM JSON-RPC
- "8546:8546" # EVM WebSocket
- "8899:8899" # SVM RPC
- "26660:26660" # Prometheus

volumes:
qorechain-data:

Initialize the data directory once (genesis and peer configuration are covered below), then start:

docker compose up -d
docker compose logs -f qorechain-node

systemd​

For a bare-metal install, run qorechaind under systemd:

# /etc/systemd/system/qorechaind.service
[Unit]
Description=QoreChain node
After=network-online.target
Wants=network-online.target

[Service]
User=qorechain
ExecStart=/usr/local/bin/qorechaind start --home /var/lib/qorechaind
Restart=on-failure
RestartSec=5
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now qorechaind
sudo journalctl -u qorechaind -f

Joining the Network​

1. Initialize​

qorechaind init my-node --chain-id qorechain-vladi

2. Fetch the manifest​

curl -s https://download.qore.host/mainnet/latest.json -o latest.json
# testnet: https://download.qore.host/testnet/latest.json

Use this file as the source for the binary, genesis, and peer values in the steps below — check jq -r .minCompatible latest.json but remember the v3.1.94 floor above holds even if that field lags behind.

3. Download and verify genesis​

GENESIS_URL=$(jq -r .genesis.url latest.json)
GENESIS_SHA256=$(jq -r .genesis.sha256 latest.json)

curl -fsSL "$GENESIS_URL" -o ~/.qorechaind/config/genesis.json
echo "${GENESIS_SHA256} $HOME/.qorechaind/config/genesis.json" | sha256sum -c -

# Cross-verify against the genesis served live by the chain:
curl -s https://rpc.qore.host/genesis | jq '.result.genesis' > /tmp/genesis-live.json

4. Configure peers and the fee floor​

Read the current peers and seeds from the manifest rather than hardcoding node IDs and hosts — these rotate:

PEERS=$(jq -r '.peers | join(",")' latest.json)
SEEDS=$(jq -r '.seeds | join(",")' latest.json)

Open ~/.qorechaind/config/config.toml and set persistent_peers (and seeds) to those values:

persistent_peers = "<value of $PEERS>"
seeds = "<value of $SEEDS>"

Then set the minimum gas price in ~/.qorechaind/config/app.toml (network fee floor: 0.1uqor):

minimum-gas-prices = "0.1uqor"

5. Start syncing​

qorechaind start --minimum-gas-prices=0.1uqor

Fast Bootstrap​

Syncing from genesis can take a long time. For integrations, use state sync or a snapshot for a fast cold start.

State sync​

State sync fetches a recent application state snapshot from trusted RPC servers instead of replaying every block. Configure the [statesync] section in config.toml:

[statesync]
enable = true
rpc_servers = "https://rpc.qore.host:443,https://rpc.qore.host:443"
trust_height = <TRUSTED_BLOCK_HEIGHT>
trust_hash = "<TRUSTED_BLOCK_HASH>"
trust_period = "168h0m0s"

Take trust_height / trust_hash from the manifest's stateSync field — it's refreshed hourly, so it's the preferred source:

TRUST_HEIGHT=$(jq -r .stateSync.trustHeight latest.json)
TRUST_HASH=$(jq -r .stateSync.trustHash latest.json)

As a fallback/alternative, you can derive a trusted height and hash yourself from the public RPC:

curl -s https://rpc.qore.host/block | jq -r '.result.block.header.height, .result.block_id.hash'

Snapshot restore​

Alternatively, download the published chain-data snapshot, verify its checksum, and extract it over your data directory. The manifest does not currently carry a snapshot pointer, so check the live listing at download.qore.host for the current filename and checksum rather than hardcoding one:

# Substitute the current filename and checksum from the download.qore.host listing
curl -fsSL https://download.qore.host/<current-snapshot-filename>.tar.gz -o snapshot.tar.gz
sha256sum snapshot.tar.gz # compare against the checksum published alongside it

tar xzf snapshot.tar.gz -C ~/.qorechaind/
qorechaind start --minimum-gas-prices=0.1uqor
note

Snapshots are published under height-stamped filenames that change regularly — check download.qore.host for the most recent snapshot and its SHA-256 checksum, and always verify before extracting. Remember the v3.1.94 minimum above applies to replay from a snapshot too.


Pruning and Indexing​

Tune pruning and transaction indexing to match your integration. Exchanges that need full transaction history should run with minimal pruning and a transaction indexer enabled.

Pruning (app.toml)​

# Keep recent state only — smallest disk footprint
pruning = "default"

# Keep everything — required for archive / full historical queries
# pruning = "nothing"
pruningBehaviourUse case
defaultKeeps recent state, prunes the restRPC node, balance/state lookups
nothingKeeps all historical stateArchive node, full history
customOperator-defined keep/interval valuesTuned retention

Transaction indexing (config.toml)​

[tx_index]
indexer = "kv"

Set indexer = "kv" (or a richer indexer) so transactions are queryable by hash and event — essential for exchanges reconciling deposits and withdrawals. Set indexer = "null" only if you do not need historical tx queries.


Exposing Endpoints for Integration​

Enable and bind the API servers integrators need in app.toml:

[api]
enable = true
address = "tcp://0.0.0.0:1317"

[grpc]
enable = true
address = "0.0.0.0:9090"

[json-rpc]
enable = true
address = "0.0.0.0:8545"
ws-address = "0.0.0.0:8546"
api = "eth,net,web3,qor"

And the RPC listener in config.toml:

[rpc]
laddr = "tcp://0.0.0.0:26657"
EndpointPortUse for
RPC26657Broadcasting transactions, querying blocks/status
REST1317HTTP queries of chain state
gRPC9090High-throughput programmatic access
EVM JSON-RPC8545Ethereum-compatible integrations (chain ID 9801)
EVM WS8546EVM event subscriptions
SVM RPC8899Solana-compatible integrations
warning

Never expose RPC, EVM JSON-RPC, or gRPC directly to the public internet without a reverse proxy, rate limiting, authentication, and a firewall. Bind to 0.0.0.0 only behind a controlled ingress layer.


Health and Sync Monitoring​

Sync status​

curl -s localhost:26657/status | jq '.result.sync_info.catching_up'
  • true — still syncing.
  • false — fully synced and serving current state.
# Latest height and network
curl -s localhost:26657/status | jq '.result.sync_info.latest_block_height, .result.node_info.network'

The network field should report qorechain-vladi (mainnet) or qorechain-diana (testnet).

Prometheus and Grafana​

QoreChain exposes Prometheus metrics on port 26660:

http://localhost:26660/metrics

Scrape these with any Prometheus-compatible collector. If you run the Docker Compose monitoring stack, Grafana is available at http://localhost:3001 — set your own credentials on first login. Track block height lag, peer count, and resource usage; alert when catching_up stays true or peer count drops to zero.

EVM endpoint check​

curl -s -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'
# Expect "0x2649" (9801) on mainnet

Operational Best Practices​

  1. Pin the chain version. Run the live tag (v3.1.97 on mainnet) and track official releases for coordinated upgrades.

  2. Run redundant nodes. Operate at least two nodes behind a load balancer so a single restart or resync does not interrupt integration traffic.

  3. Verify genesis and snapshots. Always validate the genesis SHA-256 and any snapshot checksum against the official release before starting.

  4. Protect public endpoints. Front RPC/EVM/gRPC with a reverse proxy, rate limiting, and a firewall. Never expose unauthenticated write RPC to the internet.

  5. Match pruning to need. Use pruning = "nothing" plus tx_index = "kv" for exchanges that reconcile full deposit/withdrawal history; use default for lightweight lookups.

  6. Monitor sync continuously. Alert on block-height lag, zero peers, and a node stuck in catching_up.

For ultra-light read access without running a full node, see the Light Node documentation.


Troubleshooting​

A node halted before the upgrade doesn't resume after a binary swap​

If your node was already halted or stuck before you upgraded its binary, simply dropping in the new binary and restarting is not enough — the node has stale ABCI results cached from the old run and won't re-execute the block that caused the halt. Roll back explicitly before restarting:

qorechaind rollback --home <HOME>
systemctl restart <unit>

The command is qorechaind rollback (a top-level subcommand) — there is no comet rollback subcommand and no --hard flag for it.

Snapshot restore crash-loops on a missing priv_validator_state.json​

A published archive/snapshot does not include data/priv_validator_state.json, and the node refuses to start without it. If it's missing after a snapshot restore, create it — but only if it doesn't already exist. Never overwrite a real one: on a validator this file is the anti-double-signing guard, and clobbering it risks a double-sign.

echo '{"height":"0","round":0,"step":0}' > <HOME>/data/priv_validator_state.json

Next Steps​