Skip to content

Solana RPC for validator monitoring

A validator operator's monitoring — the alerting loop, the metrics exporter, the stake dashboard — polls the same handful of cluster-state methods on a timer and never sends a transaction. Two things set it apart from every other workload on this site. You already run a node that answers most of it for free. And that node is the one endpoint sure to be behind right after it restarts, which is when you most want the numbers.


What this workload costs

Modelled on 25% getSlot, 20% getVoteAccounts, 15% getClusterNodes, 15% getEpochInfo, 10% getBalance, 5% getBlockProduction, 5% getLeaderSchedule, 5% getBlock — no writes — computed from the pricing dataset:

Provider Blended $/M At 10M calls/month
dRPC $6.00 $60
Alchemy $6.98 $70
Helius $7.25 $73
OnFinality $7.50 $75
Chainstack $10.00 $100
QuickNode $15.00 $150
Triton One $10.00 + bandwidth $100 + bandwidth — about $290 as measured

No method here is expensive per call, so the spread is narrow: 2.5× from top to bottom, against 7.6× for an indexer. Two details decide the order.

Alchemy has the cheapest standard read on the board at $4.50/M and still comes second, because getSlot and getEpochInfo are two of the methods it bills at 20 CU instead of 10, and they are 40% of this mix. Helius pays for the one call in twenty that is a getBlock: at 10 credits, that 5% of traffic is $2.50 of its $7.25.

Chainstack's getBlock is priced at 1 RU. Monitoring reads blocks at the tip, where its archive multiplier does not apply. Rates verified 2026-09-06 against each provider's published pricing; overage/pay-as-you-go basis. See price per method for the weights.

Three calls carry all the bytes

Per-call pricing hides what is unusual about this mix: it is the heaviest on this site by payload. Measured on mainnet on 2026-11-12 against api.mainnet-beta.solana.com, in an epoch with 698 vote accounts, 3,859 gossip nodes and 648 leaders:

Method Share Uncompressed On the wire (gzip)
getLeaderSchedule 5% 2.94 MB 2.95 MB
getClusterNodes 15% 1.47 MB 379 KB
getVoteAccounts 20% 314 KB 148 KB
getBlockProduction 5% 35 KB 31 KB
The other four 55% under 400 bytes each

The leader schedule arrived gzip-encoded and no smaller. gzip -6 takes the same body to 1.08 MB, so how far it is compressed is the provider's choice. getBlock is in the last row because monitoring asks for it with transactionDetails: "none", to read a leader's rewards. A full block was 3 to 5 MB.

Averaged over the mix that is 235 KB a call on the wire, where a getAccountInfo reply is about 0.5 KB. It matters in two places.

Triton One bills it. Triton charges $0.08/GB of response bandwidth on top of $10/M calls. At 235 KB a call, a million calls is 235 GB, or $18.83. Bandwidth costs nearly twice what the calls do, and the total is about $28.83/M: last in the table above, well behind QuickNode. getLeaderSchedule alone is 63% of those bytes. These figures use the sizes the public endpoint served, because we have not measured Triton's own compression. With the leader schedule compressed as far as gzip takes it the total is about $21/M, and with nothing compressed about $45/M. RPC Plane asks every provider for compressed responses.

Your client can avoid most of it. Both fixes are in the client. RPC Plane does not cache responses; it forwards every call you send.

  • Ask for one validator. getLeaderSchedule with an identity filter returned 114 KB for the busiest leader on mainnet, and less for anyone else. getBlockProduction with identity returned 223 bytes, and getVoteAccounts with votePubkey 526 bytes.
  • Fetch the schedule once per epoch. The leader schedule is fixed for the epoch, and an epoch is 432,000 slots, which is a day at 200 ms. getEpochSchedule never changes at all.

Your own node is the cheapest provider, and it is behind after a restart

A node you run answers this mix for nothing. How much of it depends on how the node is started:

  • A validator's own RPC port serves Agave's minimal set unless it runs with --full-rpc-api. From this mix that is getSlot, getVoteAccounts, getEpochInfo, getBalance and getLeaderSchedule: 75% of the calls. getClusterNodes, getBlockProduction and getBlock are outside it.
  • An RPC node beside it, or a validator with --full-rpc-api, serves all of it. getBlock also needs --enable-rpc-transaction-history, and reaches only as far back as the ledger the node keeps.

The minimal case needs one more setting. A node asked for a method it does not serve answers "method not found", which RPC Plane treats as the caller's mistake and returns without trying anyone else. List what the node serves in methods and every other method routes to the fallback. Then a quarter of this mix is the fallback's every month. At 10M calls that is 2.5M: $15 on dRPC, or $35 on Helius, where the getBlock share is most of it.

So the provider question here is mostly "which fallback", and the failure to design for is not the node going down. It is the node coming back. A validator restarts for every upgrade. When its RPC port returns it is still replaying: thousands of slots behind the cluster, and answering HTTP 200 the whole time. At 200 ms slots a 30-minute catch-up starts 9,000 slots back. Monitoring that reads through that node reports the cluster as it stood at the slot the node has reached, with no error to say so.

failover_ordered keeps reading from it

failover_ordered is the usual answer for a free primary with a paid backup, and it has a gap here. It leaves the first provider only when that provider's circuit opens, and a circuit opens on failures. A node that is behind does not fail. Slot drift lowers a provider's score, and failover_ordered does not read scores.

best_score does. With slot freshness weighted above latency, the node keeps the reads while it is near the tip and loses them when it falls behind. We ran v0.14.0 against a simulated node and a fallback 50 ms away on 2026-11-12, with the config below:

Node behind by Reads that reached the node
0 to 15 slots 200 of 200
20 slots (4 s) 2 of 200
150 slots (30 s) 1 of 200
9,000 slots (30 min) 3 of 800
Back at the tip 200 of 200

Under failover_ordered the node kept 20 of 20 reads at 9,000 slots behind.

Two things to know about the best_score result:

  • A few reads still reach the node. Each probe round compares providers against the highest slot reported in that round. Until the fallback's probe answers, the node's slot is the only one in, so for that moment it counts as the tip. The share is roughly the fallback's latency divided by interval_ms: about 1% here, and 6% in the same test with a fallback 300 ms away.
  • The node has to be the closest endpoint. Latency is what makes best_score prefer the node while both are at the tip. Run the proxy on the same host or network as the node. A node further away than the fallback loses the reads to it.

What the fallback costs when nothing is wrong

The health probe is two getSlot calls per provider per second by default. It is billed like any other call and sent whether or not there is traffic. On a fallback that serves nothing on a normal day, the probe is the bill:

Probe setting Calls per 30 days Helius dRPC Alchemy QuickNode
Default: every 1 s, processed and finalized 5.18M $25.92 $31.10 $46.66 $77.76
Every 5 s, both commitments 1.04M $5.18 $6.22 $9.33 $15.55
Every 5 s, processed only 518K $2.59 $3.11 $4.67 $7.78

Set that against the traffic. A node that is down or behind for 1% of the month, about seven hours, sends 100,000 calls of a 10M-call workload to the fallback. That costs $0.60 to $1.50.

At 5 s and processed only, the fallback for a full-API node can be a free-tier key. 518K probes plus that traffic fit inside Helius's free 1M credits a month, and use about 40% of Alchemy's free 30M CU. At the default rate they do not: 5.18M calls spends Helius's allowance in under six days. See free-tier maxxing for each provider's limits.

A 5-second round is enough for this workload. A node that falls behind is noticed within one round. A node that fails is noticed at once, because live requests feed the circuit breaker as well as probes. finalized has trailed processed by about a slot since Alpenglow, so probing it tells you little that processed does not when the question is whether your node has caught up.

Config

[health]
interval_ms          = 5000            # one probe round every 5 s
probe_commitments    = ["processed"]   # one getSlot per provider per round
slot_drift_threshold = 150             # 30 s at 200 ms slots
w_slot               = 0.4             # above latency: a stale node loses
w_latency            = 0.2             # above zero: the local node wins ties

[routing]
strategy = "best_score"

# Your own node: the validator's private RPC port, or an RPC node beside it.
[[providers]]
name    = "own-node"
url     = "http://127.0.0.1:8899"
history = "recent"    # a getBlock it cannot serve fails over
# Without --full-rpc-api: list the minimal set, the rest goes to the fallback.
# methods = [
#   "getSlot", "getVoteAccounts", "getEpochInfo", "getBalance",
#   "getLeaderSchedule", "getTransactionCount", "getBlockHeight",
#   "getHealth", "getVersion", "getIdentity", "getGenesisHash",
#   "getHighestSnapshotSlot", "getAccountInfo", "getMultipleAccounts",
# ]

# The fallback: takes the reads while the node is down or behind.
[[providers]]
name = "helius"
url  = "https://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}"

The defaults are w_slot = 0.2 and w_latency = 0.4. slot_drift_threshold is where the slot score halves, so it sets how far behind the node may be before it gives up the reads. At 150 the handover came between 15 and 20 slots with a fallback 50 ms away. A slower fallback moves it later: at 300 ms the node kept the reads 60 slots behind and had lost them by 100. By 150 slots the node has lost them whatever the fallback's latency. The default of 10 with these weights hands over at two slots, a gap two healthy providers show all the time.

Keep getSlot in any methods list. A provider that cannot answer it is not probed, and an unprobed node has no slot to measure drift from. If the fallback's own probes fail, the node is the only slot reading left and counts as the tip; an external slot reference gives it a third opinion.

Where splitting by method does not pay

The per-method cheapest provider for this mix:

Method Share Cheapest $/M
getSlot 25% Helius $5.00
getVoteAccounts 20% Alchemy $4.50
getClusterNodes 15% Alchemy $4.50
getEpochInfo 15% Helius $5.00
getBalance 10% Alchemy $4.50
getBlockProduction 5% Alchemy $4.50
getLeaderSchedule 5% Alchemy $4.50
getBlock 5% dRPC $6.00

Perfect method-splitting comes to $4.78/M, which is 20.4% under dRPC alone. At 10M calls a month that is $60 → $48. Twelve dollars does not pay for two more vendor relationships, and your own node undercuts all three.

RPC Plane does not route by cost

It routes by health, score, config order or weight — never by price. Any cost split is one you encode yourself. Cost-aware routing is on hold and the binary carries no pricing table.