注:
- 仅作技术交流,禁止商用
- 如有侵权,请联系删除
目录
- 背景
- 概述
- eip1967实现
- 易混概念——对比eip1167
背景
- 智能合约的定义(contract)
根据区块链可编程的特点,人们可以将合同变成代码的形式放到区块链上,并在约定的条件下自动执行 - 智能合约能做什么
DEX, Defi, GameFi, erc20等同质化代币(usdt), erc721等非同质化代币(NFT) - 为什么需要合约升级
升级业务逻辑
升级数据结构
保留原始数据 - 合约升级的几个标准方案
eip897
eip1967
eip1822
概述
- 原始的合约更新:对原有合约地址数据做一个快照,将原有合约地址上的数据完整拷贝到新地址上,需要扫链等,工作量大
- 可升级代理合约方案:用户访问proxy合约,实际方法由logic合约实现。数据存储在proxy合约中
- 经过一段时间的发展,目前eip1967是使用最广泛的可升级代理合约方案,同时open zeppelin官方推荐使用eip1822方案
手动升级方案——usdt以太坊版本
概述:
- 数据存储在当前合约
- 升级后需要迁移数据
缺点:
- 数据迁移代价太大
-
开发逻辑繁琐
可升级代理合约方案——简介
架构
关键技术
-
storage slot合约存储结构
- 合约存储冲突(clashing)
-
合约fallback机制
- 减少proxy合约和logic合约的方法冲突
-
delegatecall代理调用
- 调用logic合约方法修改本地(proxy合约)数据
-
admin用户对于普通请求的访问
- 引入proxyAdmin合约
代理合约知识储备——合约数据存储常见概念
- 合约的数据构成和分布 https://www.jianshu.com/p/2173ce49c10d
可升级代理合约方案——proxy合约slot数据
说明
proxy合约中需要存储至少2个关键信息,并且不能和逻辑合约上的数据冲突,所以通过读取slot的方式从proxy合约中获取数据。类似于c语言的 地址指针 和地址指针指向的数据
- implemention_slot
- 存储logic合约的地址 - admin_slot
- 有权限对合约进行升级的地址
举例
假设proxy合约的用slot0存储implemention的logic合约地址,那么logic合约的slot0的数据如何读取?
可升级代理合约方案——合约fallback机制
fallback函数定义
- 每一个合约有且仅有一个没有名字的函数。
- 这个函数无参数,也无返回值。
- 如果调用合约时,没有匹配上任何一个函数(或者没有传哪怕一点数据),就会调用默认的回退函数。
proxy合约实现
- proxy合约几乎不提供任何方法
- 除合约升级接口,其他所有访问都转交给fallback
- fallback调用的时候,校验调用者身份
- admin用户也能正常访问logic合约方法
可升级代理合约方案——合约delegatecall代理调用
说明
- 在proxy合约的请求处理中,通过delegatecall函数,运行对应的logic合约的方法代码
- 在当前合约上下文中运行
- 最终修改的是当前合约(proxy合约)的数据
- delegatecall实现原理:evm虚拟机的实现中替换目标合约运行的上下文环境(geth为例)
eip1967可升级合约架构核心数据流
说明
- 普通用户数据流
- admin用户数据流
- proxyAdmin合约
- 有权限进行合约升级的用户(admin)也能访问逻辑合约方法
流程
- 用户 --> proxy合约
- 用户 --> proxyAdmin合约 --> proxy合约