solidity0.8.0的应用案例10:可升级合约

这个案例是代理合约的实际操作,代理合约实现了逻辑和数据的分离,就可以实现在生产环境中,轻松升级合约,这就是一个如何实际升级合约的案例。

可升级模式

 实现一个简单的可升级合约,它包含3个合约:代理合约,旧的逻辑合约,和新的逻辑合约

代理合约

我们没有在它的fallback()函数中使用内联汇编,而仅仅用了implementation.delegatecall(msg.data);。因此,回调函数没有返回值,但足够教学使用了。

它包含3个变量:

  • implementation:逻辑合约地址。
  • admin:admin地址。
  • words:字符串,可以通过逻辑合约的函数改变。

它包含3个函数

  • 构造函数:初始化admin和逻辑合约地址。
  • fallback():回调函数,将调用委托给逻辑合约。
  • upgrade():升级函数,改变逻辑合约地址,只能由admin调用。
// SPDX-License-Identifier: MIT
// wtf.academy
pragma solidity ^0.8.4;// 简单的可升级合约,管理员可以通过升级函数更改逻辑合约地址,从而改变合约的逻辑。
// 教学演示用,不要用在生产环境
contract SimpleUpgrade {address public implementation; // 逻辑合约地址address public admin; // admin地址string public words; // 字符串,可以通过逻辑合约的函数改变// 构造函数,初始化admin和逻辑合约地址constructor(address _implementation){admin = msg.sender;implementation = _implementation;}// fallback函数,将调用委托给逻辑合约fallback() external payable {(bool success, bytes memory data) = implementation.delegatecall(msg.data);}// 升级函数,改变逻辑合约地址,只能由admin调用function upgrade(address newImplementation) external {require(msg.sender == admin);implementation = newImplementation;}
}

旧逻辑合约

这个逻辑合约包含3个状态变量,与保持代理合约一致,防止插槽冲突。它只有一个函数foo(),将代理合约中的words的值改为"old"

// 逻辑合约1
contract Logic1 {// 状态变量和proxy合约一致,防止插槽冲突address public implementation; address public admin; string public words; // 字符串,可以通过逻辑合约的函数改变// 改变proxy中状态变量,选择器: 0xc2985578function foo() public{words = "old";}
}

新逻辑合约

这个逻辑合约包含3个状态变量,与保持代理合约一致,防止插槽冲突。它只有一个函数foo(),将代理合约中的words的值改为"new"

// 逻辑合约2
contract Logic2 {// 状态变量和proxy合约一致,防止插槽冲突address public implementation; address public admin; string public words; // 字符串,可以通过逻辑合约的函数改变// 改变proxy中状态变量,选择器:0xc2985578function foo() public{words = "new";}
}

Remix实现

完整代码:

// SPDX-License-Identifier: MIT
// wtf.academy
pragma solidity ^0.8.4;contract SimpleUpgrade{address public implementation;//逻辑合约地址address public admin;//合约管理人地址string public words;//字符串,通过逻辑合约的函数改变//构造函数,初始化admin和逻辑合约地址constructor(address _implementation) {implementation = _implementation;admin = msg.sender;}//通过fallback函数,将调用委托给逻辑合约fallback() external payable {(bool success,bytes memory data) = implementation.delegatecall(msg.data);}//升级函数,改变逻辑合约的地址,就可以升级到新的逻辑合约,而且只能管理员才能调用function upgrade(address newImplementation) external {require(msg.sender == admin,'not owner');implementation = newImplementation;}
}contract OldLogic{address public implementation;address public admin;string public words;function foo() public {words = 'old';}
}contract NewLogic{address public implementation;address public admin;string public words;function foo() public {words = 'new';}
}

1、部署新旧逻辑合约Logic1Logic2

47-2.png

 

47-3.png

 2、部署可升级合约SimpleUpgrade,将implementation地址指向把旧逻辑合约。

47-4.png

 

 3、利用选择器0xc2985578,在代理合约中调用旧逻辑合约Logic1foo()函数,将words的值改为"old"

47-5.png

 4、调用upgrade(),将implementation地址指向新逻辑合约Logic2

47-6.png

5、 利用选择器0xc2985578,在代理合约中调用新逻辑合约Logic2foo()函数,将words的值改为"new"

47-7.png

 它是一个可以改变逻辑合约的代理合约,给不可更改的智能合约增加了升级功能。但是,这个合约有选择器冲突的问题,存在安全隐患。之后我们会介绍解决这一隐患的可升级合约标准:透明代理和UUPS

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/80881.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FPGA原理与结构——FIFO IP核原理学习

一、FIFO概述 1、FIFO的定义 FIFO是英文First-In-First-Out的缩写,是一种先入先出的数据缓冲器,与一般的存储器的区别在于没有地址线, 使用起来简单,缺点是只能顺序读写数据,其数据地址由内部读写指针自动加1完成&…

【Maven教程】(三)基础使用篇:入门使用指南——POM编写、业务代码、测试代码、打包与运行、使用Archetype生成项目骨架~

Maven基础使用篇 1️⃣ 编写 POM2️⃣ 编写业务代码3️⃣ 编写测试代码4️⃣ 打包和运行5️⃣ 使用 Archetype生成项目骨架 1️⃣ 编写 POM 到目前为止,已经大概了解并安装好了Maven环境, 现在,我们开始创建一个最简单的 Hello World 项目。如果你是初次…

笔记:transformer系列

1、和其他网络的比较 自注意力机制适合处理长文本,并行度好,在GPU上,CNN和Self-attention性能差不多,在TPU(Tensor Processing Uni)效果更好。 总结: 自注意力池化层将当做key,value,query来…

通过Putty对Linux服务器进行文件的上传与下载

1、下载安装Putty,下载地址:https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html 2、打开cmd窗口,通过命令行进入安装路径,如: 3、上传文件 pscp 文件 用户名服务器ip:目录使用“ -l ”选项可以指定用户…

SpringDataRedis 使用

1. SpringDataRedis 特点2. 使用 SpringDataRedis 步骤3. 自定义 RedisTemplate 序列化4. SpringDataRedis 操作对象 1. SpringDataRedis 特点 提供了对不同 Redis 客户端的整合(Lettuce 和 Jedis)提供了 RedisTemplate 统一 API 来操作 Redis支持 Redi…

tcl学习之路(五)(Vivado时序约束)

1.主时钟约束 主时钟通常是FPGA器件外部的板机时钟或FPGA的高速收发器输出数据的同步恢复时钟信号等。下面这句语法大家一定不会陌生。该语句用于对主时钟的名称、周期、占空比以及对应物理引脚进行约束。 create_clock -name <clock_name> -periood <period> -wa…

简单认识Docker数据管理

文章目录 为何需要docker数据管理数据管理类型 一、数据卷二、数据卷容器三、容器互联 为何需要docker数据管理 因为数据写入后如果停止了容器&#xff0c;再开启数据就会消失&#xff0c;使用数据管理的数据卷挂载&#xff0c;实现了数据的持久化&#xff0c;重启数据还会存在…

Python爬取斗罗大陆全集

打开网址http://www.luoxu.cc/dmplay/C888H-1-265.html F12打开Fetch/XHR&#xff0c;看到m3u8&#xff0c;ts&#xff0c;一眼顶真&#xff0c;打开index.m3u8 由第一个包含第二个index.m3u8的地址&#xff0c;ctrlf在源代码中一查index&#xff0c;果然有&#xff0c;不过/…

基于GRU门控循环网络的时间序列预测matlab仿真,对比LSTM网络

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 LSTM: GRU 2.算法运行软件版本 matlab2022a 3.部分核心程序 %构建GRU网络模型 layers [ ...sequenceInputLayer(N_feature)gruLayer(N_hidden)f…

SpringBoot 01 如何创建 和pom的解析

目录 1 Springboot的创建 步骤 2 项目的书写和运行 创建service包并在其下写一个service文件 项目的运行 pom文件的一些配置 parent web test 打包 打包过程 1 Springboot的创建 步骤 首先new一个新项目 然后依照如下创建 2 项目的书写和运行 创建service包并…

Unity——DOTween插件使用方法简介(上)

例子演示&#xff1a; DOTween移动 缓动动画既是一种编程技术&#xff0c;也是一种动画的设计思路。从设计角度来看&#xff0c;可以有以下描述 事先设计很多基本的动画样式&#xff0c;如移动、缩放、旋转、变色和弹跳等。但这些动画都以抽象方式表示&#xff0c;一般封装为程…

【Android】 No matching variant of com.android.tools.build:gradle:[版本号] was found

项目报错 No matching variant of com.android.tools.build:gradle:8.1.1 was found. The consumer was configured to find a library for use during runtime, compatible with Java 8, packaged as a jar, and its dependencies declared externally, as well as attribute …