Crate 结构
状态管理
状态分两层:最近的区块以差异层链表保存在内存,更早的区块落盘。
查询:从最新层向下遍历差异层,命中即返回;全部未命中则读磁盘。绝大多数请求指向
latest 或接近链头的区块,因此通常是纯内存操作。
终结化:区块深度超过 --diff-depth-limit(默认 64)时,最老的层被刷入数据库并从内存移除。
分叉:分叉块进入 hash_diff_map 但不进入 num_diff_map。按哈希查询能访问分叉状态,按高度查询始终走规范链。
细节见仓库的 docs/StateManage.md。
两种节点模式
- State 节点(默认)
- Archive 节点(--archive)
只保留最新状态,ETH 主网约 90GB。
查询走直接
get()。请求的高度超出内存窗口时返回 -39006,由 nodex-proxy 转发到 Archive 节点。docs/Database.md。
状态更新
启动时按参数选择更新器:配置了--kafka-s3-config 用 Kafka + S3,否则配置了 --rpc-addr 用 HTTP 轮询,都没有则状态静止。
Kafka + S3(生产)
bucket_name是内部桶(Header + StateDiff),outer_bucket_name是外部桶(BlockFile,用于按高度索引和预热)- 显式
assign指定分区并关闭自动提交,offset 落盘到offset_dir,因此每个副本独立消费全量消息 - 父块与当前块 state root 相同时跳过 diff 拉取
{chainID}/{height}/ 前缀把高度解析成规范哈希。
--catchup-safe-depth 用于抑制追赶期的分叉误判:链头附近这些区块改为沿 Kafka 通知里的 parent-hash 链逐块回补,而不是按高度索引查,避免选中错误分支。取值应大于目标链的最大 reorg 深度,0 表示禁用。
HTTP 轮询(开发 / 回退)
轮询写节点的trace_debankBlock。父块不在 StateTree 中时向前回溯寻找共同祖先,然后按顺序应用。适合本地开发和没有 Kafka 的环境。
细节见 docs/StateUpdater.md。
RPC 接口
eth 命名空间
call、multiCall、blockNumber、getBalance、getCode、getStorageAt、getTransactionCount、getBlockByNumber、getBlockByHash、chainId、baseFee。
DeBank 命名空间(无前缀)
version、getAddressNonce、getAddressBalance、getAddressCode、getStorageAt、contractMultiCall、simulateTransactions、estimateGas、getLatestBlock、getBlockByHeight、getBlockById、blockIsValid。
其他
完整参数见 RPC 参考。
多链执行器
--evm-type 选择执行器实现:
新增链需要实现
EvmExecutor trait,链特定逻辑放在 leafage-evm-chains crate。
--historical-rpc 与 --historical-height 用于没有 block diff 的历史区间(如 OP pre-bedrock):低于阈值的请求转发到外部 RPC。
命令行
常用参数见配置参考。
服务注册
启动时把自己写入 etcd 的{chain_id}[/{version}]/nodes/{ip}_{port},初始 stateType 为 2(落后)。之后由 consistency-checker 根据轮询结果改写状态,nodex-proxy watch 这些键更新节点池。
注册使用周期性事务(仅在键不存在时写入),不覆盖 checker 写入的状态;进程退出时删除自己的键。
指标
--prometheus-addr 开启后暴露:
开发
leafage-bench 用于比较 leafage-evm 与 geth 的 eth_call 表现:
相关文档
仓库内的设计文档:Architecture.md、StateManage.md、StateUpdater.md、Database.md、DataSpec.md。