前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Solidity:Gas 优化

Solidity:Gas 优化

作者头像
孟斯特
发布2024-06-11 18:54:34
920
发布2024-06-11 18:54:34
举报
文章被收录于专栏:code人生code人生

在Solidity中,优化gas使用是非常重要的,因为每一笔交易都需要消耗gas。以下是一些可以帮助你优化gas使用的技巧:

使用更小的数据类型:更小的数据类型消耗更少的gas。例如,使用uint8代替uint256可以节省gas。•使用calldata代替memory:在Solidity中,calldata是一个非修改的、只读的数据存储位置,用于函数参数。它只在外部函数中可用,也就是说,只有被external修饰符修饰的函数才能使用calldata。与memory相比,calldata是在EVM的执行环境中,不需要从存储或内存中读取数据。•避免在循环中进行昂贵的操作:在循环中进行昂贵的操作(如调用外部合约或写入状态变量)会消耗大量的gas。如果可能,尽量在循环外部进行这些操作。

代码语言:javascript
复制
    // 不推荐
    for (uint i = 0; i < array.length; i++) {
        array[i] = someExternalContract.calculate(i);
    }

    // 推荐
    uint[] memory results = someExternalContract.calculateAll(array.length);
    for (uint i = 0; i < array.length; i++) {
        array[i] = results[i];
    }

使用事件而不是存储数据:如果你只需要在链外访问数据,那么使用事件比存储数据更加节省gas。事件的gas成本比存储数据的gas成本要低得多。

代码语言:javascript
复制
    // 不推荐
    uint public lastUpdated;

    function update() public {
        lastUpdated = now;
    }

    // 推荐
    event Updated(uint timestamp);

    function update() public {
        emit Updated(now);
    }

删除不需要的数据:当你不再需要某些数据时,使用delete关键字删除它们可以返还gas。

代码语言:javascript
复制
    mapping(address => uint) public balances;

    function burn(address user, uint amount) public {
        require(balances[user] >= amount, "Insufficient balance");
        balances[user] -= amount;
        if (balances[user] == 0) {
            delete balances[user];
        }
    }

避免冗余的存储数据:如果需要多次读取同一个存储变量,考虑将它存储在内存变量中。

代码语言:javascript
复制
    // 不推荐
    function calculate() public {
        uint a = balances[msg.sender];
        uint b = balances[msg.sender];
        uint c = a + b;
    }

    // 推荐
    function calculate() public {
        uint balance = balances[msg.sender];
        uint c = balance + balance;
    }

使用库函数:在Solidity中,库函数可以帮助我们重用代码并优化gas消耗。这是因为库函数在EVM级别上被视为内联函数,所以它们通常比在合约中直接实现相同逻辑的函数更加节省gas。

代码语言:javascript
复制
    // 定义一个库 SafeMath
    library SafeMath {
        function mul(uint a, uint b) internal pure returns (uint) {
            if (a == 0) {
                return 0;
            }
            uint c = a * b;
            require(c / a == b, "Multiplication overflow");

            return c;
        }
    }

    contract MyContract {
        using SafeMath for uint;

        uint public value;

        function multiply(uint amount) public {
            value = value.mul(amount); // 使用SafeMath库的mul函数
        }
    }

使用静态调用:如果你只需要读取其他合约的数据,那么使用staticcall比使用call更加节省gas,因为staticcall不会改变状态。•staticcallcall更加节省gas,原因有两点:•安全性:由于staticcall不能修改状态,因此它不会引发复杂的状态变化,也就不会消耗大量的gas。另一方面,call可以修改状态,因此它可能会引发复杂的状态变化,消耗大量的gas。•简单性staticcall只需要读取数据,因此它的计算量较小,消耗的gas也较少。另一方面,call可以执行任何操作,包括计算密集型的操作,因此它可能会消耗大量的gas。•使用immutableconstant:如果有一个在合约生命周期内不会改变的值,那可以使用immutableconstant,这可以节省gas。

代码语言:javascript
复制
   // 不推荐
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    // 推荐
    address public immutable owner;

    constructor() {
        owner = msg.sender;
    }

优化数组:如果合约中使用了数组,可以考虑使用mapping来优化数组操作。

代码语言:javascript
复制
    // 不推荐
    uint[] public array;

    function remove(uint index) public {
        for (uint i = index; i<array.length-1; i++){
            array[i] = array[i+1];
        }
        array.pop();
    }

    // 推荐
    mapping(uint => uint) public map;
    uint public size = 0;

    function remove(uint index) public {
        map[index] = map[size-1];
        delete map[size-1];
        size--;
    }

使用require而不是assertrequireassert都可以用来检查条件,但require在失败时会返还剩余的gas,而assert则不会。

代码语言:javascript
复制
    // 不推荐
    function transfer(address to, uint amount) public {
        assert(balances[msg.sender] >= amount);
        balances[msg.sender] -= amount;
        balances[to] += amount;
    }

    // 推荐
    function transfer(address to, uint amount) public {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        balances[msg.sender] -= amount;
        balances[to] += amount;
    }

声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)[1]进行许可,使用时请注明出处。 Author: mengbin[2] blog: mengbin[3] Github: mengbin92[4] cnblogs: 恋水无意[5] 腾讯云开发者社区:孟斯特[6]


References

[1] 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0): https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh [2] mengbin: mengbin1992@outlook.com [3] mengbin: https://mengbin.top [4] mengbin92: https://mengbin92.github.io/ [5] 恋水无意: https://www.cnblogs.com/lianshuiwuyi/ [6] 孟斯特: https://cloud.tencent.com/developer/user/6649301

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 孟斯特 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • References
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档