zoukankan      html  css  js  c++  java
  • 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<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);
    
        }
    }
    
    

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

  • 相关阅读:
    2016年 CodePen 最热门的前端代码 Top 100
    HttpClientHelper
    .net core mvc 简易登录
    senparc 第三方授权回调,保存授权信息到文件
    盛派微信Sdk .Net Core 初始化注册服务信息
    分享一个gif截图工具
    C# 单例模式
    获取微信AccessToken,保存在内存中,过期后重新获取
    .NET Core WebAPI Swagger使用
    .net Core 读取配置文件参数
  • 原文地址:https://www.cnblogs.com/Neo007/p/9249843.html
Copyright © 2011-2022 走看看