以太坊升级对智能合约的影响

本文探讨了以太坊升级对智能合约的影响,特别是从The Merge后的升级开始,包括Paris、Shapella和Dencun,详细介绍了每个升级中引入的新特性,例如PREVRANDAO、PUSH0、Danksharding相关操作码、MCOPY、TSTORE/TLOAD以及SELFDESTRUCT的修改,并展望了未来可能的EIP 3074/7702和EOF升级。

以太坊升级对智能合约的影响

以太坊大约每年都会进行一次升级。这是一个包含新功能的协调硬分叉。这些升级大多影响区块链层,侧重于扩展和共识加强等方面。然而,这些硬分叉也经常影响应用层,这时新的功能会暴露给智能合约。并非所有这些新功能都是向后兼容的,某些假设可能会被打破。因此,在创建不可变的智能合约时,了解这些新功能至关重要。

我们将从最近的以太坊硬分叉(从 The Merge 开始)进行讲解,并探讨它们对智能合约层的影响,重点关注安全性。最后,我们将展望未来,讨论潜在的未来升级。

Paris (The Merge)

Paris,或称“The Merge”,是以太坊从工作量证明过渡到权益证明的重大分叉。整个过程无缝进行,因为这种过渡经过精心设计,对智能合约及其用户的影响非常小,但仍然存在一些细微的变化:

  • EIP-4399:DIFFICULTY 变为 PREVRANDAO 在 PoW 链上,DIFFICULTY 操作码经常被用作(不好)随机性的来源。然而,随着切换到 PoS,difficulty 已经不再具有意义,因为不再进行挖矿。这导致 DIFFICULTY 操作码变得无用。为了保持与使用 DIFFICULTY 进行随机性的智能合约的兼容性,决定将 DIFFICULTY 重命名为 PREVRANDAO,并使其返回前一个区块的 RANDAO 混合。为了实现这一点,Solidity 在 0.8.18 版本 中弃用了 block.difficulty 并引入了 block.prevrandao。注意:在底层仍然调用相同的操作码(0x44),因此 0.8.18 之前的 Solidity 中的 block.difficulty 将产生与 0.8.18 及更高版本中的 block.prevrandao 相同的值。

DIFFICULTY 一样,PREVRANDAO 也不是真正随机性的来源。它可以在一定程度上被预测和偏置,因此在使用它时必须非常小心。有关 PREVRANDAO 的安全假设 的更准确和完整的描述,请参阅 EIP。

此外,并非所有网络都以相同的方式实现 PREVRANDAO。例如,Optimism 允许 sequencer 每隔一个块设置 PREVRANDAO 的值,从而降低了安全保证。在 Arbitrum 上,PREVRANDAO 将始终返回 '1',这显然不应该用于随机性。

  • 块的时间戳更具确定性。 由于挖矿是概率性的,因此 PoW 链上块之间的时间不是恒定的。但是,平均而言,每 13 秒产生一个块。相比之下,信标链每 12 秒就有一个 slot(即产生区块的机会)。因此,合并后 block.timestamp 可能只增加 12 的倍数。这可能会影响依赖 block.timestamp 的合约。当然,这仅适用于以太坊主网,其他网络具有不同的区块时间。

Shapella

Shapella 的主要功能是提款,但它也引入了其他好东西,例如 PUSH0

  • EIP 3855:PUSH0 是一个新的操作码,它将“0”推送到堆栈。 即使在纯 Solidity 中编写或审查智能合约时,你不会直接与 PUSH0 交互,但了解它的存在和用法仍然非常重要。从 Solidity 0.8.20 版本开始,Solidity 将默认使用 PUSH0,这意味着任何编译后的合约都可能包含 PUSH0。部署编译后的合约时,重要的是检查目标网络是否支持 PUSH0,否则在遇到 PUSH0 指令时执行将恢复。

幸运的是,Solidity 会在部署代码中生成 PUSH0 指令。这意味着如果目标网络不支持 PUSH0,则会在部署时发生恢复,而不是在稍后的阶段,届时资金可能会被冻结。

如果你的目标网络不支持 PUSH0,建议将 Solidity 版本降低到 0.8.19 或更早版本,或者将目标 EVM 版本降低到 Paris 或更早版本。

Dencun

Dencun 实现了 danksharding 以及几个较小的功能:

  • EIP 4844:Danksharding 带来了两个新的操作码和一个新的预编译。从 0.8.24 版本 开始,BLOBBASEFEEBLOBHASH 分别通过 blobbasefee()blobhash() 在 Solidity 中公开。正如你所期望的那样,blobbasefee() 返回此块中 blob 的基本费用。blobhash() 返回此交易 blob 中具有给定索引的 KZG 承诺的版本化哈希。如果给定的索引不存在,则返回零字节,类似于 blockhash() 的行为。

新的“点评估”预编译允许你验证 blob 中的一个点。此外,预编译返回 blob 中的元素数和 BLS 模数。目前,Solidity 没有提供在高层调用此预编译的方法,因此必须使用对预编译地址(0x0a)的低层调用。执行此操作时,请确保预编译已部署 在目标网络上,否则该调用将默认成功。

  • EIP 5656:MCOPY 是引入的一个新操作码,用于优化某些操作,类似于 PUSH0。Solidity 将从 0.8.25 版本开始默认使用它。因此,请确保目标网络支持它,否则在遇到 MCOPY 时执行将恢复。与 PUSH0 相比,MCOPY 默认不用于 Solidity 的部署代码中。这意味着部署可能会成功,但其他操作可能会失败,这可能会导致资金被冻结。

  • EIP 1153:TSTORE / TLOAD 是提供对瞬态存储访问的新操作码。这些目前只能在 Solidity 中使用内联汇编访问。使用 tstore()tload() 时,请确保目标网络支持它们。此外,重要的是要理解所涉及的生存期:瞬态存储仅在交易结束时清除。将瞬态存储用于重入锁时,这意味着你仍然需要在调用结束时手动清除它们。否则,用户将无法在交易中与你的合约进行多次交互。

  • EIP 6780:SELFDESTRUCT 进行了修改,如果它不是在与创建合约相同的交易中执行,则合约不会被删除,但所有 ETH 余额仍然会被转移。如果 SELFDESTRUCT 是在与创建合约相同的交易中执行的,则行为保持不变,除了转移所有 ETH 余额外,合约还会被删除。此更改可能会破坏当前依赖 SELFDESTRUCT 的合约,并且在创建使用 SELFDESTRUCT 的合约时,需要注意这一点。无论如何,SELFDESTRUCT 仍然已弃用,不应使用。

Future

这些功能尚未生效,但可能很快就会实现。因此,了解它们很有用。

  • EIP 3074 7702 通过赋予 EOA 智能合约功能(即执行代码的能力)来增强 EOA 的 UX。这打破了如果 msg.sender 等于 tx.origin,则调用者必须是 EOA 而不是智能合约的假设。因此,不能再依赖此检查。

  • EOF 是一项重大更新,它为 EVM 字节码添加了结构。这些更改中的大多数应由底层 Solidity 处理。但是,某些方面对于开发人员仍然可见:

    • 删除了 Gas 可观察性。这意味着在 EOF 合约中,gas() 不可用,并且无法为调用指定 gas 限制。
    • 同样,删除了代码可观察性。这意味着无法将合约的代码复制到内存中,也无法从 EOF 合约获取合约代码的大小或哈希。从旧合约观察 EOF 合约的代码仍然是可能的,但有一个重要的注意事项:它的工作方式就像 EOF 合约的代码是 EF00 一样,例如,EOF 合约的 EXTCODEHASH 返回 keccak256(0xEF00)
    • 不允许从 EOF 代码到旧代码的 delegatecalls,并且会恢复。允许相反的方向,从旧代码到 EOF 代码。

如果你的应用程序依赖于此功能,你仍然可以使用旧(非 EOF)合约,因为这些合约保持其当前行为。

请务必查看 EOF 规范 以了解更多详细信息。不过,你需要准备一份零食,因为它很大!


以太坊的升级经常带来令人兴奋的新功能和可能性。不幸的是,它们有时会改变行为并打破假设,而且通常以不明显的方式进行。作为智能合约开发人员和安全工程师,了解这些变化对于创建强大而安全的应用程序非常重要。

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

0 条评论

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