最新消息:本站技术交流 QQ 群:28124927

智能合约的升级

区块链/比特币 exchen 2763浏览 0评论

智能合约的升级

智能合约的特点是布署完成后不可修改,但是可以通过升级的方法修改业务逻辑。在做合约审计时经常会遇到合约有升级的功能,OpenZeppelin 里提供 ERC1967 代理升级合约,其原理是使用 delegatecall 委托调用。

delegatecall 委托调用

delegatecall 和 call 都可以调用另一个合约,但是 delegatecall 是使用的委托调用,区别在于 A 合约使用 call 调用 B 合约,B 合约发送主币ETH给 C 合约,C 合约获取到的 msg.sender 是 B 合约,而使用 delegatecall 却不同,C 合约获取到的 msg.sender 是 A。下面我们来编代码测试效果,编写一个合约名为 Test,代码如下,三个变量 num, sender, value,num 是 setNum 函数输入的参数相加 2,sender 是调用者,value 是发送的主币数量。

再编写一个 UpgradeDelegatecall 合约,同样也是三个参数,setNum 函数里的 _target 参数是 Test 合约地址,具体代码如下:

将两个合约布署完成后,在 UpgradeDelegatecall 合约里输入 Test 合约地址,再输入 num 参数为 1,获取的数值会相加 2,即是 3,如下图所示:

然后我们尝试更新合约,将 Test 改名为 Test2,其中的 setNum 将输入的参数改为乘以 2,代码如下:

布署 Test2,在 UpgradeDelegatecall 合约里填入 Test2 的合约地址,输入 num 为 100,此时会看到 num 会乘以 2,即是 200,如下图所示。此时我们已经实现了一种简单的合约升级的功能,数据是保存在 UpgradeDelegatecall 合约,而逻辑可以升级。

ERC1967 升级合约

在上面我们使用了 delegatecall 完成了一个简单的合约升级的功能,但大部分合约使用的 ERC1967 升级合约,OpenZeppelin 提供了相应的接口,不过底层原理依然还是 delegatecall。下面我们编写一个 ERC1967 升级合约的实例,需要用到三个合约,第一个是 Test,功能和之前一样,还是三个参数 num, sender, value,setNum 函数会将输入的参数加 2,第二个是 ProxyAdmin,它主要负责管理代理升级合约,第三个是 TransparentUpgradeableProxy 它负责升级合约,会调用 delegatecall 委托调用新合约,完整的代码如下:

布署这三个合约,需要注意的是布署 TransparentUpgradeableProxy 需要提供三个参数,第一个是 Test 合约地址,第二个是 Proxy Admin 的地址,第三个是 initialize 函数的签名,如下图所示:

然后选择 Test 输入 TransparentUpgradeableProxy 合约的地址,点击 At Address 加载,如下图所示:

加载完成后 TransparentUpgradeableProxy 合约的地址,我们看到的是 Test 合约的函数与变量,输入 1 点击 setNum,可以看到结果会相加 2,即是 3,如下图所示:

接下来我们需要测试升级合约,将 Test 合约里的 setNum 函数相加 2 的逻辑改成乘以 2,合约名改成 Test2,在 ProxyAdmin 里面 upgrade 函数输入 TransparentUpgradeableProxy 合约地址和 Test2 合约地址,如下图所示:

此时再回到 Test 合约,操作 setNum 输入 100,结果就是乘以2,即 200,如下图所示,说明合约升级成功。

转载请注明:exchen's blog » 智能合约的升级

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址