解密Solidity:添加PAYABLE关键字真的能节省GAS吗?

本文深入探讨了Solidity中payable关键字的奥秘。通常payable关键字用于允许函数接收以太币。但一个有趣的现象是,给函数添加payable关键字实际上可以减少Gas消耗。这是因为非payable函数需要额外的opcode来检查是否接收了以太币,而payable函数则不需要,从而减少了Gas消耗。作者建议,gas优化重要,但不要为了节省少量gas而牺牲函数的本意。

嘿,朋友们 👋🏻

欢迎来到解读系列的另一篇文章,在这个系列中,我们深入探讨某个特定的智能合约/Web3 主题。

如果你最近一直在使用 Solidity 开发智能合约,那么你可能已经遇到过 payable 关键字。

这篇博客专门讨论它,我们将解读它所有有趣以及奇怪的秘密。😃

快速介绍:Payable 关键字的基础知识

在智能合约可以做的所有奇妙的事情中,存储你的钱(ETH)就是其中之一。现在,为了在智能合约中接收 ETH,Solidity 语言有一个特定的关键字叫做 payable

一个 payable 关键字,用非常简单的术语来说,是 solidity 语言中的一个修饰符,可以附加到任何函数上。一旦附加,这个关键字允许函数接收以太币。换句话说,在触发一个带有 payable 关键字的函数时,你可以连同该交易一起发送以太币 ( msg.value)。

虽然这一切都很好,但几个月前,我在滚动浏览 Twitter 时,偶然发现了一个关于 payable 关键字 的有趣警告。它吸引了我的所有注意力,我发现每当一个 payable 修饰符附加到任何函数时,都会发生一个有趣的(但真的有点奇怪)的场景 👀。

让我们快速看一下这个有趣的奇怪场景:

pragma solidity ^0.8.7;

contract payableKeyword{

    uint256 public state;

    function setStateVariable() public{
        state = 100;
    }
}

在上图附加的图片中,我们有一个非常简单的 setter 函数,它将 uint256 变量 state 设置为 100。 如果你触发这个函数,你会发现交易 gas 成本大约在 43300 左右。

好的,现在让我们看看第二种情况。

pragma solidity ^0.8.7;

contract payableKeyword{

    uint256 public state;

    function setStateVariable() public payable{
        state = 100;
    }
}

在第二种情况下,我们有完全相同的函数,它执行一个完全类似的设置状态变量的交易。 然而,这里唯一的区别是附加到该函数的额外的 payable 修饰符

非常有趣的是,如果你查看调用此函数的交易 gas 成本,它大约为 43276,低于上面提到的没有 payable 关键字的函数。

是的,你没看错。

添加一个简单的 payable 关键字就减少了函数中的 gas 消耗。 😃

AHA 时刻 💡💡

好了,现在是时候理解了 —— 为什么 payable 修饰符会降低 Gas 消耗?

对这个问题一个非常简单的答案是:

添加 payable 关键字会减少正在执行的操作码数量,从而降低 gas 消耗量。

这很奇怪,不是吗?向函数添加一个额外的修饰符,怎么会减少操作码的数量,而不是增加它呢???

好吧,这里有一些技术(和逻辑的)解释。😃

  1. 正如我们已经知道的,为了使一个函数能够接收以太币,必须在其上附加一个 payable 修饰符。 而没有任何 payable 修饰符的函数将永远无法接收任何以太币。
  2. 必须注意的是,这是 Solidity 中的一项严格规定,因此,如果你在调用一个 non-payable 函数时尝试传递 Ether,它将简单地回滚。
  3. 因此,在 Non-Payable 函数的情况下,在调用 non-payable 函数时会执行额外的操作码,以确保仅当与交易一起发送的 ether ( msg.value) 完全等于 ZERO 时,该函数才会被执行。
  4. 然而,对于 Payable 函数来说,情况并非如此。 Payable 函数允许用户在调用函数时传入非零或零以太值。
  5. 这基本上意味着,即使在调用 payable 函数 时发送了零以太 ( msg.value == 0),交易也不会回滚。 因此,在 Payable 函数的情况下,没有必要显式地检查 msg.value

概括 🥜

在 Non-Payable 函数的情况下:

a. 包含额外的检查,以确保在调用函数时没有传递 ether 值。

b. 这些检查会增加正在执行的操作码的数量。

c. 增加的操作码数量最终导致更高的 gas 使用量。

在 Payable 函数的情况下:

a. 不需要额外的检查,因为该函数可以接受 ether 的零值或非零值。

b. 没有额外的检查意味着没有执行额外的操作码。

c. 执行中的较低操作码意味着较低的 gas 消耗。

我的两分钱 🪙🪙

以上所有细节是否意味着我们应该使用 PAYABLE 函数来节省 gas?

嗯,这可能是一个讨论。

毫无疑问,gas 优化是每个智能合约大师在他们的合约中梦想的事情。

然而,一个紧迫的问题是:

虽然节省 gas 很重要,但为了节省一些额外的 gas 而损害函数的预期行为、最小化必要的状态更改或使用不充分的策略,这并不是一个好主意。

换句话说,如果一个函数与接收以太币无关,那么它就不应该附加任何 payable 关键字,即使这样可以节省你一些 gas。

因此,我坚信仅仅为了节省 gas 而在一个函数中添加一个不必要的 payable 关键字可能是一个糟糕的决定。 上面提到的在添加 payable 关键字时 gas 减少的场景只是一个奇怪的 solidity 语言设计,根本没有效果。

  • 原文链接: decipherclub.com/deciphe...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
decipherclub
decipherclub
江湖只有他的大名,没有他的介绍。