Skip to main content

Solana

Solana reads for wallets and apps, without trusting a single RPC node. Every read is sent to three independent Solana RPC operators at finalized commitment, and it is answered only when all three agree. If one is down, behind, rate limiting or says something different, you get an error, never one provider's word.

Endpoint​

POST https://mainnet.subfrost.io/v4/YOUR_API_KEY/solana

The API key is a path segment, or an X-Subfrost-Api-Key header, which takes precedence (see Authentication). It is standard Solana JSON-RPC 2.0, so @solana/web3.js, solana-client and other SDKs work by pointing their RPC URL here:

{ "jsonrpc": "2.0", "id": 1, "method": "getBalance", "params": ["25oyhHXj19hFvtut2Vd9fq3u3E2YJrHwQXoY7vRFpfBb"] }

How an answer is agreed​

The providers are api.mainnet-beta.solana.com (Solana Foundation), solana-rpc.publicnode.com (Allnodes) and solana.leorpc.com (LeoRPC): three operators on three networks.

  • Every read is made at finalized. confirmed and processed are refused, because no two nodes can agree on them.
  • Honest nodes answer finalized a few slots apart. When they differ and the answers came from different slots, the read is repeated at the newest of those slots (minContextSlot) until they agree, up to 3 times. A difference at the same slot is an error at once.
  • context.slot in the answer is the oldest slot any provider read at, so every one of them holds that state.

Agreed answers carry these headers:

headervalue
X-Subfrost-Quorum3/3
X-Subfrost-Quorum-Providersthe three operators
X-Subfrost-Commitmentfinalized
X-Subfrost-Slotthe slot the answer is from
X-Subfrost-History-From-Sloton history reads: the oldest slot every provider holds

Methods​

methodnotes
getAccountInfo, getMultipleAccounts (≤ 100), getBalancethe agreed account (lamports, owner, data, executable, rentEpoch, space)
getSlotthe newest slot every provider has finalized
getLatestBlockhashthe oldest provider's blockhash, confirmed valid at finalized by every provider (isBlockhashValid)
getTransactionreturned only when every provider has it, identical; null when no provider knows it
getSignaturesForAddressthe signatures every provider holds, newest first; page with before
simulateTransactionthe verdict (err) must agree. unitsConsumed is the highest any provider reports (budget for it). logs / accounts / returnData are returned only when identical everywhere, otherwise null.
sendTransactionyour signed transaction, sent to all three; one acceptance returns the signature. A preflight failure is passed back.
getHealthliveness

History is limited to about 6.5 hours​

One of the three providers keeps only the most recent ~58,000 slots (about 6.5 hours). Older transactions and signatures cannot be confirmed by all three, so the endpoint answers quorumMissing, naming the provider and the oldest slot it holds. It never presents a short list as "the end of history". Recent deposits and payments are within the window. Use X-Subfrost-History-From-Slot to see where it starts.

Errors​

{ "jsonrpc": "2.0", "id": 1, "error": { "code": -32051, "message": "quorumMissing: …", "data": { "edge": "quorumMissing" } } }
data.edgecodeHTTPwhat to do
quorumMissing-32051503a provider did not answer, or lacks that history; retry (Retry-After)
quorumRateLimited-32052503retry
quorumPending-32053503not finalized everywhere yet; retry in a few seconds
quorumDisagree-32054500providers disagree; nothing is returned
(invalid params / commitment)-32602400fix the request
(unknown method)-32601400

An error every provider gives alike (an invalid pubkey, say) is returned as their agreed answer.