Telegram Channel
https://laisky.notion.site/Solidity-delegatecall-usage-and-pitfalls-3833eadc06ae4528bfa23d194ea8d3cb?pvs=4

前文介绍了 solidity 中变量的持久化存储方式。而我们之所以关心变量的存储位置(slot),就是因为在使用 Proxy 模式时,需要在合约间共享变量,而合约间变量的共享方式就是通过 slot 对齐的。

合约一旦发布就是只读不可更改的,如果想要修复 bug 或升级功能而发布一个新的合约,那么就会得到一个新的地址。为了在保持地址不变的同时更改合约的代码,最常见的实现方法就是使用 Proxy-Implementation 模式。发布一个 Proxy 合约作为接口,地址永远不变。但是实际的业务代码指向 Implementation 合约,implementation 合约可以不断地升级迭代,只要同步更新 Proxy 合约的指向即可。

实现 Proxy 这一功能,依赖于 solidity 的 delegatecall(),这个函数可以让 Implementation 使用 Proxy 的上下文,即内存数据和存储。而这个数据共享的前提,就要求 Proxy 和 Implementation 的变量声明按照 slot 进行严格的对齐。

按照目前最推荐使用的 UUPS Proxy 模式(UUPS 简而言之就是将升级 Implementation 的 upgrade() method 也放在 Implementation 内定义),为了减少 Proxy 和 Implementation 间的变量冲突,一个最佳实践就是不要在 Proxy 内声明任何非必需的变量,理论上 Proxy 内仅需要定义 owner(设置管理者) 和 implementation(设置 Implementation 的地址) 两个变量即可。所有的业务数据,全部仅在 Implementation 内定义。当 Proxy 使用 delegatecall() 调用 Implementation 时,Proxy 的存储空间会被共享给 Implementation,所以虽然变量仅定义在 Implementation 内,但实际上全部存储于 Proxy 的存储空间内。当 Implementation 迭代升级时,新版本的 Implementation 内的变量声明必须严格对齐于旧版本,仅允许在尾部添加新变量,不允许修改或删除旧变量(append-only)。

此文详细介绍了 delegatecall() 时,Proxy 和 Implementation 间变量对齐的注意事项和案例。 #blockchain #evm Solidity delegatecall usage and pitfalls | Notion
 
 
Telegram Channel