当前位置:网站首页>可升级合约的原理-DelegateCall
可升级合约的原理-DelegateCall
2022-07-02 09:38:00 【灬倪先森_】
可升级合约的原理-DelegateCall
在介绍DelegateCall
时,我们需要带上Call
方法一起介绍,并做对比。
先说概念吧!
DelegateCall:有一种特殊类型的消息调用,被称为 委托调用(delegatecall)
。它和一般的消息调用(call
)的区别在于,目标地址的代码将在发起调用的合约的上下文中执行,并且 msg.sender
和 msg.value
不变。 这意味着一个合约可以在运行时从另外一个地址动态加载代码。
我不喜欢一上来就讲概念,毕竟太难理解。还是上代码演示吧
演示环境
Remix IDE:Remix是基于浏览器的 IDE,集成了编译器和 Solidity 运行时环境,不需要服务端组件,支持网页在线编写、部署和测试智能合约。
本章主要是让大家快速了解DelegateCall的特性,所以选择基于Remix来演示。
编码
我们在contracts
目录下新建delegatecall.sol
文件,并接下来把下面演示代码粘贴进delegatecall.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
contract A {
address public msgsender;
function callFunc() public {
msgsender = msg.sender;
}
}
contract B {
address public msgsender;
address public a;
constructor(address _a) {
a = _a;
}
function call_a_call() public{
// isOk 用来接收调用是否成功
(bool isOk,bytes memory result) = a.call(abi.encodeWithSignature("callFunc()"));
// 如果失败,报异常
require(isOk,"call faild");
}
function delegatecall_a_delegatecall() public{
(bool isOk,bytes memory result) = a.delegatecall(abi.encodeWithSignature("callFunc()"));
require(isOk,"call faild");
}
}
我们在这里定义两个合约A
和B
A
合约有一个msgsender
状态变量和callFunc()
方法
B
合约有两个状态变量msgsender
和a
,msgsender
是为了验证我们的实验结果,a
是存放合约A
的实例引用,并且定义了两个方法,分别用来演示用B
合约通过call
和delegatecall
两种方式调用A
合约的callFunc()
然后我们按Ctrl + s
快捷键,这里会保存合约代码,编译器会自动帮我们编译
合约部署
点击下面的按钮跳转到部署与调试
页面
先部署合约A
,再部署合约B
,因为B
中的状态变量a
引用了A
的地址
- 部署合约
A
- 部署合约
B
部署合约B
时需要传入A
的地址
合约交互
我们先点击>
按钮展开我们的合约,并点击A
合约和B
合约的msgsender
按钮查询(点击按钮会自动调用msgsender
的查询方法)当前状态变量的值,这里我们可以看到都为0
接下来我们点击B
合约delegatecall_a_delegatecall
按钮(调用delegatecall_a_delegatecall
方法),然后再次点击A
合约和B
合约的msgsender
按钮查询
奇怪的事情发生了!!!A
合约的msgsender
没有值,但是B
合约的msgsender
变成了我自己的地址0x5B38Da6a....
好了,我们可以结合上面的实验结果,再来理解文章开头的所说的概念
目标地址A
合约的代码将在发起调用的B
合约的上下文
中执行,并且 msg.sender
和 msg.value
不变。上下文
就是运行环境,就包括了合约里的状态变量
,所以当合约执行callFunc()
的内容时,callFunc()
方法是在B
合约里执行的,修改的是B
合约的状态变量,而A
合约的msgsender
却没有变化。
如果B
合约的两个状态变量msgsender
和a
在代码中互换位置,就是另一个故事了,这里涉及到另一个概念《合约数据存储布局》
接下来我们点击B
合约call_a_call
按钮,然后再次点击A
合约和B
合约的msgsender
按钮查询
现在A
合约的msgsender
有值了,B
合约的msgsender
值没有变化。
当调用B
合约call_a_call
方法时,B
合约的状态变量没有发生变化,A
合约的msgsender
有值了,这说明callFunc()
方法是在A
合约的上下文
环境中执行的,这里上下文
发生了变化。
并且我们发现A
合约的msgsender
变成了B
合约的地址,这说明在调用的过程中msg.sender
和 msg.value
发生了变化,msg.sender
不再是我自己0x5B38Da6a....
而是B
合约的地址
总结
会顾我们前面写的可升级合约,当对代理合约
发起调用时,代理合约
与逻辑合约
交互就是用的委托调用(DelegateCall)
。逻辑合约
的方法在代理合约
的上下文执行,并且修改的状态变量
也是代理合约
的。所以合约数据一直都在代理合约
里,当逻辑合约
升级时并不会影响合约原来已有的数据
有问题,或者建议请留言,谢谢。
边栏推荐
猜你喜欢
CTF record
CentOS8之mysql基本用法
II Stm32f407 chip GPIO programming, register operation, library function operation and bit segment operation
一.STM32的开发环境,keil5/MDK5.14安装教程(附下载链接)
C#多维数组的属性获取方法及操作注意
PowerBI中导出数据方法汇总
【云原生】2.5 Kubernetes 核心实战(下)
Eight sorting summaries
enumrate的start属性的坑
III Chip startup and clock system
随机推荐
mysql 基本语句
Indexer in C #
Calculate the sum of sequences
从攻击面视角,看信创零信任方案实践
Multi line display and single line display of tqdm
Never forget, there will be echoes | hanging mirror sincerely invites you to participate in the opensca user award research
Tdsql | difficult employment? Tencent cloud database micro authentication to help you
How does the whole network display IP ownership?
STM32单片机编程学习
Tick Data and Resampling
Approximate sum count (approximate
Order by injection
VS2019代码中包含中文内容导致的编译错误和打印输出乱码问题
Verilog and VHDL signed and unsigned number correlation operations
Tidb DM alarm DM_ sync_ process_ exists_ with_ Error troubleshooting
js中给数组添加元素的方法有哪些
八大排序汇总
一.STM32的开发环境,keil5/MDK5.14安装教程(附下载链接)
TIPC Service and Topology Tracking4
Functional interfaces and method references