时间:2022-02-10|浏览:562
在某些情况下,在被纳入区块之前,一个看似有效的交易可能会被丢弃。当网络拥堵时,这种情况最常见RPC节点未能将交易重播(重播)给领导(leader,当决定当前块的验证器时。对于终端用户来说,他们的交易似乎完全消失了。RPC节点配备了通用的重播算法,但应用程序开发人员也能够开发自己的自定义重播逻辑。
交易的历程
客户如何提交交易
在Solana不存在区块链mempool概念。所有的交易,无论是通过编程还是由终端用户发起,都被有效地路过给领导者,以便被处理成一个块。向领导者发送交易有两种主要方式:
通过RPC服务器和sendTransaction JSON-RPC代理方法
通过TPU客户直接传递给领导者
绝大多数终端用户将通过RPC服务器提交交易。当客户提交交易时,接收RPC节点将试图将交易广播给当前和下一个领导者。在交易被领导处理之前,除了客户和转发RPC除了节点知道交易,没有交易记录。TPU在客户端发送交易时,重播和领导者转发完全由客户端软件处理。
RPC如何广播节点交易
在RPC节点通过sendTransaction收到交易后,它将交易转换为UDP数据包,然后转发给相关领导。UDP允许验证器快速通信,但不保证交易交付。
由于Solana领导时间表(决定验证器作为下一个领导时间表)在每个时间(约2天)之前就已经知道了,RPC该节点将直接向当前和下一个领导者广播交易。与其他协议(如以太坊)相反,后者在整个网络中随机而广泛地传播交易。默认情况下,RPC该节点将尝试每两秒将交易转发给领导者,直到交易最终完成或交易区块链过期(150个区块或1分19秒)。如果未完成的重播队列超过1万笔交易,新提交的交易将被丢弃。RPC操作员可以调整一些命令行参数,从而改变重试逻辑的默认行为。
当一个RPC当节点广播交易时,它将试图将交易转发给领导者的交易处理单元(TPU)。TPU处理五个不同阶段的交易。
获取阶段
签名验证(SigVerify)阶段
银行业务(Banking)阶段
历史服务证明(Proof of History Service)
广播阶段
在这五个阶段,获取阶段负责接收交易。在获取阶段,验证器将根据三个端口对汇入的交易进行分类。
tpu处理代币转移等常规交易,NFT铸造和程序指令。
tpu_vote只关注投票交易
若当前领导不能处理所有交易,tpu_forwards将未处理的数据包转发给下一位领导。
关于TPU请参考更多信息Jito Labs这篇文章。
如何丢弃交易?
在整个交易过程中,在几种情况下,交易可能会无意中从网络中删除。
在处理交易之前
如果网络丢弃了交易,很可能在交易被领导处理之前就丢弃了。UDP数据包丢失是造成这种情况的最简单原因。当网络负载高时,验证器也可能被需要处理的交易量淹没。虽然验证器有能力通过tpu_forwards转发多余的交易,但可转发的数据量有限。此外,每个转发仅限于两个单独的验证器。也就是说,在tpu_forwards端口收到的交易不会转发给其他验证器。
还有两个不为人知的原因,即交易可能在处理前被丢弃。第一种情况涉及通过RPC池提交的交易。在一些非常罕见的情况下,RPC池的一部分可以完全领先于池的其他部分。当需要池中的节点一起工作时,这可能会导致问题。在这个例子中,最近的交易区块哈希(Blockhash)是由池的高级部分(Backend A)查询。当交易提交到池的滞后部分时。(BackendB)节点将无法识别领先的区块哈希,从而放弃交易。如果开发者在sendTransaction在提交交易时,可以通过启用预检来检测这一点。
暂时的网络分叉也会导致交易丢弃。如果验证器在银行阶段慢慢重放区块,它最终可能会创建一个少数分叉。当客户建立交易时,交易可能会引用最近只存在于少数分叉上的区块哈希。交易提交后,交易集群可以在交易处理前从其少数分叉中切换。在这种情况下,交易会因为找不到区块哈希而被丢弃。
交易处理后,在交易最终确定前丢弃
如果一笔交易引用了最近几个分叉的区块哈希,它仍然可能被处理。然而,在这种情况下,它将由少数分叉的领导者处理。当领导者试图与互联网上的其他成员分享交易时,它将无法与大多数不承认少数分叉的验证器达成共识。此时,交易将在最终完成前被丢弃。
处理丢弃的交易
虽然RPC该节点试图重新进行广播交易,但它们使用的算法是通用的,通常不适合特定应用程序的需要。为了应对网络拥堵,应用程序开发人员应该定制自己的重播逻辑。
深入了解sendTransaction
开发人员在提交交易时使用的主要工具是sendTransaction RPC方法。sendTransaction只负责从客户端转发交易RPC节点。假如节点收到交易,sendTransaction将返回交易ID,可用于跟踪交易。成功的反应并不意味着交易是集群处理还是最终完成。
请求参数
transaction: string(字符串)-完全签名的交易,作为编码字符串
(可选) configuration object: object(对象)
skipPreflight:bolean(布尔值)-如果是真的,跳过预检交易检查(默认为假)。
(可选) preflightCommitment: string(字符串)- 对bank slot进行Preflight模拟中使用的承诺级别(默认为:完成)。
(可选) encoding: string (字符串)-用于交易数据的编码。"base58"(慢速),或 "base64"。(默认:"base58")。
(可选) maxRetries: usize——RPC节点重试最大次数将交易发送给领导。如果不提供此参数,RPC节点将重终完成或区块哈希过期之前,节点将重试交易。
响应
transaction id: string (字符串)-——嵌入在交易中的第一个交易签名base-58编码字符串。这笔交易ID可以与getSignatureStatuses一起使用,轮询(poll)状态更新。
自定义重播逻辑
为了开发自己的重播逻辑,开发者应该使用它sendTransaction的maxRetries若开发人员提供相关参数,maxRetries将覆盖RPC默认节点重播逻辑允许开发者在合理范围内手动控制重播过程。
一种常见的手动重试交易模式来自getLatestBlockhash临时存储的lastValidBlockHeight。一旦存储了应用程序,可以轮询交易集群的块高,并在适当的时间间隔内手动重试交易。当网络拥堵时,maxRetries设置为0并通过自定义算法手动重播是很有利的。虽然一些应用程序可能采用指数退避算法(exponential backoff algorithm),但其他应用程序,如Mango,在发生某种超时之前,选择在恒定的时间间隔内连续重新交易。
当通过getLatestBlockhash轮询时,应用程序应指定其预期承诺水平。通过将其承诺设置为确认(投票)或最终确认(确认后约30个区块),应用程序可以避免从少数分叉轮询区块链。
如果一个应用程序可以访问负载平衡器后面RPC也可以选择在特定的节点中划分节点的工作负载。服务于数据密集型请求RPC节点,如getProgramAccounts,它可能很容易落后,也不适合转发交易。对于处理时间敏感交易的应用程序,谨慎的做法是只处理特殊节点sendTransaction。
跳过Preflight的代价
默认情况下,sendTransaction提交交易前将进行三次预检。具体来说,sendTransaction将:
验证所有签名是否有效
检查引用的区块链是否在最后150个区块内
针对preflightCommitment指定的bank slot模拟交易
若三次预检中的任何一次失败,sendTransaction在提交交易之前会出错。预检通常是失去交易和允许客户优雅地处理错误之间的区别。为了确保考虑到这些常见的错误,建议开发人员不要skipPreflight设置为false。
何时重新签名交易?
虽然所有的尝试都是为了重新广播,但有时客户可能需要重新签署交易。确保初始交易的区块哈希在重新签署任何交易之前过期是非常重要的。如果最初的区块链仍然有效,那么这两笔交易可能会被互联网接受。对于终端用户来说,这就像他们无意中发送了两笔相同的交易。
在Solana哈希比遗弃交易所引用的区块哈希比getRecentBlockhash收到的lastValidBlock长期以来,交易可以安全丢弃。开发者可以通过isBlockhashValid便于检查给定的区块链。一旦区块链失效,客户可以用新查询的区块链重新签名。
用戶喜愛的交易所
已有账号登陆后会弹出下载