{"content":{"title":"如何在EOS中调度自动智能合约执行","body":"作者: MixBytes 团队\r\n\r\n![](https://img.learnblockchain.cn/2025/03/09/06.jpg)\r\n\r\n简介\r\n\r\n软件开发通常涉及需要定期执行的任务。例如，Unix 系统有 crond 来满足这些目的。\r\n\r\n在我们开始讨论解决方案之前，先回答一下我们为什么在区块链中需要 cron。\r\n\r\n有很多应用，以下是其中一些：\r\n\r\n- 你是一个 Dapp 开发者，在表中存储数据，占用了一些 RAM 空间。内存是需要付费的，因此应用需要定期清理这些表。\r\n\r\n- 你正在开发一个货币转换器，应用需要定期从预言机获取数据。\r\n\r\n- 你是一名加密基金经理，时时需要向客户发送一部分利润分成。\r\n\r\n我们经常需要审核和编写智能合约，并且经常遇到上述问题。不幸的是，EOS 不允许创建定期任务，因此我们尝试通过编写我们的 cron 智能合约（Cronos）来填补这个空白。\r\n\r\n什么是 Cronos\r\n\r\nCronos 是一个针对 EOS 的 cron 智能合约，帮助 DApps 执行定期任务。\r\n\r\n当然，你可以手动调用合约方法或编写一个脚本来为你做到这一点。然而，支付少量费用以进行定期的 cronos 调用并停止担心要容易和安全得多。这样，你就得到了某种 cron-as-a-service :)\r\n\r\n使用 Cronos（内存清理）\r\n\r\n服务的工作原理如下：用户向智能合约发送所需数量的 EOS 代币。然后，智能合约使用调度函数创建任务。在任务执行过程中，合约将自动扣除一定量的 EOS 代币。\r\n\r\n例如，如果你想每 42 秒清理智能合约存储，可以使用 Cronos 创建这样的任务：\r\n\r\n```auto hljs apache\r\ncleos push action cron schedule '[\"andrew\", \"mydapp\", \"cleanup\", 42]' -p andrew\r\n```\r\n\r\n如果开发者正确实现了合约的清理操作，则清理将成功进行。Cronos 表中将创建任务及其执行时间的条目。\r\n\r\n底层实现\r\n\r\nCronos 相当简单。账号所有者在给定间隔（polling_interval）内调用一次 run。然后，在合约执行过程中，会创建一个带有相同 polling_interval 的 _deferred transaction_。\r\n\r\n你可以在 [官方文档](https://developers.eos.io/eosio-cpp/docs/communication-model) 中了解有关延迟交易的更多信息。别忘了查看 [使用案例](https://cmichel.io/deferred-transactions-on-eos/)。\r\n\r\n注意，在 EOS 交易执行时间限制为 30 毫秒。因此，为单个交易中处理的记录数设置限制（rows_count）是合理的。\r\n\r\n以下是带注释的代码库：\r\n\r\n```auto hljs cpp\r\nACTION run(uint32_t polling_interval, uint32_t rows_count) {\r\n    // 确保事务是由当前合约创建的\r\n    require_auth(get_self());\r\n\r\n    // 检查是否应停止执行\r\n    if (stop_execution.get())\r\n        return;\r\n\r\n    // 记录处理\r\n    scan_schedules(rows_count);\r\n    // 在 polling_interval 秒后再次调用 run\r\n    create_transaction(_self, _self, \"run\", polling_interval, make_tuple(polling_interval, rows_count));\r\n}\r\n\r\ntemplate<class ...TParams>\r\nvoid create_transaction(name payer, name account, const string &action, uint32_t delay,\r\n        const std::tuple<TParams...>& args) {\r\n    // 创建一个具有所需延迟的延迟事务\r\n    eosio::transaction t;\r\n    t.actions.emplace_back(\r\n            permission_level(_code, \"active\"_n),\r\n            account,\r\n            name(action),\r\n            args);\r\n\r\n    t.delay_sec = delay;\r\n\r\n    // 出于调试目的，你需要一个唯一 ID\r\n    auto sender_id = unique_id.get();\r\n    t.send(sender_id, payer);\r\n    unique_id.set(sender_id + 1, _code);\r\n}\r\n```\r\n\r\n表中任务的处理逻辑相当简单。Cronos 选择执行时间最短的任务，确保它必须被执行（即当前时间小于或等于执行时间），并在确保用户有足够的 EOS 代币余额后创建一个延迟交易。在任务处理结束时，Cronos 自动重新计算下一次调用的时间。\r\n\r\n```auto hljs objectivec\r\n// 我们获取下一个区块创建的 unix 时间\r\ntime_point_sec current_time(now());\r\n\r\n// 我们检查是否是执行任务的时间\r\nif (current_time >= item.next_run) {\r\n    const name& account_from = item.from;\r\n\r\n    // 确保用户在他的钱包账户上有足够的资金\r\n    if (get_balance(account_from) >= CALL_PRICE) {\r\n        reduce_balance(account_from, CALL_PRICE);\r\n        create_transaction(account_from, item.account, item.action, item.period, tuple<name>(account_from));\r\n\r\n    // 刷新运行时间\r\n    cron_table.modify(item, _self, [&](auto& row) {\r\n        row.next_run = item.next_run + item.period;\r\n    });\r\n}\r\n```\r\n\r\n延迟交易的陷阱\r\n\r\n我必须说，延迟交易的方法有一个显著缺点。例如，如果当前交易因某种原因失败，则不会创建延迟交易。为避免这种情况，你需要在调试时加倍小心。否则，mydapp 合约的所有者将不得不再次手动调用 run 操作。\r\n\r\n下一步\r\n\r\n我们的团队将添加一些功能，允许设置类似于原始 crond Unix 的任务规则。\r\n\r\n参考\r\n\r\nGithub 仓库：\r\n\r\n[https://github.com/mixbytes/cronos](https://github.com/mixbytes/cronos)\r\n\r\n- MixBytes 是谁？\r\n\r\n[MixBytes](https://mixbytes.io/) 是一支由专家区块链审计师和安全研究人员组成的团队，专注于为 EVM 兼容和 Substrate 基础的项目提供全面的智能合约审计和技术咨询服务。请加入我们 [X](https://twitter.com/MixBytes)，以随时了解最新的行业趋势和见解。\r\n\r\n>- 原文链接： [mixbytes.io/blog/schedul...](https://mixbytes.io/blog/schedule-automatic-smart-contract-execution-eos)\r\n>- 登链社区 AI 助手，为大家转译优秀英文文章，如有翻译不通的地方，还请包涵～"},"author":{"user":"https://learnblockchain.cn/people/24680","address":null},"history":null,"timestamp":1741490576,"version":1}