文章详细介绍了Solana区块链中的共识机制,特别是Tower BFT和Proof-of-History (PoH)的工作原理,以及它们在同步和最终性中的作用。还讨论了未来协议升级的可能方向,如异步执行和编程罚没。
23分钟阅读
2024年6月1日
随着 Solana 的活动增加,其堆栈的各个层次正在以前所未有的水平进行测试。关于“热门”话题,比如本地费用市场,已经有很多书写和讨论,但对 Solana 的共识长期以来却被忽视。然而,增加的活动和兴趣要求社区深入理解共识,因为恶意攻击的诱因和潜在利用的利润在增加。
共识是 Solana 对整个社区来说最重要的方面之一,因为它决定了 成千上万的验证者 如何就交易的规范顺序达成一致。
共识在分布式系统中研究多年。 拜占庭将军问题,由 Lamport、Shostak 和 Pease 撰写,发布于1980年代初。共识算法如 RAFT 在 web2 中长期使用。在加密领域,大多数共识算法是 BFT 共识的不同实现,包括 Gasper(以太坊)、Tendermint(Cosmos)、MonadBFT(Monad)、HotShot(Espresso)和 Narwhal/Tusk(Sui)。
本文并不试图正式证明 Solana 的共识机制(TowerBFT)。相反,旨在向开发者和更广泛的社区解释在 Solana 上共识是如何工作的,因为这一话题迄今为止主要存在于 Solana Labs 和 Firedancer 贡献者的思想中。同时也讨论了一些关于权衡和限制的评论。
共识协议的目标是就交易及其在区块中的相对排列达成一致。网络中验证者达成交易的规范排列一致性有两个主要类型的共识协议:
最长链和 BFT 类型的共识协议都从各自的确认规则中获得安全性。安全性,由安全性和活跃性组成,是由给定确认规则获取的,并不是链的属性。根据以太坊基金会的定义(https://github.com/ethereum/consensus-specs/pull/3339),确认规则是“运行在节点上、输出某个区块是否被确认的算法。当这种情况发生时,在某些假设下,即关于网络同步性和诚实股份的百分比,该区块保证永远不会被重组。”
最终,这一切都是 社会共识,由编写客户端代码的人定义通过某些确认规则所定义的安全性。
Proof-of-Stake 在 BFT 模型中引入了额外的层次,需要参与者提出自己的股份。参与者因遵循一组规则而获得奖励,但在发现不当行为(例如双重签名)的情况下,可能会被剥夺。这被称为有责任的安全性,允许协议识别和惩罚恶意节点,而不会对诚实节点产生外部影响。这并不取代 BFT 共识协议的基本安全机制:网络仍然需要控制少于三分之一的恶意节点,以避免暂停,并且需要控制少于三分之二的恶意节点,以防止验证虚假交易。基于股份的系统对可能干扰或降级网络效率的行为施加后果。
在这样一个 BFT 网络中,有两个关键阈值:
1/3:如果恶意节点占总数的三分之一或更多,网络可能会“暂停”。在这种情况下,这些节点可能选择退出参与,让其余节点无法达到共识所需的三分之二超级多数。因此,网络并不会生成不正确的交易。相反,它会完全停止产生任何交易。一个流行(尽管粗略的指标)是 中本聪系数,它表示产生活跃失败(停止生产区块)所需的最低节点数。
2/3:如果恶意节点占总数的三分之二或更多,他们可以合谋验证他们选择的任何交易。这代表了最坏的情况,网络停止正常运行,而是根据恶意超级多数的指示处理交易。在一个敌对方控制超过67%股份的情景下,他们可能会将一个诚实节点孤立,比如一个大型交易所的节点(例如,Binance)。这种孤立可以通过与数据中心的合谋来限制该节点的网络流量来实现。恶意实体然后可以让这个孤立的节点最终确认他们精心制作的区块,同时将一个冲突的区块分发给网络的其他部分。这种攻击利用了孤立节点有限的视角,导致潜在的双重支付,因为网络的其余部分和孤立节点对链上状态有不同的看法。
即便是更低的股份(超过33%),也可以进行类似的攻击,但这将需要制造一个网络分区,而不仅仅是孤立。在这种情况下,拜占庭利益相关者可以利用网络分区操纵网络的不同部分,使其接收冲突信息,再次面临双重支付和其他安全失败的风险。
通常,节点数量越多,任何一方试图腐蚀大部分节点以达到这些阈值的难度就越大(假设地理分隔)。然而,对更大网络的渴望通常与效率发生冲突。节点数量的增加可能会由于数据传输需求的增加而减缓共识的速度(传播投票所需更多时间),一些协议对最大节点数设置了硬限制。
虽然 Proof-of-Stake (PoS) 确保网络中的共识,Solana 将 Proof of History (PoH) 纳入其 PoS 共识机制中,以实现连续区块生产的同步。这是通过 Solana 跳过慢或无响应的槽领导者而实现的,无需等待同步的共识轮次。PoH 的关注点不在于证明某一事件发生的具体时间,而是在于证明事件之间的顺序和时间的推移。
与普遍信念相反,Proof-of-History (PoH) 本身不是一种共识机制或算法。尽管 当前的实现 使用了 PoH 的某些方面,但理论上可以剥离 PoH 并进行一些小的实现变动,使得 Solana 的共识仍能正常运作。
PoH 的核心是一个简单的哈希算法,类似于 可验证延迟函数 (VDF),但 技术上并不是 VDF。Solana 通过一个连续运行的单线程预映像抗性哈希函数 (SHA-256) 实现这个机制,使用一个迭代的输出作为下一个的输入。这个计算在每个验证者的单核心上运行。
虽然序列生成是顺序的和单线程的,但输出可以并行验证,从而实现对多核系统的高效验证。虽然哈希速度存在上限,但硬件的改进可能会提供额外的性能收益。
考虑一个涉及 Solana 网络中四个验证者的例子:验证者 A、B、C 和 D。在这个示例中,领导者调度 可能会规定区块生成的顺序为 A - B - C - D。验证者 A 首先生成一个区块。为此,验证者 A 使用 PoH 机制,这涉及反复运行 SHA-256 哈希函数,形成“tick”时间尺度。这个哈希过程创建了一个独特且可验证的时间记录,确保验证者 A 的区块反映准确的时间推移。一旦验证者 A 完成其区块,接下来轮到验证者 B 生成下一个区块,随后是验证者 C。
假设验证者 C 试图通过超前发布区块来干扰这一序列,目的是直接跟随验证者 A,从而绕过验证者 B。为使验证者 C 有说服力地取代验证者 B,它需要复制验证者 B 应当生成的 PoH 哈希序列,这意味着它必须生成一系列哈希,代表验证者 B 生成区块所需的时间。单核哈希性能存在物理最大值,意味着我们知道一定的时间已经过去,因为计算机在给定的时间区间内可以生成的哈希数量有限。
验证者 C 可以尝试通过生成一系列空块来审查验证者 B,这一系列从先前合法区块的末尾(验证者 A 的区块)开始,但不包含任何交易。为了成功审查 B,C 必须满足两个条件。首先,C 需要足够的计算能力来生成空的 PoH 链。其次,C 须迅速传播其区块给足够多的股份节点,以确保其区块在其指定的槽期间被接受,从而有效地审查 B。由于 Turbine 的存在,持有高股份的验证者信息传播更为迅速,这使得这一过程更快。
此攻击场景是可行的,但成功审查的窗口有限。它要求攻击节点具备大量计算资源(用于 SHA-256 哈希)和相当的股份,因为它能够生成的区块数量与其股份成正比。
除此之外,C 还需要比节点 A 更快地到达网络,同时以快速速度生成哈希。此攻击主要针对这样的情景:即一个在槽 n 的指定领导者旨在审查与前几个领导者槽(之前 n)的验证者。该验证者实现的审查程度取决于其股份,因为其创建领导槽的能力直接与其持有的股份数量相关。
PoH 机制还确保区块以一致的速度生成。由于每个验证者可以独立验证 PoH 序列,因此无需外部时间同步。例如,以太坊在每个区块中使用 网络时间协议 (NTP) 进行共识。在 Solana 中,每个验证者独立验证每个区块是在正确的时间槽内生成的,而无需使用外部协议。
Tower BFT,作为 Solana 的共识机制,在碎片(部分区块)传播到其他验证者之后运行:
如前所述,Solana 在 Proof-of-History 旁边运行 Tower BFT。Tower BFT 是一个类似于 pBFT 的共识算法,旨在利用来自Proof-of-History 的同步时钟计算。这在网络中建立了一个统一的时钟,使其能够有效地跳过那些缓慢或未响应的领导者分配的槽。这个过程消除了网络为每一个槽经历同步共识轮次的必要性,并使得连续的区块生成成为可能,因为验证者不必等待先前的区块到达再构建下一个区块。
另一个误解是 Solana 的共识机制当前实现程序化剥夺。 虽然 剥夺是在路线图上,但网络当前在发生安全违规后暂停,依靠社会共识来视需要进行剥夺。
Solana 的共识机制为不同节点提供不同程度的影响力。网络中的投票不平等,而是根据每个节点的股份加权。与 基于股份的服务质量 和 Turbine 的原理相同。其他条件相等的时候,持有较大股份的节点比持有较小股份的节点对确定规范共识具有更大影响力。
例如,在一个有四个节点、总股份为100的网络中,股份的分布与影响类似于:
在这个设置中,每组三个不诚实的节点的能力各不相同。单个节点,例如节点 D,由于其股份庞大,即使在节点总数仅占25%的情况下,也能够暂停网络。类似的,像节点 C 和 D 组合在一起也能够批准不正确的交易,尽管他们仅占节点的50%,但持有的股份足以影响结果。
上限为三分之一的范围,通过不诚实、妥协或者被阻塞的节点达到。验证不正确交易的超额触发阈值需要人们主动合谋,而不是仅仅依靠阻止诚实节点。因此,后者的实现显著更具挑战性。因为这涉及到腐化或妥协节点以主动参与不诚实计划,而不是单纯的阻止诚实节点。
在 Solana 中,槽领导者被分配连续四个约 1.6 秒(4 个块 x 每个块 400 毫秒)的槽。在每个时期的开始(432,000 个槽或 ~2-3 天),会随机选择 领导者调度。
领导者负责在其分配的每个槽内构建和提出新块(没有像以太坊那样的提案者-构建者分离)。其他验证者通过应用分叉选择规则给自己本地的 Solana 网络头部验证给定区块的有效性,来证明块的有效性。
领导者必须在给定的 PoH tick范围内发布块,以使该块有效;不在此范围内发布的区块将被视为跳过。
以具有四个参与者 (A, B, C, D) 的领导者调度为例,如果 D 尝试在 C 的回合中进行干预,它必须创建一个 PoH tick序列,以有效跳过 C 的区块,导致链如下所示:
A - B - [C 缺失] - D.
在 C 的区块缺失的情况下,诚实的 D 必须生成一个覆盖 C 的槽整个持续时间的 PoH 序列,然后才能开始它自己的。这将使 D 的区块看起来有效,因为它在 C 的槽时间结束后跟随着 B 的区块。
当 D 为 C 的槽生成 PoH 序列时,C 通常会流式传输自己的区块,通过与 B 的适当 PoH 序列连接。这样,可能会有两种结果:
在这两种情况下,D 成功替代 C 的几率都很小。此外,如果 D 替代 C 的尝试失败,则失去了在自己槽中广播块的机会。在 B 之后发出一个块,然后在 C 之后尝试另一个块则构成了一种违规(为 D 的槽创建两个块),这将导致被剥夺。每次尝试失败都将导致 D 失去自己产生块的机会,并且表明 D 采取这样策略的可能性不大。
从网络的角度看,D 的意图是不明确的。很难(如果不是不可能)区分 D 是否仅仅是没有看到 C 的区块(并无意审查 C)或 D 是否有意审查 B。因此,这不是容易被检测且无法被网络惩罚的行为。
Solana 的共识机制依赖于投票交易来实现共识。投票交易存在于区块中,但其优先级被提升,以免被常规交易淹没。目前,每个给定区块中的大部分交易都是投票交易:
然而,这种情况不总是如此,因为在给定区块内投票交易的比例代表了活动与参与共识的验证者数量之间的比率。在未来,投票交易可能成为给定区块中的少数。
投票交易是共识的必要条件 – 它们不是人为增加 TPS 指标的额外交易。 如果投票仅通过八卦(非正式的点对点通信)传播,可能导致验证者对塔的(投票)状态有不同的看法。这种差异可能导致验证者对哪个分叉更可能正确的观点不同,进而在验证者根据不完整或不一致的信息进行‘贪婪选择’时导致潜在的分歧。持续的区块生产需要持续投票,尤其是在先前的区块仍在被确认时。这要求对塔的状态拥有可靠且一致的视角。
与由用户发起的常规交易一样,投票交易也必须支付基本费用(0.000005 SOL)。这由 验证者身份 支付,必须保存在热钱包中以便进行持续签名,而投票账户用于账户查找和委托。
每次由验证者签署的投票都包括验证者的公钥和它们投票的区块的哈希。
当验证者接收到同一个槽多个区块时,会追踪所有可能的分叉,直到能够确定“最佳”的一个。验证者在本地运行相关的状态转换函数(在使用异步执行后,情况会发生变化),然后在重放之后对新块投票。验证者通过链上投票交易表达他们对给定分叉的投票。
在每个投票交易中,验证者发布投票并设置锁定期。此锁定作为一种承诺机制,将验证者绑定到它们选择的分叉,并对其决策施加机会成本。到目前为止,锁定并未被运行时强制执行,而是通过社会共识来执行 – 持续违规投票锁定将极有可能受到手动剥夺。对于违反锁定期的程序化剥夺,很可能在不久的将来得到增加,因为未设定投票信用可能没有足够的惩罚力量抑制行为。
验证者还会为每个其之前投票和扎根的/已最终确认块之间的每个祖先块签署一个区块的哈希。这样做是为了检测重复的区块。如果领导者向每个节点发送不同的区块,最终每个节点在同一个槽上投票的前驱都将不同。然而,在由65,000个槽组成的一个周期中,具有的投票大小在最极端的情况下或达到2MB。这是因为它可能需要对每个65,000个槽进行32字节的哈希。未来的文章将会对此进行更深入的探索。
验证者管理一个“投票塔”,这是一个投票的顺序堆栈,其中每个投票强化一个分叉,并在塔上形成对其之上的分叉的祖先。以此堆叠的新投票加入会导致堆栈中所有之前投票的锁定双倍增加,逐步增加对早期决策的承诺和锁定期。投票过程本身遵循多个检查:验证者必须遵循之前投票的锁定期;他们需确保网络的显著部分(通常是三分之二)也承诺相同的分叉;切换到新分叉前,替代分叉上需需超过38%的投票。
对于槽 n 的区块,来自领导者以外的投票最早在 n+1 时出现在链上。没有 投票小组 – 所有验证者都可以对所有区块投票。这些投票最初在 Turing 树中靠近(跨越一个跳跃的)其他验证者发布的区块中出现。对于槽 n 的投票可以在高达槽 n+512 出现,因为验证者被允许对任何其“槽哈希”仍然已知的槽进行投票,而槽哈希在512个槽中保存(感谢 Shinobi)。在某个特定区块中没有预定的上限,然而,任何建立在至少32个连续块上的扎根槽将不再接受投票并会被最终确定。
在投票方案中存在一些未完全强制执行的怪癖。例如,到目前为止,验证者的激励措施是在“扎根”槽(忽略链的尖端)上进行投票,且这一行为并没有遭到共识惩罚。这允许一个验证者不断为极有可能成为规范的分叉获得投票信用,而无须为实际共识操作所需的链尖端贡献。这正是在今天发生的事情 (https://stakeview.app/poor.html),其中一个验证者的平均“投票延迟”超过 68 个槽。一个名为 及时投票信用 的提议特性旨在缓解这一激励失衡。
像以太坊(LMD Ghost 和 Casper FFG)一样,Solana 有两个确认规则 - 一个用于短期分叉选择,另一个用于完整的 PoS 共识以实现最终性。这允许用户和客户端在不同的确认规则下进行定制的用户体验选择。这体现在两个承诺级别:“已确认”和“已最终确认”。
“已确认”的区块(也称为 乐观确认)要求至少 2/3 的验证者通过投票交易对特定区块进行投票。~4.6% 的当前股份需要在最终性违规中被剥夺。“已最终确认”的区块要求对至少32个后续槽投票或超大比例(>2/3)的投票。一次恶意攻击将需要超过三分之一的股份被剥夺。这比“已确认”区块所需的时间要长得多,因为它必须等待扎根区块 32 个区块之前的时间才能完全最终确定。
分叉选择规则让网络能够就链头达成共识。Solana Labs 实现主要通过大约4600 行 Rust 文件,命名为 heaviest_subtree_fork_choice.rs。它提供了必要的逻辑供验证者确定哪个分叉更可能成为规范分叉。将透彻的代码分析放在未来的文章中进行,从很高的层次来看,分叉选择机制的工作原理如下:
add_votes()
添加投票:这会遍历新投票,根据需要从旧槽中减去投票账户股份,并向新投票的槽中添加股份。
generate_update_operations()
创建分叉更新操作的批次:这个过程:
process_update_operations()
:mark_fork_valid()/invalid()
aggregate_slot()
更新分叉权重add_slot_stake()/subtract_slot_stake()
更新股份aggregate_slot()
:select_forks()
:根据投票添加/减去股份,聚合重新计算每个分叉的权重,并选择具有最重权重子树的根作为最佳分叉以构建和投票。
交易被纳入的可能性在满足相关确认规则的必要要求后会随着交易生命周期的变化而变化。
虽然槽可以“被跳过”,例如当领导者处于离线状态,但该交易可以在未来的区块中存在,也可以干脆不出现。
这里的槽是粗略估计,但努力向读者提供投票倾向积累的时间点。此外,每个区块的范围不同(区块可能在“已经被确认”或“被最终确认”的确认级别上以不同长度到达)。在整个交易生命周期中,回滚的风险单调递减。即便是在已最终确认(扎根)的区块之后,仍然可以通过社会共识进行分叉,从“规范”链中去除。
本文重点突出了 Tower BFT 的内部工作,Solana 的共识机制以及其他相关机制。我们探讨了 Proof-of-History、投票交易和分叉选择在 Solana 上创建交易顺序的规范分叉中的作用。
围绕这些机制还有很多额外研究和正规化的方向尚待探索,例如:
在此文中,我们探索了 Solana 实现的某些机制和阈值及其在某些领导者在特定槽内的区块生产相关性。最近在 Solana 上活动增加为这些机制提供了现实世界的活跃性和安全性测试,同时增加了恶意攻击的诱因。
感谢 anoushk(Tinydancer)、dubbel06(Overclock)、Prithvi(Helius)、Mert(Helius)和 Jarry(Ellipsis Labs)进行讨论和评论。
- 原文链接: helius.dev/blog/consensu...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!