135.003 智能合約後端優化和產品化

@(135- Block Chain| 區塊鏈)python

Introduction

  • 如何經過數據結構優化下降合約執行成本
  • 合約的繼承
  • 巧用modifier
  • 以太坊函數庫的使用和基本介紹

如何減小gas 消耗?
(本質爲節約計算資源,下降時間複雜度的問題)
數組越大,遍歷所需資源越多
遍歷數組 traverse array——> 映射 Mappingc++

1 Mapping in Solidity

類比map(c++),dict(python)
Hash table
Key - Valuegit

  • types of Key in solidity
    (bool,int ,address,string)程序員

  • types of Value in solidity
    (any type)
  • usage
    mapping (address=>Employee)employees
  • mapping只能做爲合約的成員變量,而不能作本地局部變量github

    2 Mapping底層實現

  • 不使用數組+鏈表,不須要擴容
  • hash函數爲keccak256hash(keccak 即SHA- 3)
  • 在storage 上存儲,理論上爲無限大的hash表
    *** 沒法naive地遍歷整個mapping**
  • 賦值 employees[key] = value
  • 取值 value = employees[key]
  • value 是引用,在storage上存儲,能夠直接修改
  • 當key 不存在,value = type's default // 不會拋出異常數組

3 函數返回進階

  • 命名參數返回
  • 命名返回參數直接賦值

1.命名參數返回安全

function checkEmployee(address employeeId) returns(uint salary,uint lastPayday){ //quary the information of employees
    //name the returned parameter 命名參數返回

OUTPUT

"0": "uint256: salary 1000000000000000000",
"1": "uint256: lastPayday 1530411588"
}數據結構

2.命名返回參數直接賦值app

等效代碼框架

// return (employee.salary,employee.lastPayday);
        salary = employee.salary;
        lastPayday = employee.lastPayday;

4 可視度

4.1 可視度

  • public :誰均可見
  • external:只有「外部調用」可見(特殊可視度)
  • internal:外部調用不可見,內部和子類可見(類比c++,protected)
  • private:只有當前合約可見

4.2 變量與可見度

  • 狀態變量:public,internal,private
    • 默認:internal
    • public:自動定義取值函數
    • private:不表明別人沒法看到,只表明別的區塊鏈智能合約沒法看到

合約的全部成員變量都是肉眼可見的!!!

  • 函數 :public,external,internal,private
    • 默認public

5 繼承

5.1 繼承-基本語法

private 對繼承類不可見

5.2 繼承-抽象合約

contract Parent{
    function someFunc() returns (uint);
}
contract Child is Parent{
    function someFunc() returns (uint){
        return 1;
    }
}

5.3 繼承-interface

  • 類比 Java 類似
    只是一個告訴以後程序員的一個框架
pragma solidity ^0.4.0;
interface Parent{
//不可繼承其餘合約或Interface
//沒有構造函數
//沒有狀態變量
//沒有struct
//沒有enum
//簡單來講,只有function定義,啥都沒有
    function someFunc() returns (uint);
}

contract Child is Parent{
    function someFunc() returns (uint){
        return 1;
    }
}

5.4 多繼承

  • 重名函數的override 次序
contract Base1{
    function func1(){}
}

contract Base2{
    function func1(){}
}

contract Final is Base1,Base2 {
}

contract test{
    Final f = new Final();
    f.func1();//Base2 的function1被調用(從後往前,因爲先繼承base1,再繼承base2)
}
  • Super:動態綁定上級函數
contract foundation{
    function func1{
    //do stuff
    }
}


contract Base1 is foundation{
    function func1(){
        super.func1();
    }
}

contract Base2 is foundation{
    function func1(){
    super.func1();
    }
}

contract Final is Base1,Base2{
    Final f = new Final();
    f.func1();
}



//調用順序:Base2.func1,Base1.func1,foundation.func1

多繼承 Method Resolution Order使用O3 Linearization

  • 與python 相同
  • 不能成環路

6 Modifier

pragma solidity ^0.4.0
contract Parent {
    uint public a=2;
    modifier someModifier(){
        _;
        a = 1;
    }
    function parentFunc2(uint value) someModifer public returns(uint){
    a = value;
    //下劃線等效加入一句 modify a=1;
    return a;
    }
}

7 Safe Math 和 Library

7.1 加減乘除在solidity中很危險

contract Test {
    uint8 public a = 0;
    function set(){
        a -= 100;
    }
}


OUTPUT:整型溢出
a: uint8: 156

手動解決方法_silly

contract Test {
    uint8 public a = 0;
    function set(){
        uint c = a - 100;
        assert(c<a);
        a = c;
    }
}

庫函數 Zppelin-solidity

  • 工程師——學習代碼重用
  • 不要重複造輪子
solidity ^0.4.0;

import './SafeMath.sol'; //local file,download from github

contract Test {
    using SafeMath for uint8;
    uint8 public a = 0;
    function set(){
        a = a.sub(100);
        //a = SafeMath.sub(a,100);
    }
}

8 Code in Remix (Solidity IDE)

pragma solidity ^0.4.14;

import './SafeMath.sol';
import './Ownable.sol'; //Github - Zppelin-solidity


contract Payroll{
    using SafeMath for uint;
    
    struct Employee{
        address id;
        uint salary;
        uint lastPayday;
    }
    
    
  // uint constant payDuration = 30 days;
   uint constant payDuration = 10 seconds;//for test:10 seconds
   
   uint totalSalary;
   address owner;
   mapping(address => Employee)public employees;
   
   
    // function Payroll(){//construction function
    // owner = msg.sender; // in ownable.sol
    // }
    
    // modifier onlyOwner{ //in Ownable.sol
    //     require(msg.sender == owner);
    //     _; //represent the function been modified, 除了return以外的語句
    // }
    modifier employeeExist(address employeeId){
        var employee = employees[employeeId];
        assert(employee.id != 0x0);//confirm that exist
        _;
    }
    function _partialPaid(Employee employee) private{
            uint payment = employee.salary * (now - employee.lastPayday) /payDuration;//if exist , calculate payment注意整除
            employee.id.transfer(payment);
    }
    

    function addEmployee(address employeeId,uint salary)onlyOwner{
       // require(msg.sender == owner);//whether is onwner
        var employee = employees[employeeId];//var - any type
        assert(employee.id == 0x0);//confirm that exist
        totalSalary += salary *1 ether;
        employees[employeeId] = Employee(employeeId,salary* 1 ether,now);
    }
    
    function removeEmployee(address employeeId)onlyOwner employeeExist(employeeId){
        // require(msg.sender == owner);//whether is onwner
        //  var (employee,index) = _findEmloyee(employeeId); 
        var employee = employees[employeeId];
        _partialPaid(employee);
        totalSalary -=employees[employeeId].salary;
        delete employees[employeeId];//left with a blank in the array,wasteful
}
    
    function updateEmployee(address employeeId,uint salary)onlyOwner employeeExist(employeeId){
        //require(msg.sender == owner);
        //Equivalently 等效 
        // if (msg.sender != owner){//avoid employee cheating
        //     revert();
        // }
         var employee = employees[employeeId];
        _partialPaid(employee);
        totalSalary -= employees[employeeId].salary;
        employees[employeeId].salary = salary *1 ether;
        totalSalary += employees[employeeId].salary;
        employees[employeeId].lastPayday = now;     
         

    }
    
    function addFund() payable returns(uint){
        return this.balance;//address.balance
    }
    
    
    function calculateRunway()returns(uint)
    { //how many times left to pay
        return this.balance / totalSalary; 
    }
    function hasEnoughFund() returns(bool){
        // return this.balance >=salary;
        //return this.calculateRunway() > 0; //this方法 使用的gas 較多,不推薦
        return calculateRunway() > 0; //vm jump 操做,使用gas較少,推薦
    }
    
    function checkEmployee(address employeeId) returns(uint salary,uint lastPayday){ //quary the information of employees
    //name the returned parameter 命名參數返回 
    
        var employee = employees[employeeId];
        // return (employee.salary,employee.lastPayday);
        salary = employee.salary;
        lastPayday = employee.lastPayday;
    }
    
    function getPaid() employeeExist(msg.sender){

         var employee = employees[msg.sender];
         //assert(employee.id != 0x0);//confirm that exist
        uint nextPayday = employee.lastPayday + payDuration;
         //每一次運算都是真金白銀~
         //原則:不重複運算!——省gas
        assert(nextPayday < now);
        // if( nextPayday > now){
        //     revert();
              //throw or revert
            //throw: 全部的gas 均會被消耗殆盡
            //revert:回滾,return沒有消耗的gas
           
        // }
        
            employees[msg.sender].lastPayday = nextPayday;//原則:先修改內部變量,再給錢——》以後會講,安全問題
            employee.id.transfer(employee.salary);

    }
}

參考閱讀:老董-以太坊智能合約全棧開發

相關文章
相關標籤/搜索