@(135- Block Chain| 区块链)
Introduciton
可调整地址和薪水的单员工系统
- address neo -> address employee
- funtion updateEmployee
Goal——多员工系统
Solution—— 数组+结构体
- Employee[] employees
- funtion addEmployee
- funtion removeEmployee
1 错误检测
代码风格——方便简洁
-
assert(bool) //程序运行时——确认
-
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结束后释放
- calldata
与memory类似
2.1强制类型
状态变量:storage
function 输入变量:calldata
2.2 默认类型
function 返回类型:memory
本地变量:storage
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);
}
}
参考阅读:老董-以太坊智能合约全栈开发