写节点
写节点就是这条链原本的执行客户端(ETH 用 go-ethereum 分叉,其他链用各自的分叉),加上编译进去的 pipeline 库。Leafage 没有替换它的同步和执行逻辑,只在执行路径上挂了追踪钩子。
写节点的 RPC 端口不面向应用客户端。它服务两类调用方:leafage-evm 的 HTTP 轮询模式,以及调试时比对某个区块的 StateDiff。
Leader 与备节点
一条链可以运行多个写节点。它们都同步、都执行、都上传 S3——S3 对象以区块哈希和 state root 为键,重复上传是幂等的。区别只有一个:只有 Leader 向 Kafka 发布通知。
新 Leader 会先等待
grace_period(默认 10 秒)再开始发布,给上一任留出收尾时间。
查询节点
查询节点是 leafage-evm 进程。定义它最准确的方式是列出它不做的事:
它做的事只有两件:按通知顺序应用状态差异,以及在本地状态上用 revm 执行只读调用(
eth_call、批量调用、gas 估算、调用追踪)。
因为不存交易,
eth_getBlockByNumber 和 eth_getBlockByHash 只返回区块头,transactions 与 uncles 恒为空数组。这是设计取舍,不是缺陷。三种查询节点类型
leafage-evm 按启动参数分成 State 和 Archive 两种;Native 节点是原链的全节点,由运维手动注册到 etcd 作为兜底。
State 节点收到超出窗口的高度会返回
-39006 BlockNotFound;Archive 节点收到不存在的区块返回 -39007 InvalidBlockID。前者会触发 nodex-proxy 改选 Archive 节点重试,后者不会。
三种类型的路由规则见区块上下文与路由,存储布局见状态与状态差异。
节点的生命周期
查询节点是否接收流量,不由它自己决定。三个组件在 etcd 的{chainID}[/{version}]/nodes/{ip}_{port} 键上接力:
1
leafage-evm 自注册
启动时写入自己的地址和
nodeType,stateType 置为 2(落后)。注册用“键不存在才写入”的事务,不覆盖别人写入的状态;进程退出时删除自己的键。2
consistency-checker 判定
每处理一个区块都轮询所有节点的
eth_blockNumber,把结果写回:1 已追上链头,2 落后,3 离线。离线且没有租约的节点直接删键。3
nodex-proxy 接纳
watch 到新节点后先做健康检查(
getLatestBlock),通过后才加入负载均衡池;watch 到删除事件立即移出。
排查“某个节点为什么没有流量”时,从 consistency-checker 的轮询结果查起,而不是从 nodex-proxy。
小结
- 写节点是原链执行客户端 + pipeline,唯一执行区块;多个写节点都上传 S3,只有 Leader 发 Kafka。
- 查询节点不同步、不执行、不维护 MPT、不存交易,只应用状态差异并执行只读调用。
- 查询节点分 State / Archive / Native,按保留的状态范围区分,错误码
-39006与-39008驱动 proxy 在三者之间兜底。 - 节点是否接收流量由 consistency-checker 写入 etcd 的
stateType决定,leafage-evm 只负责注册,nodex-proxy 只负责消费。