Skip to content

Rate Limits and Performance

The knobs that decide how much work one client can ask a node for, and how much of that work the node has to redo. Most matter only on a node serving wallets it does not own.

Daemon RPC controls

Primary knobs (daemon config/CLI):

  • rpc-max-rpm: per-IP request cap (0 disables).
  • rpc-max-body-bytes: max request body bytes.
  • rpc-max-global-index-range: cap for /get_global_indexes_for_range.
  • rpc-max-block-count: cap for block sync/raw block methods.
  • rpc-sync-cache-size: megabytes of finished wallet sync responses to keep (0 disables).
  • rpc-read-timeout and rpc-write-timeout.
  • db-read-buffer-size: the database read cache. An eighth of it is used as a row cache, which answers repeated point lookups without touching a data block.

Response compression

Whether the daemon compresses its responses is decided when it is built, not configured: cmake looks for zlib and only enables it if it is there. Without it, every syncing wallet pulls several times as many bytes. Check it with:

curl -s "$DAEMON_RPC_URL/info" | grep -o '"compression":"[^"]*"'

"none" means the build found no zlib. Install the zlib development package (zlib1g-dev on Debian/Ubuntu, zlib-devel on Fedora/RHEL) and rebuild. The daemon also prints a warning on startup when it is missing.

Serving many wallets

rpc-sync-cache-size (default 64 MB) keeps finished /getwalletsyncdata bodies around. Wallets syncing past the same height ask for the same range, so without it a node rebuilds the identical answer once per wallet: thousands of database reads, a full reassembly, and the encoding of the result, every time.

Only ranges well below the chain tip are cached, so a reorganisation cannot make a cached body wrong; the cache is dropped outright if the tip ever moves backwards. Raise it on a public node serving many wallets, or set it to 0 on a node that only serves one.

  • rpc-max-rpm: 240 for public-but-controlled access, higher for private LAN.
  • rpc-max-body-bytes: keep low, raise only for real payload needs.
  • rpc-max-global-index-range: keep default unless client genuinely needs larger windows.
  • rpc-max-block-count: keep conservative; paginate client requests instead.

Client-side performance patterns

  • Prefer incremental sync calls over very large batch requests.
  • Use checkpoint-based sync (blockHashCheckpoints) for wallet sync.
  • Implement retry with backoff on 429.
  • Read sync_features from /info once and use the optional sync fields the daemon advertises — skipEmptyBlocks, encoding: "base64" and endHeight — rather than sending them blind. See HTTP Endpoints.

Example: pagination instead of huge blockCount

for h in 0 100 200 300; do
  curl -s -H "Content-Type: application/json" \
    -d "{\"startHeight\":$h,\"startTimestamp\":0,\"blockCount\":100,\"blockHashCheckpoints\":[],\"skipCoinbaseTransactions\":false}" \
    "$DAEMON_RPC_URL/getwalletsyncdata" > /dev/null
done

Example: observe throttling quickly

for i in $(seq 1 500); do
  curl -s -o /dev/null -w "%{http_code}\n" "$DAEMON_RPC_URL/info"
done | sort | uniq -c

Wallet API tuning notes

  • --threads affects wallet sync worker count.
  • Higher thread counts can improve sync but increase CPU and memory pressure.
  • Keep daemon and wallet API near each other (low RTT) for best sync behavior.