<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: OrbitFlare RPC</title>
    <description>The latest articles on DEV Community by OrbitFlare RPC (@orbitflarerpc).</description>
    <link>https://dev.to/orbitflarerpc</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3813769%2F9f10e588-ac4d-43c5-9207-b2c4b7b0a835.png</url>
      <title>DEV Community: OrbitFlare RPC</title>
      <link>https://dev.to/orbitflarerpc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/orbitflarerpc"/>
    <language>en</language>
    <item>
      <title>Solana RPC for AI Agents: MCP, Tools and Guardrails</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Thu, 17 Sep 2026 12:07:34 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/solana-rpc-for-ai-agents-mcp-tools-and-guardrails-m1a</link>
      <guid>https://dev.to/orbitflarerpc/solana-rpc-for-ai-agents-mcp-tools-and-guardrails-m1a</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0crzkf2fzozw6fpc1brf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0crzkf2fzozw6fpc1brf.png" alt="Cover Image" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An AI agent acting on Solana requires exactly the same components a trading bot requires, arranged in a way safe for the language model to use: a read path to current chain state, a write path to land transactions, and guardrails that bound the agent's spending and signature power. In 2026, this means an MCP (Model Context Protocol) server and tools wrapping the provider's RPC, gRPC, and transaction-landing endpoints, keeping keys and limits on the server side. Here we cover what exactly an agent needs from Solana infrastructure, how to expose it via MCP and tools, latency and cost issues, and guardrails that prevent an autonomous agent from turning into a costly incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  What an AI agent needs from Solana infrastructure
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcbo2z9h76vb0sgfctu32.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcbo2z9h76vb0sgfctu32.png" alt="AI Agent Needs Table" width="800" height="774"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The column on the right is the relevant one. A model can reason well on structured results and terribly on raw account bytes, and must never be able to construct a transaction from a raw RPC endpoint. Each capability is a tool, and the schema is where the guardrails live.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP: the standard interface
&lt;/h2&gt;

&lt;p&gt;MCP allows a model to discover and invoke tools provided by a server via a standard protocol. In case of Solana, an MCP server wraps a provider's endpoints and exposes various tools, including &lt;code&gt;get_account&lt;/code&gt;, &lt;code&gt;get_token_balances&lt;/code&gt;, &lt;code&gt;simulate_swap&lt;/code&gt;, &lt;code&gt;send_transaction&lt;/code&gt; and others, each with typed inputs and outputs.&lt;/p&gt;

&lt;p&gt;OrbitFlare provides an MCP server and agent tooling for its endpoints; &lt;a href="https://docs.orbitflare.com/agents/overview" rel="noopener noreferrer"&gt;docs.orbitflare.com/agents&lt;/a&gt; describes the installation procedure and the available tools, including the CLI and SDK versions. The principles described below are applicable whether you use that server or implement your own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep credentials on the server side.&lt;/strong&gt; The MCP server stores the RPC key and, in case the agent is allowed to sign, the signing key or delegated signer. The model sees the tool names and results, but never the secrets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make reads broad and sends narrow.&lt;/strong&gt; Expose many read tools with generous limits and one or two send tools with strict policy. The agent should be able to explore anything freely and only able to act through a gate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Return structured and decoded data.&lt;/strong&gt; Decode token accounts, pool reserves and transaction metadata on the server side. Passing raw base64-encoded strings as the tool result wastes the context and is prone to misunderstandings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Guardrails that belong to the tool layer
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmpvu1te06cdtf73lwjlk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmpvu1te06cdtf73lwjlk.png" alt="Guardrails Table" width="800" height="714"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A prompt is not a guardrail. You can talk the model out of following the prompt instruction; but you cannot do that when the limit or cap is enforced on the server side in the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Latency: slower than a bot, but not optional
&lt;/h2&gt;

&lt;p&gt;An agent's workflow consists of observe, reason, act stages, with the reason step requiring hundreds of milliseconds to several seconds. This is much slower than a trading bot, leading some teams to think that the latency issue can be completely ignored here. But it cannot, because of the following reasons.&lt;/p&gt;

&lt;p&gt;First, outdated observation gets amplified by the long reasoning time: an agent reading a pool price, thinking for three seconds and acting upon it acts based on the price several slots old. Provide the agent with a fresh read immediately prior to sending, with a simulation returning an error in case the state moved.&lt;/p&gt;

&lt;p&gt;Second, an event-driven agent requires prompt wake-up. An agent reacting to a wallet movement or a governance proposal should be triggered by a subscription (Yellowstone gRPC or WebSockets), not a polling by a timer.&lt;/p&gt;

&lt;p&gt;For agents doing trading, the execution path is the same as for bots: a staked submission lane to avoid dropping the transaction under the load.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost: agents are very chatty
&lt;/h2&gt;

&lt;p&gt;A model exploring the problem can invoke a dozen of read tools per step. When multiplied by steps and number of agents, it will consume the entire request budget. There are three ways to handle it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cache on the server side.&lt;/strong&gt; Account reads that were not changed since the last slot require no additional RPC calls; and a Yellowstone subscription keeps the cache hot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch in the tool.&lt;/strong&gt; A &lt;code&gt;get_token_balances&lt;/code&gt; tool should do a single &lt;code&gt;getMultipleAccounts&lt;/code&gt; call, not a separate one per account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prefer a pricing model that does not weight methods.&lt;/strong&gt; Agents call expensive methods (&lt;code&gt;getProgramAccounts&lt;/code&gt;, history) freely; while credit-based pricing penalizes that.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A reference setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Provider endpoints:&lt;/strong&gt; a keyed RPC URL, a Yellowstone gRPC endpoint, and a staked send path, all in the region close to your agent's host.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP server&lt;/strong&gt; with stored credentials, exposing decoded read tools, a simulation tool, triggers for subscriptions and a policy-gated send tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent runtime&lt;/strong&gt; (any model with tool invocation) with the MCP server, a limited signing key and the kill switch checked on every send.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability:&lt;/strong&gt; every tool invocation logged with input parameters, result, latency and cost, so you can trace what the agent did and why.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluation:&lt;/strong&gt; re-run recorded tool invocations trace against new prompts or models.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Solana infrastructure for AI agents is exactly the same read, write and guardrails stack as a bot, provided as typed tools via MCP with credentials and policy on the server side. Give the agent broad, decoded and cached reads; mandatory simulation step; and a narrow, limited, allowlisted send path with a kill switch. Trigger it by subscriptions rather than timers, and price for the chatty access.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.orbitflare.com/agents/overview" rel="noopener noreferrer"&gt;Documentation of OrbitFlare's agents&lt;/a&gt; has the MCP server and SDK. The &lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;RPC plans&lt;/a&gt; and &lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;gRPC service&lt;/a&gt; are the provider endpoints behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.orbitflare.com/agents/overview" rel="noopener noreferrer"&gt;OrbitFlare agents documentation: MCP server, CLI and SDK&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/docs/rpc/http/simulatetransaction" rel="noopener noreferrer"&gt;simulateTransaction RPC method (Solana docs)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/rpcpool/yellowstone-grpc" rel="noopener noreferrer"&gt;Yellowstone gRPC (GitHub)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;Jetstream and Yellowstone gRPC streaming (OrbitFlare)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;OrbitFlare RPC plans&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>solana</category>
      <category>orbitflare</category>
      <category>ai</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Solana WebSockets vs gRPC: When to Switch and How</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Wed, 16 Sep 2026 12:33:23 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/solana-websockets-vs-grpc-when-to-switch-and-how-47kg</link>
      <guid>https://dev.to/orbitflarerpc/solana-websockets-vs-grpc-when-to-switch-and-how-47kg</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz1acx6q4ohknb4h7mf6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz1acx6q4ohknb4h7mf6g.png" alt="Cover Image" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Both WebSocket and gRPC are meant to push Solana updates to the application without the need for client-side polling; for some types of dashboard subscriptions, the two can be used interchangeably. Differences arise when working on a larger scale: WebSocket subscriptions happen on the RPC layer after the block processing, transfer JSON, and become hard to maintain past several dozen subscriptions. On the other hand, Geyser gRPC is integrated into the node process, transfers binary data, applies server-side filters, and works well with thousands of accounts on a single stream. The suggested way to migrate is from WebSockets to gRPC as soon as the subscription count, message rate, or latency become a problem, whereas WebSockets continue to be used in simple scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operational mechanisms
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;WebSocket&lt;/strong&gt; is a subscription part of the Solana JSON-RPC API. A WebSocket Secure (WSS) connection is established with an RPC node, subscribe requests are performed, and the node starts pushing notifications in JSON format when matching events reach the chosen commitment level. The events themselves are collected by the node in its internal block processing, and the RPC service then formats and sends them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Geyser gRPC&lt;/strong&gt; is a plugin running inside the node process. It receives every account write, transaction, slot, and block, processed by the node, and streams the subset of it that satisfies the user-defined filters using a gRPC connection based on Protocol Buffers. No intermediary RPC layer is involved here, and no JSON is used. Yellowstone is the default plugin, and you can find details about the subscription model of Yellowstone gRPC in &lt;a href="https://github.com/rpcpool/yellowstone-grpc" rel="noopener noreferrer"&gt;its documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparative overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1li1s8d9ionbkd3q3k13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1li1s8d9ionbkd3q3k13.png" alt="Websocket vs gRPC Table" width="800" height="907"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Use cases for WebSockets
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transaction confirmation:&lt;/strong&gt; the &lt;code&gt;signatureSubscribe&lt;/code&gt; functionality provides a simple tool to track a transaction until it reaches the desired commitment level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple dashboards:&lt;/strong&gt; keeping track of just a few accounts and the balances and logs of some programs using WebSocket capabilities is quite easy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notifications where some latency is not a concern:&lt;/strong&gt; notifications where some hundred milliseconds delay is acceptable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client simplicity:&lt;/strong&gt; wide library support with almost no dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use cases for gRPC
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mass account watching:&lt;/strong&gt; keeping track of hundreds of wallets or all accounts belonging to a certain program with gRPC subscriptions is much easier than with WebSockets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High message rate:&lt;/strong&gt; the high message rate becomes a performance bottleneck for JSON serialization and per-subscription overhead on WebSockets; gRPC can handle the high throughput of streams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency-sensitive logic:&lt;/strong&gt; apps like trading, liquidation, and copy-trading bots require earlier visibility and server-side filters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive transaction metadata at scale:&lt;/strong&gt; Yellowstone transaction updates contain inner instructions, balance changes, and logs; the information vital for indexing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a third option for workloads where a single event is being watched that comes before both WebSockets and gRPC ones: shred-based streams like &lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;Jetstream&lt;/a&gt; where the transactions reconstructed from the leader broadcasts prior to node processing of the blocks are sent. The &lt;a href="https://orbitflare.com/blog/fundamentals/shredstream" rel="noopener noreferrer"&gt;Shredstream architecture&lt;/a&gt; explains why it works in advance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration from WebSockets to gRPC
&lt;/h2&gt;

&lt;p&gt;The transition doesn't have to be a full-scale thing done at once. The steps can be the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Measure your baseline metrics:&lt;/strong&gt; number of subscriptions, message rate, and latency between the slot of the event and the processing of it by the app. It will show what subscriptions to migrate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migrating the largest subscription first:&lt;/strong&gt; it usually involves the &lt;code&gt;programSubscribe&lt;/code&gt; or many &lt;code&gt;accountSubscribe&lt;/code&gt; requests. Replace them with one gRPC accounts filter scoped to the program owner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migrating the latency-sensitive subscription next:&lt;/strong&gt; the subscription that drives the bot's logic. Replace it with gRPC transactions or accounts filter at the &lt;code&gt;processed&lt;/code&gt; or &lt;code&gt;confirmed&lt;/code&gt; commitment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keeping the simple subscriptions on WebSockets until you have reasons to migrate them:&lt;/strong&gt; for instance, &lt;code&gt;signatureSubscribe&lt;/code&gt; for your own transactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handling reconnections and possible gaps.&lt;/strong&gt; gRPC streams are prone to disconnections; perform idempotent resubscriptions and check the state of the stream against the chain after a long pause.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Opening a WebSocket for every account.&lt;/strong&gt; Better to multiplex the subscriptions on one connection or, even better, migrate them to gRPC.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client-side filtering on gRPC:&lt;/strong&gt; subscribe widely and filter locally, thus consuming extra bandwidth and latency. Use the filters in the subscription request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using &lt;code&gt;processed&lt;/code&gt; commitment without considering rollbacks:&lt;/strong&gt; the earliest commitment on either transport is reversible; use &lt;code&gt;confirmed&lt;/code&gt; ones unless you can handle the reversion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polling and subscribing to the same thing simultaneously:&lt;/strong&gt; if you have a subscription, stop polling the same data, as it wastes the request bandwidth and is slower.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignoring slot gaps:&lt;/strong&gt; keep track of the slot corresponding to each message; the growing difference between the message slots and the current slot shows that the consumer is falling behind.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cost aspects
&lt;/h2&gt;

&lt;p&gt;WebSocket is included in most plans, even free tiers, because the node processes each event only once irrespective of the subscriber count. gRPC is usually a higher tier or a separate product because it transfers much more data per client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Both WebSocket and gRPC transfer Solana updates; the differences are in the node interface, data serialization, filters, and scalability capabilities. WebSockets are to be used in simple, small-scale, and latency-tolerant subscriptions, as well as for confirming one's transactions. Geyser gRPC should be used for multi-account watching, high message rate, latency-sensitive logic, and the shred stream in case you need an early event visibility prior to the node block processing. The transition should be gradual with the prioritization of subscriptions depending on the workload.&lt;/p&gt;

&lt;p&gt;OrbitFlare provides WebSocket on all plans and Yellowstone and Jetstream gRPC across all eleven regions. You can find more details on the &lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;gRPC page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/docs/rpc/websocket" rel="noopener noreferrer"&gt;Solana WebSocket RPC methods (Solana docs)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.anza.xyz/validator/geyser" rel="noopener noreferrer"&gt;Geyser plugins (Anza docs)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/rpcpool/yellowstone-grpc" rel="noopener noreferrer"&gt;Yellowstone gRPC (GitHub)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/blog/fundamentals/shredstream" rel="noopener noreferrer"&gt;Shredstream explained (OrbitFlare)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;Jetstream and Yellowstone gRPC streaming (OrbitFlare)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;OrbitFlare RPC plans&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>solana</category>
      <category>websocket</category>
      <category>grpc</category>
      <category>orbitflare</category>
    </item>
    <item>
      <title>getProgramAccounts Alternatives: Stop Scanning, Start Streaming</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Tue, 15 Sep 2026 12:51:08 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/getprogramaccounts-alternatives-stop-scanning-start-streaming-2k2h</link>
      <guid>https://dev.to/orbitflarerpc/getprogramaccounts-alternatives-stop-scanning-start-streaming-2k2h</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpyhkybc9oh17ejo2eung.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpyhkybc9oh17ejo2eung.png" alt="Cover Image" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;getProgramAccounts&lt;/code&gt; retrieves all accounts belonging to the given program with optional filtering in one request. It makes the method extremely costly, rate-limited and prone to throttling, making it the most expensive, rate-limited and throttled call in Solana RPC API. There are multiple options to use instead for anything else than a one-shot request: Geyser gRPC subscription streaming the accounts continuously, indexer pre-populated once for cheap querying, &lt;code&gt;getMultipleAccounts&lt;/code&gt; if the addresses are known, or provider-side index like DAS API for NFTs. Below you'll find the explanation of why the call is costly, what are the use-cases for it and alternatives for each of the use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Description of the method and the source of the cost
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;getProgramAccounts(programId, filters)&lt;/code&gt; requests the node to fetch all accounts with the given program as the owner and, optionally, filter them by data size and by &lt;code&gt;memcmp&lt;/code&gt; filters on the account data. Node must look into its account index with the given owner, apply the filters and serialize the response.&lt;/p&gt;

&lt;p&gt;The request is cheap for a small program owning just a few hundred accounts. On the contrary, a token program, a major decentralized exchange or a lending protocol owns millions of accounts. Even with tight filters, the node does lots of scanning and produces a huge response. Providers limit this call (by rate, response size or require filters and &lt;code&gt;dataSlice&lt;/code&gt;), weight the call very heavy in credit pricing and may offload the call to the specialized hardware. Applications repeatedly calling this method in a loop to monitor accounts are the most common cause of throttling and unexpected invoicing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use cases in which the method remains a good choice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One-shot discovery&lt;/strong&gt;: finding all accounts of the given kind to seed an indexer or a cache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small programs&lt;/strong&gt;: programs controlled by the user with a limited number of accounts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Development&lt;/strong&gt;: exploring a program's accounts while developing it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In all three cases the use of &lt;code&gt;dataSlice&lt;/code&gt; to get only the necessary bytes and applying tight &lt;code&gt;memcmp&lt;/code&gt; filters on the discriminator is advised to reduce the size of the response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative 1: subscribe to the accounts with Yellowstone gRPC
&lt;/h2&gt;

&lt;p&gt;If the reason to call &lt;code&gt;getProgramAccounts&lt;/code&gt; repeatedly is to detect changes in accounts, a subscription is better than scanning. A Yellowstone gRPC account filter by the owner program (same &lt;code&gt;memcmp&lt;/code&gt; conditions) will stream all writes to each matching account. It eliminates the loop and provides lower latency than any polling period.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative 2: build an indexer and query your own storage
&lt;/h2&gt;

&lt;p&gt;When the goal is to answer some aggregate questions (e.g., all holders of a mint, all positions above a certain threshold, all pools for the given pair) the proper solution is a database built from the stream and queried using SQL or a key-value lookup. Seed the indexer with a single &lt;code&gt;getProgramAccounts&lt;/code&gt; call or archival backfill and keep it up-to-date via gRPC to avoid scanning the chain for the same question again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative 3: &lt;code&gt;getMultipleAccounts&lt;/code&gt; for known addresses
&lt;/h2&gt;

&lt;p&gt;If the target accounts are known (they are derived addresses or have been identified by an indexer), fetch them directly. &lt;code&gt;getMultipleAccounts&lt;/code&gt; returns up to one hundred accounts per call and takes a fraction of the cost of a scan over a whole program. Many looping implementations of &lt;code&gt;getProgramAccounts&lt;/code&gt; actually request "fetch these fifty accounts I already know" in the wrong way.&lt;/p&gt;

&lt;p&gt;Accounts like associated token accounts, PDAs and pool accounts should be derived, not searched.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative 4: provider-side indexes
&lt;/h2&gt;

&lt;p&gt;There are some questions that are asked often enough for providers to maintain their own indices. The most famous example is NFTs: Digital Asset Standard (DAS) API can answer "which assets does this wallet own" and "what is the metadata of a given asset" for standard and compressed NFTs without any program scans from the client side. &lt;a href="https://orbitflare.com/blog/developers/solana-nft-indexing-das-api" rel="noopener noreferrer"&gt;NFT and DAS indexing on Solana&lt;/a&gt; explains the issue. For token holders, balances and other questions check whether there is an index provided by your provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision framework by the question
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxa9krdzd7mu05f42epc4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxa9krdzd7mu05f42epc4.png" width="800" height="635"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  If the continuous usage of the method is still needed
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Always use &lt;code&gt;memcmp&lt;/code&gt; filters on the discriminator and use &lt;code&gt;dataSlice&lt;/code&gt; to fetch only the necessary bytes.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request data at the &lt;code&gt;confirmed&lt;/code&gt; commitment level;&lt;/strong&gt; &lt;code&gt;finalized&lt;/code&gt; commitment will give you the old snapshot anyway without any gain for a scan.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache the results and compute the diffs instead of re-fetching the whole datasets.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prefer pricing models that don't weight the method specifically.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;**Consider getting a &lt;a href="//https**://orbitflare.com/products/dedicated-nodes"&gt;dedicated node&lt;/a&gt; if the scans are critical for your product: it will have a fixed hardware cost and no per-call costs and reduce the throttling risk.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;getProgramAccounts&lt;/code&gt; is a discovery method that turned into a polling method. It explains the throttling of applications and invoice increases. Substitute endless loops with Yellowstone gRPC subscription when you need to detect changes, with indexer for fast aggregate queries, with &lt;code&gt;getMultipleAccounts&lt;/code&gt; if the addresses are known or with a provider-side index like DAS if you need to work with NFTs. Keep using the method for one-shot discovery with &lt;code&gt;dataSlice&lt;/code&gt; and filters.&lt;/p&gt;

&lt;p&gt;OrbitFlare's &lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;gRPC service&lt;/a&gt; is the streaming alternative to &lt;code&gt;getProgramAccounts&lt;/code&gt;, and the &lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;RPC plans&lt;/a&gt; are priced by requests per second with no method weighting, so the call costs the same as other methods when you need it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/docs/rpc/http/getprogramaccounts" rel="noopener noreferrer"&gt;getProgramAccounts RPC method (Solana docs)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/docs/rpc/http/getmultipleaccounts" rel="noopener noreferrer"&gt;getMultipleAccounts RPC method (Solana docs)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/rpcpool/yellowstone-grpc" rel="noopener noreferrer"&gt;Yellowstone gRPC (GitHub)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://developers.metaplex.com/das-api" rel="noopener noreferrer"&gt;Digital Asset Standard API (Metaplex docs)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/blog/developers/solana-nft-indexing-das-api" rel="noopener noreferrer"&gt;NFT and DAS indexing on Solana (OrbitFlare)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;Jetstream and Yellowstone gRPC streaming (OrbitFlare)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/products/dedicated-nodes" rel="noopener noreferrer"&gt;OrbitFlare dedicated nodes&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;OrbitFlare RPC plans&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>solana</category>
      <category>orbitflare</category>
      <category>rpc</category>
      <category>grpc</category>
    </item>
    <item>
      <title>Copy Trading Architecture: Centralized vs Decentralized</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Mon, 14 Sep 2026 12:50:02 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/copy-trading-architecture-centralized-vs-decentralized-4e9h</link>
      <guid>https://dev.to/orbitflarerpc/copy-trading-architecture-centralized-vs-decentralized-4e9h</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq283bthnabhesenxk5v1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq283bthnabhesenxk5v1.png" alt="Cover Image" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
The difference in copy trading architecture centralized vs decentralized lies in the place where the trade is copied: a private platform ledger or a public chain. A centralized platform mirrors trades between accounts which it already controls. A decentralized platform needs to detect a trade outside of its control and submit another one before the window closes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the real architectural difference between centralized and decentralized copy trading?
&lt;/h2&gt;

&lt;p&gt;Centralized copy trading mirrors a trade within the platform's infrastructure without involving blockchain. Decentralized copy trading observes a public wallet on a blockchain, detects an order made by the wallet and executes another one to follow it.&lt;/p&gt;

&lt;p&gt;eToro explains the operation principle of its CopyTrader system: you allocate $1,000 to a trader who has $10,000 on their account, and when they open a $1,000 position, a $100 position &lt;a href="https://www.etoro.com/copytrader/copy-vs-mirror/" rel="noopener noreferrer"&gt;opens automatically in your account&lt;/a&gt;. It is proportional, executed on the platform's infrastructure and custodial. There is no wallet to monitor since the platform sees everything in advance.&lt;/p&gt;

&lt;p&gt;Decentralized copy trading doesn't allow any of that visibility. The wallet's transactions arrive on the public ledger and nothing will push them to you, so you have to retrieve transactions yourself and fast enough that there is still a time to submit a copy trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does a decentralized copy trading platform's architecture actually work?
&lt;/h2&gt;

&lt;p&gt;This is a combination of a detection layer and an execution layer, and almost all mistakes are made on the detection layer, by failing to see a transaction in time. The platform should see the transaction instantly, decode the trade and execute it before it is too late.&lt;/p&gt;

&lt;p&gt;The problem lies with the detection layer. Polling an RPC endpoint for signatures of the wallet works theoretically until you realize that you miss the trades and you receive updates periodically. &lt;a href="https://orbitflare.com/solutions/traders" rel="noopener noreferrer"&gt;OrbitFlare's own trader infrastructure page&lt;/a&gt; states that "Copy trading fails on latency and on gaps. Polling &lt;code&gt;getSignaturesForAddress&lt;/code&gt; means you find out after the fact and miss anything that lands between calls." The fix for that is a push model, a gRPC stream filtered by an account id server-side so that you receive transactions instantly.&lt;/p&gt;

&lt;p&gt;The execution layer then needs to submit a copy trade fast and protect from front-running. Here the MEV protection becomes useful, since Jito bundles offer &lt;a href="https://docs.jito.wtf/" rel="noopener noreferrer"&gt;fast landing and revert protection&lt;/a&gt;, so a copy trade transaction either lands or fails without costing you the position.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4jb7nmepcoravjbfy4az.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4jb7nmepcoravjbfy4az.png" width="799" height="635"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you actually build a copy trading platform on blockchain?
&lt;/h2&gt;

&lt;p&gt;Three components must operate to submit a trade: a low-latency data stream for detecting the trades of the source wallet, a decoder which understands the instructions of the DEX, and an execution pipeline which submits the trade quickly enough. A failure in any one of the components renders useless the rest of them.&lt;/p&gt;

&lt;p&gt;We made &lt;a href="https://github.com/orbitflare/templates/tree/main/solana-copy-trader" rel="noopener noreferrer"&gt;a working example of this exact architecture&lt;/a&gt; available instead of just explaining it. &lt;code&gt;solana-copy-trader&lt;/code&gt; template uses Jetstream instead of polling, can decode swaps across Jupiter, Raydium, and Pump.fun, and uses Jito MEV protection so that a copy trade lands safely without risking getting sandwiched. The platform is written with Rust, Tokio, gRPC and Redis, not because this is an unusual tech stack, but because copy trading is a streaming problem first and this is the stack which is efficient at processing a constant flow of transactions in real time without falling behind. The majority of copy-trading bots in the wild are broken at the decoding step, because they can decode swaps of one DEX and silently miss trades routed to any other DEX.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does the future of decentralized copy trading look like?
&lt;/h2&gt;

&lt;p&gt;More and more platforms will switch to the streaming model because the platforms which copy trades one block late will keep losing fills to the platforms which use the streaming infrastructure. The copy trading infrastructure will become the question not of whether it should be decentralized or not, but how much latency it can tolerate depending on the strategy being followed. A slow-moving position tracker can get away with polling, but a sniper copy trade bot cannot.&lt;/p&gt;

&lt;p&gt;The best copy trading platforms, centralized or decentralized, converge to the same requirement: the platform must see the source event instantly, not on the next scheduled update. This is true regardless of whether you run a copy trading platform for retail followers or a copy bot for a specific strategy, because the infrastructure underlying the crypto copy trading platform is increasingly becoming the same as the infrastructure for market data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is decentralized copy trading always better than centralized?&lt;/strong&gt; Not necessarily. It trades the simplicity of the platform for the non-custodial feature and the ability to verify transactions publicly at the expense of the necessity to implement an infrastructure for detecting and racing on the blockchain transactions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the minimal latency a decentralized copy trading platform needs?&lt;/strong&gt; There is no definite answer, because the latency requirements depend on the specific strategy being implemented.&lt;/p&gt;

&lt;p&gt;Want to see how the infrastructure of streaming-based copy trading looks in reality? &lt;a href="https://orbitflare.com/solutions/traders" rel="noopener noreferrer"&gt;OrbitFlare's trader solutions&lt;/a&gt; cover RPC, gRPC and Shredstream products which are commonly used for building such a bot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/orbitflare/templates/tree/main/solana-copy-trader" rel="noopener noreferrer"&gt;OrbitFlare Solana copy trader template (GitHub)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/solutions/traders" rel="noopener noreferrer"&gt;OrbitFlare trader solutions&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;Jetstream and Yellowstone gRPC streaming (OrbitFlare)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.jito.wtf/" rel="noopener noreferrer"&gt;Jito bundles documentation&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.etoro.com/copytrader/copy-vs-mirror/" rel="noopener noreferrer"&gt;eToro: copy trading vs mirror trading&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>copytrading</category>
      <category>solana</category>
      <category>orbitflare</category>
      <category>web3</category>
    </item>
    <item>
      <title>Solana Devnet vs Mainnet vs Testnet: Which Cluster for What</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Fri, 11 Sep 2026 14:00:38 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/solana-devnet-vs-mainnet-vs-testnet-which-cluster-for-what-45if</link>
      <guid>https://dev.to/orbitflarerpc/solana-devnet-vs-mainnet-vs-testnet-which-cluster-for-what-45if</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkhkrdakwz8aj25wc6ozy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkhkrdakwz8aj25wc6ozy.png" alt="Cover Image" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
There are three public clusters in Solana: Mainnet Beta, Devnet, and Testnet. Mainnet Beta is a production network with live SOLs, Devnet provides a way to test applications for free with freely airdropped SOL, but without any financial risk, while Testnet is supposed to be used by core developers and validators to test the next release of the network itself, and it is intentionally unstable and is not intended for application testing. Develop on Devnet, deploy to Mainnet and avoid deploying to Testnet except for validator software testing. This article is devoted to a thorough description of each cluster, how to direct your wallet and code to a cluster, practical differences between them and common mistakes made because of confusion with their usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three clusters
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fngg7zdshdgk38dj9mbkf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fngg7zdshdgk38dj9mbkf.png" width="800" height="636"&gt;&lt;/a&gt;&lt;br&gt;
"Beta" in the name of Mainnet is historical, as it supports real value for years and works as a production network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Devnet: a development platform
&lt;/h2&gt;

&lt;p&gt;Devnet uses the same validator software as Mainnet (sometimes even a newer version), runs identical programs and exposes the same RPC API, which means that the code can easily be switched from Devnet to Mainnet by changing an URL. You can get SOL from the faucet (there are some limitations on rate; do not request too much), deploy programs and verify end-to-end flows with zero financial risks.&lt;/p&gt;

&lt;p&gt;There are two caveats with Devnet: firstly, it can be reset, destroying all deployed programs and accounts; keep scripts of deployments to be able to redeploy programs. Secondly, it is quiet: there is no congestion, no competition for the block space and no saturation of transaction forwarding. It verifies the correctness of the logic but does not give any information about landing rate, priority fees and latency under load.&lt;/p&gt;

&lt;p&gt;OrbitFlare provides Devnet and Mainnet URLs per account; every OrbitFlare plan, even free, includes Devnet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mainnet Beta: the home of the value
&lt;/h2&gt;

&lt;p&gt;Devoted to real SOL, real users and real competition for block space. All validations on Devnet, although helpful, are not enough here: network congestion appears during important events, leaders prioritize staked connections and priority fees are real market. The &lt;a href="https://orbitflare.com/blog/fundamentals/network-infrastructure-for-low-latency-solana-trading" rel="noopener noreferrer"&gt;low-latency infrastructure guide&lt;/a&gt; covers specifics of this environment.&lt;/p&gt;

&lt;p&gt;Testing on Mainnet before launching should be done in small scales: just replicate the same transaction flow, spend real fees and measure landing rate in peak periods.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testnet: generally not suitable for applications
&lt;/h2&gt;

&lt;p&gt;Testnet is used for validators to be able to run release candidates and for core teams to test network changes under load. It is updated frequently, may fork or be reset and tooling is oriented towards node operators. Application developers testing their programs on Testnet face instability without any benefits. In case if some tutorial tells you to use Testnet for your dApp, this tutorial is probably outdated; use Devnet instead.&lt;/p&gt;

&lt;p&gt;In case if you are going to operate a validator on Mainnet, you can run one on Testnet as a proving ground.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pointing wallets and code to a cluster
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Wallets&lt;/strong&gt;: most wallets have a network switcher (Mainnet, Devnet, Testnet) in settings and a separate RPC field per network. Switch to Devnet to verify the application running on a Devnet deployment; return to Mainnet before handling real funds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;: cluster is defined by an RPC URL. Keep one URL per environment in configuration (for example, &lt;code&gt;SOLANA_RPC_URL&lt;/code&gt; for production environment with a connection to Mainnet and a separate variable for development environment with a connection to Devnet), do not derive one from another at runtime. Local test validator (&lt;code&gt;solana-test-validator&lt;/code&gt;) is the fourth way to test your code: a private cluster on a local computer, instant and free, without any network involvement.&lt;/p&gt;

&lt;p&gt;Program addresses are different in different clusters for your own programs (each program is deployed separately per cluster), but core programs (token program, system program, associated token program) have the same addresses. Well-known third-party programs are usually deployed both on Devnet and Mainnet at identical addresses, but still better to verify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical differences
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcjxtxdxf3sl6ng8vwt9x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcjxtxdxf3sl6ng8vwt9x.png" width="800" height="688"&gt;&lt;/a&gt;&lt;br&gt;
The main difference is that Devnet verifies the correctness of the logic and Mainnet verifies the performance and economics. Bots, in particular, may work perfectly on Devnet and become unprofitable or unable to land on Mainnet, which explains the emphasis on Mainnet testing in the &lt;a href="https://orbitflare.com/blog/developers/solana-sniper-bot-guide" rel="noopener noreferrer"&gt;sniper bot guide&lt;/a&gt; with small transaction volumes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Incorrect URL in production.&lt;/strong&gt; A release targeted to Devnet looks working but actually performs no real operations. Separate configurations and startup check of genesis hash will help to overcome this problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing landing on Devnet.&lt;/strong&gt; Transactions always land on Devnet, so measure on Mainnet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expecting that a certain program exists on Devnet.&lt;/strong&gt; Some Mainnet programs are not deployed on Devnet or are deployed at different addresses; better to verify this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relying on Devnet state.&lt;/strong&gt; Resets destroy it; keep scripts of redeployments and seed data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using Testnet for dApps.&lt;/strong&gt; Its instability does not provide any benefits.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Devnet is for development, Mainnet is for production and Testnet is for network-level testing. Keep separate cluster URLs per environment, verify the genesis hash at startup, verify your logic on Devnet and performance on Mainnet with small-scale tests and understand that landing, fees or latency characteristics cannot be verified on a quiet cluster.&lt;/p&gt;

&lt;p&gt;OrbitFlare provides Devnet and Mainnet URLs through a free account; &lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;RPC plans&lt;/a&gt; cover the Mainnet path in case of deployment under load.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>orbitflare</category>
      <category>cluster</category>
      <category>web3</category>
    </item>
    <item>
      <title>Solana Archive Nodes and Historical Data: What Needs an Archive and How to Use It</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Fri, 11 Sep 2026 13:55:20 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/solana-archive-nodes-and-historical-data-what-needs-an-archive-and-how-to-use-it-j45</link>
      <guid>https://dev.to/orbitflarerpc/solana-archive-nodes-and-historical-data-what-needs-an-archive-and-how-to-use-it-j45</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiwtl67xqxwoigu9jr65z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiwtl67xqxwoigu9jr65z.png" alt="Cover Image" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
A standard Solana RPC node maintains only a recent history of ledger data, so requests for blocks, transactions, or signatures older than some time window return no results. An archive, or, more precisely, an archive data tier, holds the full ledger history in a separate long-term storage and delivers it via the same RPC API. You need access to archive data if you want to obtain a wallet's history, the trades of a pool from some months ago, or any block created before last week; most people rent it rather than maintain it themselves. This post explains what the retention window is, which methods use the archive, what it means to run an archive, and how to use historical data efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retention window
&lt;/h2&gt;

&lt;p&gt;Any Solana validator or RPC node stores the ledger (i.e., blocks and transactions) in a local database that gradually accumulates entries. Due to the huge amount of history, nodes perform pruning: they keep a certain number of recent slots and drop older ones. The window is measured in days. Requests for any slots within the window succeed, while requests for any slots outside the window return null or an error that the slot is unavailable.&lt;/p&gt;

&lt;p&gt;That might be unexpected for teams that are familiar with other chains, where a full node can deliver any history. On Solana, the full history is an explicitly separate product.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an archive tier
&lt;/h2&gt;

&lt;p&gt;An archive is a long-term storage of all blocks and transactions starting from genesis or from the moment when the archive was turned on; all blocks and transactions are delivered via the same RPC methods. The reference implementation uses a wide-column database (there is support for a BigTable-style backend), and providers maintain something similar to that. When an RPC node receives a request for a slot that is out of the local retention window, it forwards the query to the archive.&lt;/p&gt;

&lt;p&gt;On your side, nothing changes: the same call for a transaction works for transactions created yesterday or two years ago as long as the endpoint has an archive access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which methods use the archive
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F22mjf1hz92k9gki6bq6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F22mjf1hz92k9gki6bq6g.png" width="800" height="745"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This last detail changes the way you design applications. There is no "balance at slot X" method on Solana. If you need any historical balances or positions, you should rebuild them yourself from the history of transactions (from pre- and post-balance in every transaction's metadata).&lt;/p&gt;

&lt;h2&gt;
  
  
  Typical archive queries
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;wallet history&lt;/strong&gt;: all transactions of an address, done with the combination of &lt;code&gt;getSignaturesForAddress&lt;/code&gt; and subsequent &lt;code&gt;getTransaction&lt;/code&gt; calls. Required by explorers, portfolio trackers, tax calculators.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;protocol analytics&lt;/strong&gt;: all swaps at a pool during a period, re-created from blocks or from the lists of signatures for a program.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;indexer backfill&lt;/strong&gt;: filling all the pre-live data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;compliance and audit&lt;/strong&gt;: proving what happened and when.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;research&lt;/strong&gt;: any walk through history.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Running your own archive
&lt;/h2&gt;

&lt;p&gt;It is the most expensive Solana infrastructure to maintain: the historical data is huge and grows by each slot, the backing storage has to grow along with that, and the ingestion process should never lag behind. Providers or large indexers with their dedicated data team are usually the ones who run it. For most projects, the option of renting access to the archive is reasonable. OrbitFlare &lt;a href="https://orbitflare.com/products/historical-data" rel="noopener noreferrer"&gt;historical data&lt;/a&gt; tier is an archive tier and is available via the same API endpoints as the whole service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using historical data efficiently
&lt;/h2&gt;

&lt;p&gt;Historical calls are the heaviest and, under credit-based pricing, the most expensive requests in the API. There are four ways of reducing cost and latency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Page &lt;code&gt;getSignaturesForAddress&lt;/code&gt; requests with &lt;code&gt;before&lt;/code&gt; and &lt;code&gt;until&lt;/code&gt; and stop as soon as you reach the range that you need; don't scan the whole history if you need only last month.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;getBlock&lt;/code&gt; with transaction details if a block contains many interesting transactions, and use &lt;code&gt;getTransaction&lt;/code&gt; if there are few.&lt;/strong&gt; It is very wasteful to fetch an entire block to get a single transaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache immutable results.&lt;/strong&gt; Finalized transactions never change; you should store them once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backfill once, then stay live.&lt;/strong&gt; Use a gRPC stream to receive new data and an archive for pre-backfill data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose a pricing model that works well with the historical queries. Under requests-per-second pricing model, a historical call is the same as any other call; under credit pricing model, it is usually weighted heavier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Solana's standard nodes forget history after some days; anything older is an archive query delivered from a separate long-term storage via the same RPC API. Historical calls to &lt;code&gt;getBlock&lt;/code&gt;, &lt;code&gt;getTransaction&lt;/code&gt;, and &lt;code&gt;getSignaturesForAddress&lt;/code&gt; against old slots need an archive access; current-state calls never do, and there is no historical-state calls at all; thus, history reconstruction is an indexing task. Rent an archive access rather than run it yourself, do efficient paging and caching, and choose a pricing model that doesn't punish heavy requests.&lt;/p&gt;

&lt;p&gt;OrbitFlare &lt;a href="https://orbitflare.com/products/historical-data" rel="noopener noreferrer"&gt;historical data&lt;/a&gt; tier delivers the full history through the standard API endpoints; combine it with the &lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;gRPC service&lt;/a&gt; for the post-backfill data.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>orbitflare</category>
      <category>archive</category>
      <category>rpc</category>
    </item>
    <item>
      <title>Agave 4.2: Transaction V1 Breaking Changes Checklist</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Thu, 10 Sep 2026 00:02:52 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/agave-42-transaction-v1-breaking-changes-checklist-50h</link>
      <guid>https://dev.to/orbitflarerpc/agave-42-transaction-v1-breaking-changes-checklist-50h</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0cildamw8gupgri24gn3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0cildamw8gupgri24gn3.png" alt="Cover Image" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Transaction V1 activates on Solana mainnet at the next epoch boundary on 10 September 2026. The new version increases the maximum transaction size from 1,232 bytes to 4,096 bytes and adds a new format that cannot be read by the old client libraries.&lt;/p&gt;

&lt;p&gt;Only one item on the list causes an error; all others allow code to function with incorrect numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current status of each change
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff8sg6wijk90s7yz59b95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff8sg6wijk90s7yz59b95.png" alt="SIMD Table" width="800" height="726"&gt;&lt;/a&gt;&lt;br&gt;
Agave 4.2 was released on 11 August 2026; however, none of the changes have been activated on that date. Every change has its own activation gate, which explains the different dates mentioned above.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Require v1 on every call that returns transactions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What fails.&lt;/strong&gt; Any call that returns transactions and has not been declared compatible with version 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it fails.&lt;/strong&gt; With an error (the only item causing an error). The error code is -32015. The whole call fails, not just this particular transaction. As a consequence, a single v1 transaction in a block breaks the &lt;code&gt;getBlock&lt;/code&gt; call for the whole block.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where to verify.&lt;/strong&gt; &lt;code&gt;getBlock&lt;/code&gt;, &lt;code&gt;getTransaction&lt;/code&gt;, &lt;code&gt;getTransactionsForAddress&lt;/code&gt; when &lt;code&gt;transactionDetails&lt;/code&gt; is &lt;code&gt;full&lt;/code&gt;, and the &lt;code&gt;transactionSubscribe&lt;/code&gt; and &lt;code&gt;blockSubscribe&lt;/code&gt; WebSocket subscriptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommended action.&lt;/strong&gt; Add &lt;code&gt;maxSupportedTransactionVersion: 1&lt;/code&gt; to every relevant endpoint. Update the SDK first and check its ability to read v1 transactions; otherwise, requesting an unsupported version will merely move the error. For TypeScript, use &lt;code&gt;@solana/kit&lt;/code&gt; 8.0 or higher, or &lt;code&gt;@solana/web3.js&lt;/code&gt; v3. For Rust, use &lt;code&gt;solana-rpc-client-api&lt;/code&gt; 4.2 or higher.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Read the priority fee from the header
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What fails.&lt;/strong&gt; Any way to estimate the fees by looking for ComputeBudget instruction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it fails.&lt;/strong&gt; Without an error. A v1 transaction doesn't contain a ComputeBudget instruction; any code scanning for it fails to find anything, reports zero, and proceeds further. Thus, every v1 transaction appears to pay zero priority fee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reason for change.&lt;/strong&gt; With v0, validators needed to look through the instruction data to calculate the bid of a transaction, which took time. With v1, the compute budget moves into the header, where the priority fee, the compute unit limit, the account data size limit, and the heap request reside. In case a v1 transaction contains a ComputeBudget instruction, it is simply ignored.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommended action.&lt;/strong&gt; Use the &lt;code&gt;priorityFee&lt;/code&gt; property from the &lt;code&gt;transactionConfig&lt;/code&gt; object. Watch the units carefully; in legacy and v0 the number meant the price in micro-lamports per compute unit. In v1, it means the total in lamports. Thus, the &lt;code&gt;priorityFee&lt;/code&gt; of &lt;code&gt;50000&lt;/code&gt; corresponds to 50,000 lamports for the whole transaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Stop assuming updates for every writable account
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What fails.&lt;/strong&gt; Everything that correlates transactions to accounts, performs reconciliation, and counts the number of account updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it fails.&lt;/strong&gt; Without an error. Agave 4.2 stops writing accounts that a transaction locked for writing but didn't update; thus, those accounts stop emitting updates in &lt;code&gt;getBlock&lt;/code&gt; and gRPC and WebSocket streams. Providers deploying the new release start getting approximately 80% fewer events, although depending on the kind of data you monitor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommended action.&lt;/strong&gt; Consider the absence of the update event as a signal of "unchanged" rather than as an error. The fee payer is the only account that can be assumed updated reliably. Thus, adapt your monitoring code to the situation; you'll start getting a lot fewer update events, even without service failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Add a new reward type
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What fails.&lt;/strong&gt; Parsers limited to the fixed number of reward types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it fails.&lt;/strong&gt; Without an error. The stake account being deactivated produces a final payout with type &lt;code&gt;DeactivatedStake&lt;/code&gt;, which appears together with other types (fee, rent, staking, voting) in &lt;code&gt;getBlock&lt;/code&gt; and &lt;code&gt;blockSubscribe&lt;/code&gt; rewards. Parsers unaware of the new value simply skip it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommended action.&lt;/strong&gt; Add &lt;code&gt;DeactivatedStake&lt;/code&gt; to the list of accepted reward types. During the update, make sure to log the unknown values, so that you'll start seeing the newly introduced values in logs instead of holes in numeric outputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Update Token-2022 parsing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What fails.&lt;/strong&gt; Anything that parses Token-2022 instructions or mint extensions from &lt;code&gt;jsonParsed&lt;/code&gt; responses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it fails.&lt;/strong&gt; Some expected fields might be missing, whereas some absent fields might appear.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Changes.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;depositConfidentialTransfer&lt;/code&gt; and &lt;code&gt;withdrawConfidentialTransfer&lt;/code&gt; no longer have separate &lt;code&gt;source&lt;/code&gt; and &lt;code&gt;destination&lt;/code&gt; fields; there is a single &lt;code&gt;account&lt;/code&gt; field now, since the two were always equal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;unwrapLamports&lt;/code&gt;, &lt;code&gt;confidentialBurn&lt;/code&gt;, permissioned burn, and batch operations are parsed as JSON instead of raw bytes. &lt;code&gt;unwrapLamports&lt;/code&gt; has the &lt;code&gt;amount&lt;/code&gt; as a string and it can be omitted if the whole balance is unwrapped.&lt;/li&gt;
&lt;li&gt;Mints with unknown extensions no longer return an empty &lt;code&gt;extensions&lt;/code&gt; array, but the full correct one, which can have some names unknown before.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Recommended action.&lt;/strong&gt; Adapt your code to the new &lt;code&gt;account&lt;/code&gt; field structure, don't reject extension names you don't know yet, and consider the absence of &lt;code&gt;unwrapLamports&lt;/code&gt; &lt;code&gt;amount&lt;/code&gt; as the sign of complete unwrap.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Stop using the hardcoded slot time
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What fails.&lt;/strong&gt; Anything that relies on 400 ms interval.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it fails.&lt;/strong&gt; Slowly accumulates problems: timeouts trigger too soon, estimates of blocks per window go wrong, and calculations of duration based on slot count become wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommended action.&lt;/strong&gt; Mainnet has switched to 350 ms at epoch 1020 (21 August 2026) and to 300 ms at epoch 1024 (28 August). SIMD-0525 reduces the slot time by 50 ms each time, approaching 200 ms. The 250 ms value is currently active on testnet but not on mainnet. Don't hardcode the value; calculate the time either based on block timestamps or configure it so that the future changes would be done via configurations, not new releases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Versions to pin
&lt;/h2&gt;

&lt;p&gt;The minimum version corresponds to the earliest release able to read v1.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fipabms2q4tp73h4xd5uk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fipabms2q4tp73h4xd5uk.png" alt="Minimum Version Table" width="800" height="913"&gt;&lt;/a&gt;&lt;br&gt;
Note: &lt;code&gt;orbitflare-sdk-proto&lt;/code&gt; is an internal dependency of the Rust SDK and is included automatically; direct pinning is only needed if you consume the protos directly.&lt;/p&gt;

&lt;p&gt;Go users need to regenerate the protobuf bindings from the current Yellowstone protos and &lt;code&gt;solana-storage-proto&lt;/code&gt;, not from an older pinned file.&lt;/p&gt;

&lt;h2&gt;
  
  
  If decoding transactions manually
&lt;/h2&gt;

&lt;p&gt;If you parse raw transaction bytes, be it the provided decode example, a custom shred decoder, or your own parser, there are three layout changes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The version byte is 129 now, allowing distinguishing v1 transactions from legacy and v0.&lt;/li&gt;
&lt;li&gt;Signatures come at the end of the transaction, not at the beginning.&lt;/li&gt;
&lt;li&gt;The compute budget moves from the instructions into the header.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Address lookup tables do not exist in v1; practically, this is fine, because the 4,096-byte limit allows listing the accounts directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There are six items to check, with the only one failing definitively. Other five allow normal operation with erroneous measurements.&lt;/p&gt;

&lt;p&gt;Do it in the following order: first fix the reading calls (the primary source of errors), then the fee interpretation, then the account and reward parsing, and finally the timing constants.&lt;/p&gt;

&lt;p&gt;OrbitFlare's &lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;RPC&lt;/a&gt;, &lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;Yellowstone gRPC, and Jetstream&lt;/a&gt; systems deploy the current Agave release in all regions, handling the format changes on the server side. Jetstream sends v1 transactions without requiring subscription change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0296-larger-transactions.md" rel="noopener noreferrer"&gt;SIMD-0296: larger transactions&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0385-transaction-v1.md" rel="noopener noreferrer"&gt;SIMD-0385: transaction v1&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/upgrades/agave-4-2-release-overview" rel="noopener noreferrer"&gt;Agave 4.2 release overview (Solana)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/upgrades/reduced-slot-times" rel="noopener noreferrer"&gt;Reduced slot times (SIMD-0525)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/upgrades/reduced-rent" rel="noopener noreferrer"&gt;Reduced rent (SIMD-0437)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/orbitflare/shredstream-decode-example" rel="noopener noreferrer"&gt;OrbitFlare shredstream decode example&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://crates.io/crates/orbitflare-sdk" rel="noopener noreferrer"&gt;OrbitFlare Rust SDK: orbitflare-sdk (crates.io)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://crates.io/crates/orbitflare-sdk-proto" rel="noopener noreferrer"&gt;OrbitFlare proto crate: orbitflare-sdk-proto (crates.io)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.npmjs.com/package/@orbitflare/sdk" rel="noopener noreferrer"&gt;OrbitFlare TypeScript SDK: @orbitflare/sdk (npm)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/orbitflare/orbitflare-sdk-go" rel="noopener noreferrer"&gt;OrbitFlare Go SDK: orbitflare-sdk-go (GitHub)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>agave</category>
      <category>solana</category>
      <category>orbitflare</category>
      <category>simd</category>
    </item>
    <item>
      <title>Solana RPC Rate Limits: How They Work and How to Stop Hitting Them</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Tue, 08 Sep 2026 15:11:31 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/solana-rpc-rate-limits-how-they-work-and-how-to-stop-hitting-them-38bn</link>
      <guid>https://dev.to/orbitflarerpc/solana-rpc-rate-limits-how-they-work-and-how-to-stop-hitting-them-38bn</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6trhyymr6bbchc00kmd9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6trhyymr6bbchc00kmd9.png" alt="Cover Image" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
In short, the provider, not the protocol, enforces the Solana RPC rate limits, which are available in three forms: a number of requests per second, a monthly quota of credits or compute units, and per-method limits applied to costly operations such as &lt;code&gt;getProgramAccounts&lt;/code&gt;. If you reach one of these limits you receive an HTTP 429 response or a JSON-RPC error, and the solution is seldom to upgrade to a more expensive plan; instead it is generally necessary to stop polling, to batch the data you fetch, to subscribe to changes and to cache the data that doesn't change. This guide outlines how the limits work, how to determine which one you have hit, and the modifications that reduce request volume by a factor of ten.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public endpoints limit requests per IP address, and strictly so, while provider plans impose limits per key and include a budget that can be viewed in a dashboard.&lt;/li&gt;
&lt;li&gt;The three types of limits fail in different ways: if the RPS limit is exceeded the system returns a 429 immediately, if the credit allowance is exhausted it either throttles the request or charges for the overage, and a heavy method may be refused completely.&lt;/li&gt;
&lt;li&gt;Nearly all limit problems involve polling. Simply replace a poll loop with a subscription and the calls will be eliminated.&lt;/li&gt;
&lt;li&gt;Regard a keyed URL as a credential; if the key is leaked it will use up your quota on someone else's machine.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How the limits work
&lt;/h2&gt;

&lt;p&gt;The Solana protocol does not have the idea of an API rate limit; instead, a node will respond to whatever request it is able to handle. Such limits are necessary since nodes are finite and the providers have to share them. Three methods are commonly used, often being combined.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;How it is measured&lt;/th&gt;
&lt;th&gt;What hitting it looks like&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Requests per second&lt;/td&gt;
&lt;td&gt;A sliding window per key or per IP&lt;/td&gt;
&lt;td&gt;Immediate 429 on the excess requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monthly allowance (credits or compute units)&lt;/td&gt;
&lt;td&gt;Each method deducts a weight from a pool&lt;/td&gt;
&lt;td&gt;Throttling or overage billing when the pool is empty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-method limits&lt;/td&gt;
&lt;td&gt;Caps or refusals on heavy methods&lt;/td&gt;
&lt;td&gt;Errors specific to &lt;code&gt;getProgramAccounts&lt;/code&gt;, large &lt;code&gt;getBlock&lt;/code&gt; calls, archive queries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The public endpoints are the ones with the lowest numbers and are associated with your IP address. The public mainnet endpoint, for example, allows 100 requests per 10 seconds per IP, 40 requests per 10 seconds per IP for any single method, 40 concurrent connections per IP, and 100 MB of data per 30 seconds, and Solana's own documentation says that it is not intended for production applications. For provider plans, the numbers are given according to each tier and usage is displayed in a dashboard, which should be the first place you check when there's a problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diagnosing which limit you hit
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When receiving an HTTP 429 with bursts: you have exceeded the number of requests per second. Check for loops, parallel fan-out, or a retry storm.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Either 429 or the rate is reduced towards the end of the month: the allowance is used up. Check the usage at the method level since the typical cause is a heavy method being called in a loop.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Errors occur only in the case of a particular method: there is a per-method limit. The usual examples are &lt;code&gt;getProgramAccounts&lt;/code&gt; and the extensive &lt;code&gt;getLogs&lt;/code&gt; or &lt;code&gt;getSignaturesForAddress&lt;/code&gt; ranges.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you see usage that you do not recognise, the key may have been leaked. Rotate it and find out who is calling with it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cutting request volume
&lt;/h2&gt;

&lt;p&gt;The fixes listed below are given in order of the amount of request volume they usually save.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Use subscriptions instead of polling. If a loop calls &lt;code&gt;getAccountInfo&lt;/code&gt; once every second, it ends up making 86,400 calls per account each day and detects changes with a delay. However, using a WebSocket &lt;code&gt;accountSubscribe&lt;/code&gt; or a Yellowstone gRPC accounts filter results in no calls being made and means that changes are detected instantly. This one change eliminates most of the request volume in most applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do not call &lt;code&gt;getProgramAccounts&lt;/code&gt; in a loop. It is the most intensive method in the API and at the same time the one that providers restrict the most.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Batch. &lt;code&gt;getMultipleAccounts&lt;/code&gt; can retrieve up to 100 accounts with a single call; by using JSON-RPC batch requests (an array of request objects sent in a single POST, which the Solana RPC specification supports), several calls can be combined into a single round trip. Ten calls are then made as one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Store data that is immutable and changes slowly. Finalised transactions never change, so they can be cached for as long as you like. Program accounts that have been decoded once can be kept, and token metadata also changes rarely. The time-to-live period for the cache should match the frequency with which the data actually changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;dataSlice&lt;/code&gt; and precise filters. Only retrieve the bytes that are required. This is cheaper in terms of compute units and results in faster responses everywhere.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fix the retries. When receiving a 429 response, use exponential backoff with jitter and avoid attempting an immediate retry since a retry storm can turn a short-term limit into a lengthy outage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Instead of checking the status via &lt;code&gt;getSignatureStatuses&lt;/code&gt; at intervals of a few hundred milliseconds, confirm the transactions using &lt;code&gt;signatureSubscribe&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Designing for limits from the start
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use one connection per process, and reuse it with keep-alive; establishing a new connection for each request results in latency and causes the limits to be reached more quickly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prepare a budget on a per-feature basis by determining the number of calls that each part of the application makes per user action and then monitoring this figure in the provider's dashboard as the features are released.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Assign separate keys for each service and environment. A job that goes wrong in the staging environment should not use up the resources allocated to production, and a leak in one service should not cause all the other services to fail.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Monitor the 429 rate and usage in relation to the allowance, with alerts triggered well in advance of exhaustion.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When you actually need a bigger plan
&lt;/h2&gt;

&lt;p&gt;Once the adjustments mentioned above have been made, ongoing legitimate traffic that exceeds the plan's ceiling is the reason to upgrade. The other reason is when you need a feature which the tier doesn't provide: gRPC streaming, archive depth, regional endpoints, or a staked transaction path. And when high levels of sustained traffic are involved, a &lt;a href="https://orbitflare.com/products/dedicated-nodes" rel="noopener noreferrer"&gt;dedicated node&lt;/a&gt; eliminates rate limits altogether since your limitation will then be determined by the hardware rather than by a shared budget.&lt;/p&gt;

&lt;p&gt;The plans offered by OrbitFlare are based on requests per second without taking into account the weight of individual methods, meaning that a heavy method does not use up part of the allowance; the tiers are listed on the &lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;RPC nodes page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The rate limits on Solana RPC services are a feature provided by the provider and come in three forms: per second, per allowance, and per method. Work out which of these you are encountering by looking at the error messages and using the dashboard, then reduce the volume by subscribing rather than polling, phasing out loops using &lt;code&gt;getProgramAccounts&lt;/code&gt;, batching the requests, caching the results, slicing the data, and correcting the retry mechanism. It is only after that that a bigger plan becomes appropriate, and at a real scale a dedicated node makes the issue disappear.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;OrbitFlare RPC plans&lt;/a&gt; state their requests-per-second budgets and offer WebSockets on all tiers; the &lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;gRPC service&lt;/a&gt; is the subscription option which makes most polling unnecessary.&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/docs/references/clusters" rel="noopener noreferrer"&gt;Solana clusters and public RPC endpoint limits&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/docs/rpc" rel="noopener noreferrer"&gt;Solana JSON-RPC documentation&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/docs/rpc/http/getmultipleaccounts" rel="noopener noreferrer"&gt;getMultipleAccounts reference&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;OrbitFlare RPC plans&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/pricing" rel="noopener noreferrer"&gt;OrbitFlare pricing&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/products/dedicated-nodes" rel="noopener noreferrer"&gt;OrbitFlare dedicated nodes&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>How to Build a Solana Sniper Bot: Detection, Filters and Execution</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Tue, 08 Sep 2026 14:04:21 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/how-to-build-a-solana-sniper-bot-detection-filters-and-execution-2pjo</link>
      <guid>https://dev.to/orbitflarerpc/how-to-build-a-solana-sniper-bot-detection-filters-and-execution-2pjo</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fje8egfoko6p94cjc01wi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fje8egfoko6p94cjc01wi.png" alt="Cover Image" width="800" height="450"&gt;&lt;/a&gt;In a nutshell, a Solana sniper bot is a type of program that spots a new liquidity pool or a token listing as soon as it appears on the blockchain and then places a buy order before the wider market has had a chance to react. Since the entire approach is a race that takes place in milliseconds, the bot essentially consists of three parts: a detection layer which picks up the event first, a decision layer which filters out potential scams, and an execution layer which carries out the transaction while the price is still exactly as it was when it was observed. This article examines each of these layers, explains where the time is actually spent, and outlines the failure modes that distinguish bots that function in real conditions from those that only work on the testnet.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The speed of detection is what gives you the edge. A bot which learns about a pool from a finalised block is already hundreds of milliseconds slower than one that reads shreds or uses a low-latency gRPC stream.&lt;/li&gt;
&lt;li&gt;The reason for most losses isn't that the bot is slow; it's that it buys the wrong thing. Honeypot checks, authority checks, and liquidity sanity checks should be included in the hot path and not left until a later review.&lt;/li&gt;
&lt;li&gt;Execution requires a prioritised write path; if a simple &lt;code&gt;sendTransaction&lt;/code&gt; is carried out at the time of a launch, it goes out over an unstaked connection and usually loses to snipers who are on staked ones.&lt;/li&gt;
&lt;li&gt;Build around the leader schedule, since the region from which your transaction leaves is determined by where the current leader is sitting.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How does a Solana sniper bot actually work?
&lt;/h2&gt;

&lt;p&gt;A sniper bot monitors on-chain events, detects the establishment of a tradeable market, decides within microseconds whether or not to take action, and then carries out a swap. On Solana the events that are worth keeping an eye on are the instructions which create or initialise a pool on a DEX program (Raydium, Orca, Meteora and the launchpad programs that migrate into them) and the first liquidity deposit that makes the pool tradeable.&lt;/p&gt;

&lt;p&gt;The pipeline has four stages, and each stage has a latency budget:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Typical budget&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Observe&lt;/td&gt;
&lt;td&gt;See the pool creation instruction on chain&lt;/td&gt;
&lt;td&gt;Where most of the race is won or lost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decode&lt;/td&gt;
&lt;td&gt;Parse accounts, mint, liquidity, authorities&lt;/td&gt;
&lt;td&gt;Sub-millisecond if done in memory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decide&lt;/td&gt;
&lt;td&gt;Run safety filters and position sizing&lt;/td&gt;
&lt;td&gt;Sub-millisecond for precomputed rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execute&lt;/td&gt;
&lt;td&gt;Build, sign, and land the swap&lt;/td&gt;
&lt;td&gt;Network bound; region and path decide it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All the parts that come after 'observe' take place within your own process and can therefore be made faster through normal engineering techniques. Since the 'observe' and 'execute' stages rely on infrastructure, the remainder of this guide focuses most of its attention on that area.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detection: where the race is decided
&lt;/h2&gt;

&lt;p&gt;There are four methods of working out that a pool has been made, and these methods are not the same.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Polling an RPC.&lt;/strong&gt; Continuously calling either &lt;code&gt;getProgramAccounts&lt;/code&gt; or &lt;code&gt;getSignaturesForAddress&lt;/code&gt;. This is simple but terribly slow: you only find out about the pool a few seconds after it has been created, and you end up hitting your rate limit as a result. It can be of use only for research and never for actual live sniping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. WebSocket subscriptions.&lt;/strong&gt; By using &lt;code&gt;logsSubscribe&lt;/code&gt; or &lt;code&gt;programSubscribe&lt;/code&gt; on the DEX program, you will receive a push notification whenever a matching transaction is processed. This represents the basic requirement for a functioning bot, but the notifications are sent after the RPC node has processed the block, which is after the leader has produced it and after it has been propagated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Geyser gRPC (Yellowstone).&lt;/strong&gt; The Geyser plugin sends out a gRPC stream which provides account and transaction updates as the node is processing them, with filtering carried out on the server so that you only get the data for which you have subscribed. It has lower latency than WebSockets and is much more selective. This is the minimum requirement for most serious bots.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Shreds.&lt;/strong&gt; When a leader is forming a block, it sends out fragments called shreds. If you look at these fragments directly or use a service which reconstructs the transactions from them, you will be able to see the pool creation as the block is still being put together, prior to any RPC node having processed it. This represents the earliest possible point at which observation can take place, and it is what distinguishes consistently early bots from the rest.&lt;/p&gt;

&lt;p&gt;In reality the stack is as follows: it includes a Shredstream-fed stream for the hot path, a gRPC stream as the source of structured data, and WebSockets as the fallback option. Because OrbitFlare's &lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;Jetstream gRPC&lt;/a&gt; provides the stream derived from the shreds with the transaction already decoded, your bot receives a typed event instead of raw packets. Details about the mechanics can be found in &lt;a href="https://orbitflare.com/blog/fundamentals/shredstream" rel="noopener noreferrer"&gt;what is Shredstream&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decoding the event correctly
&lt;/h2&gt;

&lt;p&gt;When an event occurs, the bot requires the pool address, both token mints, the initial liquidity amounts, and the accounts that it will need in order to carry out a swap. Two rules prevent this stage from becoming a bottleneck.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parse in memory, never fetch.&lt;/strong&gt; Each time you make a &lt;code&gt;getAccountInfo&lt;/code&gt; call after the event it involves a round trip that you can't afford. Decode the instruction data and the accounts list from the transaction itself and keep the DEX program layouts in your binary, along with a warm cache of the token program, the associated token program and the common vault layouts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Precompute what you can.&lt;/strong&gt; The address of your wallet's associated token account for a particular mint is deterministic. The swap instruction for a given DEX is a template as well. Before the event takes place, prepare as much of the transaction as possible and then insert the mint and pool addresses when they become available.&lt;/p&gt;

&lt;p&gt;A good decode stage runs in less than a millisecond. If yours is slower, profile it before changing anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deciding: the filters that save you money
&lt;/h2&gt;

&lt;p&gt;It's speed that gets you into the trade, while filters keep you out of the trades which were meant to take your money. The typical traps found on Solana launches, and the safeguards that detect them:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Trap&lt;/th&gt;
&lt;th&gt;What it looks like&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mint authority retained&lt;/td&gt;
&lt;td&gt;Creator can mint unlimited supply after launch&lt;/td&gt;
&lt;td&gt;Require mint authority to be revoked or null&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Freeze authority retained&lt;/td&gt;
&lt;td&gt;Creator can freeze your token account&lt;/td&gt;
&lt;td&gt;Require freeze authority to be null&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fake or tiny liquidity&lt;/td&gt;
&lt;td&gt;Pool exists but has trivial depth&lt;/td&gt;
&lt;td&gt;Minimum liquidity threshold in SOL terms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Liquidity not locked or burned&lt;/td&gt;
&lt;td&gt;Creator pulls liquidity after you buy&lt;/td&gt;
&lt;td&gt;Check LP token destination; prefer burned LP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sell tax or transfer hook&lt;/td&gt;
&lt;td&gt;Token program extension blocks or taxes transfers&lt;/td&gt;
&lt;td&gt;Inspect Token-2022 extensions; skip unknown hooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concentrated holder&lt;/td&gt;
&lt;td&gt;One wallet holds most of the supply&lt;/td&gt;
&lt;td&gt;Holder distribution check via indexer or cached data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each of these has to be based on data that you already possess or that you can obtain from a single cached source. A filter which requires three RPC calls is one that causes you to be delayed. Since many bots have a background indexer that continuously monitors token metadata and holder distributions, the hot path performs a hash lookup instead of making a network request.&lt;/p&gt;

&lt;p&gt;This also applies to position sizing. You should decide the maximum amount of SOL per trade, the maximum slippage, and the maximum share of the pool's liquidity that you are willing to take up before the event takes place. These should be set as constants and read by the hot path, not made into calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Executing: landing the buy
&lt;/h2&gt;

&lt;p&gt;You first observed the pool and concluded that it was safe; at this stage the transaction has to get to the current leader before all the others'. This is entirely an infrastructure issue and it has four parts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Priority fee.&lt;/strong&gt; Set the compute unit price high enough to win ordering within the block. Since the fee market on Solana is specific to the accounts you interact with, the relevant price is the one that other snipers are paying on this pool, not the overall median fee for the network. Estimating the fee dynamically, based on recent transactions that have involved the same DEX program, is better than using a fixed fee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Write path.&lt;/strong&gt; When a launch is taking place the public TPU gets overwhelmed by other snipers and as a result the unstaked connections are dropped first. In this case you should use either a Jito bundle (one that includes a tip reflecting the expected edge) or a stake-weighted QoS lane. We look at all the options in &lt;a href="https://orbitflare.com/blog/fundamentals/how-to-land-transactions-on-solana" rel="noopener noreferrer"&gt;how to land transactions on Solana&lt;/a&gt;. A staked lane is generally the better default choice for single-leg sniping since the bundle auction involves an extra step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Region.&lt;/strong&gt; In the current slot the leader is a particular validator located in a specific datacentre. When a transaction goes from Frankfurt to a leader based in Ashburn, it pays for the Atlantic twice: once when your data arrives and again when the block returns. Serious bots operate in more than one region and submit their transactions from the one closest to the scheduled leader. The &lt;a href="https://orbitflare.com/solana-rpc/frankfurt" rel="noopener noreferrer"&gt;region pages&lt;/a&gt; show where OrbitFlare has a presence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retry strategy.&lt;/strong&gt; Send the transaction to both the current leader and the next one, then stop. Blindly resending it for ten seconds will burn through the rate limit and often results in a worse fill in a later slot that you didn't want.&lt;/p&gt;

&lt;h2&gt;
  
  
  A reference architecture
&lt;/h2&gt;

&lt;p&gt;Putting the stages together, a production sniper looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Streams&lt;/strong&gt;: a gRPC subscription powered by Shredstream and filtered to include only the DEX programs that you trade, together with a gRPC subscription from Yellowstone for account state, and also a WebSocket fallback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indexer&lt;/strong&gt;: a background process which keeps the token metadata, authorities, and holder distributions in memory, fed by the same streams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hot path&lt;/strong&gt;: there is one single-threaded event loop in each region which carries out the decoding, filtering, sizing, building, signing, and submission. If your language permits it, there should be no allocations on the hot path; Rust is the most commonly used language and Go can be used as well.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submission&lt;/strong&gt;: in each region there is a staked write path together with leader schedule tracking so that the appropriate region can be selected for each event.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post-trade&lt;/strong&gt;: this is a distinct process which keeps an eye on the position, handles the exits, and records the result for later analysis.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The fundamental rule concerning design is that nothing on the hot path should wait for a network request; all the data it needs must have been included with the event or should have been cached previously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measuring whether your bot is actually fast
&lt;/h2&gt;

&lt;p&gt;Statements about latency without actual measurement are just guesses. To obtain accurate figures, record three timestamps for each event: the time at which the event was observed, the time when the transaction was submitted, and the slot in which it landed. Then track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Observe-to-submit time.&lt;/strong&gt; This is your own code. You should achieve sub-millisecond performance with a well-built bot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submit-to-landing slot delta.&lt;/strong&gt; The difference between the slot you submitted in and the slot the transaction actually landed in. This is your infrastructure. A zero indicates that you landed in the slot you had aimed for.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Landing rate during launches.&lt;/strong&gt; The proportion of submitted transactions that landed at all within the 60 seconds surrounding a launch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fill quality.&lt;/strong&gt; The executed price compared to the price at the time of observation. This figure shows whether being fast actually translated into being early.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you look at the results for different regions and for different write paths, you will usually find that one region is early for a subset of the leaders but late for the others; this is the kind of data that you need in order to justify a multi-region deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Using a public or shared RPC for the hot path.&lt;/strong&gt; It is unreliable precisely when it is needed due to rate limits and the shared capacity. A &lt;a href="https://orbitflare.com/products/dedicated-nodes" rel="noopener noreferrer"&gt;dedicated node&lt;/a&gt; or a plan with reserved capacity should be the standard choice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filtering after submitting.&lt;/strong&gt; Bots end up with frozen tokens because they buy first and then check.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One region.&lt;/strong&gt; The leader schedule is global and a single-region bot is late for most of it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignoring Token-2022 extensions.&lt;/strong&gt; Transfer hooks and fees are valid features and can also be very effective as traps. Skip any tokens with extensions that you do not explicitly understand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixed priority fees.&lt;/strong&gt; The fee applicable at the time of a launch can be many times higher than the quiet-hour fee. This should be estimated dynamically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No exit plan.&lt;/strong&gt; Paper gains turn into real losses when you get in quickly without having a strategy for getting out.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A Solana sniper bot is essentially a race based on latency that also involves a safety issue; in order to win the observation phase you need to use either shred-level or gRPC streaming, keep the decode and decision phases in memory, and then carry out the transaction via a staked, region-aware write path. You should measure the time taken from observation to submission, from submission to landing, and the fill quality, and let these figures guide all of your infrastructure decisions.&lt;/p&gt;

&lt;p&gt;If you wish to make the transition from a working bot to an early one, the &lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;Jetstream gRPC service&lt;/a&gt; provides you with the event stream derived from shreds, and the &lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;RPC plans&lt;/a&gt; include the staked write path as well, and both are available in the regions where the leaders are.&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/developers/guides/advanced/stake-weighted-qos" rel="noopener noreferrer"&gt;Stake-weighted QoS guide (Solana)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.jito.wtf/" rel="noopener noreferrer"&gt;Jito bundle documentation&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/blog/fundamentals/shredstream" rel="noopener noreferrer"&gt;What is Shredstream?&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/orbitflare/shredstream-decode-example" rel="noopener noreferrer"&gt;Shredstream decode example (GitHub)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.orbitflare.com/data-streaming/jetstream-v2" rel="noopener noreferrer"&gt;Jetstream V2 docs&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/benchmarks" rel="noopener noreferrer"&gt;OrbitFlare benchmarks&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>solana</category>
      <category>orbtiflare</category>
      <category>rpc</category>
      <category>trading</category>
    </item>
    <item>
      <title>Solana Commitment Levels Explained: Processed, Confirmed and Finalized</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Mon, 07 Sep 2026 21:36:55 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/solana-commitment-levels-explained-processed-confirmed-and-finalized-gaj</link>
      <guid>https://dev.to/orbitflarerpc/solana-commitment-levels-explained-processed-confirmed-and-finalized-gaj</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxqiytiryo937ehssgqvl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxqiytiryo937ehssgqvl.png" alt="Cover Image" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you build on Solana, you may encounter the terms processed, confirmed and finalized. These are what are known as the commitment levels.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is no single right choice when it comes to deciding which commitment level to use. Each situation is different, but there is usually a wrong choice for a given job.&lt;/li&gt;
&lt;li&gt;If you see unexpected behaviour such as transactions that are present one moment and gone the next, you may be using inconsistent commitment levels.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;processed&lt;/code&gt; refers to the node having executed the block that contains the transaction. It is the fastest option but the block may still be skipped over by the cluster.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;confirmed&lt;/code&gt; means that more than two thirds of the stake voted on the block. Rollback is highly unlikely.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;finalized&lt;/code&gt; means the block has reached maximum lockout and cannot be rolled back.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What are commitment levels?
&lt;/h2&gt;

&lt;p&gt;Commitment levels define how certain you can be that the state has become permanent. A commitment level is a way for us to communicate the degree of certainty that the transaction or the block will remain in the ledger.&lt;/p&gt;

&lt;p&gt;Solana creates a block for every slot. This is currently 350ms on mainnet since the decrease from 400ms in August 2026.&lt;/p&gt;

&lt;p&gt;When blocks are produced, they are only provisional, as the next leader(s) might choose to build on a different fork. Once more than two thirds of the stake has voted on that block during subsequent slots, the block becomes confirmed. Solana uses a consensus mechanism currently known as Tower BFT, where blocks become more solidified as further votes come in. Eventually, a block is finalized when it has reached maximum lockout and cannot be undone. This usually happens around 32 slots after the block was confirmed. At the current slot time that is somewhere between 11 and 13 seconds.&lt;/p&gt;

&lt;p&gt;There is a consensus upgrade known as Alpenglow, which is designed to improve the finality time to around 150ms. The current release plan by Anza suggests it might be enabled on mainnet as soon as 28 September 2026, although Anza's schedules are tentative. Once that happens, the commitment levels will still apply, but the waiting time for &lt;code&gt;finalized&lt;/code&gt; should be much shorter than it is today.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three levels
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Level&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Typical delay&lt;/th&gt;
&lt;th&gt;Can it roll back?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;processed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The queried node has executed the block&lt;/td&gt;
&lt;td&gt;Immediate&lt;/td&gt;
&lt;td&gt;Yes, if the block is skipped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;confirmed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;More than two thirds of stake has voted on the block&lt;/td&gt;
&lt;td&gt;Usually a few slots, so around a second or less&lt;/td&gt;
&lt;td&gt;Practically never&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;finalized&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The block has reached maximum lockout (the node treats it as rooted)&lt;/td&gt;
&lt;td&gt;About 32 slots after confirmed, so roughly 11 to 13 seconds depending on slot time&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It is worth noting that if you do not pass a commitment level, the RPC will use &lt;code&gt;finalized&lt;/code&gt; by default. This is the safest option, but it is also the slowest. Many applications are waiting longer than they need to because of this default, without having made a decision about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where commitment levels come up
&lt;/h2&gt;

&lt;p&gt;As you use the RPC endpoints, you can see there are a few places where commitment levels come up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data requests
&lt;/h3&gt;

&lt;p&gt;When you make reads, for example with &lt;code&gt;getAccountInfo&lt;/code&gt;, &lt;code&gt;getBalance&lt;/code&gt; or &lt;code&gt;getTokenAccountBalance&lt;/code&gt;, you can pass in the commitment level. The same account may return a different value at each of the three levels. Each value is correct for its level. Similarly, when you subscribe to data, you can specify the commitment level. This applies to WebSocket subscriptions such as &lt;code&gt;accountSubscribe&lt;/code&gt; and &lt;code&gt;logsSubscribe&lt;/code&gt;, and to Yellowstone gRPC. A subscription at &lt;code&gt;processed&lt;/code&gt; will give you events earliest, but some of those events may belong to a block that is later skipped.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sending transactions
&lt;/h3&gt;

&lt;p&gt;When using the &lt;code&gt;sendTransaction&lt;/code&gt; method, you should keep the commitment level consistent within the flow. There is a &lt;code&gt;preflightCommitment&lt;/code&gt; parameter which decides which state the simulation runs against. Solana's documentation says that this should always be the same commitment level that you used when fetching the blockhash. This applies to &lt;code&gt;simulateTransaction&lt;/code&gt; as well. You might also be concerned about a particular piece of data changing between when you build the transaction and submit it. Reading that data at the same commitment level as the preflight helps to avoid this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fetching a blockhash
&lt;/h3&gt;

&lt;p&gt;You can pass a commitment level to &lt;code&gt;getLatestBlockhash&lt;/code&gt; as well. This matters more than you might expect. A blockhash is only valid for around 151 blocks, which is roughly 60 to 90 seconds. If you fetch the blockhash at &lt;code&gt;finalized&lt;/code&gt;, it is already around 32 slots old when you receive it. This means you lose around 11 to 13 seconds of the time in which it is valid. For this reason, it is generally recommended to fetch the blockhash at &lt;code&gt;confirmed&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking a transaction
&lt;/h3&gt;

&lt;p&gt;When you check on a transaction, for example using &lt;code&gt;signatureSubscribe&lt;/code&gt; or &lt;code&gt;getSignatureStatuses&lt;/code&gt;, the response will tell you which commitment level the transaction has reached. A transaction that has landed at &lt;code&gt;processed&lt;/code&gt; is not the same as a transaction that has landed at &lt;code&gt;confirmed&lt;/code&gt;. It may still be skipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which commitment level should I use?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Displaying a balance in a wallet&lt;/td&gt;
&lt;td&gt;&lt;code&gt;confirmed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fresh enough, will not flicker back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deciding to release goods, credit an account, or settle&lt;/td&gt;
&lt;td&gt;&lt;code&gt;finalized&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Irreversible actions need irreversible state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A trading bot reacting to a price move&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;processed&lt;/code&gt; (with rollback handling) or a shred-level feed&lt;/td&gt;
&lt;td&gt;Earliest signal, and the bot tolerates reverts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fetching a blockhash to sign&lt;/td&gt;
&lt;td&gt;&lt;code&gt;confirmed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fresh and safe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Waiting for your own transaction before the next step&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;confirmed&lt;/code&gt;, and &lt;code&gt;finalized&lt;/code&gt; for the last step of a payment&lt;/td&gt;
&lt;td&gt;Balance speed against certainty per step&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An indexer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;confirmed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Avoids having to implement rollback logic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The trading bot case is a little different from the others. There is a way to observe Solana that is earlier than any of the commitment levels. This is the shred broadcast from the leader, which happens before any node has processed the block. We have written about this in our &lt;a href="https://orbitflare.com/blog/fundamentals/shredstream" rel="noopener noreferrer"&gt;shredstream article&lt;/a&gt;. Trading systems that need the earliest possible signal may use this, but they need to be able to handle the fact that some of the blocks they see will be skipped later on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;p&gt;Most of the problems people run into come from using different commitment levels in the same flow. Some examples are below.&lt;/p&gt;

&lt;p&gt;The first is a balance that appears to change back. This can happen when one call is made at &lt;code&gt;processed&lt;/code&gt; and another at &lt;code&gt;finalized&lt;/code&gt;. The user sees one balance, then a different one. The solution is to make both calls at the same commitment level.&lt;/p&gt;

&lt;p&gt;The second is a transaction that appears and then disappears. This happens when a transaction is seen at &lt;code&gt;processed&lt;/code&gt;, the application acts on it, and then the block is skipped. It is safer to act on transactions at &lt;code&gt;confirmed&lt;/code&gt; or later.&lt;/p&gt;

&lt;p&gt;The third is an expired blockhash. This can happen when the blockhash was fetched at &lt;code&gt;finalized&lt;/code&gt;. As explained above, the blockhash is older at this level, so it may expire before the transaction lands. Fetching at &lt;code&gt;confirmed&lt;/code&gt; avoids this.&lt;/p&gt;

&lt;p&gt;The fourth is a mismatch in preflight. This happens when the transaction is simulated against state that is different from the state it actually executes against, or when the preflight commitment does not match the blockhash commitment. Both should be aligned.&lt;/p&gt;

&lt;p&gt;The fifth is an event that is later reverted. This can happen when a subscription at &lt;code&gt;processed&lt;/code&gt; delivers an event, the application writes it to a database, and the block is then skipped. You may want to subscribe at &lt;code&gt;confirmed&lt;/code&gt; instead, or implement rollback handling in the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping it consistent
&lt;/h2&gt;

&lt;p&gt;It is a good idea to decide on a commitment level for each part of your system and pass it explicitly. Relying on library defaults is not recommended, because the defaults vary between libraries and are often &lt;code&gt;finalized&lt;/code&gt;. A common approach is to use &lt;code&gt;confirmed&lt;/code&gt; for reads, &lt;code&gt;finalized&lt;/code&gt; for settlement, and &lt;code&gt;processed&lt;/code&gt; (or shreds) with rollback handling for anything that needs to be fast. It is also helpful to record the commitment level alongside each result, so that if two values disagree you can see why.&lt;/p&gt;

&lt;p&gt;The commitment level is passed in the same way whether you are using JSON-RPC or Yellowstone gRPC, so the same considerations apply on the streaming side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Commitment levels are how you choose between speed and certainty on Solana. &lt;code&gt;processed&lt;/code&gt; is the fastest option but it is provisional. &lt;code&gt;confirmed&lt;/code&gt; is the sensible default for most cases. &lt;code&gt;finalized&lt;/code&gt; should be used for anything that cannot be undone. Set the level explicitly, keep it consistent within each flow, and remember that if you need to react faster than any commitment level allows, the leader's own broadcast is available before any node has processed the block.&lt;/p&gt;

&lt;p&gt;OrbitFlare's &lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;RPC plans&lt;/a&gt; support every commitment level on every endpoint. The &lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;gRPC service&lt;/a&gt; streams at the commitment level of your choice, and &lt;a href="https://docs.orbitflare.com/data-streaming/jetstream-v2" rel="noopener noreferrer"&gt;Jetstream&lt;/a&gt; provides the view from before any commitment level exists.&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/docs/rpc" rel="noopener noreferrer"&gt;Solana RPC documentation: configuring state commitment&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/docs/core/transactions/confirmation" rel="noopener noreferrer"&gt;Solana documentation: transaction confirmation and expiration&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/upgrades/reduced-slot-times" rel="noopener noreferrer"&gt;Reduced slot times (SIMD-0525)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.anza.xyz/blog/alpenglow-a-new-consensus-for-solana" rel="noopener noreferrer"&gt;Alpenglow: a new consensus for Solana (Anza)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/anza-xyz/agave/wiki/v4.3-Release-Schedule" rel="noopener noreferrer"&gt;Agave v4.3 release schedule (Anza)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/blog/fundamentals/shredstream" rel="noopener noreferrer"&gt;What is Shredstream?&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.orbitflare.com/data-streaming/jetstream-v2" rel="noopener noreferrer"&gt;Jetstream V2 docs&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>solana</category>
      <category>orbitflare</category>
      <category>rpc</category>
      <category>web3</category>
    </item>
    <item>
      <title>Network Infrastructure for Low-Latency Solana Trading</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Mon, 07 Sep 2026 20:39:44 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/network-infrastructure-for-low-latency-solana-trading-5cl</link>
      <guid>https://dev.to/orbitflarerpc/network-infrastructure-for-low-latency-solana-trading-5cl</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8cmtkdchcrw96hbnx1v2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8cmtkdchcrw96hbnx1v2.png" alt="Cover banner" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Solana Latency Is Different
&lt;/h2&gt;

&lt;p&gt;We've watched teams overinvest in every part of the stack regardless of whether they actually need each piece.&lt;/p&gt;

&lt;p&gt;This is a problem because low latency trading infrastructure on Solana is different and it has more moving parts than what you might be used to. This guide will focus on infrastructure decisions that are specific to Solana's architecture, and how the architecture determines your infrastructure choices. It is meant for traders, bot developers, and infrastructure engineers building systems for trading or bots. We'll focus specifically on end-to-end latency on Solana (from seeing an on-chain event, to getting a transaction into a block). If you are building a wallet or an analytics product, a lot of this will be more than you need, but the first two layers will still save you money.&lt;/p&gt;

&lt;p&gt;There are four main layers that we'll cover: placement, observation, submission and routing. The first two are the most applicable for any Solana users. The latter two are applicable for more sophisticated trading bots, and can be deferred as needs arise.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Placement: refers to the geographic proximity of your servers to Solana's validator network.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Observation: how you observe the chain, from raw shreds, via the gRPC API, WebSockets or polling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Submission: how you submit transactions (with staked TX lanes, via the bundle API or otherwise)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Routing: determining the optimal region to send transactions to. This is because Solana's current architecture means that the leader (the node that produces blocks) changes every 4 slots, which is approximately 1.4s at the current slot time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A quick note on the numbers in this article. Solana's mainnet slot time was 400ms for most of the network's life, but it was reduced to 350ms on 21 August 2026 (epoch 1020) as the first stage of SIMD-0525. Further reductions to 300ms, 250ms and eventually 200ms are planned, each behind its own feature gate, and testnet is already on the 250ms to 200ms stage. So a leader window today is 4 x 350ms = 1.4s. We've used the 350ms figure throughout. If you are reading this after another reduction has been activated, just adjust the arithmetic. More on this at the &lt;a href="https://solana.com/upgrades/reduced-slot-times" rel="noopener noreferrer"&gt;reduced slot times page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Latency on Solana is relative to the leader, and the leader changes every four slots (about 1.4 seconds at 350ms slots). Whatever is fast in one region will be slow for most of the schedule.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reads are more important than writes. Seeing an event earlier makes every decision after it better. A faster submission path only helps once you've already decided.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Raw shreds are the earliest point where you can observe the chain. Anything that works off processed blocks is at least one processing step behind.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unstaked connections are the first to be dropped during congestion. A staked (prioritized) write path is what keeps your transactions flowing in the exact conditions you built the system for.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build for the worst hour, not the average hour. Average numbers don't tell you anything about what happens during a token launch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alpenglow is expected to bring finality down to around 150ms (sometimes 100ms). It doesn't remove the geographic component of latency, so placement and routing still matter after it ships.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Layer One: Placement
&lt;/h2&gt;

&lt;p&gt;Placement is the most fundamental aspect of trading infrastructure on Solana. The next three layers are important but they can only go so far to improve the latency if your servers are far from the leader.&lt;/p&gt;

&lt;p&gt;Solana's design has three properties that impact your placement.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Validators are spread globally, and the leader schedule walks through them in proportion to the stake they control. So the more stake there is in a region, the more often the leader is in that region. As of 2026 Europe is the largest cluster by a wide margin and Frankfurt in particular is the single biggest concentration of stake.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Blocks are produced by a leader who changes every 4 slots (approximately 1.4s), and the schedule is deterministic. The leader schedule for an epoch is calculated from the ledger state at the start of the previous epoch, so it is known ahead of time. An epoch is 432,000 slots, which at 350ms per slot works out to roughly 42 hours.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;While producing a block, the leader splits it up into messages called shreds (erasure coding means that there are extra coding shreds, so any given section of a block can be recovered if some of the data shreds go missing), and broadcasts them via its peer-to-peer network, Turbine, while the block is still being built. Nodes then have to recombine the shreds and replay the transactions to reconstruct the block.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Turbine is a multi-layered tree structure, with a fanout of 200 in each layer, and propagation moves from the root to the leaves. The process is documented in the &lt;a href="https://docs.anza.xyz/consensus/turbine-block-propagation" rel="noopener noreferrer"&gt;Turbine docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For any given block, a user that is observing raw shreds will observe the block much faster than users via RPC. RPCs will report blocks at processed commitment (which requires replaying the block on the node itself) which introduces another hundreds of milliseconds or potentially an entire slot of latency on top of however long the shreds took to arrive.&lt;/p&gt;

&lt;p&gt;These three properties mean that you can expect to see a pattern of fast and slow time, where you will be very fast when the leader is close by, but slower during the rest of the schedule. A tradeoff can be made between costs and this fast/slow time, depending on your strategy.&lt;/p&gt;

&lt;p&gt;Some options for placement, in approximate increasing order of cost and complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Have a server in a single region. Ideally this would be where a lot of stake is (e.g. Frankfurt, Amsterdam, the US east coast). This would mean that your system is slow for a good part of the schedule, but the cost is much lower. If you are using unstaked routes, it would also mean your transactions are dropped first during congestion (which is why we recommend at least one staked connection).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have servers in multiple regions. This is the preferred option for latency-sensitive trading systems. By spreading servers closer to each of the leaders, and submitting from whichever one is closest to the current leader, you can minimize the impact of a leader being far away, and the cost is still reasonable given the value. Europe plus one US region covers most of the schedule in practice. This is the part of the infrastructure that is the least obvious on how to build, but also the most important for overall latency. It may not be obvious where to put servers initially, but we've seen where a lot of stake is concentrated, and can advise on it. We also publish per-region pages like &lt;a href="https://orbitflare.com/solana-rpc/frankfurt" rel="noopener noreferrer"&gt;Solana RPC in Frankfurt&lt;/a&gt; and &lt;a href="https://orbitflare.com/solana-rpc/new-york" rel="noopener noreferrer"&gt;Solana RPC in New York&lt;/a&gt; so you can see where the infrastructure actually is.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run your own node next to your bot (colocation). This means a Solana node on the same host or in the same rack as your strategy, near stake, so you remove a network hop on both the read and the write side. It is the fastest option and also the most expensive, since a healthy node needs fast NVMe, 100+ Mbps of Turbine traffic, and somebody on call when it breaks.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some other important points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reads are more important than writes because being able to see data faster gives you a more substantial edge. It helps you make all other decisions faster (including transaction submission). The best trading strategies have to do with acting faster than other people, so this matters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Network latency between continents is a real bottleneck. The current minimum round-trip time between the US east coast and Europe is approximately 70-90 milliseconds over good fiber, and this is impossible to build around. This is why it's so important to have servers in each region.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alpenglow, the next major Solana upgrade, is expected to have much lower finality times (around 150ms median, sometimes 100ms). It won't remove the geographic component of latency or obviate the importance of placement and routing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The network isn't always under maximum capacity. It is important to build a system that is optimized for times of high congestion because many strategies will make money during that time, and congestion is worst during periods of token launches. You can't build your infrastructure to handle average usage per hour. The system has to be able to hold up during times of launch.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Layer Two: Observing the Chain
&lt;/h2&gt;

&lt;p&gt;There are five different points at which you can observe the chain. They are listed here from earliest to latest. Each of them is the right choice for some use case. The expensive mistake is using one of the later ones for a strategy that is sensitive to latency, and then trying to make up the difference in code.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Observation point&lt;/th&gt;
&lt;th&gt;What you see&lt;/th&gt;
&lt;th&gt;Relative timing&lt;/th&gt;
&lt;th&gt;Fits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Raw shreds&lt;/td&gt;
&lt;td&gt;Block fragments as the leader broadcasts them&lt;/td&gt;
&lt;td&gt;Earliest&lt;/td&gt;
&lt;td&gt;Sniping, liquidations, anything reacting to a single event&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shred-derived gRPC&lt;/td&gt;
&lt;td&gt;Transactions reconstructed from shreds and decoded&lt;/td&gt;
&lt;td&gt;Near earliest&lt;/td&gt;
&lt;td&gt;Copy trading, sniping with less client complexity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Geyser gRPC (Yellowstone)&lt;/td&gt;
&lt;td&gt;Account and transaction updates as the node processes the block&lt;/td&gt;
&lt;td&gt;After processing&lt;/td&gt;
&lt;td&gt;Market making, indexing, state tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebSocket subscriptions&lt;/td&gt;
&lt;td&gt;Notifications after the node processes and commits&lt;/td&gt;
&lt;td&gt;Later&lt;/td&gt;
&lt;td&gt;Dashboards, alerts, non-critical bots&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RPC polling&lt;/td&gt;
&lt;td&gt;Whatever you ask for, when you ask&lt;/td&gt;
&lt;td&gt;Latest&lt;/td&gt;
&lt;td&gt;Research, reconciliation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The difference between raw shreds and Geyser gRPC is the block processing time on the node. In most setups this is the largest delay that can actually be avoided. We have written about this in more detail in our &lt;a href="https://orbitflare.com/blog/fundamentals/shredstream" rel="noopener noreferrer"&gt;shredstream article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some things to know before choosing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Shred data is raw. A full shred stream is somewhere in the range of 50-100 Mbps of UDP traffic, and to turn it into transactions you need to do &lt;a href="https://github.com/orbitflare/shredstream-decode-example" rel="noopener noreferrer"&gt;deshredding, Reed-Solomon recovery, and deserialization&lt;/a&gt;. This has to happen somewhere, either in your own code or in a service. In our experience it is the biggest single leverage point in the whole stack, and it's what &lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;Jetstream gRPC&lt;/a&gt; is for: transactions reconstructed from shreds sourced at the top of Turbine, delivered over a normal gRPC stream, with the deshredding done on our side.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Match the level of detail to the decision. Shred-level streams are faster partly because they leave out inner instructions and full metadata. Yellowstone gives you all of that (inner instructions, account updates and so on) but it arrives one processing step later. Most serious systems use both. The shred-level feed is the hot path that tells you something happened, and Yellowstone is the structured source of truth that you check before acting on state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commitment levels are a choice, not a default. If your logic waits for "confirmed" or "finalized", you are waiting hundreds of milliseconds to whole seconds longer than "processed". Sometimes that fork protection is what you want. It should just be a decision you made and not something you inherited from a code sample.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Layer Three: Submitting Transactions
&lt;/h2&gt;

&lt;p&gt;Seeing an event early is not much use if your transaction doesn't land. During congestion the leader's transaction processing unit (TPU) is saturated, and Solana decides whose connections get served first based on stake. This is the &lt;a href="https://solana.com/developers/guides/advanced/stake-weighted-qos" rel="noopener noreferrer"&gt;stake-weighted QoS&lt;/a&gt; mechanism, which gives stake-weighted priority to 80% of the leader's TPU capacity. There are four ways to get a transaction in, and &lt;a href="https://orbitflare.com/blog/fundamentals/how-to-land-transactions-on-solana" rel="noopener noreferrer"&gt;our comparison&lt;/a&gt; covers them in more depth. In short:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Plain RPC forwarding. The node forwards your transaction to the leader over an unstaked connection. This is fine when the network is quiet and is the first thing to be dropped when it isn't.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stake-weighted QoS lane. Your transaction goes over a staked connection and is served before unstaked traffic. This should be the default for anything high volume.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Jito bundles. A group of up to 5 transactions that execute sequentially and atomically at the top of a Jito-enabled leader's block. Bundles compete with each other on tips. If any transaction in the bundle fails, none of them are committed. This is the tool for multi-leg strategies and for bidding on priority explicitly. See &lt;a href="https://docs.jito.wtf/" rel="noopener noreferrer"&gt;Jito's docs&lt;/a&gt; for the details.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Direct TPU forwarding. Your own forwarder speaks QUIC directly to the leader's TPU. This is the fastest option when you are colocated and staked, and unreliable when you are not.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Priority fees and tips sit above all four of these. A transaction paying the base fee on the best connection will still lose to a worse connection that pays more. Fees are bids in an auction, and it is a mistake to treat them as a cost to be minimized.&lt;/p&gt;

&lt;p&gt;The rule we give people is: bundles when you need atomicity, the staked lane for everything else, and direct forwarding only if you are colocated and staked. If you'd rather not build this layer yourself, there are landing services for it. OrbitFlare's Apex, for example, combines Shredstream-routed submission, Jito bundle support, and stake-weighted QoS behind one endpoint, with per-transaction analytics so you can see the landing rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer Four: Routing Between Regions
&lt;/h2&gt;

&lt;p&gt;Once you have servers in more than one region and you have the leader schedule, the router has one job per transaction, which is to decide which region sends it. It needs three inputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The current slot and the upcoming leaders. These come from the deterministic schedule via &lt;a href="https://solana.com/docs/rpc/http/getleaderschedule" rel="noopener noreferrer"&gt;getLeaderSchedule&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A mapping from validator identity to datacenter region. This has to be built by parsing gossip continuously, because validators move and the mapping goes stale.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The latency from each of your regions to each leader region. This should be measured with your own probes and not taken from a published ping table (those are someone else's numbers from someone else's rack).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output is something like "submit from region X, and also from region Y if the next leader is there". You cover the slot boundary by targeting the current leader and the next one, and then you stop. Resending from every region for seconds at a time is how bots burn through rate limits, get dropped as duplicates, and land in the wrong slots. It is the most common routing mistake we see, and usually it's someone's idea of being safe.&lt;/p&gt;

&lt;p&gt;Routing helps on the read side as well. A feed in Frankfurt sees Frankfurt blocks first, so a strategy that reacts to events globally should consume feeds from several regions and deduplicate by signature. The same shred data arriving twice is redundancy, not two events.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Alpenglow Changes, and What It Doesn't
&lt;/h2&gt;

&lt;p&gt;Alpenglow is Solana's consensus overhaul and no infrastructure guide written in 2026 can really skip it. The governance vote (SIMD-0326) passed in early September 2025 with 98.27% of the participating stake voting yes. Community validator testing started in May 2026. Anza's Agave v4.3 release schedule has mainnet feature activation targeted for 28 September 2026, with the usual caveat that Anza's schedules are tentative. Two pieces of it matter for this article.&lt;/p&gt;

&lt;p&gt;Votor replaces Tower BFT voting. Votes move off chain into lightweight aggregated certificates, and finality drops from about 12.8 seconds to around 150ms median (sometimes as fast as 100ms). Vote transactions also stop taking up block space.&lt;/p&gt;

&lt;p&gt;Rotor replaces Turbine's multi-hop tree with a single-hop, stake-weighted relay broadcast. Blocks are still erasure-coded into shreds. In the whitepaper's numbers, with 1 Gb/s of bandwidth, transmitting 1,500 shreds takes about 18ms.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.anza.xyz/blog/alpenglow-a-new-consensus-for-solana" rel="noopener noreferrer"&gt;Alpenglow whitepaper&lt;/a&gt; has the full detail. For your infrastructure the effects are fairly specific:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The read side stays shred-first. Rotor still uses shreds, so the earliest observation point is still the propagation layer and not the processed block. Faster propagation actually makes the node's processing gap a bigger share of the total delay, not smaller.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Geography still matters. In Anza's simulations the consensus overhead is roughly a 2x multiplier on the raw network latency, so finality is bounded by how far the leader is from the stake supermajority. A leader in New York with most of the stake in Europe is still looking at something like 200ms. Placement and leader-aware routing don't change.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Congestion moves, it doesn't go away. Freed-up vote capacity adds throughput headroom, and demand has always grown to fill block space. Keep the prioritized write path.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Block production gets more regular. Alpenglow drops Proof of History timing in favor of fixed slot timeouts, which should make your latency measurements more repeatable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plan for Alpenglow as the current model getting faster and not as a replacement for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ultra-Low Latency: What Separates the Top Tier
&lt;/h2&gt;

&lt;p&gt;Everything above gives you a fast stack. The tier where trading firms compete with each other adds three more decisions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;VPS or bare metal. A Solana VPS near stake is the right starting point (cheap, deployed in minutes, milliseconds from the regional leader). The problem is that virtualized neighbors burn your CPU and add jitter that an average ping never shows. The top tier moves to bare metal or &lt;a href="https://orbitflare.com/products/dedicated-nodes" rel="noopener noreferrer"&gt;trader nodes&lt;/a&gt;, meaning a machine that runs only your strategy, because at that level tail consistency matters more than average speed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Temporal submission. Default routing targets the current leader. Because the schedule is deterministic you can instead send to the next leader while it is still building its block, and land at the start of its window rather than the end of the previous one. This is a legitimate use of public information and it is how the fastest bots make the 1.4 second rotation work for them instead of against them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Proximity to the block engine, not just the validators. For bundle strategies, distance to the Jito block engine relays matters as much as distance to the leaders. Colocating your submission in a region with block engine presence removes one more hop from the write path that is most sensitive to latency.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The principle at this tier does not change. Each upgrade should remove one identifiable stage from the loop, and if you can't say which milliseconds an upgrade removes, you are buying marketing and not speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting the Layers Together
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;Placement&lt;/th&gt;
&lt;th&gt;Read path&lt;/th&gt;
&lt;th&gt;Write path&lt;/th&gt;
&lt;th&gt;Routing&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;New-pool sniping&lt;/td&gt;
&lt;td&gt;Multi-region near stake, or colocated&lt;/td&gt;
&lt;td&gt;Shred-derived gRPC&lt;/td&gt;
&lt;td&gt;Staked lane, or bundle with edge-based tip&lt;/td&gt;
&lt;td&gt;Leader-aware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Copy trading&lt;/td&gt;
&lt;td&gt;Multi-region&lt;/td&gt;
&lt;td&gt;Shred-derived gRPC with wallet filters&lt;/td&gt;
&lt;td&gt;Staked lane&lt;/td&gt;
&lt;td&gt;Leader-aware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Atomic arbitrage&lt;/td&gt;
&lt;td&gt;Colocated near block engine and stake&lt;/td&gt;
&lt;td&gt;Raw shreds plus Yellowstone for pool state&lt;/td&gt;
&lt;td&gt;Jito bundles&lt;/td&gt;
&lt;td&gt;Nearest block engine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Market making&lt;/td&gt;
&lt;td&gt;Single or dual region&lt;/td&gt;
&lt;td&gt;Yellowstone gRPC&lt;/td&gt;
&lt;td&gt;Staked lane&lt;/td&gt;
&lt;td&gt;Leader-aware for cancels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Liquidations&lt;/td&gt;
&lt;td&gt;Multi-region&lt;/td&gt;
&lt;td&gt;Shred-derived for oracle updates&lt;/td&gt;
&lt;td&gt;Jito bundles&lt;/td&gt;
&lt;td&gt;Leader-aware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wallet or payments app&lt;/td&gt;
&lt;td&gt;Single region&lt;/td&gt;
&lt;td&gt;WebSockets&lt;/td&gt;
&lt;td&gt;Staked lane or reliable RPC with retries&lt;/td&gt;
&lt;td&gt;Not needed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pattern is the same in every row. The read path depends on how early you need to see events. The write path depends on whether you need atomicity. The placement depends on how much of the leader schedule you need to be fast for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the Milliseconds Go
&lt;/h2&gt;

&lt;p&gt;If you walk through one loop from event to landing, the optimization targets pick themselves.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The leader builds the block and broadcasts shreds. This is fixed by the protocol, there is nothing to optimize.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Shreds reach a node. This is network distance to the leader, so it's a placement problem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The node processes the block and exposes it. You skip this entirely if shreds are your event source. Otherwise you pay the node's processing time. This is your read path choice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your feed delivers events to your process. Local network plus serialization. Minimal if you are colocated.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Decode, decide, build, sign. This is your own code, and it should be under a millisecond.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your transaction reaches the leader. Network distance plus TPU queuing. Placement and write path.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The leader includes it. Priority fee, stake, or tip. Write path.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Stages two, three and six dominate, and all three are infrastructure decisions. Stage five is the one that everybody over-optimizes.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Benchmark Before You Buy
&lt;/h2&gt;

&lt;p&gt;Vendor numbers are measured from the vendor's rack to their nearest leader. You should measure from wherever your bot is actually going to run. The fastest RPC for trading is not the one with the best number on a landing page, it is the one that wins these four measurements from your own servers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Observation lag. Timestamp the same transaction on each feed (shred-derived, Yellowstone, WebSocket) and take the spread. That spread is the value of the earlier feed, in your region, on your traffic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Landing rate by leader region. Send a cheap transaction through each write path every few seconds for a week. Record the slot it landed in relative to the slot you sent it in, and bucket the results by the leader's region. Then look at the worst hours (token launches, liquidation cascades) and not the averages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fill quality. For a live strategy, this is the executed price against the price at the time you observed the event. It is the only number that proves the stack is actually early.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Feed continuity. Count gaps and reconnects per day on each feed. A feed that is 5ms faster but drops twice a day during launches is slower in expectation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our &lt;a href="https://orbitflare.com/benchmarks" rel="noopener noreferrer"&gt;benchmarks page&lt;/a&gt; is built on exactly this methodology. It is run from multiple regions against the live leader schedule, so the numbers can be reproduced and don't have to be taken on faith.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Optimizing code before infrastructure. A sub-millisecond decoder behind a feed that is 300ms late is a fast bot that is always late.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One region. You are fast for a minority of the schedule and slow for the rest.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An unstaked write path in production. It works in testing and then fails during exactly the launches you built the bot for.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Resending forever. This burns rate limits, causes late landings, and makes your own metrics lie to you.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A zero priority fee on a fast path. Connection quality and fees multiply. If either one is zero you still lose the auction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Measuring averages. The average hides the congested hours, and that is where the edge is. Measure the tail.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not reconciling. Without the observed slot, submit time and landed slot for each transaction, you can't tell which layer went slow.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What does low-latency network infrastructure for Solana trading look like?
&lt;/h3&gt;

&lt;p&gt;Servers placed near stake concentrations, a data feed that is as early as possible (ideally shred-level), a prioritized submission path, and routing that follows the rotating leader schedule. The whole point is to shrink the loop from an on-chain event to your responding transaction landing in a block.&lt;/p&gt;

&lt;h3&gt;
  
  
  How many regions do I need to trade on Solana?
&lt;/h3&gt;

&lt;p&gt;One region near stake (Frankfurt, Amsterdam, or the US east coast) is a sensible start. Two or three regions covering Europe and North America will handle most of the leader schedule. Beyond that the returns diminish quickly once the stake-heavy regions are covered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Are shreds faster than gRPC?
&lt;/h3&gt;

&lt;p&gt;Yes. Shreds stream while the leader is still building the block. Yellowstone gRPC delivers after the node has processed the block, which adds the processing time on top. Shred-based gRPC services reconstruct transactions from shreds and keep almost all of that lead, and you don't have to do the deshredding yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I use Jito bundles?
&lt;/h3&gt;

&lt;p&gt;Only if you need atomicity (several transactions that must land together, as in multi-leg arbitrage) or you want to bid for priority explicitly through tips. For everything else a single transaction on a staked lane is the better trade.&lt;/p&gt;

&lt;h3&gt;
  
  
  Will Alpenglow make low-latency infrastructure obsolete?
&lt;/h3&gt;

&lt;p&gt;No. Finality drops to around 150ms and Rotor speeds up propagation, but both are still bounded by the physical network latency between leaders and stake. Shreds stay the earliest observation point, and placement near stake still decides who sees and lands first.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I measure before choosing an RPC provider?
&lt;/h3&gt;

&lt;p&gt;Observation lag between feed types, landing rate bucketed by leader region during congested hours, fill quality against the price at observation, and feed continuity. Measure from your own servers for at least a week and weight the worst hours, because averages hide exactly the conditions you are building for.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does any of this change for AI trading agents?
&lt;/h3&gt;

&lt;p&gt;No. An agent in the trading loop runs the same event-to-landing loop as a rule-based bot: listen on a feed, decide, submit. The only difference is that the decision step takes longer, which makes the milliseconds saved everywhere else more valuable, not less.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four Decisions
&lt;/h2&gt;

&lt;p&gt;Where do you sit relative to a leader that moves every four slots? How early do you observe the chain? How does your transaction get into a saturated leader? And which region submits as the schedule rotates? Whether you are a solo bot operator or a firm evaluating providers, the framework is the same. Place near stake in more than one region. Read the hot path from shreds or a shred-derived stream. Write through a staked lane, or bundles when you need atomicity. Route by the schedule. Then measure observation lag, landing rate in the worst hour, and fill quality, and let the data decide the next upgrade. Alpenglow will make all of this faster. It won't make any of it optional.&lt;/p&gt;

&lt;p&gt;The OrbitFlare stack maps onto the four layers directly: &lt;a href="https://orbitflare.com/products/shredstream" rel="noopener noreferrer"&gt;Shredstream&lt;/a&gt; and &lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;Jetstream gRPC&lt;/a&gt; on the read side, staked transaction landing in the &lt;a href="https://orbitflare.com/pricing" rel="noopener noreferrer"&gt;RPC plans&lt;/a&gt; on the write side, and &lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;eleven regions&lt;/a&gt; to route across. Start with the measurements, and the rest follows from the data.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://orbitflare.com" rel="noopener noreferrer"&gt;OrbitFlare&lt;/a&gt; builds Solana infrastructure for teams that need speed: &lt;a href="https://orbitflare.com/products/rpc-nodes" rel="noopener noreferrer"&gt;RPC nodes&lt;/a&gt;, &lt;a href="https://orbitflare.com/products/solana-grpc" rel="noopener noreferrer"&gt;Jetstream gRPC streaming&lt;/a&gt;, trading APIs, and &lt;a href="https://orbitflare.com/products/shredstream" rel="noopener noreferrer"&gt;Shredstream&lt;/a&gt;. &lt;a href="https://orbitflare.com/contact" rel="noopener noreferrer"&gt;Get in touch&lt;/a&gt; if you want help designing your stack.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.anza.xyz/consensus/turbine-block-propagation" rel="noopener noreferrer"&gt;Solana documentation on Turbine&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.anza.xyz/blog/alpenglow-a-new-consensus-for-solana" rel="noopener noreferrer"&gt;Alpenglow: a new consensus for Solana (Anza)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/upgrades/reduced-slot-times" rel="noopener noreferrer"&gt;Reduced slot times (SIMD-0525)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/anza-xyz/agave/wiki/v4.3-Release-Schedule" rel="noopener noreferrer"&gt;Agave v4.3 release schedule (Anza)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/blog/fundamentals/shredstream" rel="noopener noreferrer"&gt;What is Shredstream?&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/blog/fundamentals/how-to-land-transactions-on-solana" rel="noopener noreferrer"&gt;How to land transactions on Solana&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/developers/guides/advanced/stake-weighted-qos" rel="noopener noreferrer"&gt;Stake-weighted QoS guide&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.jito.wtf/" rel="noopener noreferrer"&gt;Jito bundle documentation&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.orbitflare.com/data-streaming/jetstream-v2" rel="noopener noreferrer"&gt;Jetstream V2 docs&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://orbitflare.com/benchmarks" rel="noopener noreferrer"&gt;OrbitFlare benchmarks&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>solana</category>
      <category>trading</category>
      <category>lowlatency</category>
      <category>orbitflare</category>
    </item>
    <item>
      <title>The OrbitFlare SDK Comes to Go: Building a Slot Radar</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Mon, 03 Aug 2026 14:25:12 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/the-orbitflare-sdk-comes-to-go-building-a-slot-radar-27p6</link>
      <guid>https://dev.to/orbitflarerpc/the-orbitflare-sdk-comes-to-go-building-a-slot-radar-27p6</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7qqq8ejwa5m5k90be12w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7qqq8ejwa5m5k90be12w.png" alt="Cover Image" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The OrbitFlare SDK now speaks Go. It's the third language after Rust and TypeScript, and it ships the same surface as both: RPC, WebSocket, Yellowstone gRPC, and Jetstream clients, each in its own package, with the same builder pattern and the same connection plumbing handled for you. If you've used either of the other SDKs, you already know this one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/orbitflare/orbitflare-sdk-go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To show it off, we wanted to build something small that no other post on this blog has built. Every tutorial we've written so far watches transactions: a wallet ticker, a TPS meter, an indexer, a trade tracker. Nobody has watched the thing underneath all of them. Slots.&lt;/p&gt;

&lt;p&gt;A slot is the network's heartbeat. Every 400 milliseconds or so, some validator has the leader role, produces a block, and hands off. Sometimes a leader fails to produce and the slot is skipped. Your transactions land inside this rhythm, and if you send them, the rhythm decides your fate: who the current leader is, how far away the next one is, and whether slots are completing cleanly or dying.&lt;/p&gt;

&lt;p&gt;Jetstream v2 has a stream for exactly this, and the Go SDK ships it. &lt;code&gt;SubscribeSlots&lt;/code&gt; emits an event when a slot goes &lt;code&gt;ALIVE&lt;/code&gt; (first shred received), &lt;code&gt;COMPLETE&lt;/code&gt; (last shred received), or &lt;code&gt;DEAD&lt;/code&gt; (skipped or superseded). So the demo picked itself: a slot radar. One terminal screen showing the current slot and leader, the measured slot time, who's up next, and every skipped slot as it happens. Around 180 lines of Go, using two clients from the SDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;slot radar · epoch 1011

  slot 436945880 · leader Fd7b…69Nk
  measured slot time: 443ms avg over last 30

  next up:
    slot 436945884  Awes…vpLM  (in 4 slots, ~1.6s)
    slot 436945888  GYx8…3YGQ  (in 8 slots, ~3.2s)
    slot 436945892  EdFU…sk6w  (in 12 slots, ~4.8s)
    slot 436945896  5pPR…HzSm  (in 16 slots, ~6.4s)

  last 60 slots: ✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✗✗✗✗✓✓✓✓✓✓✓●
  skipped this session: 4  (latest: 436945871)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Clients
&lt;/h2&gt;

&lt;p&gt;Two builders, one per client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;rpcClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://ams.rpc.orbitflare.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;APIKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ORBITFLARE_LICENSE_KEY"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;jet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;jetstreamv2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://ams.jetstream.orbitflare.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every client accepts multiple URLs if you want failover, and the first one is the primary. That's the whole setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Schedule
&lt;/h2&gt;

&lt;p&gt;The slot stream tells us what's happening right now, but "who leads next" lives in the leader schedule, which is an RPC question. Two calls give us the schedule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rpcClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"getEpochInfo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Epoch&lt;/span&gt;        &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="s"&gt;`json:"epoch"`&lt;/span&gt;
    &lt;span class="n"&gt;AbsoluteSlot&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="s"&gt;`json:"absoluteSlot"`&lt;/span&gt;
    &lt;span class="n"&gt;SlotIndex&lt;/span&gt;    &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="s"&gt;`json:"slotIndex"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;epoch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;epochStart&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AbsoluteSlot&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SlotIndex&lt;/span&gt;

&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rpcClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"getLeaderSchedule"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;schedule&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;][]&lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;leaderBySlot&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;432&lt;/span&gt;&lt;span class="n"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idxs&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;schedule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;idxs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;leaderBySlot&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;epochStart&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;leader&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's one small trap here, and it's the reason for the &lt;code&gt;getEpochInfo&lt;/code&gt; call. The schedule comes back keyed by validator identity with slot indexes relative to the epoch start, not absolute slot numbers. Subtracting &lt;code&gt;slotIndex&lt;/code&gt; from &lt;code&gt;absoluteSlot&lt;/code&gt; gives you the epoch's first absolute slot, and adding that to each index turns the whole schedule into a flat &lt;code&gt;slot → leader&lt;/code&gt; map.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Slot Stream
&lt;/h2&gt;

&lt;p&gt;Now the live side. &lt;code&gt;SubscribeSlots&lt;/code&gt; returns a stream, and a goroutine drains it into a channel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;slots&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;jet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SubscribeSlots&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;slots&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SlotEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;slots&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main loop is one &lt;code&gt;select&lt;/code&gt; over two channels: slot events mutate state, and a 500ms ticker redraws the screen. This is the whole engine of the program:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetSlot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;maxSlot&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;maxSlot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SlotStatus_SLOT_STATUS_ALIVE&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;lastSlot&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;lastAlive&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsZero&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;timings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastAlive&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;lastSlot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lastAlive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SlotStatus_SLOT_STATUS_DEAD&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;skipped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skipped&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ticker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;leaderBySlot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxSlot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;skipped&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Epoch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Solana's 400ms slot time is a target, not a promise, and the honest way to measure the real one is the gap between consecutive &lt;code&gt;ALIVE&lt;/code&gt; events, since &lt;code&gt;ALIVE&lt;/code&gt; fires when the first shred of a slot reaches the network. Averaging the last 30 gaps gives you the network's actual current pace, measured from your own connection. Our run above says 443ms.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Render
&lt;/h2&gt;

&lt;p&gt;The render function walks state and prints. The next-up list scans forward from the current slot and collects the next four distinct leaders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;printed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;leaderBySlot&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;maxSlot&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;maxSlot&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;printed&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;maxSlot&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;leaderBySlot&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"    slot %d  %s  (in %d slots, ~%.1fs)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;short&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;maxSlot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;maxSlot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="m"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;printed&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
        &lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the tape, which maps the last 60 slots to one glyph each: &lt;code&gt;✓&lt;/code&gt; for complete, &lt;code&gt;●&lt;/code&gt; for alive, &lt;code&gt;✗&lt;/code&gt; for dead, and &lt;code&gt;·&lt;/code&gt; for slots we haven't heard about. A skipped slot shows up as a &lt;code&gt;✗&lt;/code&gt; in the tape the moment the network gives up on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/orbitflare/slot-radar.git
&lt;span class="nb"&gt;cd &lt;/span&gt;slot-radar
&lt;span class="nv"&gt;ORBITFLARE_LICENSE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ORBIT-... go run &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The schedule loads in a couple of seconds, the first slot event lands right after, and from there the radar just ticks. Leaders hand off every four slots, the measured slot time drifts between roughly 390 and 430 milliseconds depending on the day, and every few minutes a &lt;code&gt;✗&lt;/code&gt; appears when a leader misses its window.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the SDK Did
&lt;/h2&gt;

&lt;p&gt;The program never mentions reconnection, and that's the point. If the Jetstream connection drops, the stream re-establishes and keeps delivering. If the primary endpoint misbehaves and you gave the builder fallback URLs, the client rotates through them and brings the primary back when it recovers. Keepalives, retry backoff, and API key redaction in error output all come along without a line of your code, and they behave identically to the Rust and TypeScript SDKs, because the three are kept in lockstep.&lt;/p&gt;

&lt;p&gt;What's left in the source is the part that's actually yours: two RPC calls, one subscription, and a &lt;code&gt;select&lt;/code&gt; loop. That's the trade the SDK offers in every language now, including Go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/orbitflare/slot-radar" rel="noopener noreferrer"&gt;Full source: github.com/orbitflare/slot-radar&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/orbitflare/orbitflare-sdk-go" rel="noopener noreferrer"&gt;&lt;code&gt;orbitflare-sdk-go&lt;/code&gt; on GitHub&lt;/a&gt;&lt;/strong&gt; | &lt;strong&gt;&lt;a href="https://pkg.go.dev/github.com/orbitflare/orbitflare-sdk-go" rel="noopener noreferrer"&gt;pkg.go.dev reference&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.orbitflare.com/sdk/overview" rel="noopener noreferrer"&gt;Go SDK docs&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.orbitflare.com/data-streaming/jetstream-v2" rel="noopener noreferrer"&gt;Jetstream v2 docs&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you build something with the Go SDK, or hit an edge that should be smoother, come tell us on &lt;strong&gt;&lt;a href="https://discord.gg/orbitflare" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;&lt;/strong&gt;. We'd love to see what you ship.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>rpc</category>
      <category>orbitflare</category>
      <category>jetstream</category>
    </item>
  </channel>
</rss>
