Remix 中的以太坊 Gas 优化策略

区块链 2026-03-28

本文以 Remix 为重点,旨在帮助读者深入了解以太坊的 gas 机制,并获取技能,成为一名专业的以太坊开发人员。通过专为 Remix IDE 设计的最佳方法,不断改进你的智能合约。

Remix设置

在本文开始之前,想必大家已经具备了一定的以太坊智能合约开发经验,也应该注意到每笔交易和部署过程都会产生gas费用。Gas确保以太坊网络健康运作,没有垃圾信息,但这也意味着我们在智能合约中编写的每一行代码在执行时都可能花费实实在在的金钱。我们将深入了解gas成本,并探讨降低gas成本的方法。在开始优化技术之前,我们需要熟悉基础概念和工具。

设置Remix

为什么选择Goerli测试网?

以太坊的测试网类似于主网,但开发人员可以在不花费真正的以太币(ETH)的情况下进行测试。由于Goerli测试网在以太坊社区中具有较高的稳定性和采用率,我们将使用它进行示例讲解。

为什么选择Remix?

Remix是一款专为以太坊智能合约开发而设计的开源工具,提供了一个用户友好的环境,用于创建、部署和测试智能合约。它内置的静态分析工具对我们课程的开展至关重要,有助于大家理解各个函数的gas消耗。

在Remix上设置Goerli测试网

在浏览器中启动Remix IDE。

进入Deploy & Run Transactions。

在Environment下拉列表中,选择Injected Provider。此选项将使Remix连接到任何Web3提供商,如MetaMask。

270

确保MetaMask与Goerli测试网连接。如果尚未设置,请将MetaMask中的网络切换为Goerli测试网。

270

完成后,你的Remix现在应该显示Goerli测试网和帐户地址。

270

通过Remix在Goerli上部署基础合约

Solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.9;
contract SimpleStorage {
    uint256 public storedValue;
    function set(uint256 value) public {
        storedValue = value;
    }
    function get() public view returns (uint256) {
        return storedValue;
    }
}

复制以上合约代码。

在Remix的Solidity选项卡下,单击+图标创建一个新文件,并将其命名为SimpleStorage.sol。

粘贴合约代码。

进入Deploy & Run Transactions选项卡。

单击Deploy按钮。确认MetaMask交易。现在,你的合约便成功在Goerli测试网上部署了!(在部署合约前,请确保你的Metamask钱包中有足够的GoerliETH。若需要GoerliETH,可以访问https://goerlifaucet.com/并根据说明领取。)

270

思考

尝试运行Remix中已部署的合约的set和get函数,并注意gas消耗情况。思考以下问题:

哪些操作会消耗更多的gas?

函数的复杂性与gas成本有何关系?

对以上问题的思考有助于大家为我们即将开始的gas优化课程奠定基础。

什么是Gas成本?

基本的以太坊操作和Gas成本

运营成本

在以太坊中,每个操作都会产生一定的gas成本。一些常见的成本包括:

基本成本:基本操作,如添加和设置变量。

内存成本:在内存中存储或检索数据。

存储成本:更新以太坊状态(如更新合约存储)。存储成本通常是最昂贵的。

了解常见的成本非常重要,因为许多gas优化策略即是用较便宜的操作代替较昂贵的操作。

在Remix中了解Gas成本

通过Remix,你可以轻松地了解我们的合约操作所消耗的gas。

步骤

静态分析:进入Remix中的Analysis选项卡(显微镜图标)。此工具将提供代码中的潜在问题和优化机会。

部署和运行:部署合约后(在第1课中已经执行),每次运行合约都将显示一个gas估值。当调用函数时,使用的gas将会在右下角的窗格中显示。

详细信息窗格:部署或运行函数后,单击交易日志(右下角)中的向下箭头,展开日志,查看交易的详细gas成本。

实践:了解gas消耗较多的操作

请看一个示例合约及其操作:

Solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.9;
contract GasDemo {
    uint256 public count;
    mapping(address => uint256) public balances;
    function increment() public {
        count += 1;
    }
    function updateBalance(uint256 newBalance) public {
        balances[msg.sender] = newBalance;
    }
}

通过Remix在Goerli测试网上部署GasDemo合约。

多次运行increment函数。

在交易详情中查看使用的gas。

运行updateBalance函数,设置不同的余额。

再次查看使用的gas。

270

思考:

哪个函数消耗的gas更多,为什么?(注意:每个函数附近都显示了预估的gas消耗)

更新映射与增加简单计数器在gas消耗上有何不同?

Remix中的Gas优化策略

以太坊的大部分gas支出都集中在存储方面。每个改变以太坊网络状态(存储)的操作通常都很昂贵。因此,专注于数据的保存和访问方式可以显著降低成本。在本章中,我们将探讨几种在Remix中进行存储优化的方法。

存储为何如此昂贵?

以太坊区块链提供永久存储。只要区块链存在,保存在区块链上的所有内容都将永远可用,但这种永久性是有代价的。优化存储不仅可以降低成本,还可以确保以太坊的全局状态得到高效利用。

打包存储变量

介绍

Solidity将变量存储在存储插槽中。每个插槽大小为32字节。当变量可以容纳在单个插槽时,可以分别使用单个SLOAD或SSTORE操作来读取或更新它们。

示例

请看两份合约:

Solidity
// Without Optimization
pragma solidity ^0.8.9;
contract UnoptimizedStorage {
    uint256 public value1;
    uint256 public value2;
}
Solidity
// With Optimization
pragma solidity ^0.8.9;
contract OptimizedStorage {
    uint128 public value1;
    uint128 public value2;
}

在Remix中部署这两个合约,并注意在使用不同变量时gas的差异。

在优化版本中,value1和value2共享一个32字节的插槽。

复用存储插槽

介绍

在完成存储插槽的使用后(尤其是完成临时数据存储时),你可以删除插槽或将其清零,以获得gas费用返还。

示例

Solidity
pragma solidity ^0.8.9;
contract RefundExample {
    uint256 public temporaryData;
    function storeTemporaryData(uint256 data) public {
        temporaryData = data;
    }
    function clearTemporaryData() public {
        delete temporaryData;
    }
}

在Remix中部署此合约。

存储一些临时数据,然后清除数据。

查看gas费用。留意执行删除(delete)操作获得的gas退款。

用事件代替存储

介绍

如果数据不需要在链上访问,可以考虑将其记录为事件而不是存储该数据。事件比存储操作便宜得多。

示例

Solidity
pragma solidity ^0.8.9;
contract EventExample {
    event DataStored(uint256 data);
    function storeData(uint256 data) public {
        emit DataStored(data);
    }
}

在Remix中部署并运行合合约。

请注意,与存储相比,gas成本更低。

Remix调试器和高级Gas优化技术

了解并充分利用Remix调试器是一项有用技能,不仅有助于诊断问题,还可以完善合约,节省gas成本。通过逐步执行代码,你可以发现不容易识别的大额gas消耗问题。

了解Remix调试器

在进行更复杂的优化策略前,了解如何正确使用Remix调试器非常关键。调试器提供有关每个操作的详细信息,是发现代码中大额gas消耗的重要工具。

启动调试器

在Remix中,部署合约或执行交易。

进入交易列表(在Deploy & Run选项卡下),单击交易旁的“bug”图标,启动调试器。

使用调试器

进入调试器后:

导航:使用步骤控件浏览交易的每个操作。你可以跳过、进入或退出函数并跳转到特定步骤。

详情面板:此面板将显示操作码详细信息、当前执行步骤和其他相关细节。

Solidity Locals:显示本地Solidity变量及其当前值。

状态:显示合约的状态变化。这里可以看到合约的任何变更,可能会产生更高的gas费用。

调用栈:说明当前函数调用栈。有助于理解当前的执行情境。

存储更改:在执行过程中突出显示存储更改。有助于发现可以进行gas优化的地方。

用调试器分析Gas

调试器不仅可以修复错误,还是分析合约中gas使用情况的绝佳工具。要充分提升gas的利用效率,你可以:

确定gas消耗大的操作:在逐步执行代码时,关注每个操作的gas使用情况。Gas消耗量大的操作将是优化目标。

监控存储操作:过多的存储更改(尤其是那些没有删除的更改)可能会消耗大量gas。

函数调用:外部函数调用,尤其是对其他合约的调用,可能成本较高。因此,最好确保每一次函数调用都是必要的。

案例

用Remix调试器调试一个简单的合约:

Solidity
pragma solidity ^0.8.9;
contract GasProfiler {
    uint256 public count;
    function setCount(uint256 _count) public {
        for (uint256 i = 0; i < _count; i++) {
            count += i;
        }
    }
}

在Remix中部署并运行合约。

使用调试器对setCount函数进行调试并确定gas消耗量大的操作。在上述合约中,随着_count的增加,循环操作消耗的gas也更多。

智能合约优化之高级技巧与诀窍

我们介绍了在以太坊智能合约上优化gas的基本概念和所需工具,并以Remix IDE为例进行了重点讲解。在本课程的最后一章,我们将深入探讨一些高级技术和最佳实践。本章将综合我们学到的知识,确保大家对以太坊智能合约中的gas优化有一个全面的理解。

重构和降低代码复杂性

节省gas最直接的方法之一是简化代码。执行的代码越少,消耗的gas就越少。

案例

请看以下函数:

Solidity
pragma solidity ^0.8.9;
contract OptimizationExample {
    address[] public admins;
    function isUserAdmin(address user) public view returns (bool) {
        for (uint i = 0; i < admins.length; i++) {
            if (admins[i] == user) return true;
        }
        return false;
    }
}

上面的函数使用了一个循环,随着更多管理员被添加其中,循环的成本会更高。更节省gas的结构将使用映射:

Solidity
contract OptimizationExampleOptimized {
    mapping(address => bool) public admins;
    function isUserAdmin(address user) public view returns (bool) {
        return admins[user];
    }
}

复用数据

在使用以太坊时,你需要为每一个存储付费。如果你在多个地方存储了相同的数据,可以考虑仅在一个地方存储并在其他地方引用。

库的使用

Solidity中的库是可复用的代码,可以帮助你编写模块化代码。由于库只部署一次并链接到其他合约,因此从长远来看可以节省gas。

Solidity
library SafeMath {
    function add(uint a, uint b) internal pure returns (uint) {
        uint c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }
    //... other math functions
}
contract UsingSafeMath {
    using SafeMath for uint;
    uint public value;
    function increment(uint _value) public {
        value = value.add(_value);
    }
}

删除不必要的存储

Solidity中的delete关键字可以使变量无效,从而返还部分gas。如果你不再需要特定的存储数据,请使用delete操作以申请gas返还。

使用事件日志

虽然在区块链上存储数据可能成本高昂,但记录事件相对便宜。如果有不需要从合约中读取但需要进行验证的数据,可以考虑使用事件日志。

避免成本较高的操作

某些操作消耗的gas相对更高,如:

外部函数调用比内部函数调用更昂贵。

使用存储比使用内存更昂贵。

动态数组有时会比固定大小的数组花费更多的gas。

结语

为节省gas进行的智能合约优化既是一门艺术,也是一门科学。综合使用本课程介绍的优化方法有望大大降低合约的gas成本。由于以太坊生态系统及其工具(包括Remix)总是在不断变化,我们一定要及时了解社区和生态系统的最新动态,并定期测试和优化合约。以太坊拥有一个庞大且乐于助人的社区,因此永远不要害怕寻求指导或学习最佳实践。祝编程愉快!

免责声明:本网站、超链接、相关应用程序、论坛、博客等媒体账户以及其他平台和用户发布的所有内容均来源于第三方平台及平台用户。网站及其内容不作任何类型的保证,网站所有区块链相关数据以及其他内容资料仅供用户学习及研究之用,不构成任何投资、法律等其他领域的建议和依据。用户以及其他第三方平台在本网站发布的任何内容均由其个人负责,与本网无关。

相关文章