跳转到主要内容
一笔交易最终会落入三种结果之一,每种结果的处理方法都不同。在修改任何东西之前,先弄清是哪一种。

第 1 步:弄清发生了什么

用签名向集群查询。searchTransactionHistory 让查询对任意时间的交易都有效。
如果是 sendTransaction 本身返回了错误,就没有可查询的签名。交易在发送前就被拒绝了。请转到发送前被拒绝。 如需在代码中检查签名,请参考等待确认的示例。

发送前被拒绝

默认情况下,sendTransaction 会先模拟交易,如果模拟失败就拒绝发送。您会收到错误 -32002,其中包含原因和程序日志:
按以下顺序阅读:
  1. data.logs 通常会用直白的语言说明出了什么问题。这里,付款方只有 0.06 SOL,却试图转出 1,000 SOL。
  2. data.err 指出哪条指令失败。InstructionError: [0, ...] 是第一条指令,从零开始计数。
  3. 自定义错误码属于失败的那个程序,而不是 Solana。System Program 的 Custom: 1 表示“余额不足”,但其他程序的 Custom: 1 含义不同。请在该程序的错误列表(其 IDL 或源码)中查找这个数字。消息中以十六进制显示,因此 0x1770 就是 6000,即 Anchor 程序中的第一个自定义错误。
被拒绝不会产生任何费用。交易根本没有离开 RPC 节点。

常见拒绝原因

使用 simulateTransaction 调试

如果只想查看日志而不发送任何内容,请进行模拟。调试时,以下两个选项会让模拟有用得多:
  • replaceRecentBlockhash: true 会替换为当前的 blockhash,因此在交易的 blockhash 过期后,您仍可以继续模拟同一笔交易。它不能与 sigVerify: true 同时使用。
  • sigVerify: false 会跳过签名检查,因此您可以模拟未签名或部分签名的交易。
即使模拟成功,结果中也包含 err、logs 和 unitsConsumed。用 unitsConsumed 设置准确的计算单元上限:上限越紧,您按单元支付的优先费就越划算。
调试时避免使用 skipPreflight: true。它会跳过模拟直接发送交易,因此有问题的交易会上链、失败并扣除手续费,而错误要到之后在 getSignatureStatuses 中才会出现。等确认交易可以正常工作、并且需要速度时再开启它。

已上链但失败

交易已经上链,手续费已扣除,但它的所有更改都没有生效。获取完整记录:
meta.err 与模拟错误的结构相同,meta.logMessages 包含程序日志。请按发送前被拒绝中描述的方法阅读。 模拟成功的交易仍可能在链上失败,因为在此期间状态发生了变化。常见原因包括兑换时的滑点、某个账户被他人关闭或修改,或者 nonce 已被使用。请基于当前状态重新模拟以确认原因,然后留出容错空间:放宽滑点、获取新报价,或在重试时重新构建交易。

从未上链

getSignatureStatuses 返回 null:RPC 节点接受了这笔交易,但没有任何领导者将其打包。不会产生任何费用。

blockhash 已过期

交易仅在其 blockhash 之后的 150 个区块内有效。每个槽约 215 毫秒,相当于大约 30 到 35 秒。一旦超过,交易就永远无法上链,因此请停止等待并重新构建交易。 检查 blockhash 是否仍然可用:
将 getLatestBlockhash 返回的 lastValidBlockHeight 与 blockhash 一起保存。将它与 getBlockHeight 比较:只要区块高度更低,就持续重发同一笔已签名的交易。一旦区块高度更高,这笔交易就已失效。

优先费过低

区块繁忙时,领导者会优先打包每个计算单元支付最多的交易。查看最近涉及您所操作账户的交易支付了多少:
从最近的结果中选择一个值,用 SetComputeUnitPrice 设置,并配合通过模拟得到的准确 SetComputeUnitLimit。

在传输途中被丢弃

已发送的交易可能在 RPC 节点和领导者之间丢失,在网络拥堵时尤其如此。每隔几秒重发同样的已签名字节,直到交易确认或 blockhash 过期。重发是安全的:同一个签名只能上链一次。 对于需要快速上链的交易,请通过 Apex 发送。Apex 会同时通过多条路径将每笔交易发送给即将出块的领导者,并持续重试,直到交易上链或过期。Apex 自身的错误列在 Apex 错误与速率限制中。

仍未解决

请收集签名(如果交易从未获得签名,则收集 base64 交易)、包含 data.logs 的完整错误、您发送时使用的区域,以及是否开启了预检。然后在 Discord 中提问。