135.003 智能合约后端优化和产品化

@(135- Block Chain| 区块链)

Introduction

  • 如何通过数据结构优化降低合约执行成本
  • 合约的继承
  • 巧用modifier
  • 以太坊函数库的使用和基本介绍

如何减少gas 消耗?
(本质为节约计算资源,降低时间复杂度的问题)
数组越大,遍历所需资源越多
遍历数组 traverse array——> 映射 Mapping

1 Mapping in Solidity

类比map(c++),dict(python)
Hash table
Key - Value

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

  • types of Value in solidity
    (any type)
  • usage
    mapping (address=>Employee)employees
  • mapping只能作为合约的成员变量,而不能做本地局部变量

    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.命名返回参数直接赋值

等效代码

        // 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

库函数 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);

    }
}

参考阅读:老董-以太坊智能合约全栈开发

你可能感兴趣的:(135.003 智能合约后端优化和产品化)