新消息:Helius 收购 Light Protocol
如何处理 Solana 上的区块哈希错误
博客/开发

如何处理 Solana 上的区块哈希错误

开发者体验工程师X 上的 Owen VenterLinkedIn 上的 Owen Venter
阅读需 7 分钟

什么是区块哈希?

要理解什么是区块哈希,首先要了解时隙和区块。

  • 时隙是验证者可以生成区块的一段时间 
  • 区块是由验证者处理的一组交易和元数据。每个区块中的元数据会将其链接到上一个区块,从而形成一条链。

需要注意的是,每个时隙持续 400 到 600ms,在此期间,验证者可以提议一个新区块。如果没有创建区块,时隙编号会递增,并由另一个验证者尝试创建新区块。这意味着并非所有时隙都有对应的区块,但每个区块都有其被提议时对应的时隙。

那么,什么是区块哈希?区块哈希是某个时隙内创建的所有区块链账本条目的唯一哈希值。它根据区块的最后一个条目 ID 计算得出。每生成一个区块,都会创建一个唯一的区块哈希。这些区块哈希可用作时间戳。

Solana 的承诺级别是什么?

另一个需要理解的重要概念是承诺级别。承诺级别用于衡量网络对特定区块的确认程度,共有三个选项:已处理、已确认和已最终确认。

当验证者向链上提交区块时,该区块会处于已处理状态。当所需数量的验证者(66% 的验证者)投票同意纳入该区块后,它就会被添加到链上,承诺级别也会变为已确认。当该区块之上又构建了 31 个区块后,承诺级别会变为已最终确认。

为什么会出现区块哈希错误?

所有交易都包含一个用作时间戳的近期区块哈希。当该区块哈希不再被视为足够新时,交易就会过期。处理交易的验证者会检查“BlockhashQueue”(包含最近 300 个区块哈希的列表),确认交易的区块哈希是否足够新。如果该区块哈希不在列表中,交易就会被拒绝。由于时隙通常持续 400ms 到 600ms,因此区块哈希的有效期为 60 到 90 秒。

找不到区块哈希(交易模拟失败:找不到区块哈希)

当验证者处理交易时,如果交易中包含的区块哈希被判定为无效,就会出现“找不到区块哈希”错误。原因可能是区块哈希太旧,有时也可能是太新。 

此错误最常见的原因是,交易中包含的区块哈希不在验证者用于比对的最近 300 个区块哈希队列中。这会触发找不到区块哈希错误。即使交易在规定时限内创建并开始处理,也可能过期。例如,用户可能花了很长时间签署交易。也可能出现这种情况:一笔有效交易已提交,但未被纳入当前区块;等到它可以被纳入后续区块时,交易的区块哈希已经太旧。

在这类交易实际上已经过期的情况下,经常会看到超出区块高度错误(TransactionExpiredBlock heightExceededError)。要更好地理解此错误,首先需要了解区块高度的含义。区块高度是指当前区块之下的区块数量。如果当前区块是区块 1000,则区块高度为 1000。创建交易时,会记录该交易保持有效的最大区块高度。如果在处理交易时发现当前区块高度高于交易的最大有效区块高度,就会抛出此错误。

另一种可能导致“找不到区块哈希错误”的情况是,交易的区块哈希比用于检查该交易是否过期的区块哈希更新。这有点难理解,下面举个例子:你创建了一笔交易,并加入特定区块(假设为区块 1000)的区块哈希,然后立即将其发送到 RPC。RPC 可能会获取前一个区块的区块哈希,在本例中可能是区块 999(因为 RPC 使用了更高的承诺级别,或者 RPC 节点落后于网络)。因此,交易中的区块哈希将无法找到。虽然这种情况并不常见,但可能出现在以下两种场景中:

1. 承诺级别不一致

创建交易时使用已确认承诺级别,但 RPC 在计算交易有效性时,默认使用已最终确认承诺级别。

由于已最终确认的区块比最新区块“落后”31 个区块,这可能导致用于检查的区块哈希比交易的区块哈希更旧。

如果使用已处理承诺级别获取少数分叉上某笔交易的区块哈希,而该分叉最终被丢弃,那么这个区块哈希将失效,并且在处理交易时无法找到。

2. RPC 不一致

如果使用两个不同的 RPC 分别获取区块哈希和发送交易,那么发送交易的 RPC 一旦出现延迟,其用于检查有效性的区块可能会早于创建交易时使用的区块。

如何修复区块哈希错误

你可以采取以下几个步骤来处理上述各种情况。

1. 确保提交交易时使用的区块哈希不会太旧:

获取交易的区块哈希时,请使用 confirmed 承诺级别。与 finalized 承诺级别相比,这能确保使用更新的区块哈希。

你也可以使用 processed 承诺级别来获取稍新的区块哈希,但约 5% 的已处理区块不会被集群最终确认。这意味着交易的区块哈希将属于已被丢弃的分叉,因而不再有效。

2. 确保交易的区块哈希不比用于检查交易有效性的区块哈希更新:

始终将 preflightCommitment(即使使用 skipPreflight)设置为与获取交易区块哈希时相同的承诺级别。这有助于避免交易的区块哈希比用于检查交易有效性的区块哈希更新。

为应对发送交易时 RPC 节点落后的情况,应持续向 RPC 重新发送交易。你可以按固定时间间隔执行此操作。这样,即使 RPC 暂时落后,最终也会赶上并检测到交易已过期。

如果使用 simulateTransaction 请求,则应设置 replaceRecentBlockhash 参数。此标志会指示 RPC 将模拟交易的区块哈希替换为一个始终可用于模拟的有效区块哈希。

3. 在区块哈希有效期间持续重试交易:

创建交易并获取最新区块哈希时,应记录该区块哈希的 lastValidBlockHeight。然后,你可以继续使用该区块哈希重试交易,直到当前区块高度超过交易的有效区块高度。可以使用 getBlockHeight RPC 调用持续检查交易是否仍然有效。一旦当前区块高度高于交易的 lastValidBlock 高度,就应获取并使用新的区块哈希。

希望本文能帮助你更好地理解区块哈希错误,并减少这些错误的发生。如果你还有任何问题,欢迎加入我们的 Discord 社区,或在 X 上向我们发送私信。

其他资源:

‍

订阅 Helius

及时了解 Solana 开发的最新动态,并在我们发布新内容时收到更新

放大图片