DeFi中的临时存储:加密数据处理

本文详细介绍了以太坊提案EIP-1153中的瞬时存储概念,该提案引入了一种临时数据存储机制以优化智能合约的效率和安全性。瞬时存储是一种短期存储方式,仅在交易期间有效,通过新引入的TLOAD和TSTORE操作码降低存储成本并解决现有存储系统的局限性。文章还探讨了使用案例、潜在的安全考虑以及EIP-1153的影响。

"DeFi 中的瞬态存储:加密数据处理 - Three Sigma" 横幅

什么是瞬态存储 (EIP-1153)?

瞬态存储 (EIP-1153) 在内存、存储和 calldata(返回数据和代码)之外引入了另一个数据位置。新的数据位置表现为一个类似于存储的键值存储,其主要区别在于瞬态存储中的数据不是永久的。因此,Solidity 瞬态存储是一种临时存储机制,旨在为基于以太坊的区块链网络提供服务。

与永久区块链存储选项不同,它充当临时数据存储库,旨在降低成本。它的设计也允许在每笔交易结束时立即清除存储数据。这种存储数据的方法提高了效率,降低了成本,并解决了影响数据隐私、完整性和区块链应用程序整体可靠性的问题。

瞬态存储提供了内存和存储之间的折衷,为不需要长期保存的信息提供了一个临时区域,这与典型的存储系统在区块链上永久保存数据的方式形成对比。这一发明大幅降低了数据存储和检索的成本,同时优化了区块链资源的使用。

此外,开发人员可以使用 EIP-1153 在链上构建全球单例,例如 KYC 验证或重入锁,无需支付普通存储的成本。这些单例通过使事务信息可以被任何合约访问而不需要直接交互,来促进多个组件之间的信息共享,无论调用栈的深度如何。

如下图所示,一个借贷 dApp 不必直接存储 KYC 数据,因为特定的 DEX 可以处理 KYC 验证并与 dApp 交换这些信息。许多设计模式,例如费用锁定的 ERC20 代币、KYC、白名单,都因 KYC 数据在首次验证后在瞬态存储中保留且在交易结束时自动清除而变得简单化。采用这种策略,借贷 dApp 不需要了解 KYC 执行情况,也不需要在内部调用中携带额外的有效负载。

除了瞬态存储的多种应用,从技术实施到更具争议的用途外,认为在以太坊交易中使用全球单例是不明智的,被认为是一个反模式,可能会显著限制未来的发展。在开发领域,全球单例几乎在许多编程语言中被普遍认为是一种反模式。与单例相关的一个主要问题是它们往往会破坏封装性。打破封装会对常规程序产生严重后果,但在一个允许任何人部署代码且程序之间经常未经信任相互作用的无许可执行环境中,这尤其危险。

我们为什么需要 EIP-1153?

EIP-1153 提出了一个框架,极大地改善了智能合约的执行和设计,以满足以太坊交易中对有效瞬态存储解决方案的需求。为了应对当前存储和退款流程的一系列问题,这一提案于 2018 年 6 月 15 日由 Alexey AkhunovMoody Salem 提出,将提供一种可通过两个新操作码 TLOADTSTORETSTORE 不受 EIP-2200 中定义的气体补贴检查的限制)访问的过渡存储,其中“T”代表“瞬态”。这一创新通过仅在交易期间使用存储,提供比传统存储方法更便宜和简单的选项。

TLOAD (0x5c)

TSTORE (0x5d)

当前存储系统的缺点,例如自 伦敦硬分叉 以来对退款的限制为交易所用气体的五分之一、在交易反转时没有存储退款以及存储退款逻辑的复杂性,使得 EIP-1153 的实现变得必要。由于有效管理 storage slots 的困难,这些问题不仅增加了账务操作的Gas成本,还使得进行与同一合约交互的并发交易变得更困难。通过避免由于 reentrancy locksSSTORE/SLOAD 在合约状态之间传递状态信息时产生的问题,它使得可安全和经济地进行跨状态通信成为可能。

用户应注意,编译器目前尚不允许在高级 Solidity 代码中使用 transient 作为数据位置。目前,存储在此位置的数据只能通过内联汇编中的 TSTORETLOAD 操作码访问。

本节的结论是, EIP-1153 为以太坊当前存储系统的缺点和复杂性提供了有效的补救措施,承诺大幅减少Gas消耗,简化智能合约实现,以及整体简化 EVM 架构。

用例

EIP-1153 引入了瞬态存储,通过添加两个新的操作码 TLOADTSTORE,代表了以太坊设计的显著改进。通过这一进展,以太坊的效率将最大化,允许智能合约利用瞬态存储槽,在每笔交易后被清除。该技术不仅增强了安全性并简化了合约设计,而且减少了对持续存储的依赖,降低了交易费用,避免了相关成本,并消除了气体退款的需要。

瞬态存储为智能合约开辟了新的可能性,包括:

  • 重入锁:

在深入讨论瞬态存储如何安全管理 reentrancy 而无需承担传统存储相关的高成本之前,有必要了解何为 reentrancy

重入是指合同已被进入,并将执行流程控制权交给另一个正在再次进入第一个合同的合约。重入的危险源于数据竞争,重入合约的执行框架竞争相同的存储位,因此可能导致不一致的读写。通常通过重入锁来防止这种情况。

另外,合约可以通过限制与不可信调用一起发送的气体来限制重入的可能性。例如,计划仅转移 ETH 的合约通常使用 Solidity 的 transfer() 或 Vyper 的 send(),通过仅以 2300 的气体转移 ETH 来防止重入攻击。目前,这种非重入假设受到 EIP-2200 的强制执行,该提案因“Constantinople 上的重入”问题而包含在 Constantinople 硬分叉中。EIP-2200 导致 SSTORE 在气体低于 2300 的情况下失败(即使有足够的气体可以使用)。因此,由于 transfer()send(),没有 SSTORE 是可能的。因此,直到现在为止,重入(按照其常见定义)是不可能的。

然而,瞬态存储的引入改变了重入攻击的动态。由于 TSTORE 没有像 SSTORE 一样的最低气体要求,即使气体低也可能导致重入情况,打破了之前认为“低气体转储是安全的”的假设。

EIP-1153 提出的一个用例是将其用于 重入锁。然而,将瞬态存储用于智能合约钱包中的 重入锁 可能会意外导致拒绝服务(DOS)风险。

在 90%的情况下,构建重入锁将成功,但这会让该合约变得难以组合(因为它只能在每个交易中调用一次),并将所有与其通信的智能合约钱包暴露于拒绝服务攻击。

如果将两个操作合并为一个交易并且两个都与此合约交互,则第二个AA操作将发现自己会被回滚(因为重入锁)。这一问题将导致AA用户需支付回滚交易的费用,因为在大多数 AA 设置中,智能合约钱包必须在回滚交易时支付交易费用。

最糟糕的是,在大多数 AA 方案中,钱包拥有者无法控制打包者是否将该操作与其他操作结合,这意味着任何人都可以故意尝试将这些过程结合,钱包拥有者必须每次都支付其中一个过程失败时的费用。

虽然受欢迎程度较低的协议可能选择采取更少的预防措施,但开发人员可能会选择注意这种边缘情况并删除他们的重入锁。在智能合约钱包普及之前,这一问题可能会保持 dormant(直到该 dapp 变得受欢迎)。在这两种情况下,解决问题都为时已晚。

  • 链上可计算的 CREATE2 地址:

构造函数参数来自工厂合约,而不是作为 init code hash 的一部分传递。

Uniswap V3 使用此方法(链上可计算地址)来存储 pool 的构造函数参数,以便 pool init code 始终相同,而不是将构造函数参数作为 init code 的一部分传递。这使在链上计算池地址的费用更便宜。

为此,Uniswap V3 采用以下步骤:

  1. 池参数存储在瞬态存储中
  2. 从池参数生成 pool init code
  3. 使用 pool init code 创建池。
  4. 从瞬态存储中删除池参数。
  5. pool init code 是在创建池时执行的一段代码,用于初始化池状态。

旨在使 ERC20 代币的开发者能够施加和批准仅限于单笔交易持续时间的方案。这意味着用户不必担心此批准在将来“泄露”并被攻击者利用,当他们批准另一个合约提取 ERC20 代币时。

由于一个用户从定义上控制整个交易,因此这种方法对于 EOA 账户应能良好运行。然而,这创造了一种虚假的安全感,因为攻击者仍然可以通过交易本身发起攻击。他们可以通过利用操作(如果用户使用智能合约钱包)或回调,来实现类似于重入锁的功能。

最糟糕的智能合约风险是那些未被检测到的风险。在这种情况下,该合约通常仅受这一条防御措施的保护,虽然正如之前所提及,这一防御措施并不是很强大。

在不需要瞬态存储的情况下,如今仍然可以使用此模式。当前的实现成本会稍高一些,但通过简化存储退款结构和在交易后清除授权,可能会降低。

  • 基于费用的合约:

有很多 ERC20 代币(智能合约)。一些代币会在执行任何代币转账时收取费用(例如 STA、PAXG、USDT、USDC)。这将使用户在支付税费后在单个交易中可以无限次与合约互动。如果一个代币希望征收税但对完成交易需多少“跳跃”无关紧要,则这个设计可以是有用的。

当智能合约钱包与其交互时,这个模式的破坏应该显而易见。代币合约自动假设所有后续调用者必须与支付税费的初始用户关联,即使一些转移可能是由其他用户发起的。

使用此代币的唯一方法是通过过滤 msg.sender,但这会否定瞬态存储的好处,因为往后任何 transferFrom 操作不会识别用户 1 作为其所有者。

如果用户 1 不调用限制性的代币以释放存储,则代币合约没有其他手段来判断用户是否已更改。用户 1 可能会最后一次调用代币,以便让它知道他已经完成,但代币无法保证。

由于代币的收入损失是唯一的问题,所以这个案例看似并不太成问题。然而,请记住,这个模式实际上限制了谁可以访问限制性代币。人们认为,开发者在试图实现这些模式时,如果 EIP 示例本身出错并留下攻击的漏洞,可能会遭遇类似的漏洞。

在执行 L1 上的 L2 消息 时,瞬态存储被用来表示 L2 状态。这意味着 Arbitrum 合约可以进行任何任意调用,并且不需要假定 L1 合约 的任何接口。此外,L1 合约 可以从调用中访问 L2 状态

瞬态存储还简化了复杂的交易模式,例如“直到”模式和代理调用元数据:

  • “直到”模式:

通过这一模式,回调函数 可以更安全、更便宜地实现。这可以通过在 回调函数 的开始和结束实现路径无关的变量,以及通过瞬态存储确保路径独立性来实现(EIP-1153 的作者称之为“直到”模式)。

类似于 CREATE2temporaryApprove 模式,上述描述的漏洞不会直接影响此模式。也就是说,这并非一种概括。

值得一提的是,普通存储仍然可以用于实现“直到”模式。“直到”模式 已被正在开发的 Uniswap v3 合约使用。

虽然瞬态存储确实可能降低这一模式的成本,但常规存储也可以直接受益于类似的价格降低。

  • 代理调用元数据:

将元数据传递给实现合约,而不使用 calldata。这描述了使用瞬态存储作为任何类型元数据(如“什么是瞬态存储(EIP-1153)”部分中的 KYC 示例)的通用载体。该模式存在与“基于费用的合约”模式完全相同的问题:数据在操作之间泄露,相关合约无法可靠地控制。

本节的结论是,瞬态存储的效率源于其设计,消除了从存储加载初始值的需求(因为初始值总被视为 0),从而通过免除退还费用简化了气体计费规则。这一性能在 Arbitrum 的 L2 状态的 L2 到 L1 消息编码Uniswap V3 等用例中尤为明显。这些用例证明了瞬态存储如何节省运行成本并提高以太坊智能合约开发的适应性。

EIP-1153 的关键安全考虑、优点和缺点

TSTORE 引入了一种在节点上以线性成本分配内存的新方法。具体来说,TSTORE 使开发人员能够为每 100 气体使用分配 32 字节的内存,不包括设置堆栈所需的其他操作。以 3000 万气体的预算,TSTORE 的最大内存分配约为 9.15MB,计算如下:

相比之下,使用相同的气体预算,单个 MSTORE 操作的最大内存分配约为 3.75MB,由以下公式得出:

然而,在每个上下文中分配 1M 气体用于内存,并通过调用重置内存扩展成本,可能达到每百万气体分配约 700KB,总计大约 3000 万气体可分配大约 20MB 的内存:

计算来源

值得注意的是,EIP-1153 中写道:

“智能合约开发者在使用之前应了解瞬态存储变量的生命周期。由于瞬态存储在交易结束时自动清除,智能合约开发者可能会被诱使避免在调用中清除槽以节省气体。然而,这可能会阻止在同一笔交易中与合约的进一步交互(例如在重入锁的情况下),或导致其他错误,因此智能合约开发者应小心,确保仅在那些槽旨在为同一交易内未来调用使用时,才留下非零值的瞬态存储槽。否则,这些操作码的行为与 SSTORESLOAD 完全相同,因此所有通常的安全考虑都适用,特别是在重入风险方面。”

“智能合约开发者也可能会被诱使使用瞬态存储作为内存映射的替代品。他们应该意识到瞬态存储在调用返回或回滚时并不会被丢弃,而内存则是这样,因而在这些用例中最好使用内存,以免在同一交易中的重入上产生意外行为。瞬态存储相较于内存的高成本应该已足够阻止这一使用模式。大多数内存映射的使用可通过键排序条目列表更好地实现,而且在智能合约中很少需要使用内存映射(即作者不知晓在生产环境中有任何已知的使用案例)。”

现在让我们看一下 EIP-1153 的一些利弊:

优点:

  • 处理瞬态使用而不修改现有合约。
  • 升级到协议时,独立考虑新理念。
  • 通过不要求加载原始值,简化了客户的气体记账规定。
  • 使用后无需清除存储槽。

缺点:

  • 不考虑现有合约的瞬态存储使用。
  • 为黄皮书引入的新概念。

瞬态存储的最新消息

大约一年前,瞬态存储 (EIP1153) 在 3/5 个 EL 客户端中实现,2/5 的 PR 正在等待中。当时开发人员已完成对这一 EIP 支持的所有可能工作。(根据 Hayden Adams

瞬态存储的“重大进展”是最新版本的 Solidity 编译器 (0.8.24) 包含对 瞬态存储(EIP-1153) 的支持。

Solidity 0.8.24 发布公告 中写道:

“Cancun 网络升级以操作码和预编译的形式提供了新特性,这需要明确使用以获得任何好处,但也引入了现有 EVM 行为的变化,这会自动影响已部署的合约。Solidity 0.8.24 为新操作码提供了全面的 Yul 级支持,并为其中一些提供了 Solidity 级内置功能。”

“本文的硬分叉将包括以下 执行层更改: • EIP-1153: 瞬态存储操作码

“瞬态存储是 EVM 层期待已久的特性,引入了另一种数据位置,除了内存、存储、calldata(及返回数据和代码)以外。新的数据位置像存储一样表现为键值存储,主要区别在于瞬态存储中的数据不是永久的,而是仅作用于当前交易,并在交易结束时重置为零。因此,瞬态存储的使用成本与热存储访问一样低,读取和写入的费用均为 100 气体。”

结论与展望

瞬态存储促进了 dApp 功能的安全和有效实现。TLOAD / TSTORE 预计将在 “Dencun" 更新 后生成一系列用例,例如重入保护、链上可计算的 CREATE2 地址、单交易 ERC-20 授权和基于费用的合约。

然而,瞬态存储的操作对现有的 Solidity 开发者来说将是新的,可能出现意外的安全问题。与代理合约通过各种安全事件(如 Parity 钱包黑客事件)的标准化一样,瞬态存储操作码的使用也应该在标准方面积极讨论。

Uniswap V4 是一个利用瞬态存储的 dApp 最具代表性的例子,希望能广泛讨论在此方面应考虑的安全事项。

_致谢:HackmdEIP-1153Solidity 0.8.24 发布_


如果你想了解自动化做市商 (AMMs) 如何革新 DeFi 协议,请查看我们另一篇关于 掌握 AMMs:自动化做市商完全指南 的文章。

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

0 条评论

请先 登录 后评论
Three Sigma
Three Sigma
Three Sigma is a blockchain engineering and auditing firm focused on improving Web3 by working closely with projects in the space.