更详细信息参考 官方文档

同步模式(sync-modes)

同步(sync)是 Geth 赶上最新的以太坊区块和当前全局状态的过程。同步 Geth 节点的方法有多种,它们的速度、存储要求和信任假设各不相同。现在以太坊使用基于权益证明的共识,Geth 需要一个共识客户端来同步。

全节点(Full-node)

有两种类型的全节点,它们使用不同的机制同步到链的头部:

快照同步(snap)(默认)

快照同步的节点在内存中保存最近的 128 个块状态(block state),因此该范围内的事务总是快速访问。但是,快照同步仅从相对较新的块开始处理(与完整节点的创世相反)。在初始同步块和最近的 128 个块之间,节点存储偶尔的检查点(checkpoint),可用于即时重建状态。这意味着事务可以追溯到用于初始同步的块。跟踪单个事务需要重新执行同一块中的所有先前事务以及所有先前块中的所有先前存储的快照(snapshot)。因此,快照同步的节点是完整节点,唯一的区别是初始同步需要一个检查点块来同步,而不是从创世开始一直独立验证链。然后,快照同步仅验证工作量证明和祖先-子块进展(ancestor-child block progression),并假设状态转换是正确的,而不是重新执行每个块中的事务来验证状态更改。快照同步比逐块同步快得多。启动节点时通过--syncmode snap 来开启 snap sync。

快照同步首先下载一部分区块头部(block header)。一旦验证了区块头部,就会下载这些块的body和收据(receipt)。同时,Geth 也同步开始状态同步(state-sync)。在状态同步中,Geth 首先下载每个块的状态树的叶子,没有中间节点(intermediate nodes)以及范围证明(range proof?什么是范围证明)。然后在本地重新生成状态树(state trie)。状态下载是快照同步中完成时间最长的部分,可以使用日志消息中的 ETA 值监控进度。但是,区块链也在同时进步,使部分再生状态数据失效。这意味着还需要有一个修复状态错误的“修复”阶段(healing phase)。无法监视状态修复的进度,因为在当前状态已经重新生成之前无法知道错误的程度。

Geth 在状态修复期间定期报告Syncing, state heal in progress,这会通知用户状态修复尚未完成。也可以使用eth.syncing确认这一点:如果此命令返回 false,则节点处于同步状态。如果它返回 false 以外的任何内容,则同步仍在进行中。

# this log message indicates that state healing is still in progress INFO
[10-20|20:20:09.510] State heal in progress accounts=313,309@17.95MiB
slots=363,525@28.77MiB codes=7222@50.73MiB nodes=49,616,912@12.67GiB
pending=29805
# this indicates that the node is in sync, any other response indicates that
syncing has not finished eth.syncing >> false

修复速度必须超过区块链的增长速度,否则节点将永远赶不上当前状态。 有一些硬件因素决定了状态修复的速度(磁盘读/写和互联网连接的速度)以及每个块中使用的总 gas(更多的 gas 意味着必须处理更多的状态变化)。

总而言之,快照同步按以下顺序进行:

  • 下载并验证标头。
  • 下载块体和收据。同时,下载原始状态数据并构建状态树。
  • 修复状态试图解释新到达的数据。

注意:快照同步是默认行为,因此如果在启动时没有将 --syncmode 值传递给 Geth,Geth 将使用快照同步。 使用 snap 启动的节点一旦赶上链的头部,就会切换到逐块同步。

完全同步(full)

完全同步通过执行从创世块开始的每个块来生成当前状态。完全同步通过重新执行整个历史区块序列中的交易来独立地验证工作量证明和区块出处以及所有状态转换。只有最近的 128 个块状态存储在全节点中 - 较旧的块状态会定期修剪并表示为一系列检查点,可以根据请求从这些检查点重新生成任何先前的状态。 128 个区块大约是 25.6 分钟的历史,区块时间为 12 秒。要创建一个完全同步的节点,请在启动时传递--syncmode full

在完全同步模式下,同步模块调用BlockChain.InsertChain向数据库中插入从别它节点获取到的区块数据。而在BlockChain.InsertChain中,会逐个计算和验证每个块的staterecepits等数据,如果一切正常就将同步而来的区块数据以及自己计算得到的 state、recepits 数据一起写入到数据库中。

存档节点(Archive nodes)

存档节点是保留所有历史数据的节点。无需从检查点重新生成任何数据,因为所有数据都直接在节点自己的存储中可用。因此,归档节点非常适合快速查询历史状态。在撰写本文时(2022 年 9 月),一个存储自创世以来所有数据的完整存档节点占用了近 12 TB 的磁盘空间(与 Etherscan 上的当前大小相同)。归档节点是通过配置 Geth 的垃圾收集来创建的,这样旧数据就不会被删除:geth --syncmode full --gcmode archive

也可以创建一个部分/最近的存档节点,该节点使用 snap 进行同步,但从不修剪状态。这将创建一个存档节点,该节点保存从节点首次同步的点开始的所有状态数据。这是通过使用--syncmode snap --gcmode archive启动 Geth 来配置的。

完全同步会修剪块(prune block),而存档节点不会。

轻节点(Light nodes)

轻节点同步速度非常快,并存储了最少的区块链数据。轻节点只处理块头,而不是整个块。这大大减少了相对于全节点所需的计算时间、存储和带宽。这意味着轻节点适用于资源受限的设备,并且当它们是新的或已经离线一段时间时可以更快地赶上链的头部。缺点是轻节点严重依赖其他利他全节点提供的数据。轻客户端可用于从以太坊查询数据并提交交易,充当本地托管的以太坊钱包。但是,由于它们不保留以太坊状态的本地副本,轻节点无法以与完整节点相同的方式验证块 - 它们从完整节点接收证明并根据其本地头链验证它。要以 light 模式启动节点,请传递--syncmode light。请注意,服务轻数据的完整节点相对稀缺,因此轻节点可能难以找到对等节点。轻节点目前不在使用权益证明的以太坊上工作。

在我们的 LES 页面(原文这个链接失效了)上阅读更多关于轻节点的信息。

共识层同步(Consensus layer syncing)

现在以太坊已经切换到权益证明,所有共识逻辑和区块传播都由共识客户端处理。这意味着同步区块链是共识和执行客户端之间共享的过程。区块由共识客户端下载并由执行客户端验证。为了让 Geth 同步,它需要来自其连接的共识客户端的标头。 Geth 在共识客户端指示之前不会导入任何数据。如果没有连接到共识客户端,Geth 就无法同步。这包括从创世点逐块同步。

一旦区块头可用作同步目标,Geth 就会按时间倒序检索该目标标头和本地标头链之间的所有标头。这些区块头表明块的顺序是正确的,因为父块哈希(parenthashes)将一个块链接到下一个块,直到目标块。最终,同步将到达本地数据库中保存的块,此时本地数据和目标数据被认为是“链接”的,节点同步正确链的可能性非常高。然后下载块体,然后下载状态数据。共识客户端可以更新目标标头——只要同步速度超过区块链的增长速度,那么节点最终就会同步。

共识客户端有两种可以找到供 Geth 用作同步目标的块头的方法:乐观同步(Optimistic sync)和检查点同步(Checkpoint sync):

乐观同步(Optimistic sync)

乐观同步在执行客户端验证它们之前下载块。在乐观同步中,节点假定它在下载阶段从其对等点接收到的数据是正确的,但随后会追溯验证每个下载的块。当节点仍然“乐观”时,不允许节点证明或提议区块,因为他们还不能保证他们对链头的看法是正确的。

阅读更多乐观同步规范

检查点同步(Checkpoint sync)

或者,共识客户端可以从一个受信任的来源获取一个检查点,该来源提供一个要同步的目标状态,然后切换到完全同步并依次验证每个块。在这种模式下,节点相信检查点是正确的。这个检查点有很多可能的来源——黄金标准是从另一个值得信赖的朋友带外获取它,但它也可能来自区块浏览器或公共 API/Web 应用程序

有关更多详细信息,请参阅有关同步(todo:原文链接已经失效)的页面。有关故障排除,请参阅控制台日志消息页面(todo:原文链接已经失效)上的同步部分。

请注意,目前无法在权益证明以太坊上使用 Geth 轻节点作为执行客户端。

概括(summary)

有几种方法可以同步 Geth 节点。默认是使用快照同步来创建一个完整的节点。这会使用一些最近的块来验证所有块,这些块足够老,可以安全地作为同步目标进行重组。信任最小化的替代方案是完全同步,它验证自创世以来的每个块。这些模式丢弃超过 128 个块的状态数据,只保留启用历史状态请求再生的检查点。对于历史数据的快速查询,需要归档节点。存档节点将所有历史数据的本地副本保存到创世记 - 目前大约 12 TB 并且还在增长。相反的极端是一个不存储任何区块链数据的轻节点——它从全节点请求一切。这些配置是通过在启动时将 fullsnaplight 传递给 --syncmode 来控制的。对于存档节点,--syncmode 应该是full--gcmode 应该设置为archive。目前,由于向权益证明的过渡,轻同步点无法工作(正在开发新的轻客户端协议)。