如何防止外部Upkeep调用合约的checkUpkeep函数避免状态篡改
如何防止外部调用Chainlink Automation的checkUpkeep函数修改合约状态
核心原则:让checkUpkeep保持只读
Chainlink Automation的checkUpkeep设计初衷是仅用于状态检查,本身不应该包含任何修改合约状态的逻辑。如果你的函数里有写操作,这是违反最佳实践的,也是外部调用能修改状态的根源。
正确的做法是给checkUpkeep添加view修饰符,确保它只能读取状态:
function checkUpkeep(bytes calldata) external view returns (bool upkeepNeeded, bytes memory performData) { // 仅读取状态判断是否需要执行Upkeep upkeepNeeded = (currentBalance > threshold && block.timestamp > nextExecutionTime); // 传递给performUpkeep的参数(可选) performData = abi.encode(currentBalance); }
强制校验调用者(仅在特殊场景下使用)
如果因为业务需求,必须在checkUpkeep中执行非只读操作(不推荐),可以通过校验调用者地址来限制只有Chainlink Automation合约能调用。不同链上的Chainlink Automation注册合约地址是固定的,你可以硬编码或通过构造函数传入:
// 以以太坊主网为例,Chainlink Automation Registry地址:0x02777053d6764996e594c3E88AF1D58D5363a2e6 address public immutable chainlinkAutomationRegistry; constructor(address _registry) { chainlinkAutomationRegistry = _registry; } function checkUpkeep(bytes calldata) external returns (bool upkeepNeeded, bytes memory performData) { // 校验调用者权限 require(msg.sender == chainlinkAutomationRegistry, "Only Chainlink Automation allowed"); // 你的业务逻辑(尽量避免状态修改) upkeepNeeded = true; performData = ""; }
关于Flexible Upkeeps的额外防护
在Chainlink控制台创建Flexible Upkeep时,你可以配置Upkeep的触发条件和权限,但这只是平台层的限制。合约层的防护才是最可靠的,因为任何人都能直接调用合约的公开函数。
关键提醒
状态修改逻辑应该放在performUpkeep函数中,Chainlink Automation节点在调用performUpkeep前会自动校验权限,外部地址无法随意触发该函数执行状态修改。
内容的提问来源于stack exchange,提问作者asusrid
相关产品推荐
相关产品推荐

