EOS 区块查询全解:cleos get block 命令的三种模式与底层 RPC 实现
EOS 区块查询全解cleos get block 命令的三种模式与底层 RPC 实现【免费下载链接】eosAn open source smart contract platform项目地址: https://gitcode.com/gh_mirrors/eo/eoscleos get block是 EOS本仓库为 eos 开源智能合约平台中用于从区块链检索完整区块的核心命令支持以区块号或区块 ID 作为参数并通过--header-state与--info两个选项切换三种不同的查询模式。本文将以官方命令参考文档为主体结合仓库源码命令定义、RPC 端点声明、链插件实现深入剖析每条命令背后的 HTTP 调用链与返回字段含义帮助读者在本地节点上准确、高效地完成区块数据查询与调试。命令概述cleos get block用于从区块链检索一个完整的区块full block。它属于cleos get子命令族中的一员定义于 programs/cleos/main.cpp子命令描述为Retrieve a full block from the blockchain。执行后命令会将区块数据以格式化 JSON 的形式输出到标准输出。与查询当前链信息cleos get info、查询账户cleos get account等命令不同cleos get block需要显式指定要查询的目标区块并且依据选项的不同可以返回完整区块对象、固定大小的区块信息摘要、或来自分叉数据库fork database的区块头状态。位置参数与选项位置参数blockblock是唯一的必填位置参数类型_TEXT_表示要检索的区块**编号number**或区块ID区块号block number一个正整数例如1、12345从创世块开始递增。区块 IDblock id一个 64 字符32 字节的十六进制字符串它是区块内容的哈希与区块号的组合例如0000000130d70e94e0022fd2fa035cabb9e542c34ea27f572ac90b5a7aa3d891。在源码中该参数被定义为必填项getBlock-add_option(block, blockArg, localized(The number or ID of the block to retrieve))-required();值得注意的是在使用--info模式时参数必须是区块号见下文约束命令内部会先尝试将其解析为 64 位整数并校验其大于 0否则直接断言报错EOSC_ASSERT( block_num (*block_num 0), Invalid block num: ${block_num}, (block_num, blockArg) );选项--header-state--header-state用于从分叉数据库fork database获取区块头状态block header state而不是从主链数据库获取完整区块。该选项对应的 RPC 端点为get_block_header_state。源码中的定义为getBlock-add_flag(--header-state, get_bhs, localized(Get block header state from fork database instead) );该模式适合需要观察区块在分叉视图中的链接关系、活跃生产者调度、确认深度等共识层信息的场景详见后文。选项--info--info用于仅按区块号获取区块信息block info返回一个固定大小的、剔除了大字段的紧凑摘要对象。该选项对应的 RPC 端点为get_block_infogetBlock-add_flag(--info, get_binfo, localized(Get block info from the blockchain by block num only) );选项互斥约束--header-state与--info两个选项不能同时使用。命令回调的第一行即对此做了断言EOSC_ASSERT( !(get_bhs get_binfo), ERROR: Either --header-state or --info can be set );同时由于--info模式只接受区块号若传入的字符串无法被解析为正整数也会抛出Invalid block num断言错误。三种查询模式的调用分派cleos get block的完整回调逻辑如下节选自 programs/cleos/main.cppgetBlock-callback([blockArg, get_bhs, get_binfo] { EOSC_ASSERT( !(get_bhs get_binfo), ERROR: Either --header-state or --info can be set ); if (get_binfo) { // --info 模式只接受区块号调用 /v1/chain/get_block_info ... const auto arg fc::variant_object(block_num, static_castuint32_t(*block_num)); std::cout fc::json::to_pretty_string(call(get_block_info_func, arg)) std::endl; } else { // 默认/--header-state 模式接受区块号或区块 ID调用对应 RPC const auto arg fc::variant_object(block_num_or_id, blockArg); if (get_bhs) { std::cout fc::json::to_pretty_string(call(get_block_header_state_func, arg)) std::endl; } else { std::cout fc::json::to_pretty_string(call(get_block_func, arg)) std::endl; } } });由此可以总结出三种模式及其对应的 RPC 端点端点定义见 programs/cleos/httpc.hpp命令行形式底层 RPC 端点请求参数返回内容cleos get block blockPOST /v1/chain/get_block{block_num_or_id: num_or_id}完整区块对象cleos get block --info numPOST /v1/chain/get_block_info{block_num: num}固定大小的区块信息摘要cleos get block --header-state blockPOST /v1/chain/get_block_header_state{block_num_or_id: num_or_id}分叉库中的区块头状态这三个端点均在 plugins/chain_api_plugin/chain_api_plugin.cpp 中注册为只读read-only调用CHAIN_RO_CALL(get_block, 200, http_params_types::params_required), CHAIN_RO_CALL(get_block_info, 200, http_params_types::params_required), CHAIN_RO_CALL(get_block_header_state, 200, http_params_types::params_required),因此cleos get block实际上是一组 Nodeos RPC 接口的轻量命令行封装熟悉其行为也就同时掌握了chain_api_plugin中对应 HTTP 接口的用法。使用示例以下示例均以单节点本地链创世块区块号为 1为例假设cleos已正确连接至本地nodeos节点默认http://127.0.0.1:8888可通过-u/--url指定其他节点地址详见 cleos 如何连接指定网络。获取完整区块按区块号查询cleos get block 1或按区块 ID 查询cleos get block 0000000130d70e94e0022fd2fa035cabb9e542c34ea27f572ac90b5a7aa3d891两种写法等价区块 ID 即由区块内容哈希与区块号复合而成输出一个完整的区块对象例如{ timestamp: 2018-03-02T12:00:00.000, producer: , confirmed: 1, previous: 0000000000000000000000000000000000000000000000000000000000000000, transaction_mroot: 0000000000000000000000000000000000000000000000000000000000000000, action_mroot: 0000000000000000000000000000000000000000000000000000000000000000, schedule_version: 0, new_producers: null, header_extensions: [], producer_signature: SIG_K1_111111111111111111111111111111111111111111111111111111111111111116uk5ne, transactions: [], block_extensions: [], id: 0000000130d70e94e0022fd2fa035cabb9e542c34ea27f572ac90b5a7aa3d891, block_num: 1, ref_block_prefix: 3526296288 }获取区块信息固定大小摘要cleos get block --info 1输出一个精简的区块信息对象{ block_num: 1, ref_block_num: 1, id: 0000000130d70e94e0022fd2fa035cabb9e542c34ea27f572ac90b5a7aa3d891, timestamp: 2018-03-02T12:00:00.000, producer: , confirmed: 1, previous: 0000000000000000000000000000000000000000000000000000000000000000, transaction_mroot: 0000000000000000000000000000000000000000000000000000000000000000, action_mroot: 0000000000000000000000000000000000000000000000000000000000000000, schedule_version: 0, producer_signature: SIG_K1_111111111111111111111111111111111111111111111111111111111111111116uk5ne, ref_block_prefix: 3526296288 }获取区块头状态cleos get block --header-state 1该模式返回分叉数据库中该区块的block_header_state视图包含区块之间的链接关系header前驱链、当前活跃生产者调度active_schedule、待确认的区块链接、dpos_proposed_irreversible_blocknum等共识层字段主要用于分析链的分叉与不可逆进度内容比完整区块对象更偏内部状态。返回字段详解完整区块对象字段字段类型含义timestampstring区块生产时间UTC毫秒精度producerstring生产该区块的 BP 账户名confirmeduint16生产者确认的深度由生产者指定的待确认区块数previousstring前一个区块的 ID哈希transaction_mrootstring区块内所有交易构成的 Merkle 树根哈希action_mrootstring区块内所有 action 构成的 Merkle 树根哈希schedule_versionuint32生产者调度版本号用于追踪调度变更new_producersobject/null若本区块内发生了生产者调度变更则为新调度否则为nullheader_extensionsarray区块头扩展字段列表producer_signaturestring生产者对该区块头的签名SIG_K1_...格式transactionsarray区块内打包的交易列表可为空数组block_extensionsarray区块级扩展字段列表idstring区块 ID由服务端附加见下文block_numuint32区块号由服务端附加ref_block_prefixuint32区块引用的前缀值供交易构造时引用由服务端附加其中id、block_num、ref_block_prefix三项并非区块原始数据而是由服务端在响应时附加的。对应实现见 plugins/chain_plugin/chain_plugin.cpp// serializes signed_block to variant in signed_block_v0 format fc::variant pretty_output; abi_serializer::to_variant(*block, pretty_output, ...); const auto id block-calculate_id(); const uint32_t ref_block_prefix id._hash[1]; return fc::mutable_variant_object(pretty_output.get_object()) (id, id) (block_num, block-block_num()) (ref_block_prefix, ref_block_prefix);ref_block_prefix取自区块 ID 哈希的第 2 个 32 位字id._hash[1]它常被 cleos 用于构造新交易时的参考区块信息防止交易在过期区块上被广播。区块信息对象与完整区块的差异原文档明确说明区块信息对象block info具有固定大小fixed size并且排除了以下字段new_producers、header_extensions、transactions、block_extensions。同时对比两种输出可见--info返回对象还额外包含ref_block_num字段区块号截断为 16 位无符号整数且不重复输出schedule_version之外的大字段。该摘要由服务端逐字段手工组装实现位于 plugins/chain_plugin/chain_plugin.cppreturn fc::mutable_variant_object () (block_num, block-block_num()) (ref_block_num, static_castuint16_t(block-block_num())) (id, id) (timestamp, block-timestamp) (producer, block-producer) (confirmed, block-confirmed) (previous, block-previous) (transaction_mroot, block-transaction_mroot) (action_mroot, block-action_mroot) (schedule_version, block-schedule_version) (producer_signature, block-producer_signature) (ref_block_prefix, ref_block_prefix);由于不含交易列表与扩展字段--info的响应体积恒定且远小于完整区块对象非常适合需要频繁轮询区块元信息如监控链头进度、核对区块生产者与签名的场景可显著降低带宽与解析开销。服务端解析逻辑与错误处理cleos get block将block_num_or_id原样透传给 Nodeos由chain_plugin的read_only::get_block进行识别chain_plugin.cpp。其核心逻辑为校验参数非空且长度不超过 64 个字符否则抛出block_id_type_exception尝试将参数解析为无符号 64 位整数若成功则按区块号调用db.fetch_block_by_number(*block_num)若失败则按区块 ID调用db.fetch_block_by_id(...)若找不到对应区块抛出unknown_block_exception错误消息Could not find block找到后序列化为 variant 并附加id、block_num、ref_block_prefix返回。get_block_info则严格要求block_num为无符号整数直接调用db.fetch_block_by_numberget_block_header_state与get_block类似地接受区块号或 ID但底层查询的是db.fetch_block_state_by_number/by_id且只能获取可逆reversible分叉库中的区块状态因此对早已不可逆的旧区块调用该模式可能会返回Could not find reversible block错误。对应的请求参数结构定义于 plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hppget_block_params与get_block_header_state_params均为字符串block_num_or_idget_block_info_params为无符号整型block_num。与 Nodeos RPC 接口的对应关系如果你不使用 cleos而是直接调用 HTTP API例如用curl或自研工具可参考 plugins/chain_api_plugin/chain.swagger.yaml 中的 OpenAPI 描述。三个端点的契约如下POST /v1/chain/get_block请求体{block_num_or_id: ...}返回完整区块对象BlockschemaPOST /v1/chain/get_block_info请求体{block_num: int}返回固定大小的较小区块数据子集BlockInfoschemaswagger 描述为Similar toget_blockbut returns a fixed-size smaller subset of the block dataPOST /v1/chain/get_block_header_state请求体{block_num_or_id: ...}返回区块头状态。例如用curl获取第 1 个区块的完整数据curl -X POST http://127.0.0.1:8888/v1/chain/get_block \ -d {block_num_or_id: 1}注意以上 RPC 由chain_api_plugin提供需要在nodeos启动时加载该插件相关插件说明见 chain_api_plugin 文档。常见问题与使用建议传入的区块号/ID 不存在时服务端会返回unknown_block_exceptionCould not find blockcleos 会将其作为错误输出。若区块尚未同步到本地节点也会得到同样的结果此时应先确认节点区块高度cleos get info。--info传入了区块 ID会触发Invalid block num断言错误因为该模式只接受正整数区块号。同时使用--header-state与--info触发Either --header-state or --info can be set断言错误。--header-state查询不可逆旧区块可能返回Could not find reversible block因为分叉数据库只保留可逆区块状态。区块 ID 的用途完整区块对象中的id与ref_block_prefix可被cleos用于构造后续交易时引用正确的链上下文避免交易因参考区块过期而失败同时id也可直接作为cleos get block id的参数使用。综合来看cleos get block以最小学习成本覆盖了链上区块查询的全部常见需求日常调试与分析使用默认模式获取完整区块需要轻量轮询时使用--info需要深入共识与分叉分析时使用--header-state。配合本仓库的 命令定义源码 与 链插件实现 阅读即可完整掌握从命令行参数到 RPC 端点再到数据库读取的整条调用链。【免费下载链接】eosAn open source smart contract platform项目地址: https://gitcode.com/gh_mirrors/eo/eos创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考