• 基于 Openzeppelin 的可升级合约解决方案的注意事项


    基于 Openzeppelin 的可升级合约解决方案的注意事项

    注意事项

    构造函数

    在编写可升级合约时请不要使用构造函数contructor(),我们知道可升级合约运行时逻辑与数据分离的,合约数据保存在代理合约中,我们编写的合约是逻辑合约,当合约部署时,逻辑合约调用contructor()初始化的数据是逻辑合约的,代理合约中的数据并没有被初始化,所以是无效的。
    包括全局变量声明时赋值初始值,因为这种做法相当于在构造函数contructor()中设置这些值。

    父类合约初始化

    如果MyContract继承自合约 BaseContract, 那么BaseContract合约的初始化函数 initialize() 的modifier(修饰器) 必须使用 onlyInitializing,比如:

    contract BaseContract is Initializable {
        uint256 public y;
    
        function initialize() public onlyInitializing {
            y = 42;
        }
    }
    // BaseContract 继承自 Initializable,这里无需重复显式继承 Initializable
    contract MyContract is BaseContract {
        int storageValue;
    
        // modifier(修饰器) initializer 可以确保initialize只会被调用一次
        function initialize(int initValue) public initializer {
            BaseContract.initialize();
            storageValue = initValue;
        }
        ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    声明状态变量

    • 声明状态变量时,不能对其赋值 初始值

    像这样做是错误的

    contract MyContract is Initializable {
        int storageValue = 666; //初始值无效
    
        function initialize() public initializer {
        }
        ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    因为这种做法相当于在构造函数contructor()中设置这些值,因此不适用于可升级的约定。

    • 定义常量状态变量仍然可以

    像这样是可以的

    contract MyContract is Initializable {
        // constant 常量关键字
        int public constant storageValue = 666; //有效
    
        function initialize() public initializer {
        }
        ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在合约代码中创建新合约实例

    • 不要在合约中创建新的合约实例,创建出的合约是不可升级的

    像这样,即使MyContract是可升级的,但 ERC20 实例不可升级

    import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
    
    contract MyContract is Initializable {
        ERC20 public token;
        
        function initialize() public initializer {
            token = new ERC20("Test", "TST"); // 这个合约是不可升级的
        }
        ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 如果你希望在MyContract引用其他可升级合约,那么将已部署好的可升级合约实例注入到MyContract中,是很好的解决方案

    像这样

    import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
    
    contract MyContract is Initializable {
        IERC20Upgradeable public token;
    
        function initialize(IERC20Upgradeable _token) public initializer {
            token = _token;
        }
        ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    升级合约时声明状态变量

    在编写合约的新版本时,无论是由于新功能还是 bug 修复,还有一个额外的限制需要遵守:不能更改合约状态变量的声明顺序,也不能更改其类型。

    比如当前版本(V1)合约状态变量布局

    contract MyContractV1 {
        uint256 private x;
        string private y;
    }
    
    • 1
    • 2
    • 3
    • 4

    那么在编写新版本合约时,请避免一下错误操作:

    • 更改变量的类型

    这是错误的

    contract MyContractV2 {
        string private x;
        string private y;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 更改声明它们的顺序

    这是错误的

    contract MyContractV2 {
        string private y;
        uint256 private x;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 在现有变量之前引入一个新变量

    这是错误的

    contract MyContractV2 {
        bytes private a;
        uint256 private x;
        string private y;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这是正确的

    contract MyContractV2 {
        uint256 private x;
        string private y;
        bytes private a;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 删除现有变量

    这是错误的

    contract MyContractV2 {
        string private y;
    }
    
    • 1
    • 2
    • 3

    参考文档:
    Openzeppelin编写可升级合约:https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable

  • 相关阅读:
    56、MQ(异步通讯的的缺点/优点)
    HarmonyOS 习题(二)
    逢人必推的4款实用软件,国产良心,相遇不易
    btc钱包探索纪实
    数据分析手册-R语言
    【无标题】超时超时超时超时超时
    vue+elementui 多级多选穿梭框(常用于省市区三级联动)
    发个地区和对应的价格方案
    Linux下基于HTTP网页视频监控
    【Autosar 存储栈Memery Stack 3.存储读写流程的要求与时序】
  • 原文地址:https://blog.csdn.net/Lyon_Nee/article/details/125523306