重试交易
有时,一个看似有效的交易可能在被包含在区块之前被丢弃。 这通常发生在网络拥堵期间,当RPC节点未能将交易重新广播给领导者时。
对于终端用户来说,这可能看起来像他们的交易完全消失了。 虽然RPC节点配备了通用的重新广播算法,但应用程序开发人员也可以开发自己的自定义重新广播逻辑。
要点概述(TLDR)
- RPC节点将尝试使用通用算法重新广播交易。
- 应用程序开发人员可以实现自己的自定义重新广播逻辑。
- 开发人员应利用
sendTransaction
JSON-RPC方法中的maxRetries
参数。 - 开发人员应启用预检检查,以在提交交易前引发错误。
- 在重新签署任何交易之前,确保初始交易的区块哈希已过期非常重要。
交易的旅程
客户端如何提交交易
在Solana中,没有mempool
的概念。
所有交易,无论是通过编程方式还是由终端用户发起的, 都会有效地路由到领导者,以便处理并纳入区块。
有两种主要方式可以将交易发送给领导者:
- 通过RPC服务器和
sendTransaction
JSON-RPC方法代理发送。 - 直接通过TPU客户端发送 给领导者。
绝大多数终端用户将通过RPC服务器提交交易。
当客户端提交交易时,接收的RPC节点将尝试将交易广播给当前和下一个领导者。
在交易被领导者处理之前,除了客户端和中继RPC节点所知道的之外,没有任何交易记录。
对于TPU客户端,重新广播和领导者转发完全由客户端软件处理。
RPC节点如何广播交易
RPC节点通过sendTransaction
接收到交易后,
会将交易转换为UDP数据包,
然后再转发给相关的领导者。
UDP允许验证者快速互相通信,但不保证交易传递。
由于Solana的领导者时间表在每个时期(epoch
)(大约2
天)之前就已知,
因此RPC节点会将交易直接广播给当前和下一个领导者。
这与其他如以太坊的gossip
协议不同,后者随机且广泛地传播交易。
默认情况下,RPC节点将尝试每两秒钟将交易转发给领导者,
直到交易被最终处理或交易的区块哈希过期(150
个区块或约1
分19
秒)。
如果未处理的重新广播队列大小超过10,000
笔交易,新提交的交易将被丢弃。
RPC操作员可以通过命令行参数调整此重试逻辑的默认行为。
当RPC节点广播交易时,
它将尝试将交易转发给领导者的交易处理单元(TPU
)。
TPU在五个不同阶段处理交易:
- Fetch阶段
- SigVerify阶段
- Banking阶段
- 历史证明(
PoH
)服务 - 广播阶段
在这五个阶段中,Fetch阶段负责接收交易。
在Fetch阶段,验证者会根据三个端口对传入交易进行分类:
tpu
处理常规交易,如代币转移、NFT铸造和程序指令。tpu_vote
专门处理投票交易。tpu_forwards
在当前领导者无法处理所有交易时,将未处理的数据包转发给下一个领导者。
有关TPU的更多信息,请参阅Jito Labs的优秀文章。
交易如何被丢弃
在交易的旅程中,有几种情况下交易可能会无意中从网络中丢失。
在交易处理之前
如果网络丢弃交易,很可能在交易被领导者处理之前就发生。 UDP数据包丢失是最简单的原因。
在网络负载过高时,验证者也可能因需要处理的大量交易而不堪重负。
虽然验证者配备了通过tpu_forwards
转发多余交易的功能,但可转发的数据量有限。
此外,每次转发仅限于验证者之间的一跳。
也就是说,通过tpu_forwards
端口接收的交易不会进一步转发给其他验证者。
还有两个不太为人知的原因也可能导致交易在处理之前被丢弃。
- 第一种情况涉及通过RPC池提交的交易。
有时,RPC池的一部分可能显著领先于其余部分。
当池中的节点需要协同工作时,这可能会导致问题。
在此示例中,交易的
recentBlockhash
从池的先进部分(后端A)查询。 当交易提交到池的滞后部分(后端B)时,节点将无法识别高级的区块哈希并丢弃交易。 如果开发人员在sendTransaction
上启用预检检查,可以在交易提交时检测到这一点。 - 临时的网络分叉也可能导致交易丢弃。
如果验证者在银行阶段慢于重放其区块,它可能会创建一个少数分叉。
当客户端构建交易时,交易可能引用仅存在于少数分叉中的
recentBlockhash
。 在交易提交后,集群可能会在交易处理前切换离开其少数分叉。 在这种情况下,由于找不到区块哈希,交易将被丢弃。