Move Solana reads, transaction delivery, and Yellowstone streams between providers with shadow traffic, acceptance gates, and a tested rollback path.
Rrpc edge Team·Jul 22, 2026·12 min read
Frequently asked questions
Can I migrate Solana RPC providers by changing one endpoint URL?
Only if the application uses a narrow set of stateless reads. Production systems should validate method coverage, cluster identity, commitment behavior, transaction delivery, subscriptions, rate limits, and rollback before moving all traffic.
Is getHealth enough to qualify a replacement Solana RPC?
No. Solana defines getHealth in terms of the node's configured slot distance from the cluster tip. Also measure slot freshness, response semantics, latency, errors, stream continuity, and the behavior of your own critical methods.
Should two Solana RPC providers return identical results during shadow testing?
Not for every request. Providers can answer from different slots, especially at processed commitment. Evaluate cluster identity, response shape, context slot, value invariants, and eventual convergence instead of requiring byte-for-byte equality at the live tip.
How should transaction sending be migrated?
Canary transaction delivery separately from reads. Simulate representative transactions, preserve one authoritative submission path per transaction, record the blockhash and last valid block height, and confirm signatures independently before increasing traffic.
What makes a Solana RPC migration reversible?
Keep the old provider configured and warm, make routing changes independently reversible, retain stream cursors and deduplication state, define stop conditions before cutover, and rehearse the rollback command with a production-shaped workload.
Changing a Solana endpoint can take seconds. Proving that the new path preserves application
behavior takes longer.
An application may use the same provider for account reads, blockhashes, transaction simulation,
transaction delivery, WebSocket subscriptions, and Yellowstone gRPC. Those paths do not fail in the
same way. A clean migration separates them and preserves a working return route at every stage.
Start with what the application sends, not a provider feature table.
List every RPC method, commitment level, timeout, retry rule, region, expected response size, and
downstream owner. Add WebSocket subscriptions and gRPC filters. On transaction paths, document
where the blockhash comes from, where simulation runs, which endpoint submits the signed bytes, and
how confirmation is checked.
The inventory should answer these questions:
Reads that block a user action or trading decision.
Cached responses and their retention time.
Requests that rely on minContextSlot.
Transaction errors that are retried, surfaced, or ignored.
Events that can arrive through both polling and streaming.
The durable key that prevents replay from repeating a business action.
The operator who can return each traffic class to the old provider.
Method support is binary. Operational behavior is not. Two providers may both support
getProgramAccounts while applying different limits, timeouts, or response-size controls to the
application's workload.
The replacement endpoint must point at the intended cluster. The
method returns the connected
cluster's genesis hash. Verify it before sending shadow traffic. Record
as environment evidence, not as a quality
score.
Then check liveness and freshness separately. Solana defines
getHealth as healthy when the node is within its
configured slot distance of the cluster tip. That makes it a useful node signal, but not an
application-level acceptance test.
Sample getSlot at the same commitment from the old
endpoint, the candidate, and an independent reference. Keep the timestamp and region with every
sample. The method returns the highest slot reached at the requested commitment, so comparisons only
make sense when commitment and sampling time match.
Do not copy a universal acceptable slot gap from another team. Set the limit from the application's
current baseline, commitment choice, region, and consequence of stale data.
Shadowing sends a copy of real read traffic to the candidate while the old provider remains
authoritative. The candidate response is measured and discarded.
Capture enough context to explain a mismatch:
Field
Why retain it
Method and normalized parameters
Reproduce the request
Commitment and context slot
Distinguish a stale answer from a wrong answer
Status, RPC error, and latency
Separate transport and method failures
Response bytes
Find payload limits and cost drivers
Value fingerprint
Compare large responses without logging private application data
Provider, region, and sample time
Make results attributable
Do not demand byte-for-byte equality at the live tip. Nodes can answer from different slots. Define
method-specific invariants instead:
Cluster identity must match exactly.
Schema and required fields must match the application's parser.
Account owner and executable status should agree at a comparable slot.
Confirmed or finalized state should converge within the team's accepted window.
Errors must be classified consistently enough for the retry policy.
Large production-shaped requests must complete inside their allocated deadline.
Sample both ordinary and difficult traffic. A benchmark made only from getBalance says little
about a workload dominated by large account scans or transaction history.
The getLatestBlockhash method returns a recent
blockhash with its last valid block height. Store both with the transaction attempt. Use
isBlockhashValid when diagnosing whether a
candidate considers that blockhash valid at the selected commitment.
Before submitting real canaries, run representative payloads through
simulateTransaction. Simulation is a
compatibility check, not proof that a later send will land.
With real traffic, keep one authoritative submission decision per signed transaction. The
sendTransaction documentation notes that a
successful RPC response means the node accepted the request, not that the transaction was confirmed.
Record the signature, endpoint, region, blockhash, last valid block height, submission time, RPC
result, and independent confirmation result.
Move the send path in small cohorts. Measure landing and error outcomes for the same transaction
class. Never spray a transaction to multiple providers unless the application has explicitly
designed for duplicate submission and can still attribute the outcome.
A healthy socket can carry stale, incomplete, or misfiltered data. Run the old and candidate streams
at the same time and give each update this envelope:
The transaction signature is its durable base identity. An account update identity should include
the account address, slot, and write version where the service exposes it. Treat source and reconnect
generation as observation metadata, not in the business-event key.
Measure coverage, first-arrival time, duplicate rate, quiet periods, reconnect behavior, and queue
age. The upstream Yellowstone gRPC repository documents
subscription filters and replay from a slot. Provider limits and retention can differ, so validate
the exact production filter against the service you plan to use.
If both streams feed one consumer during the test, deduplicate before side effects. A second
observation may update status or telemetry. It must not repeat an alert, order, webhook, or ledger
entry.
Use independent routing controls for each traffic class. A practical order is:
Internal and non-critical reads.
A bounded share of user-facing reads.
One read-only stream consumer.
Remaining stream consumers by shard.
Transaction simulation.
A bounded cohort of transaction sends.
Full traffic after the observation window passes.
At every step, record the previous routing value and the command that restores it. Leave the old
credentials, quotas, connections, and dashboards live through the rollback window.
Pause the migration when any stop condition fires. Useful stop conditions cover stale slots,
unexpected error classes, missing stream updates, growing consumer queue age, confirmation
regression, or a material cost anomaly. The numerical threshold belongs in the team's acceptance
sheet, not in a generic article.
Cutover is not completion. Continue comparison during a defined observation window. Reconcile
transactions and durable stream state, then confirm that retries, backfills, and scheduled jobs no
longer reference the old endpoint.
Only then remove credentials and capacity. Retain the migration record, baselines, and rollback notes
for the next provider or regional failover exercise.
If you want to qualify RPCEdge with your own method mix, transaction path, and Yellowstone filters,
start with the RPCEdge plans and endpoints, then run this acceptance sheet against both
paths.
if (!response.ok) throw new Error(`${method} returned HTTP ${response.status}`);
const body = (await response.json()) as RpcResult<T>;