Snowblossom Docs
Docs › Running software › Node

Node

SnowBlossomNode is the full node: it maintains peer links, downloads and validates every block of the shards it follows, keeps the UTXO trie and the optional indexes, and answers wallets, miners, pools and explorers over gRPC. It holds no funds - only identity keys for TLS and the trust network - so it can safely live on a different machine than the wallet.

Configuration reference

Keys read by the node (all overridable with snowblossom_<key> environment variables, see Configuration):

KeyDefaultMeaning
networksnowblossomNetwork to join (list).
db_typerequiredrocksdb (recommended, 64-bit only), lobstack (pure Java, for 32-bit JVMs; no mutation sets) or atomic_file (one file per key; fine for MrPlow, unsuitable for a node).
db_pathrequiredDatabase directory, created if missing.
db_separatefalseRocksDB: one instance per map instead of one shared DB. Loses cross-map write ordering on crash; not recommended.
service_portnonePlaintext gRPC port(s), comma-separated. Convention 2338 / 2339 / 2340. If unset no plaintext port is opened.
tls_service_portnoneTLS gRPC port(s); requires tls_key_path. Convention 2348 / 2349 / 2350.
tls_key_pathDirectory holding the node's one-key identity wallet; created with a fresh key if missing, address written to address.txt (node:…).
trustnet_key_pathDirectory for the trust-network signing key (signs tips and the node's own peer record). Optional; auto-created.
trustnet_signersComma list of node:… addresses whose signed tips this node trusts for shards it does not validate itself (trust network).
shards0 and all belowShard ids to follow; the interest set is their cover sets plus all ancestors. Default follows the whole network.
addr_indexfalseIndex address → transactions (needed for GetAddressHistory, wallets' history, seed recovery, explorers). Not retroactive: enable before the first sync or resync.
tx_indexfalseStore every transaction and a tx → block index (needed for GetTransaction / GetTransactionStatus). Same retroactivity caveat.
peer_count8Target number of open peer links.
interest_peer_count4Target links per shard in the interest set.
trust_peer_count4Target links to trusted-signer peers per other shard.
seed_urisExtra peers to try at start (grpc://host:port, grpc+tls://host:port), merged with the built-in DNS seeds.
peer_logPath; on start the persisted peer list is dumped there, one PeerInfo per line.
bypass_sync_checkfalseServe block templates even when not synced (private networks).
mempool_reject_p2p_txfalseAccept transactions only from local SubmitTransaction, not from peers.
log_config_filejava.util.logging properties (logging).
metric_logPath for structured per-operation metrics (duckutil MetricLogger).
profiler_log, profiler_period- / 20000Append timing reports every period ms.

Example: public mainnet node with indexes

network=snowblossom
log_config_file=configs/logging.properties
db_type=rocksdb
db_path=node_db/mainnet
addr_index=true
tx_index=true
service_port=2338
tls_service_port=2348
tls_key_path=node_db/tls_mainnet
trustnet_key_path=node_db/trustnet

Requirements

  • 64-bit JVM, Java 17+ recommended. The Bazel target pins -Xms4g -Xmx4g; when running the jar yourself use at least -Xmx4g. RocksDB uses native memory on top, so plan 6–8 GB for the node.
  • Disk: an indexed mainnet database is ~100 GB (2026) and grows with the chain; nothing is pruned. SSD strongly recommended - validation, the UTXO trie and address-history lookups are random-access heavy. The one-time summary rebuild of the 2.0 upgrade needed extra space until compaction ran.
  • Network: inbound on the service ports for other peers (optional but good for the network), outbound to peers, DNS seeds, ipv4-lookup.snowblossom.org/ipv6-lookup.snowblossom.org (own IP discovery) and timecheck.snowblossom.org (clock check).
  • Clock: NTP. Blocks more than 45 s in the future are rejected; a warning is logged when the clock is off by more than 5 s.

Start-up and what happens inside

  1. Registers BouncyCastle, loads the config, requires db_type, logs “Starting SnowBlossomNode version …”.
  2. Loads network parameters and the shard interest set (“Shard interest set: […]”).
  3. Opens the database - a shutdown hook flushes RocksDB cleanly (“RocksDB flush started/completed”), so stop the node with SIGTERM, not SIGKILL, and give it time.
  4. Loads the peerage (persisted peer list + seeds), transaction broadcaster, forge, UTXO importer, mempools and maintenance thread.
  5. Opens a BlockIngestor per shard with a stored head (“Loaded chain tip: shard 0 height …”), recomputing summaries if their version is old (“Reindexing …”).
  6. Binds the ports (“Ports: [2338] [2348]”), tries UPnP, starts the gRPC services.
  7. Starts peering, the clock watcher and the broadcaster; then “SnowBlossomNode started”.

Threads

ThreadPeriodJob
PeerageMaintThread12 sPrune dead links, connect to new peers, send tips for up to 16 shards, re-learn seeds hourly, save peer list every 60 s.
TxBroadcaster2 tx/s, burst 5 sRelays accepted transactions to all links (queue 2,500).
MemPool Tickler / TicklerBroadcast300 s / 5 sRebuild priorities after a new head; re-gossip one random pool transaction.
SnowUserService Tickleron new block, ≤ 30 sPush block templates to subscribed miners; send address updates to subscribers.
ShardBlockForge ConceptUpdateThread15 sRecompute candidate next blocks; idles after 5 min without template requests.
DBMaintThreadcheck every 60 sRuns a full RocksDB compaction every 2,160–4,320 blocks (15–30 days, randomised); logs “Running db maint” / “Compaction run in N seconds”.
TimeWatcher300 sClock check against timecheck.snowblossom.org.

Database layout

All maps share one RocksDB with prefixed keys:

MapContent
blockfull blocks by hash
blocksummaryBlockSummary per block; keys head / head-<shard> hold the current tips
txtransactions by id (with tx_index)
uUTXO hashed-trie nodes (all historical states)
citchain-index trie: a2tx address history, tx2b tx → block, fbo2/id2o indexes
height(shard, height) → block hash
bh, ib, xshm, trustheaders learned from peers, cached imported blocks, external shard heads, trusted block hashes (sharding)
bbm, cbmsbest work at (shard, height); parent → children set (forge)
specialpeerlist, node_id, db_maint_height

Because the summary is written last, after the block, its transactions and the UTXO nodes, a crash can at worst leave orphaned nodes, never a half-applied block.

Monitoring sync and health

  • Log lines: “Got first tip from a remote peer”, “Requesting block: …”, “New block: Shard 0 Height H … (tx:N sz:B)”, “New chain tip: Shard 0 Height H hash” followed by “The activated field is 9 (hippo). This block was age ago” - the age tells you how far behind you are.
  • SnowBlossomClient client.conf nodestatus prints the NodeStatus JSON: head height per shard, connected_peers (should approach peer_count), estimated_nodes, mem_pool_size, peer version histogram. Compare the height with the explorer.
  • Miners and pools get “We are not yet synced, refusing to send block template” until the node is within 10 blocks of the best header it has seen.
  • Peers on the wrong network are dropped silently (visible at FINE level: “Peer has wrong name”).

Deployment

systemd

[Unit]
Description=Snowblossom node
After=network.target

[Service]
User=snowblossom
WorkingDirectory=/var/snowblossom
ExecStart=/usr/bin/java -Xmx4g -jar /var/snowblossom/SnowBlossomNode_deploy.jar configs/node.conf
Restart=on-failure
TimeoutStopSec=120

[Install]
WantedBy=multi-user.target

(example/systemd/ in the repository has the original units; they run a node.sh wrapper and have no Restart=.) Logs: journalctl -u snowblossom-node -f plus the rotating files in logs/.

Docker

docker run -d --restart always --name snowblossom.node --network host \
  -v snownode:/data \
  -e snowblossom_addr_index=true -e snowblossom_tx_index=true \
  snowblossom/node:latest
docker logs -f snowblossom.node
docker container stop -t 90 snowblossom.node      # let RocksDB flush

Testnet: add -e snowblossom_network=testnet -e snowblossom_service_port=2339 -e snowblossom_tls_service_port=2349. The images keep everything under /data; SNOWBLOSSOM_JAVA_OPTIONS passes JVM flags.

Reverse proxies and firewalls

Expose 2338/2348 directly. The seed operators also listen on 80/443 for users behind restrictive firewalls; that works because gRPC over HTTP/2 is just TCP - but a proxy that terminates TLS with its own certificate breaks the identity check for grpc+tls:// clients. Web explorers run on their own HTTP port and are the thing to put behind Apache or nginx.

Upgrading

  • Stop the node cleanly, replace the jar, start. The database format has been stable since 1.6; summaries with an old summary_version are recomputed at start automatically.
  • 2.0.0 rebuilt the summary table on first start (up to an hour, heavy IO, temporary extra disk until compaction). Nodes had to be upgraded by block 211,600 (May 2022).
  • 2.2.0 added the post-quantum signatures (mandatory by block 358,700, March 2025), trust-network signed peer info, GetPeerList, TLS for pool miners.
  • Turning on addr_index/tx_index later means deleting db_path and resyncing.
  • Older milestones: 1.6.0 moved the indexes into the hashed trie (minutes of reindexing); 1.0.8 changed the default DB location; 1.7.0 changed the template protocol so MrPlow needs a node ≥ 1.7.

Troubleshooting

SymptomCause / fix
“rocksdb does not work with 32-bit jvm”Install a 64-bit Java, or use db_type=lobstack (slower, no TLS).
“Missing required key: …”Add db_type, db_path or tls_key_path (when a TLS port is set).
“FAILED TO INITIALIZE LOGGING”Create the logs/ directory named in the logging properties.
“Block too far into future”Your clock is wrong; fix NTP.
“Local clock seems to be off by N ms”Same - more than 5 s drift.
Port mapped to another host (UPnP warning)Another machine on the LAN already mapped the port; configure the router manually or change service_port.
No peers / stuck syncCheck outbound connectivity and DNS; add seed_uris=grpc+tls://snow-a.1209k.com; make sure network= matches.
Miner says “not yet synced”Wait for the head to come within 10 blocks of the network; on a private network set bypass_sync_check=true.
Wallet history empty / “node does not support address history”The node lacks addr_index; enable it and resync, or use a public node that has it.
GetPeerList hangs (blocking clients)Released node versions up to 2.2.0 never complete that RPC (SnowUserService.getPeerList lacks ob.onCompleted()); call it with a deadline or an async stub, or apply the one-line fix to your node.
JVM crash in librocksdbjniSeen with old JDK 11 builds; use Java 17+ and a restart loop / Restart=on-failure.