135.002 智能合约设计-——多员工薪酬系统

@(135- Block Chain| 区块链)c++

Introduciton

可调整地址和薪水的单员工系统数组

  • address neo -> address employee
  • funtion updateEmployee

Goal——多员工系统
Solution—— 数组+结构体安全

  • Employee[] employees
  • funtion addEmployee
  • funtion removeEmployee

1 错误检测

代码风格——方便简洁less

  • assert(bool) //程序运行时——确认ide

  • require(bool)//程序输入时——要求区块链

    require(msg.sender == owner);
      // if(msg.sender != employee){//了解调用者信息
      //     revert();
      // }
      assert(nextPayday < now);
      // if( nextPayday > now){
      //     revert();

2 Data Location | Solidity数据存储

  • storage
    永久存储在区块链上
  • memory

临时空间,在function结束后释放ui

  • calldata
    与memory相似

2.1强制类型

状态变量:storage
function 输入变量:calldatathis

2.2 默认类型

function 返回类型:memory
本地变量:storagecode

2.3 变量本质

类比c++的地址
指向 EVM中的一块内存区域内存

2.4 规则

  • 相同的存储空间变量赋值
    • 传递reference(EVM上的内存地址)
  • 不一样存储空间变量赋值
    • 拷贝

3 Code in Remix (Solidity IDE)

pragma solidity ^0.4.0;

contract Payroll{
    
    
    struct Employee{
        address id;
        uint salary;
        uint lastPayday;
    }
    
    
  // uint constant payDuration = 30 days;
   uint constant payDuration = 10 seconds;//for test:10 seconds
   
   address owner;
   Employee[] employees;//dynamic array 
     function Payroll(){//construction function
    
    owner = msg.sender;
        
    }
    function _partialPaid(Employee employee) private{
            uint payment = employee.salary * (now - employee.lastPayday) /payDuration;//if exist , calculate payment注意整除
            employee.id.transfer(payment);
    }
    
    function _findEmloyee(address employeeId) private returns (Employee,uint){//Encapsulation 封装 
        for (uint i=0;i<employees.length;i++)//avoid needless duplication (repeat)
        {
            if (employees[i].id == employeeId){
                return (employees[i],i);
            } 
        }
    
    }
    function addEmployee(address employeeId,uint salary){
        require(msg.sender == owner);//whether is onwner

        var (employee,index ) = _findEmloyee(employeeId); //var - any type
        assert(employee.id == 0x0);//confirm that exist
        
        employees.push(Employee(employeeId,salary,now));
    }
    
    function removeEmployee(address employeeId){
         require(msg.sender == owner);//whether is onwner
         var (employee,index) = _findEmloyee(employeeId); 
         assert(employee.id != 0x0);//confirm that exist
        _partialPaid(employees[index]);
        delete employees[index];//left with a blank in the array,wasteful
        employees[index] = employees[employees.length - 1];//fill the blank
        employees.length -= 1;
      

    
}
    
    function updateEmployee(address employeeId,uint salary) {
        require(msg.sender == owner);
        //Equivalently 等效 
        // if (msg.sender != owner){//avoid employee cheating
        //     revert();
        // }
        
         var (employee,index) = _findEmloyee(employeeId); 
         assert(employee.id != 0x0);//confirm that exist
        _partialPaid(employee);
        employees[index].salary = salary;
        employees[index].lastPayday = now;     
         

    }
    
    function addFund() payable returns(uint){
        return this.balance;//address.balance
    }
    
    
    function calculateRunway()returns(uint)
    { //how many times to pay
        uint totalSalary = 0;
        for (uint i=0;i<employees.length;i++)
         {
             totalSalary += employees[i].salary; 
         } 

        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 getPaid (){
         var (employee,index) = _findEmloyee(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[index].lastPayday = nextPayday;//原则:先修改内部变量,再给钱——》以后会讲,安全问题
            employee.id.transfer(employee.salary);

    }
}

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