存储兼容性:使用 "proxy" 设计模式和更改映射类型的 Solidity 可升级智能合约

Storage compatibility: Solidity upgradable smart contract using "proxy" design pattern and changing the mapping type

有人使用“代理”模式编写 upgradable smart contracts 吗? 我打算 upgrade/extend 我的旧智能合约,最初,我的代码如下所示:

mapping(address => uint256)  balance;

我打算这样写:

struct PackedBalance {
    uint256 balance;
    uint256 locked_balance;    // to support a new feature.
}
mapping(address => PackedBalance) balance;

我担心的是“存储”是否与“旧版本智能合约”兼容。

我刚刚阅读了“Layout of State Variables in Storage”。据我了解,它是兼容的。但是我是新手,所以想请教一些高手。

“兼容”意味着:我仍然可以读取现有存储槽的正确“余额”。我可以写“locked_balance”而不破坏任何东西(比如覆盖)。

是的,将映射中的 uint256 扩展到同一映射中的 struct 是安全的。

让我们调试这两个示例合约:

pragma solidity ^0.8;

contract MyContract {
    mapping(address => uint256) balance;
    
    function setBalanceForAddress(address _address, uint256 _balance) external {
        balance[_address] = _balance;
    }
}
pragma solidity ^0.8;

contract MyContract {
    struct PackedBalance {
        uint256 balance;
        uint256 locked_balance;
    }

    mapping(address => PackedBalance) balance;
    
    function setBalanceForAddress(address _address, uint256 _balance, uint256 _lockedBalance) external {
        balance[_address] = PackedBalance(_balance, _lockedBalance);
    }
}

address 总是 0x1231231231231231231231231231231231231231(用于调试目的)。

第一个合约将uint256字段存储到存储槽0xf100689cc6bb188feb3c0ef4658bee6e8042e58e79daebcd84870d7f336a8422

发送数据:

0x4fa1007300000000000000000000000012312312312312312312312312312312312312310000000000000000000000000000000000000000000000000000000000000064

重新混合调试器屏幕截图:


第二个合约将 struct 存储到插槽 0xf100689cc6bb188feb3c0ef4658bee6e8042e58e79daebcd84870d7f336a8422(与第一个合约相同)和 0xf100689cc6bb188feb3c0ef4658bee6e8042e58e79daebcd84870d7f336a8423(紧挨着它)。

发送数据:

0x6f7223d9000000000000000000000000123123123123123123123123123123123123123100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064

重新混合调试器屏幕截图: