代码由OpenZeppelin的Proxy合约简化而来。
代理模式
Solidity
合约部署在链上之后,代码是不可变的(immutable)。这样既有优点,也有缺点:
- 优点:安全,用户知道会发生什么(大部分时候)。
- 坏处:就算合约中存在bug,也不能修改或升级,只能部署新合约。但是新合约的地址与旧的不一样,且合约的数据也需要花费大量gas进行迁移。
有没有办法在合约部署后进行修改或升级呢?答案是有的,那就是代理模式。
代理模式将合约数据和逻辑分开,分别保存在不同合约中。我们拿上图中简单的代理合约为例,数据(状态变量)存储在代理合约中,而逻辑(函数)保存在另一个逻辑合约中。代理合约(Proxy)通过delegatecall
,将函数调用全权委托给逻辑合约(Implementation)执行,再把最终的结果返回给调用者(Caller)。
代理模式主要有两个好处:
- 可升级:当我们需要升级合约的逻辑时,只需要将代理合约指向新的逻辑合约。
- 省gas:如果多个合约复用一套逻辑,我们只需部署一个逻辑合约,然后再部署多个只保存数据的代理合约,指向逻辑合约。
提示:对delegatecall
不熟悉的朋友可以看下本教程第23讲Delegatecall。
代理合约
一个简单的代理合约,它由OpenZeppelin的Proxy合约简化而来。它有三个部分:代理合约Proxy
,逻辑合约Logic
,和一个调用示例Caller
。它的逻辑并不复杂:
- 首先部署逻辑合约
Logic
。 - 创建代理合约
Proxy
,状态变量implementation
记录Logic
合约地址。 Proxy
合约利用回调函数fallback
,将所有调用委托给Logic
合约- 最后部署调用示例
Caller
合约,调用Proxy
合约。 - 注意:
Logic
合约和Proxy
合约的状态变量存储结构相同,不然delegatecall
会产生意想不到的行为,有安全隐患。