• 基于 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

  • 相关阅读:
    Java项目的程序里为什么老用注解?注解有哪些作用
    (swjtu西南交大)数据库实验(数据库需求分析):音乐软件数据管理系统
    腾讯云~docker onlyoffice7.1.1 word excel ppt在线编辑、在线预览_部署01
    PV静态创建和动态创建
    矩阵连乘问题(区间DP)
    Java Spring Cloud XV 之 Redis I
    机器学习 | 基本概念梳理——数据集评估,任务,训练和测试,期望结果
    云上竞技,360°见证速度与激情
    python基础(二、基础语法)
    什么牌子的蓝牙耳机耐用?平价蓝牙耳机里面性价比高的推荐
  • 原文地址:https://blog.csdn.net/Lyon_Nee/article/details/125523306