这篇文章上次修改于 796 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

Zeppeline 使用几种代理模式进行实现合约升级。

1.png

1 Inherited Storage

2.png

proxy 和 contract 都需要继承相同的存储结构 UpgradeabilityStorage,以确保两者都存储相同的代理状态变量。

Registry 合约用来跟踪不同版本的 contract 实现。

2 Eternal Storage

3.png

proxy 和 contract 都继承一个相同的外部存储结构 ExternalStorageExternalStorage 包含了 contract 所需的所有状态变量。因为 proxy 也能感知到 ExternalStorage,所以它可以定义升级所需的变量而无需担心被覆盖。需要注意的是,contract 的新版本将不能再定义其它的状态变量,只能使用一开始定义好的 ExternalStorage

3 Unstructured Storage

4.png

Unstructured Storage 和 Inherited Storage 很像,但是 contract 不需要继承任何与升级相关的状态变量。该模式使用 proxy 中定义的 unstructured storage slot。

在 proxy 中以特定字串的哈希值作为 Slot Index 去存储 _implementation。

bytes32 private constant implementationPosition = 
keccak256("org.zeppelinos.proxy.implementation");

因为常量不占用 storage slots,所以不需要担心 implementationPosition 会被 contract 覆盖。

这种模式中,contract 不需要知道 proxy 的存储结构。但是 contract 的新版本都必须继承前一个版本的存储变量。和 Inherited Storage 模式一样,contract 的新版本可以升级已有的方法,也可以引入新方法和新的存储变量。

参考

Proxy Patterns
Solidity Data Collision
Proxy Upgrade Pattern