代理的 EIP 1967 存储槽

  • RareSkills
  • 发布于 2023-12-22 12:43
  • 阅读 235

EIP 1967 是一个关于代理合约存储信息位置的标准,用于解决代理合约与实现合约之间的存储冲突问题。文章详细介绍了实现地址和管理员地址的存储位置,并解释了如何防止存储冲突及如何使用 EIP 1967 来识别代理合约。

EIP 1967 是一个关于代理合约需要存储信息的标准。UUPS(通用可升级代理标准)和 透明可升级代理模式 都使用它。

请记住:EIP 1967 仅说明了某些存储变量的位置以及它们变化时会发出的日志,没有更多内容。它不说明这些变量如何更新或谁可以管理它们。 它不定义任何公共函数来实现。更新这些变量的规范在透明可升级代理模式或 UUPS 规范中给出。

代理需要操作的两个关键变量是 实现地址管理员。实现地址是代理委派调用的地方。在升级期间,实现地址 被更改为升级后的合约;只有来自 管理员 的调用会被接受以进行更改。

前置条件

本文假设读者对代理和 delegatecall 的工作原理、存储槽是什么、函数选择器 是什么以及在代理上下文中函数选择器冲突是什么有基本的了解。

代理槽的错误设计方式

以下是一个 不好的 代理设计:

不良代理设计的图像

首先,changeAdmin() 的函数选择器与实现中的某个函数发生冲突的概率是不可忽视的。EIP 1967 规范并没有说明如何处理这个问题 - 正确的避免这个问题的方法在透明可升级代理规范或 UUPS 规范中处理。EIP 1967 与函数选择器冲突无关。

ERC 1967 解决的问题是,implementationadmin 变量 非常可能 与实现合约中定义的存储变量发生冲突。具体来说,它们使用存储槽 0 和 1,这些是实现合约可能使用的槽。

防止冲突

由于管理员和实现地址可以更改,因此这些需要在存储变量中,不能是不可变的。但它们必须位于不会与实现合约中的存储变量发生冲突的存储槽中。

关键的想法是:可能的存储槽空间是极其庞大的:2**256 - 1。

如果我们随机选择一个存储槽,实现合约基本上不可能选择相同的槽。实现合约选择相同槽的几率与哈希函数碰撞大致相同,因此风险几乎是不存在的。

实现地址和存储槽

实现地址存储在槽中

0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc

管理员地址存储在槽中

0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103

这些槽是通过伪随机方式派生的

`bytes32(uint256(keccak25...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/