eos 节点验证:cleos get schedule 命令详解与生产者调度表(Producer Schedule)查询实战
【免费下载链接】eosAn open source smart contract platform项目地址: https://gitcode.com/gh_mirrors/eo/eos
导读
在 EOSIO 智能合约平台中,出块生产者(Block Producer)由链上选举决定,而决定"谁在什么时候出块"的正是生产者调度表(Producer Schedule)。本文围绕cleos get schedule命令展开,讲解如何通过该命令查询节点当前的 active / pending / proposed 三张调度表,并结合 eos 仓库源码(cleos 客户端、chain_api_plugin、chain_plugin 与 controller 实现)剖析其底层原理与数据来源,帮助你快速掌握生产者调度状态的日常巡检与调试方法。
cleos get schedule 命令概览
cleos get schedule是 cleos 客户端get子命令族中的一员,用于从所连接的 nodeos 节点检索生产者调度表(producer schedule)。在 cleos 命令入口 中,该子命令被注册为:
actionRoot->add_subcommand("schedule", localized("Retrieve the producer schedule"));其完整语法如下:
cleos get schedule [OPTIONS]支持的命令行选项
根据 get/schedule.md 文档 与 main.cpp 中 get_schedule_subcommand 的实现,本命令支持以下选项:
| 选项 | 别名 | 说明 |
|---|---|---|
-h | --help | 打印帮助信息并退出 |
-j | --json | 以 JSON 格式输出结果 |
从源码看,--json标志被保存在bool print_json成员中(默认false):
struct get_schedule_subcommand { bool print_json = false; ... get_schedule->add_flag("--json,-j", print_json, localized("Output in JSON format"));当print_json为true时,cleos 会将原始 RPC 返回结果以美化 JSON 格式打印;否则按人类可读的表格形式输出 active、pending、proposed 三张表。
基本用法示例
cleos get schedule该命令直接返回当前生产者调度表。以下是一次典型输出(对应文档中的示例):
active schedule version 0 Producer Producer key ============= ================== eosio EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV pending schedule empty proposed schedule empty输出分为三段:active schedule(当前生效)、pending schedule(等待生效)、proposed schedule(链上提案中)。当某一阶段的调度表为空时,显示empty。
深入理解输出字段:version、Producer 与签名密钥
schedule version(调度表版本号)
在 producer_schedule.hpp 中,生产者调度表被定义为:
struct producer_schedule_type { uint32_t version = 0; ///< sequentially incrementing version number vector<producer_key> producers; ... };其中version是逐次递增的版本号,每当调度表内容发生变化(如新一届生产者名单生效)时递增。cleos 输出中的active schedule version 0即打印该字段。多版本协议特性激活前,调度表版本号通常从 0 开始递增。
Producer 与 Producer key / Authority
cleos 的打印逻辑位于 main.cpp 的 print 函数,它针对新旧两种调度表格式做了兼容处理:
for( auto& row: schedule["producers"].get_array() ) { if( row.get_object().contains("block_signing_key") ) { // pre 2.0 printf( " %-13s %s\n", row["producer_name"].as_string().c_str(), row["block_signing_key"].as_string().c_str() ); } else { printf( " %-13s ", row["producer_name"].as_string().c_str() ); auto a = row["authority"].as<block_signing_authority>(); ... } }- pre 2.0 格式:每条生产者记录包含
producer_name与block_signing_key(单一出块签名公钥),输出列标题为Producer key。 - 2.0+ 格式:引入
authority字段,即block_signing_authority_v0结构(包含threshold阈值与keys多公钥权重列表),输出列标题为Producer Authority,并以 JSON 序列化形式打印该 authority。
文档示例中的Producer key列即对应 pre-2.0 的旧格式输出;连接 2.0 及以上版本节点时,会看到Producer Authority列。两种格式可以在链上升级协议特性后并存,cleos 通过contains("block_signing_key")自动判别,保持向后兼容。
使用 --json 获取机器可读的完整结构
当需要将调度表信息交给脚本或其他程序处理时,使用-j/--json选项:
cleos get schedule -j其输出对应 RPC 返回的原始 JSON,顶层包含active、pending、proposed三个字段。pending 与 proposed 为空时对应字段为null。一个 2.0+ 格式的 JSON 输出示例如下:
{ "active": { "version": 2, "producers": [ { "producer_name": "eosio", "authority": { "threshold": 1, "keys": [ { "key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "weight": 1 } ] } } ] }, "pending": null, "proposed": null }从 cleos 源码看,JSON 模式下直接透传节点返回的变体对象(variant),不做任何二次加工,因而与 HTTP RPC 的响应结构完全一致:
if ( print_json ) { std::cout << fc::json::to_pretty_string(result) << std::endl; return; }底层链路:从 cleos 到 nodeos 的 RPC 调用
HTTP 端点映射
cleos get schedule实际调用的是 nodeos 的只读链 API。在 httpc.hpp 中定义了端点常量:
const string chain_func_base = "/v1/chain"; const string get_schedule_func = chain_func_base + "/get_producer_schedule";即最终请求POST /v1/chain/get_producer_schedule,请求体为空对象{}。
服务端注册与鉴权
在 chain_api_plugin.cpp 中,该接口被注册为只读(read-only)接口,无需任何请求参数:
CHAIN_RO_CALL(get_producer_schedule, 200, http_params_types::no_params_required),这意味着:
- 调用节点必须加载
chain_api_plugin(通常随 nodeos 默认启用); - 该接口不修改链状态,属于只读查询,适合巡检脚本定时调用。
对应的请求参数与响应结构体定义在 chain_plugin.hpp:
struct get_producer_schedule_params { }; struct get_producer_schedule_result { fc::variant active; fc::variant pending; fc::variant proposed; };其中active、pending、proposed的反射序列化顺序与 JSON 输出字段顺序一致。
源码级原理:三张调度表的数据来源
get_producer_schedule的服务端实现位于 chain_plugin.cpp:
read_only::get_producer_schedule_result read_only::get_producer_schedule( const read_only::get_producer_schedule_params& p ) const { read_only::get_producer_schedule_result result; to_variant(db.active_producers(), result.active); if(!db.pending_producers().producers.empty()) to_variant(db.pending_producers(), result.pending); auto proposed = db.proposed_producers(); if(proposed && !proposed->producers.empty()) to_variant(*proposed, result.proposed); return result; }结合 controller.hpp 的声明可以理解三张表的语义:
| 字段 | 数据来源 | 语义 |
|---|---|---|
active | db.active_producers() | 当前正在生效的生产者名单,直接决定下一区块由谁出块,始终非空 |
pending | db.pending_producers() | 已确定将在未来生效的调度表;仅当producers非空时才填充,否则字段为null |
proposed | db.proposed_producers() | 链上提案中、尚未生效的调度表;由set_proposed_producers等操作产生,可为空 |
值得注意的实现细节:pending与proposed在"内容为空"时不会出现在结果中(对应null),而active总是被填充。这解释了 cleos 表格输出中pending schedule empty/proposed schedule empty的来源——print函数在字段为null时打印empty:
if (schedule.is_null()) { printf("%s schedule empty\n\n", name); return; }controller层对调度表的管理(set_proposed_producers声明于 controller.hpp)最终影响 active / pending 状态的切换,整个过程由链上多签提案、投票与出块循环共同驱动。
实战场景与注意事项
场景一:巡检当前出块人是否异常
cleos get schedule | grep -A20 "active schedule"通过比对 active 表中的 producer_name 与密钥,可快速判断节点是否处于预期的生产轮次;若 active 表为空或版本号异常,说明节点状态可能与主网脱节。
场景二:脚本化监控调度表切换
cleos get schedule -j | jq '.pending != null'结合jq可在调度表切换前获得告警信号(pending 非空意味着即将发生生产者换届)。
注意事项
- 依赖节点可用性:该命令是纯只读查询,必须确保 nodeos 正在运行且已加载
chain_api_plugin,否则 cleos 会报连接失败。 - 格式差异:2.0 版本后
authority结构取代单一block_signing_key,解析 JSON 输出时应同时兼容两种字段(详见上文"Producer 与 Producer key / Authority"小节)。 - 与 get_producers 的区别:
cleos get producers(对应/v1/chain/get_producers)返回的是所有参选生产者及其投票权重(含total_votes、url等竞选信息),而get schedule只返回已进入调度轮转的最终名单,两者用途不同,排查节点出块问题时经常搭配使用。
小结
cleos get schedule是查询 EOSIO 链生产者调度状态的快捷入口:它通过POST /v1/chain/get_producer_schedule只读接口,返回active、pending、proposed三张调度表,覆盖"当前生效—即将生效—链上提案"三个阶段。结合 eos 仓库源码可以看到,cleos 在客户端完成了旧版block_signing_key与新版authority格式的兼容呈现,而 chain_plugin 则从 controller 的调度表对象中直接取数。掌握这一命令及其底层实现,是日常监控与调试出块节点的重要基本功。
【免费下载链接】eosAn open source smart contract platform项目地址: https://gitcode.com/gh_mirrors/eo/eos
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考