知世金融网专注于股票行情,期货开户,外汇储备等最新相关资讯信息提供投资者参考学习!

当前位置:网站首页 > 区块链 > 正文

停止使用Solidity的transfer()函数

原创
文章作者
知世-金融领域资深作者
知名金融领域作者,从事金融超过十余年,在行业内有一定影响力。
金融风险管理师认证证书 常识职业资格认证 特许金融分析师 国际金融理财师认证证书
发布时间:2020-02-16 18:52:20 发布来源:区块链研究实验室 文章点击:120

以太坊看起来EIP 1884正在伊斯坦布尔硬叉前进。这一变化增加了sload操作的gas成本,因此打破了一些现有的智能合约。 这些合约将破裂,因为它们的fallback函数过去消耗的gas少于2300,现在...

目录

    本文标题停止使用Solidity的transfer()函数,作者:知世,本文有1481个文字,大小约为6KB,预计阅读时间4分钟,请您欣赏。知世金融网众多优秀文章,如果想要浏览更多相关文章,请使用网站导航的搜索进行搜索。本站虽然不乏优秀之作,但仅作为投资者学习参考。

    以太坊看起来EIP 1884正在伊斯坦布尔硬叉前进。这一变化增加了sload操作的gas成本,因此打破了一些现有的智能合约。

    这些合约将破裂,因为它们的fallback函数过去消耗的gas少于2300,现在它们将消耗更多。为什么2300gas是重要的? 如果通过Solidity的transfer()或send()方法调用合约的fallback函数,则它是合约的fallback函数。

    自从transfer()引入以来,它通常被安全社区推荐,因为它有助于防止重入攻击。在gas成本不变的假设下,这一指导意见是有意义的,但事实证明这一假设是错误的。我们现在建议避免transfer()和send()。

    气体成本可以也将改变

    evm支持的每个操作码都有一个相关的gas成本。例如,sload从存储器中读取一个单词,目前(但不是很长时间)需要200气体。gas的价格不是随意的。它们旨在反映构成以太坊的节点上每个操作所消耗的底层资源。

    EIP的动机部分:

    操作价格与资源消耗(CPU时间、内存等)之间的不平衡有几个缺点:

    · 它可以用于攻击,通过填充区块与定价过低的操作,导致区块处理时间过长。
    · 定价过低的操作码会导致区块gas限值倾斜,有时区块气体快速完成,但其他类似gas使用的块体缓慢完成。
    · 如果操作平衡,我们可以最大限度地提高区块气限,并有一个更稳定的处理时间。

    sload历来定价过低,而eip 1884纠正了这一点。

    智能合约不能依赖气体成本

    如果gas成本会发生变化,那么智能合约就不能依赖于任何特定的gas成本。

    任何使用transfer()或send()的智能合约都会通过转发固定gas数量2300来严格依赖gas成本。

    我们的建议是停止在代码中使用transfer()和send(),改为使用call():

    contract Vulnerable {
    function withdraw(uint256 amount) external {
    // This forwards 2300 gas, which may not be enough if the recipient
    // is a contract and gas costs change.
    msg.sender.transfer(amount);
    }
    }

    contract Fixed {
    function withdraw(uint256 amount) external {
    // This forwards all available gas. Be sure to check the return value!
    (bool success, ) = msg.sender.call.value(amount)("");
    require(success, "Transfer failed.");
    }
    }

    这两份智能合约除了gas的传输数量不同,其余都是相等的。

    可重入性?(Reentrancy )

    希望您在看到上述代码时首先考虑过这个问题。引入transfer()和send()的全部原因是为了解决DAO臭名昭着的黑客攻击的原因。 其思想是2300 gas足以发出一个日志条目,但不足以发出一个可重入调用,然后修改存储。

    不过,请记住,gas成本可能会发生变化,这意味着无论如何,这是解决重入问题的糟糕方法。今年早些时候,君士坦丁堡叉子被推迟了,因为降低gas成本导致先前安全的代码无法再进入。

    如果我们不再使用transfer()和send(),我们将不得不以更健壮的方式防止重入。幸运的是,这个问题有很好的解决方案。

    检查 - 效果 - 交互模式

    消除重入错误的最简单方法是使用检查-效果-交互模式。这是一个可重入错误的典型例子:

    1contract Vulnerable {
    2 ...
    3
    4 function withdraw() external {
    5 uint256 amount = balanceOf[msg.sender];
    6 (bool success, ) = msg.sender.call.value(amount)("");
    7 require(success, "Transfer failed.");
    8 balanceOf[msg.sender] = 0;
    9 }
    10}

    如果msg.sender是智能合约,它在第6行有机会在第7行发生之前再次调用withdraw()。在第二次调用中,balanceOf [msg.sender]仍然是原始金额,因此将再次传输。这可以根据需要重复多次以消耗智能合约。

    检查 - 效果 - 交互模式的想法是确保所有交互(外部调用)最终发生。上述代码的典型修复方法如下:

    1contract Fixed {
    2 ...
    3
    4 function withdraw() external {
    5 uint256 amount = balanceOf[msg.sender];
    6 balanceOf[msg.sender] = 0;
    7 (bool success, ) = msg.sender.call.value(amount)("");
    8 require(success, "Transfer failed.");
    9 }
    10}

    请注意,在此代码中,余额在传输之前被清零,因此尝试对withdraw()进行可重入调用将不会使攻击者受益。

    使用Reentrancy 保护

    防止重入的另一种方法是明确检查和拒绝此类调用。这是一个简单版本的reentrancy 保护,你可以看到这个想法:

    1contract Guarded {
    2 ...
    3
    4 bool locked = false;
    5
    6 function withdraw() external {
    7 require(!locked, "Reentrant call detected!");
    8 locked = true;
    9 ...
    10 locked = false;
    11 }
    12}

    使用此代码,如果尝试重入调用,第7行上的require将拒绝它,因为lock仍设置为true。

    在OpenZeppelin的ReentrancyGuard合同中可以找到一个更复杂、更省gas的版本。如果从ReentrancyGuard继承,则只需使用nonReentrant修饰函数以防止重入。

    请注意,此方法仅在显式将其应用于所有正确的函数时才保护您。由于需要在储存中保持一定的价值,这也增加了gas成本。

    Vyper如何?

    Vyper的send()函数使用与Solidity的transfer()相同的硬编码gas,因此也应避免使用。你可以改用raw_call。

    Vyper内置了一个@nonreentrant(<unique_key>)装饰器,其工作方式与OpenZeppelin的ReentrancyGuard类似。

    总结

    1. 在假定gas成本不变的情况下,推荐transfer()是有意义的。
    2. gas成本并不恒定。智能合同对这个事实应该是健全的。Solidity的transfer()和send()使用硬编码的gas量。
    3. 应该避免这些方法。请改用.call.value(...)(“”)。
    4. 这就带来了重新进入的风险。请确保使用可用于防止重入漏洞的健壮方法之一。
    5. vyper的send()也有同样的问题。

    本文相关推荐: 什么是哈希函数

    以上便是知世金融网给大家分享的关于停止使用Solidity的transfer()函数/qkl/27473.html的相关信息了,希望能帮助到大家,更多金融相关信息,敬请关注知世金融网!

    网站内容均来自互联网,如侵害您的利益联系客服进行删除!

    关键词:函数
    (0)
    (0)

    上一篇:获四大矿池支持联合挖矿,Vcash志成最隐私安全的价值存储链

    下一篇:如何运用元交易来吸引客户 (2)

    本文标题:停止使用Solidity的transfer()函数

    本文地址:/index.php?s=article&c=search&keyword=%E5%87%BD%E6%95%B0

    金融知名领域

    南方财富网 | 金融界 | 金融界 |

    更多推荐

    • 茅台吃饱,经销商哭倒
      茅台吃饱,经销商哭倒
    • 汇金的五次增持从短期看具有一定的“稳定器“作用,但从市场表现看效果逐次递减
      汇金的五次增持从短期看具有一定的“稳定器“作用,但从市场表现看效果逐次递减
    • 158亿元!比亚迪收购!
      158亿元!比亚迪收购!
    • 9月价格回落近五成 “冷静期”酒店业备战“十一”市场
      9月价格回落近五成 “冷静期”酒店业备战“十一”市场
    • 2023哈马博览会哈尔滨银行展区精彩纷呈
      2023哈马博览会哈尔滨银行展区精彩纷呈
    • 大额解禁撂倒股价 医疗影像龙头跌出千亿俱乐部 葛兰二季度大幅减仓
      大额解禁撂倒股价 医疗影像龙头跌出千亿俱乐部 葛兰二季度大幅减仓
    • A股,又上了热搜!数字要素概念走高多股涨停,锂电池板块走低恩捷股份大举跌停
      A股,又上了热搜!数字要素概念走高多股涨停,锂电池板块走低恩捷股份大举跌停
    • 最新!巨头出手,加仓宁王51%
      最新!巨头出手,加仓宁王51%
    • 600亿巨头暴雷
      600亿巨头暴雷
    • 一天32家!科创板回购潮涌来
      一天32家!科创板回购潮涌来
    • 提振信心实招来了!30余家上市公司密集出手 最高要买10亿
      提振信心实招来了!30余家上市公司密集出手 最高要买10亿
    • 高盛再发50年后预测:2075年印度股市全球市值占比将升4倍 中国升3成
      高盛再发50年后预测:2075年印度股市全球市值占比将升4倍 中国升3成

    新闻资讯栏目

    站长QQ: 2397470084