如何确保performUpkeep执行完成前不会被重复触发调用?
Chainlink Keeper重复触发performUpkeep的解决方案
你可以通过添加请求状态锁的方式解决这个问题,同时不会影响原有的失败重试逻辑,具体实现步骤如下:
- 新增一个布尔类型的状态变量,用来标记当前是否存在正在等待链下数据返回的请求
- 在
checkUpkeep的判断逻辑中新增状态锁校验,只有没有待处理请求时才允许返回upkeepNeeded=true - 进入
performUpkeep后第一时间修改状态锁标记,避免等待链下返回的窗口期被重复触发 - 链下数据回调时无论请求成功还是失败都释放状态锁,失败场景下因为没有更新
latestDateChecked,后续checkUpkeep会自动重新返回true触发重试
修改后的代码示例:
// 新增状态锁变量,默认值为false bool public isRequestPending; function checkUpkeep(bytes calldata checkData) external view returns (bool upkeepNeeded, bytes memory performData) { require(revealed); require(round < 7); uint32 secondsInDay = 86_400; // 新增状态锁判断,只有无待处理请求才满足触发条件 upkeepNeeded = !isRequestPending && _getDateBeforeTimestamp(block.timestamp) >= latestDateChecked + secondsInDay; performData = checkData; } function performUpkeep(bytes calldata /* performData */) external { // 执行请求前先上锁,避免重复触发 isRequestPending = true; requestVolumeData(); } // 原有的链下数据回调函数 function fulfillVolumeData(uint256 volume, bool requestSuccess) external onlyOracle { // 无论请求成功失败都先释放锁 isRequestPending = false; if(requestSuccess) { // 仅请求成功时更新日期 latestDateChecked = _getDateBeforeTimestamp(block.timestamp); // 其余业务逻辑 } // 请求失败时不更新latestDateChecked,后续checkUpkeep会自动触发重试 }
注意需要给fulfill回调函数添加权限控制,仅允许你对接的预言机节点调用,避免恶意用户手动解锁状态锁导致异常重复执行。
内容的提问来源于stack exchange,提问作者Alexa S
相关产品推荐
相关产品推荐

