从源码分析openzeppelin的三种可升级模式和两种代理模式

从源码分析openzeppelin的三种可升级模式和两种代理模式

本文作者: gasshadow

github.com/OpenZeppelin

源码里有三种可升级模式:

主要是为了解决:如何确保逻辑合约不会覆盖代理中用于升级的状态变量

下文图中的内容,绿色文字表示 function 是 public 的。方框表示每个合约声明的存储

upgradeability_using_eternal_storage


用户和EternalStorageProxy交互。

这种情况,是通过逻辑合约全部使用 map 映射来和升级变量进行隔离

部署过程

  1. 部署EternalStorageProxy合约,地址为 E1
  2. 部署Token_V0合约,地址为 T1
  3. 调用EternalStorageProxy合约的upgradeTo()或者upgradeToAndCall()方法(_call some function to redo the setup_),传入 T1。

完成部署后:

在这里,Token_V0是逻辑合约,数据存在代理合约EternalStorageProxy

升级过程

  1. 部署Token_V1合约,地址为 T2
  2. 调用EternalStorageProxy合约的upgradeTo()或者upgradeToAndCall()方法

在这里,实际修改的就是代理合约EternalStorageProxy_implementation成员指向了Token_V1地址。后续调用就会转到Token_V1合约。

小结

可以看到,这种代理模式,要求合约里的所有数据存储,都放到 map 里面来。编码不够灵活。

upgradeability_using_inherited_storage

这种情况,是通过继承,让逻辑合约不会占用升级变量

部署过程

  1. 部署Registry合约,地址 R1
  2. 部署Token_V0合约,地址为 T1
  3. 调用Registry合约的addVersion将 T1 进行注册
  4. 调用Registry合约的createProxy(version)方法,获取一个UpgradeabilityProxy合约地址,地址 U1。此时 U1 里的registry变量就是 R1(构造函数里赋值为msg.sender
  5. 调用 U1 的upgradeTo方法,设置_implementation变量

部署完以后,代理合约UpgradeabilityProxy_implementation就指向了 T1,后续的调用都会转到 T1 上来。

升级过程

  1. 部署Token_V1合约,地址为 T2
  2. 调用Registry合约的addVersion将 T2 进行注册
  3. 调用UpgradeabilityProxy合约的upgradeTo方法,进行升级,修改_implementation变量。

upgradeability_using_unstructured_storage

这种情况,是通过固定的槽位分散存储,和逻辑合约进行隔离,赌的是逻辑合约本身的存储不会和升级数据的槽位冲突

部署过程

  1. 部署OwnedUpgradeabilityProxy合约,地址为 O1
  2. 部署Token_V0合约,地址为 T1
  3. 调用OwnedUpgradeabilityProxy合约的upgradeTo或者upgradeToAndCall方法进行升级,向implementationPosition槽位写入值

升级过程

  1. 部署Token_V1合约,地址为 T2
  2. 调用OwnedUpgradeabilityProxy合约的upgradeTo或者upgradeToAndCall方法进行升级

关于 TransparentUpgradeableProxy 和 UUPSUpgradeable

github.com/OpenZeppelin
这两者解决的不是存储冲突的问题,而是谁(代理合约还是逻辑合约)来升级(调用upgradeTo(address))的问题。他们底层都用的unstructured_storage

透明代理

合约的升级,由代理合约来进行,也就是逻辑合约根本不关心升级的事情。所以,需要代理合约来完成。

透明代理工作原理

透明代理,需要部署三个合约:逻辑合约(业务代码)、代理合约(TransparentUpgradeableProxy)、管理合约(ProxyAdmin)

用户和代理合约进行交互。代理合约里有_IMPLEMENTATION_SLOT槽位数据。
升级过程就是用逻辑合约和代理合约的地址,调用管理合约的upgrade或者upgradeAndCall方法。然后在方法里,会调用代理合约的updateTo或者upgradeToAndCall方法,修改代理合约里的_IMPLEMENTATION_SLOT槽位对应的变量

透明代理的问题

因为由透明代理来完成升级工作,那么透明代理合约里,必然有处理升级的函数,比如upgradeTo,所以,就存在代理合约和逻辑合约两者有函数名冲突的情况。比如都有upgradeTo函数,那么针对普通用户,应该需要调用到逻辑合约,对于管理员(负责升级)应该要调用代理合约。所以,在透明代理模式上,一定要有用户权限的判断。也就是TransparentUpgradeableProxy的如下代码:

至于是不是每一次用户函数调用是否都需要如上的判断,是有的。原因是不能让管理员能调到逻辑合约的函数。代码如下:

所以,透明代理会比普通的合约要更费 gas(多一次存储数据读取)。

UUPS 代理

合约的升级,由逻辑合约来进行,不需要代理合约参与。

UUPS 代理工作原理

UUPS 代理,只需要部署两个合约:逻辑合约(业务代码)、代理合约。没有管理合约(因为直接在逻辑合约里升级即可)。逻辑合约从UUPSUpgradeable继承。

由于所有的用户调用都是通过代理合约直接转到逻辑合约,所以代理合约本身不需要什么数据。代理合约的生成,可以使用plugin-hardhat生成。

实际上plugin-hardhat生成的代理合约就是ERC1967Proxy,参考代码: github.com/OpenZeppelin
export async function getProxyFactory(hre: HardhatRuntimeEnvironment, signer?: Signer): Promise<ContractFactory> {
return hre.ethers.getContractFactory(ERC1967Proxy.abi, ERC1967Proxy.bytecode, >signer);
}

可以看到确实没有对外的函数

用户和代理合约进行交互。代理合约里有_IMPLEMENTATION_SLOT槽位数据。
升级过程就是直接通过代理合约,调用逻辑合约里的upgradeTo方法或者upgradeToAndCall方法。

UUPS 代理的问题

由于升级过程是调用逻辑合约的升级方法,如果逻辑合约没有该升级方法,那么就可能导致后续无法升级。为了解决这个问题,要求逻辑合约必须继承UUPSUpgradeable合约。该合约要求子类必须实现_authorizeUpgrade方法


有问题欢迎留言,相互探讨


本文首发于登链社区: gasshadow 从源码分析 openzeppelin 的三种可升级模式和两种代理模式

登链社区-区块链技术爱好者的家园 twitter Discord

代做工资流水公司莆田工作收入证明办理包头打流水账单天津房贷流水样本九江制作签证银行流水商丘查房贷收入证明三亚银行流水价格临沂开工资代付流水苏州做离职证明德阳房贷收入证明办理桂林对公银行流水模板佛山代办企业对公流水上饶查离职证明泰安工资代付流水办理遵义查询工资流水账单信阳企业对公流水代办洛阳打企业贷流水宜春做工作收入证明蚌埠房贷银行流水 价格苏州个人银行流水样本南京查工资流水西宁公司流水制作厦门办理贷款银行流水扬州消费贷流水制作贵阳房贷流水多少钱宜春企业银行流水开具温州流水账单办理九江制作签证流水吉林入职银行流水代做郑州代做工资流水账单石家庄代办房贷银行流水香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声卫健委通报少年有偿捐血浆16次猝死汪小菲曝离婚始末何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言男子被猫抓伤后确诊“猫抓病”周杰伦一审败诉网易中国拥有亿元资产的家庭达13.3万户315晚会后胖东来又人满为患了高校汽车撞人致3死16伤 司机系学生张家界的山上“长”满了韩国人?张立群任西安交通大学校长手机成瘾是影响睡眠质量重要因素网友洛杉矶偶遇贾玲“重生之我在北大当嫡校长”单亲妈妈陷入热恋 14岁儿子报警倪萍分享减重40斤方法杨倩无缘巴黎奥运考生莫言也上北大硕士复试名单了许家印被限制高消费奥巴马现身唐宁街 黑色着装引猜测专访95后高颜值猪保姆男孩8年未见母亲被告知被遗忘七年后宇文玥被薅头发捞上岸郑州一火锅店爆改成麻辣烫店西双版纳热带植物园回应蜉蝣大爆发沉迷短剧的人就像掉进了杀猪盘当地回应沈阳致3死车祸车主疑毒驾开除党籍5年后 原水城县长再被查凯特王妃现身!外出购物视频曝光初中生遭15人围殴自卫刺伤3人判无罪事业单位女子向同事水杯投不明物质男子被流浪猫绊倒 投喂者赔24万外国人感慨凌晨的中国很安全路边卖淀粉肠阿姨主动出示声明书胖东来员工每周单休无小长假王树国卸任西安交大校长 师生送别小米汽车超级工厂正式揭幕黑马情侣提车了妈妈回应孩子在校撞护栏坠楼校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变老人退休金被冒领16年 金额超20万西藏招商引资投资者子女可当地高考特朗普无法缴纳4.54亿美元罚金浙江一高校内汽车冲撞行人 多人受伤

代做工资流水公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化