Solidity 优化 - 控制 gas 成本
常见的排序列表数据结构,如果向列表中添加元素并确保其仍是排序的,缺乏经验的实现需要在整个集合中进行迭代,以找到合适的位置。
一种更有效的方法是使合约需要进行链下计算,为其提供要添加元素的确切位置。链上计算仅需要进行验证(例如:添加的值时候位于其相邻元素之间),这可以防止成本随数据结构的总大小线性增长。
左边: 在列表链上循环会消耗 O(n) gas ,该 gas 会随着列表的增长而线性扩展。
右边(正确):计算链下位置并验证链上价值会消耗固定量的 gas ,而与列表的大小无关。
使用提款模式:智能合约可以记录每个用户是否执行该操作的映射,而不是遍历每个地址并对其执行操作。由每个用户负责发送交易以启动操作,而智能合约仅验证没有执行来自同一用户的重复操作。采用这种方案,每笔交易的成本保持不变,不会随着用户总数的增长而增加。这消除了一次交易中超出 gas 限制的可能性。但是,需要注意的是, gas 总成本会比在一次交易中完成所有操作更多。
左边: 调用一次 Distribute 操作所花费的费用与一笔交易中的接收方数量成正比,这在足够多的用户的情况下会失败。
右边(正确): 所有交易(1 个 Add 和 4 个 Claim)的成本都不会随用户数量而增加。
仅将默克尔根存储为状态:减轻状态膨胀的一种更极端的方法是在区块链上仅存储 32 字节的 Merkle Root。交易的调用方负责为交易在执行过程中需要使用的任何数据提供适当的值和证明。智能合约可以验证证明是正确的,但不需要在链上持久存储任何信息-只需保留和更新一个 32 字节根。
潜在的无限迭代:作为图灵计算机语言,Solidity 允许执行可能无限制的循环。例如,如果一组用户没有明显的大小限制,那么为“每个”用户做某事的函数可能消耗大量的 gas 。避免无限循环将使 gas 成本更易于管理。这是你可以用来改善智能合约的一些技巧。
一些 Solidity 编程模式,这些模式可能会导致昂贵的交易费用,或者更糟糕的是由于区块 gas 限制导致无法执行智能合约。
这绝不是一个详尽的清单,但它应该使你了解如何优化合约。