ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

cleos validate signatures 命令详解:EOS 交易签名验证与公钥恢复实战

cleos validate signatures 命令详解:EOS 交易签名验证与公钥恢复实战 区块链【免费下载链接】eosAn open source smart contract platform项目地址https://gitcode.com/gh_mirrors/eo/eos点击查看免费下载本指南完整讲解 EOS 节点工具cleos中validate signatures子命令的用法、参数与底层实现。该命令不依赖钱包、不上链仅凭交易 JSON 与链 ID 即可验签并恢复出签名所用公钥适用于交易签名自检、离线验签、多签权限核查等场景。阅读本文后你将掌握该命令的完整语法、如何构造合法交易 JSON、--chain-id参数的作用以及命令背后的签名恢复原理与源码级调用链。命令概述验证签名并恢复公钥cleos validate signatures是cleos validate命名空间下的唯一子命令其功能正如命令本身的描述所示Validate signatures and recover public keys验证签名并恢复公钥它接收一份已签名交易的 JSON 表示在本地对交易摘要进行签名校验并从签名中恢复出对应的公钥最终以 JSON 数组的形式打印出来。该命令的定位是纯离线校验工具它不会把交易广播到链上也不会调用钱包签名因此在排查某笔签名是否有效这笔交易到底由哪些公钥签署之类的问题时非常实用。在cleos的命令树中该命令位于validate分支之下相关定义可见 programs/cleos/main.cpp#L2652-L2686// validate subcommand auto validate app.add_subcommand(validate, localized(Validate transactions)); validate-require_subcommand(); // validate signatures string trx_json_to_validate; string str_chain_id; auto validate_signatures validate-add_subcommand(signatures, localized(Validate signatures and recover public keys)); validate_signatures-add_option(transaction, trx_json_to_validate, localized(The JSON string or filename defining the transaction to validate), true)-required(); validate_signatures-add_option(-c,--chain-id, str_chain_id, localized(The chain id that will be used in signature verification));提示关于 JSON 输入格式的稳定性官方文档对此命令有一则重要提示该命令的 JSON 输入依赖于底层 C 类定义即transaction、signed_transaction、action等数据结构的序列化布局因此这类 JSON 输入在 EOSIO 未来版本中可能发生变化。在编写自动化脚本时应留意版本差异并尽量基于当前版本导出/生成 JSON避免硬编码长期依赖。语法与参数基本用法cleos validate signatures [OPTIONS] transaction位置参数参数类型说明transactionTEXT定义待验证已签名交易的 JSON 字符串或指向该 JSON 的文件名必填从源码可见programs/cleos/main.cpp#L2660-L2661该参数通过add_option(...)-required()声明为必填项同时命令内部使用json_from_file_or_string()解析输入programs/cleos/main.cpp#L541因此既可以直接传入 JSON 字符串也可以传入包含 JSON 的文件路径两者等价。选项选项类型说明-c, --chain-idTEXT签名验证所使用的链 IDchain id--chain-id的行为在源码中有明确分支programs/cleos/main.cpp#L2672-L2680未指定--chain-id时cleos 会调用 RPC 接口get_info()从当前连接的节点默认http://127.0.0.1:8888可用-u/--url覆盖拉取链 ID并输出日志grabbing chain_id from nodeos指定--chain-id时则直接使用该值构造chain_id_type完全不需要与任何节点通信实现离线验签。if( str_chain_id.size() 0 ) { ilog( grabbing chain_id from ${n}, (n, node_executable_name) ); auto info get_info(); chain_id info.chain_id; } else { chain_id chain_id_type(str_chain_id); }为何链 ID 如此关键EOS 交易的签名摘要由sig_digest(chain_id, context_free_data)计算得出链 ID 参与哈希拼接详见 libraries/chain/transaction.cpp#L59-L78 对get_signature_keys的实现。链 ID 不匹配验签必然失败这也正是 EOS 签名天然绑定特定链、无法跨链重放的根本原因。主网与各测试网的链 ID 各不相同例如文档示例中使用的cf057bbfb72640471fd910bcb67639c22df9f92470936cddc1ade0e2f2e7dc4f即为某一测试网的链 ID实际使用时应以目标链cleos get info输出的chain_id为准。底层原理签名恢复的完整调用链validate signatures虽然只是 cleos 的一个子命令但其核心逻辑直接复用链内核libraries/chain的签名恢复实现与节点在交易执行前的验签路径完全一致因此结果具有权威性。第一步解析 JSON 为 signed_transaction命令回调首先将输入字符串或文件解析为fc::variant再通过abi_serializer::from_variant反序列化为signed_transaction对象programs/cleos/main.cpp#L2664-L2670fc::variant trx_var json_from_file_or_string(trx_json_to_validate); signed_transaction trx; try { abi_serializer::from_variant( trx_var, trx, abi_serializer_resolver_empty, abi_serializer::create_yield_function( abi_serializer_max_time ) ); } EOS_RETHROW_EXCEPTIONS(transaction_type_exception, Invalid transaction format: ${data}, ...)注意此处使用的是abi_serializer_resolver_emptyprograms/cleos/main.cpp#L371-L373即不依赖任何合约 ABI 解析 action data因为验签只关心交易的签名摘要data字段以原始 hex 形式参与计算即可无需解码。signed_transaction在链内核中的定义libraries/chain/include/eosio/chain/transaction.hpp#L104-L125表明它继承自transaction并额外携带两类字段signatures交易签名列表context_free_data与各 context-free action 一一对应的上下文无关数据。第二步get_signature_keys 恢复公钥随后命令调用交易对象的签名恢复方法programs/cleos/main.cpp#L2682-L2685flat_setpublic_key_type recovered_pub_keys; trx.get_signature_keys( *chain_id, fc::time_point::maximum(), recovered_pub_keys, false ); std::cout fc::json::to_pretty_string(recovered_pub_keys) std::endl;其底层实现位于 libraries/chain/transaction.cpp#L59-L78fc::microseconds transaction::get_signature_keys( const vectorsignature_type signatures, const chain_id_type chain_id, fc::time_point deadline, const vectorbytes cfd, flat_setpublic_key_type recovered_pub_keys, bool allow_duplicate_keys)const { try { auto start fc::time_point::now(); recovered_pub_keys.clear(); const digest_type digest sig_digest(chain_id, cfd); for(const signature_type sig : signatures) { auto now fc::time_point::now(); EOS_ASSERT( now deadline, tx_cpu_usage_exceeded, ... ); auto[ itr, successful_insertion ] recovered_pub_keys.emplace( sig, digest ); EOS_ASSERT( allow_duplicate_keys || successful_insertion, tx_duplicate_sig, transaction includes more than one signature signed using the same key ... ); } return fc::time_point::now() - start; } FC_CAPTURE_AND_RETHROW() }从中可以提炼出几个关键行为先算摘要再逐签恢复sig_digest(chain_id, cfd)根据链 ID 与上下文无关数据生成交易摘要然后对signatures列表中的每个签名执行椭圆曲线签名恢复ECDSA recover得到对应公钥并放入flat_set自动去重、排序默认禁止重复密钥签名命令调用时传入allow_duplicate_keys false若同一密钥对同一交易签署多份签名将抛出tx_duplicate_sig异常这符合链上对交易签名的约束存在 CPU 时间上限检查deadline参数用于防止验签耗时过长cleos 此处传入fc::time_point::maximum()表示不限时而在节点侧同样的方法会以区块上下文限定的 deadline 执行并计入tx_cpu_usage计量。值得一提的是节点在打包、验证交易时也走同一路径transaction_metadata.cpp中同样调用trx-get_transaction().get_signature_keys(...)完成签名恢复libraries/chain/transaction_metadata.cpp#L19-L22。因此cleos validate signatures的输出等价于节点视角下的这笔交易由哪些公钥授权。实战示例待验证的已签名交易 JSON官方文档给出了一个完整的示例一笔eosio::voteproducer投票交易由initbactive权限发起携带一个 K1 曲线签名。该 JSON 的关键结构如下{ expiration: 2020-04-23T04:47:23, ref_block_num: 20, ref_block_prefix: 3872940040, max_net_usage_words: 0, max_cpu_usage_ms: 0, delay_sec: 0, context_free_actions: [], actions: [ { account: eosio, name: voteproducer, authorization: [ { actor: initb, permission: active } ], data: 000000008093dd74000000000000000001000000008093dd74 } ], transaction_extensions: [], signatures: [ SIG_K1_Jy81u5yWSE4vGET1cm9TChKrzhAz4QE2hB2pWnUsHQExGafqhVwXtg7a7mbLZwXcon8bVQJ3J5jtZuecJQADTiz2kwcm7c ], context_free_data: [] }字段含义一览字段说明expiration交易过期时间UTC用于限制交易的生命周期ref_block_num/ref_block_prefix引用的最近区块号与区块前缀用于防止重放max_net_usage_words/max_cpu_usage_ms资源使用上限0 表示不限制delay_sec延迟交易秒数0 表示立即生效context_free_actions上下文无关动作列表actions常规动作列表含account、name、authorizationactorpermission与 hex 编码的datatransaction_extensions交易扩展signatures已签名列表此处为一条SIG_K1_前缀的签名K1 曲线context_free_data与 context-free action 对应的数据方式一直接传入 JSON 字符串cleos validate signatures --chain-id cf057bbfb72640471fd910bcb67639c22df9f92470936cddc1ade0e2f2e7dc4f { expiration: 2020-04-23T04:47:23, ref_block_num: 20, ref_block_prefix: 3872940040, max_net_usage_words: 0, max_cpu_usage_ms: 0, delay_sec: 0, context_free_actions: [], actions: [ { account: eosio, name: voteproducer, authorization: [ { actor: initb, permission: active } ], data: 000000008093dd74000000000000000001000000008093dd74 } ], transaction_extensions: [], signatures: [ SIG_K1_Jy81u5yWSE4vGET1cm9TChKrzhAz4QE2hB2pWnUsHQExGafqhVwXtg7a7mbLZwXcon8bVQJ3J5jtZuecJQADTiz2kwcm7c ], context_free_data: [] }方式二连接节点自动获取链 ID若不显式指定--chain-id则需保证能访问到目标链的节点例如通过-u指定 API 地址cleos 会调用get info自动获取链 IDcleos -u https://api.testnet.eos.io validate signatures { expiration: 2020-04-23T04:47:23, ref_block_num: 20, ref_block_prefix: 3872940040, max_net_usage_words: 0, max_cpu_usage_ms: 0, delay_sec: 0, context_free_actions: [], actions: [ { account: eosio, name: voteproducer, authorization: [ { actor: initb, permission: active } ], data: 000000008093dd74000000000000000001000000008093dd74 } ], transaction_extensions: [], signatures: [ SIG_K1_Jy81u5yWSE4vGET1cm9TChKrzhAz4QE2hB2pWnUsHQExGafqhVwXtg7a7mbLZwXcon8bVQJ3J5jtZuecJQADTiz2kwcm7c ], context_free_data: [] }输出解读命令成功执行后输出恢复出的公钥数组每行一个[ EOS7pCywBCz5zw2bc7teCVcT7MEWUr9s749qnYDNPEsBoH32vGqqN ]该公钥即签署这笔交易所用私钥对应的 EOS 格式公钥。开发者可将其与账户initb的active权限中声明的公钥进行比对例如cleos get account initb从而确认这笔交易确实由该账户的授权密钥签署。多条签名时输出数组中会包含多个公钥flat_set自动去重排序可用于核对多签交易的签名方集合。如何构造待验证的交易 JSONvalidate signatures只负责验签不负责生成交易。构造一份合法的已签名交易 JSON 通常有三种途径cleos push transaction配合-ddry-run与-jjson选项先不广播仅输出交易 JSON再交由钱包签名后保存cleos sign或cleos multisig propose等命令的输出签名或提案相关命令可生成带signatures字段的 JSON自行构造参照上文 JSON 结构手工组装signatures字段留空或填入既有签名。注意data字段为 action 数据的 hex 编码签名计算不依赖 ABI 解码因此手写 JSON 也能验签。完整的提交流程可参考 如何提交一笔交易其中详细介绍了如何用cleos push transaction -d -j生成交易 JSON再按需签名并广播配合validate signatures可在广播前完成一次独立的签名正确性检查。注意事项与常见问题链 ID 必须与签名时一致签名摘要包含链 ID使用错误的--chain-id或连接了错误的节点将导致验签失败或恢复出错误的公钥JSON 输入格式依赖版本如文档提示该命令的 JSON 输入受底层类定义影响EOSIO 后续版本可能调整结构请勿将 JSON 结构视为长期稳定的 API默认拒绝重复签名同一密钥对同一交易的多份签名会被判定为非法对应tx_duplicate_sig多签场景应确保每个签名来自不同密钥纯本地校验时不需节点只要显式提供--chain-id该命令即可在完全离线的环境下完成验签与公钥恢复expiration / ref_block 字段不影响验签验签只针对交易摘要本身交易是否过期、引用区块是否有效属于节点侧入块校验的范畴离线验签不会对这些做判断。相关文档cleos validate 命令索引validate父命令及子命令总览如何提交一笔交易交易 JSON 的生成与广播全流程签名恢复核心实现transaction::get_signature_keys源码signed_transaction 结构定义签名与上下文无关数据的承载结构cleos validate signatures 命令实现命令行解析与回调逻辑赞分享区块链【免费下载链接】eosAn open source smart contract platform项目地址https://gitcode.com/gh_mirrors/eo/eos点击查看免费下载相关推荐Rust 交叉编译到 PlayStation 1mipsel-sony-psx 目标定义与实战构建指南Rust 交叉编译到 PlayStation 1mipsel sony psx 目标定义与实战构建指南 本文基于 Rust 编译器官方文档 mipsel so区块链cleos convert unpack_transaction 命令详解将打包交易还原为明文签名 JSONcleos convert unpack_transaction 命令详解将打包交易还原为明文签名 JSON cleos convert unpack_tra区块链Wasp 安装方式迁移实战从脚本安装器到 npm 全局包migrate-to-npmWasp 安装方式迁移实战从脚本安装器到 npm 全局包migrate to npm Wasp 自 0.21 版本起将安装方式从传统的 curl 脚本安装区块链上一篇Rust pcap性能优化指南提升数据包捕获效率的10个方法下一篇100 个 Rust 练习从零入门每道练习都有 cargo test 验证创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表