- 区块链
【免费下载链接】eos
An open source smart contract platform
导读
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_account | TEXT | 原延迟交易授权(authorization)中出现的账户名,即"谁来执行取消" |
canceling_permission | TEXT | 原延迟交易授权中出现的权限名,与canceling_account共同构成取消所需的权限级别 |
trx_id | TEXT | 原始延迟交易的交易 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>alice→canceling_account,即原延迟交易授权中的账户;active→canceling_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 构造
cleos中canceldelay子命令定义在 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()); }其核心动作是:
require_authorization(canceling_auth.actor):标记并强制要求canceling_auth.actor参与了本 action 的授权;- 将
trx_id通过transaction_id_to_sender_id转换为延迟交易的 sender_id; - 调用
cancel_deferred_transaction,在链上删除对应的待执行延迟交易。
4. 授权校验:只有"原交易授权人"才能取消
取消操作并非任意账户可为,链端会在授权阶段严格校验"取消者"与"原延迟交易"之间的绑定关系。校验逻辑见 authorization_manager.cpp 的check_canceldelay_authorization,其要点包括:
- 单一授权:
canceldelayaction 只能声明一个 authorization; - 权限满足:签名所用的权限必须满足
canceling_auth所要求的权限; - 交易存在:以
trx_id在generated_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命令本身——即你可以在取消动作上也叠加延迟,但这在大多数场景下没有必要。 - 无需部署合约:
canceldelay由eosio系统账户的内置处理器提供,任何 EOSIO 节点(含测试网、本地单节点)开箱即用。 - 性能与带宽:与普通交易一样,取消交易同样受 CPU/网络预算约束,可通过
--max-cpu-usage-ms与--max-net-usage显式设置上限。
延伸阅读
- 本命令所属的完整命令族索引见 system 命令参考,其中同样列出了
system newaccount、system buyram、system delegatebw等系统合约操作; - 延迟交易的调度与计费逻辑可深入阅读 transaction_context.cpp(延迟交易的前置 net 计费)与 transaction_context.cpp(
schedule_transaction的入队与过期设置); - 合约侧取消延迟交易的原语
cancel_deferred由 WebAssembly 接口暴露,定义于 webassembly/transaction.cpp,供智能合约在业务逻辑中自行实现同类取消能力。
- 区块链
【免费下载链接】eos
An open source smart contract platform
相关推荐
EOSIO 账户创建完全指南:cleos create account 命令详解与链上实现原理
EOSIO 账户创建完全指南:cleos create account 命令详解与链上实现原理 导读 在 EOSIO 区块链中,账户是承载资产、权限与智能合约交
区块链EOSIO cleos 命令参考全指南:链上交互、钱包管理与资源操作实战
EOSIO cleos 命令参考全指南:链上交互、钱包管理与资源操作实战 本指南以开源智能合约平台 EOSIO 的官方命令参考文档( docs/02_cleos
区块链EOSIO cleos system unregprod 命令详解:注销区块生产者与链上治理实操
EOSIO cleos system unregprod 命令详解:注销区块生产者与链上治理实操 本篇技术指南围绕 EOSIO 开源智能合约平台中 cleos
区块链
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考