Skip to main content

保持连接预热

冷启动发送中最慢的部分是建立连接,而不是 Apex。请在需要之前就打开连接,并保持其打开。
Rust 客户端会为您处理这一切。针对 Apex 端点 30 秒的空闲超时,它每秒 ping 一次,使用 0-RTT 恢复连接,并在发现断线后立即在后台重新握手。
  • 在启动时为每个进程和每个 Apex 端点创建一个客户端,而不是每次发送创建一个。各个流在这一个连接上多路复用。
  • 客户端的 Clone 开销很低,克隆出的副本共享同一个连接。给每个任务分发一个克隆。
  • health()reconnects_total()zero_rtt_resumptions_total() 导出到您的指标中,以便观察断线情况。
如果您自行实现 QUIC,请在远小于 30 秒空闲超时的间隔内发送 QUIC PING,并保留会话票据以用于 0-RTT。

从靠近 Apex 端点的位置发送

选择从您的发送方出发往返时间最短的 Apex 端点,并用 /ping 实际测量,而不是看地图猜测。每个 Apex 端点都会路由到离即将出块的领导者最近的验证者客户端,因此您只需要尽快到达端点。 如果您在多个区域运行,请从每个区域发送到各自最近的端点。将同一笔已签名交易发送到多个 Apex 端点是安全的,因为网络对一个签名只执行一次,但每一份副本都会计入您的速率限制。

根据交易价值确定小费

下限(标准等级为 0.001 SOL)是被接受的最低要求,并不是对每笔交易的建议值。
  • 小费为您的 Jito 出价提供资金:出价等于小费减去 5,000 lamports 基础费用。在竞争激烈的区块中,仅达到下限的出价可能会在拍卖中落败。质押加权路径和 TPU 路径仍会运行,但您放弃了三条路径中的一条。
  • 只在交易上链时支付小费,因此为重要交易设置更高的小费,在未上链时不会产生任何费用。
  • 让小费与上链的价值成比例。常规转账可以保持在下限。竞争性交易的小费应与抢先上链对您的价值成正比。
如果不确定自己的等级,可以从拒绝消息中读取下限:低于下限的错误会注明该值。

为每笔交易设置计算预算

Apex 把您送达领导者。随后领导者的调度器按优先费排序。如果没有计算预算,您就只能在队列末尾竞争。
  • 计算单元上限:在您的常规 RPC 上模拟交易,取其消耗的单元数,再加上约 10% 到 20% 的余量。未设置时的默认上限远高于大多数交易的需要,这会浪费您的优先级。
  • 计算单元价格:跟随您所写入账户的市场行情。以您的可写账户调用 getRecentPrioritizationFees 是一个合理的起始参考。
  • 将 ComputeBudget 指令放在交易的最前面
  • 以上适用于 legacy 和 v0 交易。交易 v1 改为在消息的 TransactionConfig 中设置预算,ComputeBudget 指令在那里不起作用。
本文档中的 memo 交易使用 100,000 单元的上限,因为 memo 程序的开销异常高。它不适合作为您自己上限的参考。请根据您自己的指令来确定大小。

确认每一次发送

响应中的签名表示已接受,而不是已上链。
  • 在 Solana RPC 上轮询 getSignatureStatuses,或使用 signatureSubscribe 订阅,直到状态为 confirmedfinalized
  • 检查 err 字段。交易可能上链但仍在链上执行失败。小费是交易的一部分,因此执行期间失败的交易也会回滚小费转账,您只需支付网络费用。
  • blockhash 过期后停止等待。跟踪 getLatestBlockhash 返回的 lastValidBlockHeight。一旦链超过该高度,交易就永远无法上链。
在 Rust 中,rpc::SolanaRpc::confirm(signature, timeout) 会执行轮询并返回 slot,超时时返回 None,交易在链上失败时返回错误。

让 Apex 重试,然后重新构建

Apex 会重新发送已接受的交易,直到它上链或其 blockhash 过期。请配合这一机制,而不是绕开它:
  • 不要循环重发已接受的交易。 这没有任何帮助,还会消耗您的速率限制。
  • 使用新的 blockhash。 在签名前一刻以 confirmed 承诺级别获取。一个已经存在一分钟的 blockhash 留给 Apex 的时间非常少。
  • blockhash 过期后,重新构建。 获取新的 blockhash,重新签名,并发送新交易。在此之前请确保第一笔交易已无法上链,或者使用即使两笔都执行也安全的逻辑。
  • 重试传输失败。 如果发送在收到响应之前失败,请再次发送相同的字节。端点按签名去重。
  • 遇到 rate limitedbusy 时退避。 参见哪些错误可以重试
maxRetries 限制 Apex 重新发送一笔交易的次数。除非您希望交易提前放弃,例如一两秒后就过时的报价,否则请保持默认值。

集成时使用反馈,运行时无需反馈

在集成阶段,请使用能告诉您交易为何被拒绝的传输方式:JSON-RPC、HTTP 路由或双向 QUIC 流。一旦您的交易能够稳定地被接受,就将热路径迁移到单向 QUIC 流,并保留一个双向流或 HTTP 发送方式用于调试。

让每笔交易都唯一

Apex 按签名去重。两笔指令、签名者和 blockhash 完全相同的交易具有相同的签名,会被视为一笔。如果您打算将同一操作发送两次,请改动某些内容,例如 memo,或将计算单元价格调整一个 micro-lamport。

检查清单

  • 每笔交易一笔小费,位于顶层,由签名者出资,小费账户位于静态密钥中
  • 每笔交易从缓存的 getTipAccounts 列表中随机选择小费账户
  • 每笔交易都设置计算单元上限和价格
  • 在签名前一刻获取 blockhash
  • 在启动时打开连接并预热
  • 确认每一次发送,并检查 err 字段
  • 遇到限速和繁忙时退避,遇到无效时重新构建
  • API 密钥存放在环境变量或密钥存储中,而不是代码里