Skip to main content
Leafage 的所有组件都围绕同一条区块流工作:写节点按执行顺序发布区块变更通知,查询节点和 consistency-checker 按同样的顺序消费。这条流里有三个需要分清的概念:通知、规范链与分叉块、已发布与已确认。

区块变更通知

写节点每确定一次新的 canonical head,就向 Kafka 内部 topic 发布一条 BlockChangeNotification
通知里只有元信息,没有数据体。消费者拿到哈希后自己去 S3 取 Header 和 StateDiff。Kafka 因此只承担顺序和低延迟,大对象走 S3 可以并行拉取。
S3 上传与 Kafka 发布不是原子操作。消费者收到通知时对应的 S3 对象通常已就绪,但必须容忍短暂的 404 并重试。

规范链与分叉块

规范链是写节点当前 canonical head 所在的那条链。写节点发布通知前,把上一条已发布的区块与新 head 做共同祖先比较:
只有新块时 changeType1newBlocks 按高度升序;存在被丢弃的分支时 changeType2,同时带 dropBlocksnewBlocks 被丢弃的块就是分叉块。它们不会从系统里消失: 同一高度在 S3 外部桶的前缀 {chainID}[/{version}]/{height}/ 下可能有多个对象,is_fork 是区分它们的唯一依据。查询节点冷启动追赶时靠它把高度解析成规范哈希。

已发布与已确认

写节点发布通知的那一刻,查询节点还没有应用这个区块。直接订阅内部 topic 的消费者会在“去查还查不到”的时候收到通知。consistency-checker 在中间加了一道确认:
外部通知用同一个结构表达新块和被丢弃的块,靠 is_fork 区分。重组时 checker 先发 drop 通知,再发新块通知。 外部消费者因此得到一个保证:收到通知时,去查询集群一定能读到这个区块。等待副本超过 check_timeout_ms(默认 2000 毫秒)仍未达标时,checker 不发布该区块并整体重试。

同一个区块,三处记录

一个区块被确认后,链路上有三个地方各自记着它,服务不同的读取者: leafage-evm 和 consistency-checker 都提供 getLatestBlock / getBlockByHeight / getBlockById / blockIsValid,方法名相同但语义不同:前者返回本节点当前视图,后者返回已确认的区块。

小结

  • 区块变更通知只含哈希、高度等元信息,单分区全序,仅 Leader 发布;数据体在 S3。
  • 重组表达为 changeType: 2dropBlocks;被丢弃的分叉块在 S3 和查询节点内存中都保留,由 consistency-checker 回写 is_fork
  • 已发布(内部 topic)与已确认(外部 topic)是两条不同的流,外部消费者应当只订阅后者。
  • 已确认高度写在 etcd 的 lastBlockNumber,是 nodex-proxy 判断 State / Archive 的依据。
继续阅读:
  • 区块上下文与路由:请求如何表达“要哪个区块”,以及已确认高度如何参与路由。
  • 数据链路:reorg 在写节点、leafage-evm 与 checker 三处的处理细节。
  • 接口契约:两个 topic 的命名、编码与生产者配置。