• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

竹千代

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

合约的代理与升级

合约主要有3种代理模式:

一、透明代理Transparent

contract TransparentAdminUpgradeableProxy {
    address implementation;
    address admin;

    fallback() external payable {
        require(msg.sender != admin);
        implementation.delegatecall.value(msg.value)(msg.data);
    }

    function upgrade(address newImplementation) external {
        if (msg.sender != admin) fallback();
        implementation = newImplementation;
    }
}

这种模式直观好理解,代理合约负责升级,实现合约负责具体逻辑。

二、UUPS

// 代理合约
contract UUPSProxy { address implementation; fallback() external payable { implementation.delegatecall.value(msg.value)(msg.data); } }
// 实现合约里定义implementation属性(因为是delegatecall,所以运行时是代理合约的上下文slot)指向实现合约地址 abstract contract UUPSProxiable { address implementation; address admin;
// 升级方法修改
implementation属性, 也就修改了运行时代理合约指向实现合约地址了
function upgrade(address newImplementation) external {
require(msg.sender
== admin); implementation = newImplementation;
}
}

代理合约是空的,几乎不包含任何逻辑;实现合约既要有具体业务逻辑,还要有升级逻辑。

升级时,调用代理合约的upgrade方法, 会deletegatecall到实现合约的upgrade方法; 因为delegate实现合约会运行在代理合约的上下文中,所以实现合约的upgrade方法修改implementation属性,实际上就修改了代理合约的implementation属性。

三、钻石模式

1个代理合约,会有多份实现合约

  透明代理 UUPS 钻石模式
优点 容易理解 gas费用低  
缺点

运行gas费高,每次函数调用,都要从存储中找admin

代理部署gas费高,

新代理合约必须记得实现upgrade,否则再也无法升级  
openzepplin实现方式  contract MERC1967Proxy is Proxy, ERC1967Upgrade    

 

参考:https://blog.openzeppelin.com/the-state-of-smart-contract-upgrades

 

可升级合约不同之处

不要使用constructor,而是定义initialize函数。 因为实现合约不会直接与用户交互,都是通过代理合约用delegatecall把调用转发到实现合约里。所以实例化属性应该实例代理合约的,而不是实现合约自己的。
constructor完成的事情,就是实例化实现合约自己的属性值。 这个后续就毫无意义,纯粹是浪费gas。

posted on 2024-02-06 15:35  竹千代  阅读(106)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3