EOSIO cleos `system canceldelay` 实战指南:取消延迟交易的命令用法与链上实现原理
2026/9/24 23:48:29 网站建设 项目流程
  • 区块链

【免费下载链接】eos

An open source smart contract platform

项目地址:https://gitcode.com/gh_mirrors/eo/eos
点击查看免费下载

导读

cleos system canceldelay是 EOSIO 生态中用于**取消尚未执行的延迟交易(delayed transaction)**的标准命令行工具。在节点上提交带--delay-sec延迟参数的交易、或合约通过eosio::check之外的延迟调度机制排队交易后,只要交易尚未到达延迟窗口或仍在延迟期间,授权账户即可通过本命令将其从链上撤销。读完本文,你将掌握cleos system canceldelay的完整参数语义、可复制的实战命令、其底层canceldelayaction 的数据结构与链端授权校验逻辑,从而能在自己的测试网或业务场景中准确、安全地管理延迟交易。

延迟交易机制简述:为什么需要 canceldelay

在 EOSIO 区块链中,交易可以设置一个delay_sec延迟秒数。当一笔交易的delay_sec > 0时,节点不会立即执行它,而是将其放入"生成的交易"(generated transaction)索引中,待到delay_until时间点再真正入块执行。从链核心实现看,延迟交易会被调度进generated_transaction_multi_index,并设置delay_until = published + delay以及基于全局配置的deferred_trx_expiration_window过期窗口,相关调度逻辑见 transaction_context.cpp。

延迟交易常见于:

  • 通过cleos提交交易时附带--delay-sec选项,例如多签(multisig)提案执行前的等待期;
  • 合约内部使用eosio::transaction延后执行的业务动作;
  • 需要人为留出"反悔窗口"的资源操作(如代理、转账等)。

由于延迟交易在真正执行前一直处于"待命"状态,业务上可能因为参数错误、条件变化或安全原因需要撤销它——这就是canceldelay存在的意义。该命令对应的 action 由系统账户eosio提供,属于内置系统合约能力(在链核心中以SET_APP_HANDLER(eosio, eosio, canceldelay)注册,见 controller.cpp),因此无需部署任何额外合约即可使用。

命令语法与位置参数

cleos system canceldelay canceling_account canceling_permission trx_id [OPTIONS]

cleos system canceldelay接受三个必填位置参数,其语义与canceldelayaction 的字段一一对应:

参数类型说明
canceling_accountTEXT原延迟交易授权(authorization)中出现的账户名,即"谁来执行取消"
canceling_permissionTEXT原延迟交易授权中出现的权限名,与canceling_account共同构成取消所需的权限级别
trx_idTEXT原始延迟交易的交易 ID(Transaction ID)

命令同时提供与标准 cleos 交易提交一致的选项集。下表基于本仓库命令参考文档 system-canceldelay.md 完整整理:

选项说明
-h, --help打印帮助信息并退出
-x, --expiration TEXT设置交易过期前的秒数,默认 30 秒
-f, --force-unique强制交易唯一;会消耗额外带宽,并取消"防止重复提交同一交易"的保护
-s, --skip-sign指定不使用钱包中已解锁的密钥对交易进行签名
-d, --dont-broadcast不将交易广播到网络(仅打印到 stdout)
-r, --ref-block TEXT设置用于 TAPOS(Transaction as Proof-of-Stake)的参考区块号或区块 ID
-p, --permission TEXT指定授权账户与权限级别,格式为account@permission;默认值为canceling_account@canceling_permission
--max-cpu-usage-ms UINT设置交易执行 CPU 预算上限(毫秒),默认 0 表示不设上限
--max-net-usage UINT设置交易网络使用预算上限(字节),默认 0 表示不设上限
--delay-sec UINT设置本笔(取消)交易的delay_sec秒数,默认 0 秒
-j, --json以 JSON 格式打印执行结果

注意:-p/--permission的默认值并非常见的account@active,而是由位置参数推导出的canceling_account@canceling_permission。这一点在 cleos 源码中通过add_standard_transaction_options_plus_signing(cancel_delay, "canceling_account@canceling_permission")显式声明,见 main.cpp。

实战用法:完整可复制的命令示例

1. 创建一笔带延迟的交易(准备场景)

要获得一个可被取消的延迟交易,首先需要提交一笔设置了延迟秒数的交易。以最简单的转账为例:

cleos push action eosio.token transfer '["alice", "bob", "1.0000 EOS", "delay test"]' \ -p alice@active \ --delay-sec 300

命令输出中会包含这笔交易的transaction_id(即后续取消所需的trx_id),并且交易不会立即生效,而是在 300 秒后进入执行队列。

2. 取消这笔延迟交易

在延迟窗口内,使用原交易授权中的账户与权限执行取消:

cleos system canceldelay alice active <transaction_id>
  • alicecanceling_account,即原延迟交易授权中的账户;
  • activecanceling_permission,即原延迟交易授权中的权限;
  • <transaction_id>→ 原延迟交易的交易 ID。

若原延迟交易使用非默认权限(例如alice@pay)授权,则取消时也必须使用完全一致的account@permission组合:

cleos system canceldelay alice pay <transaction_id> -p alice@active

上面的-p alice@active用于给这笔取消动作本身签名(默认取canceling_account@canceling_permission,即alice@pay;若你的钱包中没有该权限对应的密钥,可显式指定其他有权限的级别)。

3. 常见调试组合

  • 先预览不广播,确认 payload 无误:
    cleos system canceldelay alice active <transaction_id> -d -j
  • 在无钱包环境下手动签名(配合外部签名流程):
    cleos system canceldelay alice active <transaction_id> -s --dont-broadcast
  • 显式设置交易过期时间,避免默认 30 秒窗口内因网络原因提交失败:
    cleos system canceldelay alice active <transaction_id> -x 120

链上实现原理:从 CLI 到链端处理的完整链路

1. CLI 侧:payload 构造

cleoscanceldelay子命令定义在 main.cpp 的canceldelay_subcommand结构中。其回调逻辑把三个位置参数组装为一个canceldelayaction:

auto canceling_auth = permission_level{name(canceling_account), name(canceling_permission)}; fc::variant act_payload = fc::mutable_variant_object() ("canceling_auth", canceling_auth) ("trx_id", trx_id); auto accountPermissions = get_account_permissions(tx_permission, canceling_auth); send_actions({create_action(accountPermissions, config::system_account_name, "canceldelay"_n, act_payload)}, signing_keys_opt.get_keys());

可以看到:

  • 该 action 的接收方固定为系统账户config::system_account_name(即eosio),action 名为canceldelay
  • payload 仅含两个字段:canceling_auth(由账户名 + 权限名构成的permission_level)和trx_id
  • 交易授权默认取canceling_auth本身,即"用谁的权限取消,就由谁签名"。

2. 数据结构:canceldelay action 的 ABI 定义

canceldelayaction 的数据结构定义于 contract_types.hpp:

struct canceldelay { permission_level canceling_auth; transaction_id_type trx_id; static account_name get_account() { return config::system_account_name; } static action_name get_name() { return "canceldelay"_n; } };

其中permission_level{actor, permission}二元组,transaction_id_type即 32 字节的交易哈希。系统合约 ABI 也正式注册了该 action(见 eosio_contract_abi.cpp 与 eosio_contract_abi.cpp)。

3. 链端处理:内置处理器

由于系统合约以内置(native)方式实现,canceldelay的链端处理函数是apply_eosio_canceldelay,位于 eosio_contract.cpp:

void apply_eosio_canceldelay(apply_context& context) { auto cancel = context.get_action().data_as<canceldelay>(); context.require_authorization(cancel.canceling_auth.actor); const auto& trx_id = cancel.trx_id; context.cancel_deferred_transaction(transaction_id_to_sender_id(trx_id), account_name()); }

其核心动作是:

  1. require_authorization(canceling_auth.actor):标记并强制要求canceling_auth.actor参与了本 action 的授权;
  2. trx_id通过transaction_id_to_sender_id转换为延迟交易的 sender_id;
  3. 调用cancel_deferred_transaction,在链上删除对应的待执行延迟交易。

4. 授权校验:只有"原交易授权人"才能取消

取消操作并非任意账户可为,链端会在授权阶段严格校验"取消者"与"原延迟交易"之间的绑定关系。校验逻辑见 authorization_manager.cpp 的check_canceldelay_authorization,其要点包括:

  • 单一授权canceldelayaction 只能声明一个 authorization;
  • 权限满足:签名所用的权限必须满足canceling_auth所要求的权限;
  • 交易存在:以trx_idgenerated_transaction_multi_index中必须能查找到对应的延迟交易(且sender为空账户,即系统级延迟交易),否则报tx_not_found——即"没有该交易 ID 的延迟交易,无法取消";
  • 授权匹配canceling_auth必须出现在原延迟交易内某个 action 的 authorization 列表中,否则报错"canceling_auth in canceldelay action was not found as authorization in the original delayed transaction"。

这意味着:取消者必须恰好是原延迟交易某个 action 的授权账户与权限,不能是任意第三方;同时,若原交易已经执行完毕或已过期移除,取消同样会失败。

注意事项与限制

  • 时机窗口:只有仍处于延迟期(尚未执行)且未过期的延迟交易可以被取消。交易已入块执行、或超出deferred_trx_expiration_window过期窗口后,链上不再保留该交易,取消将报"cannot cancel trx_id=…, there is no deferred transaction with that transaction id"。
  • 授权一致性canceling_account@canceling_permission必须与原延迟交易中某个 action 的授权完全一致(含权限级别),否则校验不通过。
  • 延迟交易的延迟交易--delay-sec选项同样适用于canceldelay命令本身——即你可以在取消动作上也叠加延迟,但这在大多数场景下没有必要。
  • 无需部署合约canceldelayeosio系统账户的内置处理器提供,任何 EOSIO 节点(含测试网、本地单节点)开箱即用。
  • 性能与带宽:与普通交易一样,取消交易同样受 CPU/网络预算约束,可通过--max-cpu-usage-ms--max-net-usage显式设置上限。

延伸阅读

  • 本命令所属的完整命令族索引见 system 命令参考,其中同样列出了system newaccountsystem buyramsystem delegatebw等系统合约操作;
  • 延迟交易的调度与计费逻辑可深入阅读 transaction_context.cpp(延迟交易的前置 net 计费)与 transaction_context.cpp(schedule_transaction的入队与过期设置);
  • 合约侧取消延迟交易的原语cancel_deferred由 WebAssembly 接口暴露,定义于 webassembly/transaction.cpp,供智能合约在业务逻辑中自行实现同类取消能力。
  • 区块链

【免费下载链接】eos

An open source smart contract platform

项目地址:https://gitcode.com/gh_mirrors/eo/eos
点击查看免费下载
上一篇:Sunshine游戏串流服务器:打造个人游戏云的终极指南
下一篇:AMD Ryzen调试工具SMU Debug Tool:5分钟掌握核心参数调节技巧

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询