@@ -1,58 +0,0 @@ 区块链之设计模式 | 凤凰涅槃进阶之路

区块链之设计模式

Abel sun2022年12月25日
约 1202 字大约 4 分钟

设计模式

《Design Patterns For Smart Contracts In the Ethereum Ecosystem》

安全 Security

  • Checks-Effects-Interaction 保证状态完整,再做外部调用

    Checks:参数验证,Effects:修改合约状态,Interaction:外部交互 这个模式要求合约按照Checks-Effects-Interaction的顺序来组织代码。它的好处在于进行外部调用之前,Checks-Effects已完成合约自身状态所有相关工作,使得状态完整、逻辑自洽,这样外部调用就无法利用不完整的状态进行攻击

  • Mutex - 禁止递归

    使用修饰符防止函数被递归调用。防止重放攻击

    contract Mutex {
      bool locked;
      modifier noReentrancy() {
          //防止递归
          require(!locked, "Reentrancy detected");
          locked = true;
          _;
          locked = false;
      }
    
      //调用该函数将会抛出Reentrancy detected错误
      function some() public noReentrancy{
          some();
      }
    
    

}


### 可维护性 Maintaince

高度模块化、高内聚低耦合

* Data segregation - 数据与逻辑相分离
```javascript
contract DataRepository{

  uint private _data;

  function setData(uint data) public {
      _data = data;
  }

  function getData() public view returns(uint){
      return _data;
  }
}
contract Computer{
  DataRepository private _dataRepository;
  constructor(address addr){
      _dataRepository = DataRepository(addr);
  }

  //业务代码
  function compute() public view returns(uint){
      return _dataRepository.getData() * 10;
  }    
}
  • Satellite - 分解合约功能
contract Base {
    uint public _variable;

    function setVariable(uint data) public {
        _variable = _satellite.compute(data);
    }

     Satellite _satellite;
    //更新子合约(卫星合约)
    function updateSatellite(address addr) public {
        _satellite = Satellite(addr);
    }
}
contract Satellite {
    function compute(uint a) public returns(uint){
        return a * 10;        
    }
}
  • Contract Registry - 跟踪最新合约
contract Registry{

    address _current;
    address[] _previous;

    //子合约升级了,就通过update函数更新地址
    function update(address newAddress) public{
        if(newAddress != _current){
            _previous.push(_current);
            _current = newAddress;
        }
    }

    function getCurrent() public view returns(address){
        return _current;
    }
}
contract Base {
    uint public _variable;

    function setVariable(uint data) public {
        Satellite satellite = Satellite(_registry.getCurrent());
        _variable = satellite.compute(data);
    }

    Registry private _registry = //...;
}
  • Contract Relay - 代理调用最新合约
contract Base {
    uint public _variable;

    function setVariable(uint data) public {
        _variable = _proxy.compute(data);
    }
    SatelliteProxy private _proxy = //...;
}
contract SatelliteProxy{
    address _current;
    function compute(uint a) public returns(uint){
        Satellite satellite = Satellite(_current);   
        return satellite.compute(a);
    }

    //子合约升级了,就通过update函数更新地址
    function update(address newAddress) public{
        if(newAddress != _current){
            _current = newAddress;
        }
    }   
}
contract Satellite {
    function compute(uint a) public returns(uint){
        return a * 10;        
    }
}

生命周期 Lifecycle

  • Mortal - 允许合约自毁
contract Mortal{
    //自毁
    function destroy() public{
        //selfdestruct指令,用于销毁合约
        selfdestruct(msg.sender);
    }
}
  • Automatic Deprecation - 允许合约自动停止服务

    当用户调用service,notExpired修饰符会先进行日期检测,这样,一旦过了特定时间,调用就会因过期而被拦截在notExpired层。

contract AutoDeprecated{

    uint private _deadline;

    function setDeadline(uint time) public {
        _deadline = time;
    }

    modifier notExpired(){
        require(now <= _deadline);
        _;
    }

    function service() public notExpired{
        //some code    
    }
}

权限 Authorization

  • Ownership
contract Ownable {
    address public owner;

    event OwnershipRenounced(address indexed previousOwner);
    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );

    constructor() public {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner);
        _;//表示所修饰函数中的代码,也就是将这个 require 在最前面执行
    }

    function transferOwnership(address newOwner) public onlyOwner {
        require(newOwner != address(0));
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }

    function renounceOwnership() public onlyOwner {
        emit OwnershipRenounced(owner);
        owner = address(0);
    }
}
//继承并添加修饰器
contract Biz is Owned{
    function manage() public onlyOwner{
    }
}

行为控制 Action And Control

  • Commit - Reveal - 延迟秘密泄露 Commit And Reveal模式允许用户将要保护的数据转换为不可识别数据,比如一串哈希值,直到某个时刻再揭示哈希值的含义,展露真正的原值。
    以投票场景举例,假设需要在所有参与者都完成投票后再揭示投票内容,以防这期间参与者受票数影响
contract CommitReveal {
    struct Commit {
        string choice;
        string secret;
        uint status;
    }
    mapping(address => mapping(bytes32 => Commit)) public userCommits;
    event LogCommit(bytes32, address);
    event LogReveal(bytes32, address, string, string);

    function commit(bytes32 commit) public {
        Commit storage userCommit = userCommits[msg.sender][commit];
        require(userCommit.status == 0);
        userCommit.status = 1; // comitted
        emit LogCommit(commit, msg.sender);
    }

    function reveal(string choice, string secret, bytes32 commit) public {
        Commit storage userCommit = userCommits[msg.sender][commit];
        require(userCommit.status == 1);
        require(commit == keccak256(choice, secret));
        userCommit.choice = choice;
        userCommit.secret = secret;
        userCommit.status = 2;
        emit LogReveal(commit, msg.sender, choice, secret);
    }
}
  • Oracle - 读取链外数据 获取外部数据会通过名为Oracle的链外数据层来执行。当业务方的合约尝试获取外部数据时,会先将查询请求存入到某个Oracle专用合约内;Oracle会监听该合约,读取到这个查询请求后,执行查询,并调用业务合约响应接口使合约获取结果。 oracle
contract Oracle {
    address oracleSource = 0x123; // known source

    struct Request {
        bytes data;
        function(bytes memory) external callback;
    }

    Request[] requests;
    event NewRequest(uint);
    modifier onlyByOracle() {
        require(msg.sender == oracleSource); _;
    }

    function query(bytes data, function(bytes memory) external callback) public {
        requests.push(Request(data, callback));
        emit NewRequest(requests.length - 1);
    }

    //回调函数,由Oracle调用
    function reply(uint requestID, bytes response) public onlyByOracle() {
        requests[requestID].callback(response);
    }
}
contract BizContract {
    Oracle _oracle;

    constructor(address oracle){
        _oracle = Oracle(oracle);
    }

    modifier onlyByOracle() {
        require(msg.sender == address(_oracle));
        _;
    }

    function updateExchangeRate() {
        _oracle.query("USD", this.oracleResponse);
    }

    //回调函数,用于读取响应
    function oracleResponse(bytes response) onlyByOracle {
    // use the data
    }
}

闪电网络

RSMC

Revocable Sequence Maturity Contract(序列到期可撤销合约)

HTLC

Hashed Timelock Contract(哈希时间锁定)

评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.9.1