ERC-7201:命名空间存储布局

本文介绍了ERC-7201提案,旨在解决Solidity合约存储槽中存在的DelegateCall安全风险和升级不便等问题。ERC-7201引入命名空间概念,通过特定算法为不同逻辑组件分配独立的存储区域,实现存储隔离、升级友好、模块化支持和工具兼容等优势。文章还提供了实现示例,展示了如何在合约中使用ERC-7201。

背景

Solidity 合约将状态存储在存储槽中,这些存储槽是 32 字节的空间,从零开始按顺序标识。这种模式存在一些问题。

  • 当合约通过 DelegateCall 执行逻辑时,多个合约将共享相同的存储空间并通过槽位更改存储,这带来了巨大的安全风险。
  • 当涉及到可升级的合约时,无法修改状态变量(仅追加)。如果在具有继承关系的合约中,修改父合约的变量也会对子合约产生影响。这些都非常不方便。

所以这些是 ERC7201 想要解决的问题。

概览

ERC-7201 引入了突破性的“命名空间”概念,使开发人员能够为不同的逻辑组件分配独立的存储区域。其主要功能包括:

  • 将存储变量封装在结构体中
  • 通过特定算法计算存储根位置
  • 使用 NatSpec 注释标记存储命名空间

ERC-7201 定义了一个用于计算存储根位置的独特公式:

keccak256(keccak256(namespace) - 1) & ~0xff

该公式确保:

  • 生成的存储根不会与默认存储布局冲突
  • 提供伪随机但确定性的存储位置
  • 为未来以太坊 Verkle Trees 迁移做准备

实现示例

这是示例合约

contract ERC7201Example is Extend {
    /// @custom:storage-location erc7201:ERC7201Example
    struct MainStorage {
        uint256 x;
        uint256 y;
    }
// keccak256(abi.encode(uint256(keccak256("ERC7201Example")) - 1)) & ~bytes32(uint256(0xff));
    bytes32 private constant MAIN_STORAGE_LOCATION = 0xcb9fa12623879b77d9ed7b1c782042856a80da112b7898c6b7012bb9c0588f00;
    function _getMainStorage() private pure returns (MainStorage storage $) {
        assembly {
            $.slot := MAIN_STORAGE_LOCATION
        }
    }
    function setX(uint256 _x) external {
        MainStorage storage s = _getMainStorage();
        s.x = _x;
    }
    function setY(uint256 _y) external {
        MainStorage storage s = _getMainStorage();
        s.y = _y;
    }
}

这是使用不同存储位置的父合约

contract Extend {
    /// @custom:storage-location erc7201:Extend
    struct ExtendStorage {
        uint256 e;
    }
    // keccak256(abi.encode(uint256(keccak256("Extend")) - 1)) & ~bytes32(uint256(0xff));
    bytes32 private constant EXTEND_STORAGE_LOCATION =
        0xdc7c3789c251966f77e4ff9dc602e16101d09d1cf2378a0a6c0a2e5b1148cf00;
    function _getExtendStorage() private pure returns (ExtendStorage storage $) {
        assembly {
            $.slot := EXTEND_STORAGE_LOCATION
        }
    }
    function setExtend(uint256 _e) external {
        ExtendStorage storage s = _getExtendStorage();
        s.e = _e;
    }
}

你可以在 https://github.com/sunnybinb/contract-storage 中查看完整代码

以下是这种模式的一些优点

  1. 存储隔离:每个命名空间都拥有一个独立的存储区域
  2. 升级友好:最大限度地降低与存储布局修改相关的风险
  3. 模块化支持:有助于构建复杂的智能合约系统
  4. 工具兼容性:为静态分析工具提供标准化的存储位置信息

参考

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

0 条评论

请先 登录 后评论
blockmagnates
blockmagnates
The New Crypto Publication on The Block