Solana白皮书v0.8.13中文

112 次浏览
2024年08月09日创建

法律免责声明

本白皮书中的任何内容均不构成出售或购买任何代币的要约或要约邀请。Solana 发布本白皮书仅是为了从公众那里获得反馈和意见。如果 Solana 提供任何代币(或未来代币的简单协议)出售,它将通过正式的发行文件进行,包括披露文件和风险因素。这些正式文件预计还将包括本白皮书的更新版本,该版本可能与当前版本有显著不同。如果 Solana 在美国进行此类发行,该发行可能仅向合格投资者提供。

本白皮书中的任何内容均不应被视为对 Solana 业务或代币的发展、实用性或价值的保证或承诺。本白皮书概述了当前计划,这些计划可能会根据 Solana 的自行决定进行更改,其成功将取决于许多 Solana 无法控制的因素,包括市场因素以及数据和加密货币行业内的因素等。关于未来事件的任何声明仅基于 Solana 对本白皮书中描述问题的分析。这种分析可能被证明是错误的。

摘要

本文提出了一种基于历史证明(Proof of History,PoH)的新型区块链架构——一种用于验证事件之间顺序和时间流逝的证明。PoH 被用于将无需信任的时间流逝编码到账本中,这是一种仅追加的数据结构。当与工作量证明(Proof of Work,PoW)或权益证明(Proof of Stake,PoS)等共识算法结合使用时,PoH 可以减少拜占庭容错复制状态机中的消息开销,从而实现亚秒级的最终确定时间。本文还提出了两个利用 PoH 账本时间保持特性的算法——一种可以从任意大小的分区中恢复的 PoS 算法和一种高效的流式复制证明(Proof of Replication,PoRep)。PoRep 和 PoH 的结合提供了一种针对账本在时间(顺序)和存储方面伪造的防御机制。在 1 Gbps 网络上对该协议进行了分析,本文表明,使用当今的硬件可以实现高达每秒 710,000 笔交易的吞吐量。

引言

区块链是一种容错复制状态机的实现。目前公开可用的区块链并不依赖于时间,或者仅对参与者保持时间的能力做出弱假设 [4, 5]。网络中的每个节点通常依赖于它们自己的本地时钟,而不了解网络中其他参与者的时钟。缺乏可信的时间来源意味着,当使用消息时间戳来接受或拒绝消息时,无法保证网络中的每个参与者都会做出完全相同的选择。本文提出的历史证明(Proof of History,PoH)旨在创建一个具有可验证时间流逝的账本,即事件之间的持续时间和消息排序。预计网络中的每个节点都能够依赖账本中记录的时间流逝,而无需信任。

大纲

本文其余部分的组织结构如下:

第 3 节描述了整体系统设计。

第 4 节深入描述了历史证明(Proof of History)。

第 5 节深入描述了提出的权益证明(Proof of Stake)共识算法。

第 6 节深入描述了提出的快速复制证明(Proof of Replication)。

第 7 节分析了系统架构和性能限制。

第 7.5 节描述了一种高性能、适合 GPU 的智能合约引擎。

3 网络设计

如图 1 所示,在任何给定时间,系统节点中会指定一个节点作为领导者(Leader),负责生成历史证明(Proof of History)序列,为网络提供全球一致的读取和可验证的时间流逝。领导者对用户消息进行排序,并按顺序排列这些消息,使得系统中的其他节点可以高效地处理它们,从而最大化吞吐量。领导者在存储于 RAM 中的当前状态上执行交易,并将交易和最终状态的签名发布给称为验证者(Verifiers)的复制节点。验证者在其状态副本上执行相同的交易,并发布其计算出的状态签名作为确认。这些发布的确认作为共识算法的投票。

在非分区状态下,网络中在任何给定时间只有一个领导者(Leader)。每个验证者节点(Verifier)都具有与领导者相同的硬件能力,并且可以通过基于 PoS 的选举被选为领导者。关于提出的 PoS 算法的选举将在第 5.6 节深入讨论。

根据 CAP 定理,在发生分区事件时,几乎总是选择一致性(Consistency)而不是可用性(Availability)。对于大型分区的情况,本文提出了一种机制,可以从任意大小的分区中恢复对网络的控制。此机制将在第 5.12 节中详细介绍。

4 历史证明(Proof of History)

历史证明(PoH)是一种计算序列,可以提供一种加密验证两个事件之间时间流逝的方法。它使用一种加密安全的函数,该函数的输出无法从输入预测,且必须完全执行才能生成输出。该函数在单个核心上按序列运行,其前一个输出作为当前输入,定期记录当前输出以及调用次数。然后,外部计算机可以通过在不同核心上检查每个序列段来并行重新计算和验证输出。

数据可以通过将数据(或某些数据的哈希值)附加到函数的状态中来进行时间戳记录。记录状态、索引和数据在被附加到序列中的时间戳可以保证数据是在下一个哈希值生成之前的某个时间创建的。这种设计还支持水平扩展,因为多个生成器可以通过将它们的状态混合到彼此的序列中来进行同步。水平扩展将在第 4.4 节中详细讨论。

4.1 描述

该系统的设计工作流程如下。使用一种加密哈希函数,其输出在未运行该函数之前无法预测(例如 SHA-256、RIPEMD 等),从某个随机起始值开始运行该函数,并将其输出再次作为输入传递给同一个函数。记录函数被调用的次数以及每次调用的输出。选择的起始随机值可以是任何字符串,例如当天的《纽约时报》头条。

哈希N表示实际的哈希输出,只需要间隔发布部分哈希值和索引。例如:

只要选择的哈希函数具有抗碰撞性,这组哈希值只能由单个计算机线程按顺序计算。这是因为在实际运行算法300次之前,无法预测索引300处的哈希值。因此,我们可以从数据结构中推断出,从索引0到索引300之间确实经过了实际时间。

在下图的例子中,哈希值62f51643c1是在计数510144806912时生成的,而哈希值c43d862d88是在计数510146904064时生成的。根据之前讨论的PoH算法的特性,我们可以相信,在计数510144806912和计数510146904064之间确实经过了实际时间。

4.2 事件的时间戳

这串哈希序列也可以用来记录某些数据是在特定哈希索引生成之前创建的。通过使用一个“组合”函数将这段数据与当前索引处的哈希值结合起来。数据可以是任意事件数据的一个加密唯一哈希值。组合函数可以是简单的数据附加,或者任何具有抗碰撞性的操作。下一个生成的哈希值代表了数据的时间戳,因为它只能在该特定数据插入之后生成。

某个外部事件发生了,比如拍摄了一张照片,或者创建了任意的数字数据:

Hash336 是通过将 hash335 和照片的 sha256 二进制数据附加在一起计算得出的。照片的索引和 sha256 被记录为序列输出的一部分。因此,任何验证此序列的人都可以重现此序列中的更改。验证仍然可以并行进行,这在第 4.3 节中讨论。

因为初始过程仍然是顺序的,所以我们可以确定,进入序列的事件必然发生在未来的哈希值计算之前。

在表 1 所示的序列中,photograph2 在 hash600 之前被创建,photograph1 在 hash336 之前被创建。将数据插入哈希序列会导致序列中所有后续值的变化。只要使用的哈希函数具有抗碰撞性,并且数据是附加的,那么基于先前对将要整合到序列中的数据的知识,预先计算任何未来的序列在计算上应该是不可能的。

混入序列中的数据可以是原始数据本身,也可以是附带元数据的数据哈希值。

在图 3 的示例中,输入 cfd40df8... 被插入到了历史证明(Proof of History)序列中。插入时的计数是 510145855488,插入时的状态是 3d039eef3。所有未来生成的哈希值都会因这一序列的变化而被修改,这一变化在图中通过颜色变化来表示。

每个观察该序列的节点都可以确定所有事件插入的顺序,并估计插入之间的实际时间。

4.3 验证

该序列可以通过多核计算机在比生成它所需时间短得多的时间内验证其正确性。

假设有一定数量的核心,比如一个拥有4000个核心的现代GPU,验证者可以将哈希序列及其索引分成4000个片段,并行地确保每个片段从起始哈希到该片段的最后一个哈希都是正确的。如果生成该序列的预期时间是:

在图4的示例中,每个核心能够并行验证序列的每个切片。由于所有输入字符串都记录在输出中,并附有它们附加时的计数器和状态,验证者可以并行地复制每个切片。红色的哈希值表示序列因数据插入而被修改。

4.4 横向扩展

可以通过将每个生成器的序列状态混合到其他生成器中来同步多个历史证明(Proof of History)生成器,从而实现历史证明生成器的横向扩展。这种扩展是在不进行分片的情况下完成的。要重建系统中事件的完整顺序,需要两个生成器的输出。

给定生成器 A 和 B,A 从 B 接收到一个数据包 (hash1b),该数据包包含生成器 B 的最后状态,以及生成器 B 所观察到的生成器 A 的最后状态。生成器 A 中的下一个状态哈希值因此依赖于生成器 B 的状态,因此我们可以推导出 hash1b 发生在 hash3a 之前。这个属性是可传递的,所以如果通过一个共同的生成器 A ↔ B ↔ C 使三个生成器同步,即使 A 和 C 没有直接同步,我们也可以追溯 A 和 C 之间的依赖关系。

通过定期同步生成器,每个生成器可以处理一部分外部流量,从而整体系统能够处理更多的事件。然而,由于生成器之间的网络延迟,这会以牺牲真实时间精度为代价。仍然可以通过选择某种确定性函数来对同步窗口内的任何事件进行排序(例如,根据哈希值本身的值),以实现全局顺序。

在图5中,两个生成器插入彼此的输出状态并记录操作。颜色变化表明来自对等方的数据修改了序列。混入每个流中的生成哈希值以粗体显示。

同步是传递性的。A ↔ B ↔ C,通过B可以在A和C之间证明事件的顺序。

以这种方式扩展的代价是可用性。10个1 Gbps的连接,其可用性为0.999,则整体可用性为0.999^10 = 0.99。

4.5 一致性

用户应能够通过将他们认为有效的序列的最后一个观察输出插入到他们的输入中来强制执行生成序列的一致性,并使其对攻击具有抵抗力。

一个恶意的PoH生成器如果能够同时访问所有事件,或者能够生成一个更快的隐藏序列,就可能会生成一个事件顺序相反的第二隐藏序列。

为了防止这种攻击,每个客户端生成的事件应包含客户端认为有效序列中的最新哈希值。因此,当客户端创建“Event1”数据时,他们应附加上他们观察到的最后一个哈希值。

当序列被发布时,Event3 将引用 hash30a,如果它在这个事件之前没有出现在序列中,那么序列的消费者就会知道这是一个无效的序列。部分重新排序攻击将会被限制在客户端观察到事件和事件被插入之间生成的哈希数量内。客户端应该能够编写软件,在最后观察到的哈希和插入的哈希之间的一小段时间内,不假设顺序是正确的。

为了防止恶意的 PoH 生成器重写客户端事件的哈希,客户端可以提交事件数据和最后观察到的哈希的签名,而不仅仅是数据。

对这些数据的验证需要进行签名验证,并在此之前的哈希序列中查找哈希值。

在图6中,用户提供的输入依赖于生成的序列中在某个时间点之前存在的哈希 0xdeadbeef...。蓝色的左上箭头表示客户端正在引用先前生成的哈希。客户端的消息仅在包含哈希 0xdeadbeef... 的序列中有效。序列中的红色部分表示序列已经被客户端的数据修改。

4.6 开销

每秒4000个哈希将产生额外的160千字节数据,并且需要访问具有4000个核心的GPU,大约需要0.25到0.75毫秒的时间来验证。

4.7 攻击

4.7.1 逆序攻击

生成逆序需要攻击者在第二个事件之后启动恶意序列。这个延迟应该允许任何非恶意的对等节点之间就原始顺序进行通信。

4.7.2 速度

拥有多个生成器可以使部署对攻击更加具有抵抗力。一个生成器可以是高带宽的,接收许多事件以混合到其序列中,另一个生成器可以是高速度低带宽的,定期与高带宽生成器混合。高速序列将创建一个次要数据序列,攻击者必须逆转这个序列。

4.7.3 长期攻击

长期攻击涉及获取旧的废弃客户端私钥,并生成伪造的账本。历史证明(Proof of History)提供了一些对长期攻击的保护。一个恶意用户若获得旧的私钥,必须重新创建一个需要与他们试图伪造的原始记录一样长的历史记录。这需要比当前网络使用的处理器更快的处理器,否则攻击者永远无法在历史长度上赶上。

此外,单一时间源允许构建更简单的复制证明(Proof of Replication,详见第6节)。由于网络设计是让所有参与者依赖于单一的历史事件记录。

PoRep和PoH共同应当在空间和时间上对伪造账本提供防御。

5.2 术语

**bonds(质押)**

质押相当于工作量证明(Proof of Work)中的资本支出。矿工购买硬件和电力,并将其投入到工作量证明区块链中的单一分支。质押是验证者在验证交易时作为抵押的代币。

**slashing(惩罚机制)**

这是为了解决权益证明(Proof of Stake)系统中“无风险问题”(nothing at stake problem)而提出的解决方案。当投票支持不同分支的证明被发布时,该分支可以销毁验证者的质押。这是一种经济激励机制,旨在阻止验证者确认多个分支。

**super majority(超级多数)**

超级多数是指由质押权重计算的验证者的 2/3。超级多数投票表明网络已达成共识,如果这个分支无效,至少需要 1/3 的网络进行恶意投票。这将使攻击的经济成本达到代币市值的 1/3。

5.3 质押

质押交易将一定数量的代币转移到用户身份下的质押账户中。质押账户中的代币不能被花费,必须保留在账户中直到用户将其移除。用户只能移除已过期的代币。质押在当前持有者的超级多数确认序列后有效。

5.4 投票

预计历史证明(Proof of History)生成器将在预定时间段内发布状态签名。每个质押身份必须通过发布自己的签名来确认该状态签名。投票是简单的赞成票,没有反对票。

如果在超时内获得超级多数的质押身份投票,则该分支将被接受为有效。

5.5 解质押

缺少 N 次投票将标记这些代币为过期,不再有资格进行投票。用户可以发起解质押交易将这些代币移除。

N 是一个基于过期投票与有效投票比例的动态值。随着过期投票数量的增加,N 也会增加。在大规模网络分区的情况下,这使得较大分支能够比较小分支更快恢复。

5.6 选举

当检测到历史证明(PoH)生成器失败时,会进行新的 PoH 生成器选举。拥有最大投票权的验证者,或者在投票权相同时拥有最高公钥地址的验证者,将被选为新的 PoH 生成器。

新的序列需要获得超级多数的确认。如果新的领导者在获得超级多数确认之前失败,则选择下一个最高投票权的验证者,并需要一组新的确认。

要切换投票,验证者需要在更高的 PoH 序列计数器上进行投票,并且新投票需要包含它想要切换的投票。否则,第二次投票将被惩罚。投票切换预期设计为只能在没有超级多数的高度进行。

一旦 PoH 生成器确定后,可以选举一个次要生成器(Secondary)来接管交易处理职责。如果存在次要生成器,它将在主要生成器(Primary)失败时被视为下一个领导者。

平台设计为在检测到异常或预定时间表上,次要生成器成为主要生成器,且低等级生成器被提升。

5.7 选举触发条件

5.7.1 分叉的历史证明生成器

历史证明(PoH)生成器通过身份签名生成的序列来设计。只有在 PoH 生成器的身份被破坏的情况下才会发生分叉。分叉的检测是因为在同一个 PoH 身份下发布了两个不同的历史记录。

5.7.2 运行时异常

硬件故障、软件漏洞或 PoH 生成器中的故意错误可能导致其生成无效状态,并发布与本地验证者结果不匹配的状态签名。验证者将通过传闻协议发布正确的签名,这一事件将触发新一轮选举。任何接受无效状态的验证者将被惩罚,质押的代币将被销毁。

5.7.3 网络超时

网络超时将触发选举。

5.8 惩罚机制

当验证者对两个不同的序列进行投票时,将发生惩罚。恶意投票的证据将把质押的代币从流通中移除,并添加到矿池中。

包含对竞争序列的先前投票的投票不作为恶意投票的证据。相反,这种投票将移除当前在竞争序列上的投票,而不是销毁质押代币。

如果对 PoH 生成器生成的无效哈希进行投票,也会发生惩罚。生成器预计会随机生成无效状态,这将触发回退到次要生成器。

5.9 次要选举

可以提议和批准次要及更低等级的历史证明生成器。提议在主要生成器的序列上进行。提议包含一个超时时间,如果在超时之前获得超级多数投票通过,该次要生成器将被认为当选,并按计划接管职责。主要生成器可以通过在生成的序列中插入一条消息指示将进行交接,或插入无效状态并迫使网络回退到次要生成器,从而进行软交接。

如果次要生成器当选,而主要生成器失败,次要生成器将在选举中被视为第一个回退选项。

5.10 可用性

在处理分区的 CAP 系统中,必须在一致性或可用性之间进行选择。我们的方法最终选择了可用性,但由于我们有一个客观的时间度量,在合理的人类超时时间内也能保证一致性。

权益证明(PoS)验证者锁定一定数量的代币作为质押,这使他们可以对特定的一组交易进行投票。锁定代币的操作与其他交易一样,作为一个交易被输入到 PoH 流中。要进行投票,PoS 验证者必须对状态的哈希进行签名,该状态是在处理到 PoH 账本中特定位置的所有交易后计算出来的。这个投票也作为一个交易被输入到 PoH 流中。通过查看 PoH 账本,我们可以推断每次投票之间经过了多少时间,以及如果发生分区,每个验证者不可用的时间有多长。

为了在合理的人类时间范围内处理分区,我们提出了一种动态的解质押不可用验证者的方法。当验证者数量高于 2/3 时,解质押过程可以很快完成。在不可用验证者的质押完全解质押并且不再被计入共识之前,需要生成的哈希数量较少。当验证者数量低于 2/3 但高于 1/2 时,解质押计时器会变慢,需要生成更多的哈希数量才能解质押缺失的验证者。在大规模的分区中,比如缺失 1/2 或更多验证者的分区,解质押过程会非常非常慢。交易仍然可以被输入到流中,验证者仍然可以投票,但直到生成了大量的哈希并且不可用的验证者被解质押之前,无法实现 2/3 的共识。网络恢复活跃所需的时间差异允许我们作为网络的用户在合理的人类时间范围内选择要继续使用的分区。

5.11 恢复

在我们提出的系统中,账本可以从任何故障中完全恢复。这意味着,世界上任何人都可以从账本中的任何随机位置开始,通过附加新生成的哈希和交易来创建一个有效的分叉。如果所有的验证者都缺失,这个分叉需要很长时间才能使任何额外的质押变得有效,并且这个分支要达到 2/3 的超级多数共识也需要很长时间。因此,在没有可用验证者的情况下进行完全恢复需要在账本中附加大量的哈希。