Published: 30 Oct 2022 › Updated: 30 Oct 2022
代理升级模式 / 学习智能合约#61
前不久研究了下重入攻击的玩法,里面有个重要的特性:合约的fallback()函数。 fallback是合约的底层函数,在没有其它函数匹配的情况下会执行。这个特性导致了重入的风险性,但在另一方面,合约的升级性也会用到这一特性。这充分体现了一物的两面性:是好是坏取决于你!
由于区块链不可篡改性,合约如果有漏洞就很难更改!那么,怎么才能安全地升级合约呢?这里要用到一种解藕的想法。把一个合约分成:代理、数据和逻辑三部分,通常要升级的也就是逻辑部分,其它不受影响,如下图所示:
我们来看下具体实现:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
//定义数据合约
contract storageStructure {
//记录球员和分数
address public implementation;//逻辑合约地址
mapping(address=>uint256) public points;
address public owner;
}
//定义逻辑合约
contract implementationV1 is storageStructure {
modifier onlyowner() {
require(msg.sender == owner, "only owner can do");
_;
}
//增加球员和分数
function addPlayer(address player, uint256 point) public onlyowner {
require(points[player] == 0, "player already exists");
points[player] = point;
}
//修改球员和分数
function setPlayer(address player, uint256 point) public onlyowner {
require(points[player] != 0, "player must already exists");
points[player] = point;
}
}
//代理合约 代理合约调用逻辑合约的逻辑去修改本身(代理合约)的数据
contract proxy is storageStructure {
modifier onlyowner() {
require(msg.sender == owner, "only owner can call");
_;
}
constructor() {
owner = msg.sender;
}
//更新逻辑合约的地址
function setImpl(address _impl) public onlyowner {
implementation = _impl;
}
//fallback函数 调用逻辑合约中的函数,在本地(代理合约)执行
fallback() external {
address impl = implementation; //逻辑合约的地址
require(impl != address(0), "implementation must exists");
//底层调用
assembly {
//调用delegateccall
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize())
//delegatecall(g, a, in, insize, out, outsize)
let result := delegatecall(gas(), impl, ptr, calldatasize(), 0, 0)
let size := returndatasize()
//returndatacopy(t, f, s)
returndatacopy(ptr, 0, size)
switch result
case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
}
可以看出,里面最核心的就是assembly中调用delegateccall。assembly属于汇编的写法,是比较底层的语法(yul),不太好理解。我们大概可以理解整个地调用过程:用户调用代理合约,代理合约调用逻辑合约修改本身的数据。如果需要升级,代理合约调用逻辑合约时就可以指向新的逻辑合约即可!
//逻辑合约升级
contract implementationV2 is implementationV1 {
function addPlayer(address player, uint256 point) override public onlyowner virtual {
require(points[player] == 0, "player already exists");
points[player] = point;
totalPlayers ++;
}
}
升级合约差不多就是个解藕的思路,分成三个部分,把需要升级的部分单独更改升级就可以啰!
Leave 代理升级模式 / 学习智能合约#61 to:
Read more #smartcontract posts
Best Posts From lemooljiang
We have not curated any of lemooljiang's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.
More Posts From lemooljiang
- Nextjs初体验,和Nuxt的异同
- DeepTutor:AI个性化辅导平台 / ai #57
- ComfyUI:可编程和自动化的PS / ai #56
- 将Neo4j封装进Agent / ai #55
- 闲鱼省钱大法:极限0.5折!
- 对Neo4j批量导入结构化数据 / ai #54
- langchain对neo4j进行交互,写入和查询数据 / ai #53
- 知识图谱和图数据库Neo4j的作用和使用场景 / ai #52
- SpaceX、美股和比特币
- 又是币圈血洗日!
- 链股合流,当币安也开始卖股票啰
- 天涯社区重启,爷青回?
- 诺基亚在AI时代重新杀回来啦
- 《2049:未来10000天的可能》书中的镜像世界为什么不叫元宇宙
- 今天适合吃披萨
- 开通即被封,别再给Claude送人头了!
- 两根内存条引发的“官司”
- AI·Joe V12更新, 更新GPT-5.5和DeepSeek V4 等
- 中医进校园活动反响热烈
- 猪价低伤农,猪价贵伤民