实现可升级智能合约
智能合约升级的基本思路以及具体简单demo实现1.智能合约可升级性智能合约一旦部署无法进行修改,常见方案1.1 主从合约Master-Slave contracts部署一个主合约,以及其他合约,其中主合约负责存储所有其他合约的地址,并在需要时返回所需的地址。优点:简单缺点:不易进行合约资产转移到新合约1.2永久存储合约Eternal Storage contracts逻辑合约...
智能合约升级的基本思路以及具体简单demo实现
1.智能合约可升级性
智能合约一旦部署无法进行修改,常见方案
1.1 主从合约
Master-Slave contracts
部署一个主合约,以及其他合约,其中主合约负责存储所有其他合约的地址,并在需要时返回所需的地址。
优点:简单
缺点:不易进行合约资产转移到新合约
1.2永久存储合约
Eternal Storage contracts
逻辑合约和数据合约彼此分开。 数据合约是永久性的,不可升级。 逻辑合约可以根据需要多次升级,并将更改通知给数据合约。通常会和主从技术相结合。
缺点:数据合约不可更改、逻辑合约外部调用数据合约消耗gas
1.3 可升级存储代理合约
Upgradable Storage Proxy Contracts
代理合约以及逻辑合约,将继承同一存储合约。
代理合约将有一个回退函数,委托调用逻辑合约,从而实现逻辑合约在代理存储中进行更改。
1.4委托调用
EVM所提供的DELEGATECALL操作码,DELEGATECALL就像是一个普通的CALL 调用操作码,不同之处在于目标地址上的代码是在调用合约上下文中执行的,而原始调用的msg.sender以及msg.value将被保留。
分离逻辑和数据合约
逻辑合约通过setter更新数据,而数据合约只允许逻辑合约调用setter。这允许在保持数据不变的同时更换实现逻辑,从而实现完全可升级的系统。
通过引导用户使用新的逻辑合约(通过诸如ENS的解析器)并更新数据合约的权限来允许新的逻辑合约执行setter,就可以实现合约的更新。
键值对数据模型分离逻辑和数据合约
不使用最终期望数据结构(struct,mapping等)来定义合约数据模型,所有数据都被抽象化并存储在键值对中,然后使用一个标准的命名系统以及sha256散列算法用于查找数据值。
2.实现DEMO
storage 存储
implementionV1 原智能合约
implementionV2 新智能合约
//0.4.25
contract StorageStructure {
address public implementation;
address public owner;
mapping (address => uint) internal points;
uint internal totalPlayers;
}
contract Proxy is StorageStructure {
//确保只有所有者可以运行这个函数
modifier onlyOwner() {
require (msg.sender == owner);
_;
}
//设置管理者owner地址
constructor() public {
owner = msg.sender;
}
//更新实现合约地址
function upgradeTo(address _newImplementation)
external onlyOwner
{
require(implementation != _newImplementation);
_setImplementation(_newImplementation);
}
//回调
function () payable public {
address impl = implementation;
require(impl != address(0));
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize)
let result := delegatecall(gas, impl, ptr, calldatasize, 0, 0)
let size := returndatasize
returndatacopy(ptr, 0, size)
switch result
case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
//设置当前实现地址
function _setImplementation(address _newImp) internal {
implementation = _newImp;
}
}
contract ImplementationV1 is StorageStructure {modifier onlyOwner() {
require (msg.sender == owner);
_;
}
function addPlayer(address _player, uint _points)
public onlyOwner
{
require (points[_player] == 0);
points[_player] = _points;
}
function setPoints(address _player, uint _points)
public onlyOwner
{
require (points[_player] != 0);
points[_player] = _points;
}
}
contract ImplementationV2 is ImplementationV1 {
function addPlayer(address _player, uint _points)
public onlyOwner
{
require (points[_player] == 0);
points[_player] = _points;
totalPlayers++;
}
}
-
依次部署 proxy合约、ImplementationV1合约
-
调用proxy合约的upgradeTo(address)函数:
address为部署后的implementionV1合约地址。
-
重新部署 proxy合约,此时只需使用proxy合约即可
-
合约升级: 重写并部署implementionV2合约 ,并将其合约地址,作为调用proxy合约的upgradeTo(address)参数
相关文章链接
https://hackernoon.com/how-to-make-smart-contracts-upgradable-2612e771d5a2
https://yos.io/2018/10/28/upgrading-solidity-smart-contracts/
更多推荐
所有评论(0)