Skip to main content
Monad 架构概述解释了异步执行特性。在消费 Monad 最快的实时数据源之前,基本了解此特性的工作原理至关重要,特别是推测性执行区块状态章节。

我为什么需要理解推测性执行?

Monad 的设计比典型的 EVM 兼容区块链具有更多的并行性。这包括节点在确定新收到的区块会最终确认之前,推测性地执行其中的交易。实时数据源是在推测性执行期间创建的,因此如果您消费它们,您可能会看到关于交易及其效果(例如,日志和余额变化)的数据,但 这些交易可能永远不会真正发生! 为避免对不”真实”的区块链数据做出反应,您需要知道 Monad 实时数据源如何表达推测性执行,以及它们如何在稍后通知您区块(及其交易和状态效果)是否最终被添加到区块链中。 考虑到这种额外的复杂性,您为什么要消费这些实时数据源?答案是,这样 您的 软件就可以从推测性执行中获得与 Monad 本身相同的性能优势(如下所述) 您为此获得的好处所付出的代价是,您需要更多地了解 Monad 的工作原理,以便正确编写数据处理代码。

我可以在不处理推测性执行的情况下消费实时数据吗?

可以。 Monad 的 JSON-RPC 接口支持 "safe""finalized" 区块标签,这些标签仅返回已达到更强承诺级别(分别为 VotedFinalized)的区块数据。有关每个承诺级别所保证内容的详细信息,请参阅区块状态
monadNewHeadsmonadLogs 订阅中不会发生 Geth 风格的重组。相反,您会被明确告知共识算法对您已经看到的区块所做的操作,因此您知道哪些区块链数据被提交或未被提交。本文档的目的是准确解释此信息的含义,以便您知道如何对其作出反应。

我从推测性执行中获得什么好处?

推测性执行生成的实时数据对消费者有价值,原因有二:
  1. 它允许您使用 Monad 本身使用的相同流水线化技巧
  2. 有时尽快做出反应是有价值的,即使您看到的数据并非确定

优势 #1:流水线化

Monad 的流水线化技巧在这里这里进行了解释。您可能还记得下面的洗衣类比图,它有助于在两个地方解释这一概念: Pipelining, Laundry Day

流水线化洗衣日。上:朴素方案;下:流水线方案。图片来源:Prof. Lois Hawkes, FSU

以下是您如何自己使用流水线化的具体示例: 假设您正在编写一个自动化交易应用程序。进一步假设当某个合约(例如 CLOB 合约)发出特定日志事件时,您的交易算法使用来自该日志事件的数据作为买入或卖出的信号。 在实际交易之前,您可能需要先执行其他操作。您可能做的一些事情包括:
  • 检查您的风险限制,以查看增加头寸是否会给您带来太多敞口,或使您太接近潜在的清算
  • 运行更复杂的数学模型,如果您的策略需要基于交易信号的输入执行复杂计算
  • 创建并加密签名您的买入/卖出订单交易
所有这些事情都需要时间,您可以为您最终的交易 做准备,同时等待发现包含市场信号的区块是否真的被最终确认。如果区块 确实 被最终确认,您已经完成了必要的工作,可以直接”扣动扳机”(即发送预先签名的交易消息)。如果区块 没有 被最终确认,您只需将准备工作丢弃,永远不进行交易。

优势 #2:在我们知道它是”真实”的之前做出反应

考虑一个想要让用户了解其交易进度的 UI 组件。当交易被推测性执行时,可以在 UI 中将其标记为 Pending,这样用户就知道它已被看到,并且有很大机会通过。即使它未能推进到较晚的提交状态,看到一点即时反馈往往是更好的用户体验。 另外,再次考虑我们的自动化交易应用示例。时机在金融市场中非常重要。当价格快速变化时, 现在 立即进行交易可能比几秒钟后进行交易更有价值。基于推测性数据 立即 发起交易可能是合理的,即使知道有一小部分时间,交易是基于错误前提的。 您有时可能会亏钱,即当您的策略对未能最终确认的区块中的”非真实”市场数据做出反应时。但 通常 这不会发生,大多数时候提前的收益可能超过偶尔对”假”数据做出反应时的损失。 还有其他类型的应用程序,例如链上游戏,更具互动性比一直完全准确更好。

区块提交状态

文档的其他地方,我们了解到一个区块可以处于四种状态之一:ProposedVotedFinalizedVerified。这些有时在文档中被称为”提交状态”或”共识状态”。 在推测性实时数据源中,每当您获得区块链数据时,您也会被告知:
  • 相关区块处于哪个提交状态
  • 如果初始状态不是 verified,您将在稍后某个时刻收到通知,告知区块转换到了不同的状态
在本文后面,我们将逐步了解当前版本软件中此过程是如何发生的。

区块编号和区块 ID

一旦一个区块被规范地追加到区块链上,它就由(顺序递增的)区块编号唯一标识,也称为”区块高度”。将区块包含到区块链上是共识算法的目标,称为”最终确认”。 当一个区块首次被构造时,它是假设将成为下一个区块编号 N 而构造的。但在最终确认之前,共识节点仍在试图就此候选区块是否实际会成为区块 N 达成一致。 在共识术语中,领导者构造一个区块并将其 提议 给 Monad 网络。共识节点对将特定候选区块 B 成为编号为 N 的最终确认区块的提案进行投票。我们称此候选区块为”提议区块”。它还不是区块链的一部分,但很可能很快就会是。 提案可能因许多原因失败。在最常见的情况下,由于网络问题,提议区块在超时期限到期之前未能到达足够多的其他节点。 在这种情况下,您稍后会看到另一个候选者要成为相同的区块编号 N。因为实时数据源是由推测性执行提供的,您可能会看到 两个 区块 N 候选者的区块链数据,并且稍后会被告知哪个是正确的。 需要理解的关键是,此区块链数据可能声称是”区块编号 N”的,但它还不是”真实”的区块 N:它只是成为区块 N 的一个 提案 因此,当您在区块 最终确认之前 看到该区块的实时数据时,仅区块编号不足以唯一标识它。这只是区块 将来 会有的区块编号,如果它最终被最终确认的话。相反,共识使用”区块 ID”来唯一标识提议区块。ID 可以用来跟踪特定区块的提交状态生命周期。 考虑以下情况:
在此图中:
  • 区块 101 是最新被最终确认的区块
  • 有两个竞争提议区块争相成为区块 102;它们可以通过区块 ID 加以区分
  • 其中一个提议区块 (13a33) 是另一个提议区块的父区块
  • 您可能会看到 所有 这些区块的实时数据;对于那些尚未最终确认的,您可以立即开始您的流水线处理,但您 可能 想等到它们达到更好的承诺状态后再采取行动
上述情况在实践中非常罕见,但您应该意识到这是可能的。

共识、执行和提交状态

Monad 的实时数据流由 EVM 直接发出。在 Category Labs 的 Monad 节点实现中,执行和共识是解耦的,就像大多数以太坊兼容区块链软件一样。也就是说,共识和执行不 仅仅 是不同的算法,而是完全独立的程序,它们彼此通信。共识是决定潜在区块是否会成为区块链一部分的算法(和守护进程)。 执行托管 EVM,并在推测性基础上执行区块,在共识算法告知它区块的命运之前。同时,共识处于”驾驶座”:它是创建新区块的主要驱动者,而执行则作为共识使用的服务。然而,只有执行产生实时数据并维护状态数据库,因为它是唯一看到每条日志、每个调用帧等细节的部分。 区块从一个状态推进到下一个状态的确切方式如下所述。请注意,区块的状态是从特定观察者的角度出发的——例如,如果您收到一个区块的 QC,那么您可以将该区块移至 Voted 状态,但如果您的朋友还没有收到该 QC,那么她仍会认为该区块处于 Proposed 状态。 构建分布式共识机制的挑战在于定义规则,让节点能够在收到消息时单独更新其状态机,即使假设最坏情况,即假设它们可能是唯一收到该消息的节点。

第一个提交状态:Proposed

当领导者(Monad 验证者节点)提议新区块时,该区块从该领导者的共识节点发送到所有其他共识节点进行投票。从这些节点(以及任何观察者)的角度来看,如果区块有效(即遵守所有协议规则),则它处于 Proposed 状态。 在收到有效区块后,每个共识节点将向下一个领导者发送”yes”投票,同时安排其本地执行守护进程立即进行推测性执行 在这之后不久——甚至在”yes”投票开始通过互联网传输时——执行守护进程开始在 EVM 中执行提议区块。几毫秒后,EVM 将开始为此区块发布实时数据。 在当前软件实现中,所有 区块链数据都是首先在 Proposed 状态下观察到的。Proposed 区块是一个棘手的事情。收到的提案中近 100% 最终会被最终确认。因此,从统计意义上讲,看到 Proposed 区块似乎相当不错。 然而,那是因为通常全球 Monad 网络运行正常:绝大多数时候,互联网上没有重大电信中断,也没有企图的恶意活动。 您如此早地看到该区块,以至于除了您(如果您是验证者)和提议它的领导者之外,没有人为它投票。第一阶段投票正在并行进行,大致与您正在观察其执行的实时数据同时。 这就是 Proposed 区块的悖论:其中的交易几乎肯定会发生。然而,如果您在行动之前需要非常高的保证水平,那么假设它们肯定会发生就是愚蠢的:区块链对错误、中断和攻击的主要防御(其共识算法)尚未参与。 请确保您理解区块处于 Proposed 状态的含义:它很早,但对网络问题、软件错误或恶意行为没有防御。每个后续阶段都会降低出现问题的可能性以及可能出现的问题类型。

第二个提交状态:Voted

如上所述,共识算法正在进行第一轮投票,以决定该区块是否会被追加到区块链中。此次投票的目标是产生”多数”(公投通过所需的最少投票数)的”yes”投票。 投票由第二轮领导者协调,他将一个法定人数的加密签名”yes”投票聚合成一个称为”法定人数证书”(QC)的聚合签名。第二轮领导者将该 QC 发送给所有共识节点。 如果您收到了某个区块的 QC,这意味着您拥有该区块通过第一轮投票的证据。发生这种情况时,您可以认为该区块处于 Voted 状态。 关于已投票状态的一些注意事项:

Voted 并不意味着它在区块链上

当区块达到 Voted 状态时,它 尚不能 明确地追加到区块链上。Monad 的共识算法使用两轮投票。拥有 QC(即第一轮以大多数参与者投票赞成结束的证据)消除了最常见的风险,但仍有一些被回滚的风险。 拥有 QC 消除了由于最常见问题(如网络中断和延迟问题)导致区块”丢失”的风险。即使由于严重的网络中断,您是唯一拥有此 QC 的观察者,Monad 的共识算法也有一种回退机制,可确保原始区块几乎在所有条件下都会被重新提议并最终确认。 在什么条件下 QC 的存在不够呢?必须发生几件事,但最值得注意的是原始领导者必须 等价签名,即在同一区块高度提议两个不同的区块,并将每个发送给不同的节点集。 等价签名是领导者不太可能做的事情,因为它是一个容易归属的故障(证据只是同一领导者签名的一对冲突区块),并且领导者只会通过使自己的提案无效来伤害自己。这就是为什么达到 Voted 阶段的区块很可能被最终确认的原因。

一个区块可能永远不进入 Voted 状态

如果第一次共识投票失败,提议的区块可能永远不会收到 QC。区块未被投票通过的最常见原因是网络延迟问题。例如,假设您的节点和领导者都在澳大利亚,并且跨大陆网络流量存在严重拥塞。在这种情况下,大多数区块链节点可能无法在超时期限到期之前得知该提案,投票将失败。请注意,您 不会 被告知投票失败。投票的失败是 隐含的,但您可以通过下一个属性判断它发生了。

对于某个区块编号 N,某个 提议区块最终会被投票通过

如果您没有收到编号为 N 的特定区块的 QC,那么在其他某个时候,您将收到一个 不同 的提议区块以成为区块 N,并且 区块将收到 QC。 可能会发生类似以下的序列:
  • 您看到某个区块 B1 的所有实时数据,该区块被提议成为区块编号 N
  • 您看到一个 不同的 区块 B2(及其所有执行事件)也在争相成为区块 N
  • B2 收到了 QC,这是唯一发生的事情。即,B1 没有 收到明确的”放弃”事件:它只是再也不会被提及,并且通过网络认可另一个编号相同的区块被隐式放弃

第三个提交状态:Finalized

Finalized 意味着该区块现在是规范区块链的一部分,除非硬分叉,否则不能回滚。从这一点开始,我们不再需要区块 ID,可以仅通过区块编号引用一个区块。 当区块编号 N 被最终确认时,它 隐式地 放弃所有其他编号为 N 的提议区块。此类区块可能处于提议或投票状态。我们说放弃是隐式的,因为不会记录任何事件来明确宣布放弃之前看到的区块 ID。 如果您在消费实时数据时使用流水线化编程技术,那么您可能会跟踪一些与未最终确认区块相关的状态。在我们的交易示例中,这将是预先准备的买入或卖出订单交易消息。 每次区块被最终确认时,您必须检查任何(1)具有相同区块编号但(2)具有不同 ID 的区块,并中止对这些区块的流水线处理。它们永远不会被追加到区块链中,相关的交易及其效果——您已经看到过它们的执行事件——永远不会发生。

为什么有两个不同的投票阶段?

这是因为投票的 主题(我们试图就此达成一致的事情)不同。
  1. 第一次 投票中,网络想要验证一个区块是否满足所有协议规则。如果获得 QC,我们知道大多数诚实节点同意该区块 应该 被添加。这第一次投票被称为”voted”阶段,因为 区块本身 已被投票。
  2. 第二次 投票中,我们想要获得加密安全的一致同意,即 网络中有足够的部分实际上看到了第一次投票的结果。这第二次投票被称为”finalized”阶段,因为既然每个人都知道第一次投票成功了,他们也可以同意它必须是区块链上的下一个区块。
第二次投票试图回答那句老话所提出的问题:“如果一棵树在森林里倒下,而周围没有人听到,它会发出声音吗?” 考虑 BFT 协议的”扇入-扇出”线性通信模式是如何工作的。我们谈论节点”拥有 QC”,但 QC 是由下一轮的领导者计算的——这个领导者才是实际”主持”投票的人。 即使领导者不诚实,它也无法伪造投票,因为它无法伪造其他节点的加密签名。但它 可以 未能成功地告知足够多的对等节点关于 QC,因为它必须将 QC 传达给每个人。网络问题很常见,因此通信总是可能失败。 因此,我们需要第二轮投票,让验证者对他们已看到第一个 QC 这一事实达成分布式共识。现在可以安全地假设每个人(或至少诚实的多数)将拥有相同的规范区块链。 Voted 在 Monad 上是一个非常可靠的提交状态的原因是,如果在 第二 阶段投票期间发生常见问题,算法将继续尝试进行第二阶段投票,仅在涉及等价签名的一些狭窄边界情况下失败。

第四个提交状态:Verified

共识算法为区块产生最后一次状态转换,称为 Verified Verified 状态是 Monad 异步执行的结果。回想一下,共识节点在区块 执行完成之前 就对其投票。这意味着共识必须对区块的执行输入进行投票,但 对区块的执行输出投票。 例如,共识节点不能对区块执行产生的状态根的正确值投票,因为它们不知道它是什么(记住,它是在投票发生的同时并行计算的)。这意味着 Voted 状态不认证以太坊区块头中任何输出字段(如 state_rootreceipts_root 等)的正确性。 这是可能的,因为任何格式良好的以太坊区块在由符合规范的 EVM 实现执行时,对区块链状态都会有完全确定的效果。因此,将一个区块追加到区块链上是安全的,因为知道每个人都会同意其行为,即使我们不确切知道行为将是什么。 然而,显然,为了使区块链可靠,共识节点 必须 最终对执行输出的正确性进行投票。假设它们不这样做,进一步假设某些执行节点(可能运行不同版本的客户端软件)存在错误,而其他节点没有。如果没有机制将执行输出反馈到共识决策中,状态可能会在没有人注意到的情况下分叉。共识提案通过假设所有执行节点将计算正确状态而 开始,但为了防止错误和恶意行为损害网络,它必须最终检查这确实发生了。 以下是 Monad 解决此问题的方法: 为了给执行留出充足时间完成,区块 B 的执行输出直到未来三轮才被纳入共识协议,与区块 B+3 的提案一起。当 提案被最终确认时(理想情况下是两轮后,在区块 B+5 的提案期间),那么超级多数节点将对执行输出的正确值投票。 大致总结区别:
  • Finalized 意味着该区块的定义(即其交易)明确是区块链的一部分
  • Verified 意味着超级多数质押价值的其他节点已经验证了您本地节点对这些交易的状态变更的计算与超级多数一致
要了解更多信息,请阅读这里 这是否意味着已验证状态是”100%,永不失败”交易报告的黄金标准?也不是,如果您信任的是单个节点产生的数据源。例如,谁能说产生数据的节点没有遭受错误,或者已被入侵? 正如区块链宇宙中一贯的情况,需要 完全 安心的关键交易只能通过广泛的一致同意来验证,广泛地 定义。这包括明确与其他节点核对,以确保没有主机或网络中介被入侵,并且软件正常工作。 实际上,Voted 状态通常对大多数事情来说已经足够好:实际上它 非常 罕见地回滚,因此它也用作 Monad RPC 实现中的 "safe" 区块标签。