把最可能决定最终结果且最便宜的条件放在最前面,让后面的昂贵检查尽可能被短路掉。&&串联:最左边的条件应当是最可能为false且最便宜的。||串联:最左边的条件应当是最可能为true且最便宜的。
把 最可能决定最终结果 且 最便宜 的条件放在最前面,让后面的昂贵检查尽可能被短路掉。
&& 串联:最左边的条件应当是 最可能为 false 且最便宜 的。
|| 串联:最左边的条件应当是 最可能为 true 且最便宜 的。
同时,考虑 gas 成本排序:
便宜操作:比较局部变量(栈变量)、常量、函数参数、msg.sender 等
昂贵操作:SLOAD(读取状态变量)、跨合约调用、计算哈希等
例:
// 状态变量
address public owner;
mapping(address => bool) public whitelist;
bool public paused;
// 未优化:每次都读取 paused 和 whitelist(SLOAD),即使调用者是 owner
function sensitiveAction() external {
require(paused == false, "Paused");
require(whitelist[msg.sender] || msg.sender == owner, "Not allowed");
// ... 业务逻辑
}
每次都会执行 2 次 SLOAD(paused、whitelist),即使 msg.sender == owner 直接允许。
// 优化后(利用短路)
function sensitiveAction() external {
require(msg.sender == owner || (!paused && whitelist[msg.sender]), "Not allowed");
// ... 业务逻辑
}
执行逻辑:
msg.sender == owner(极便宜,比较栈上的地址)。true,短路,不再读取 paused 和 whitelist,直接通过。msg.sender 不是 owner,才继续读取 paused 和 whitelist[msg.sender](两次 SLOAD)。结果:普通用户调用时 gas 差不多,但 owner 调用时可省下两次 SLOAD(~2100+ gas)。如果合约有大量仅管理员可用的函数,节省非常可观。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!
作者暂未设置收款二维码