区块链信任基础的数据不可修改的特性, 让它传统应用程序有一个很大的不同的地方是一经发布于区块链上就无法修改 (不能直接在原有的合约上直接修改再重新发布)
写在前面
阅读本文前, 你应该对以太坊智能合约及 Solidity 语言有所了解, 如果你还不了解, 建议你先看以太坊是什么
当智能合约出现 bug
一方面正式由于智能合约的不可修改的特性, 因为只要规则确定之后, 没人能够修改它, 大家才能够信任它但另一方面, 如果规则的实现有 Bug, 可能会造成代币被盗, 或是调用消耗大量的 gas 这时就需要我们去修复错误
我们知道一个智能合约包含两部分: 代码逻辑和数据, 而代码逻辑又是最容易出问题的部分, 如在实现如下合约时, 由于手抖在写 addTen() 时, 10 写成了 11
- pragma solidity ^0.4.18;
- contract MyContract {
- mapping (address => uint256) public balanceOf;
- function setBlance(address _address,uint256 v) public {
- balanceOf[_address] = v;
- }
- function addTen(address addr) public returns (uint){
- return balanceOf[addr] + 11;
- }
- }
假如我们在部署之后发现了这个问题, 想要修复这个 bug 的话, 只好重新部署合约, 可是这时会有一个尴尬的问题, 原来的合约已经有很多人使用, 如果部署新的合约, 老合约的数据将会丢失
数据合约及控制合约
那么如何解决上面的问题了, 一个解决方案是分离合约中的数据, 使用一个单独的合约来存储数据 (下文称数据合约), 使用一个单独的合约写业务逻辑 (下文称控制合约)
我们来看看代码如何实现
- pragma solidity ^0.4.18;
- contract DataContract {
- mapping (address => uint256) public balanceOf;
- function setBlance(address _address,uint256 v) public {
- balanceOf[_address] = v;
- }
- }
- contract ControlContract {
- DataContract dataContract;
- function ControlContract(address _dataContractAddr) public {
- dataContract = DataContract(_dataContractAddr);
- }
- function addTen(address addr) public returns (uint){
- return dataContract.balanceOf(addr) + 11;
- }
- }
现在我们有两个合约 DataContract 专门用来存数据, ControlContract 用来处理逻辑, 并利用 DataContract 来读写数据通过这样的设计, 可以在更新控制合约后保持数据合约不变, 这样就不会丢失数据, 也不用迁移数据
读写控制
通过 DataContract 我们可以单独更新合约逻辑, 不过你也许发现了一个新的问题, DataContract 的数据不仅仅可以被 ControlContract 读写, 还可以被其他的合约读写, 因此需要对 DataContract 添加读写控制我们给 DataContract 添加一个 mapping, 用来控制哪些地址可以访问数据, 同时添加了修饰器及设置访问的方法, 代码如下:
- pragma solidity ^0.4.18;
- contract DataContract {
- mapping (address => uint256) public balanceOf;
- mapping (address => bool) accessAllowed;
- function DataContract() public {
- accessAllowed[msg.sender] = true;
- }
- function setBlance(address _address,uint256 v) public {
- balanceOf[_address] = v;
- }
- modifier platform() {
- require(accessAllowed[msg.sender] == true);
- _;
- }
- function allowAccess(address _addr) platform public {
- accessAllowed[_addr] = true;
- }
- function denyAccess(address _addr) platform public {
- accessAllowed[_addr] = false;
- }
- }
- ...
订阅我的小专栏可参看合约的完整代码
部署方法如下:
先部署 DataContract 合约
使用 DataContract 合约地址作为部署 ControlContract 合约的参数
用 ControlContract 合约地址作为参数调用 DataContract 合约的 allowAccess 方法
如果需要更新控制合约 (如修复了 addTen) 则重新执行第 2-3 步, 同时对老的控制合约执行 denyAccess()
更多
当我们在实现数据合约时, 它包含的逻辑应该越少越好, 并且应该是严格测试过的, 因为一旦数据合约部署之后, 就没法更改
大多数情况下, 和用户交互的是 DApp, 因此当控制合约升级之后, 需要升级 DApp, 使之关联新的控制合约
尽管合约可以通过本文的方式升级, 但我们依然要谨慎升级, 因为升级表示你可以重写逻辑, 会降低用户对你的信任度
本文介绍升级方法更多的是一种思路, 实际项目中可能会对应多个控制合约及数据合约
欢迎来我的知识星球讨论区块链技术
深入浅出区块链 - 系统学习区块链, 打造最好的区块链技术博客
来源: https://www.cnblogs.com/tinyxiong/p/8600201.html