1、智能合约的基本组成
1.1.程序版本
1.2. 合约声明
1.3.状态变量
1.4.合约方法
在这里constant相当于他声明这个局部变量不能更改,但是他并没有实际作用(实际就只是警示作用)
2、地址adress
- address.balance 账户余额
- adress.transfer(value) 返回调用者
- adress.send(value) 返回调用状态
- adress.call,adress.callcode and adress.delegatecall 用在智能合约与智能合约彼此相互调用
3、ether单位
- wei
- szabo = 10^12wei
- finney=10^15wei
- ether=10^18wei
4、时间单位
- seconds
- minutes
- hours
- days
- weeks
- years
5、块
- block.blockhash(uint blockNumber) returns(bytes32)
- block.coinbase(adress) 谁挖到这个block
- block.difficulty(uint) 块难度
- block.gaslimit(uint) gas限制(最多)
- block.number(uint) 块的序号
- block.timestamp(uint) 块创建时间
- now
6、消息msg
- msg.data 消息携带的参数
- msg.gas(uint) 函数调用者所携带的gas数
- msg.sender(address) 函数调用者
- msg.sig
- msg.value(uint)
7、单员工薪酬智能合约实例
pragma solidity ^0.4.22;
contract Pay{
uint salary = 1 ether; //工资总额
address frank =0x57ec6c8f13c46b43dcd28c83753dec9224d23ef2; //frank的账户地址
uint constant payDuration = 30 days; //发放薪资的周期
uint lastPayday = now;
function addFund() payable returns(uint){
return this.balance; //返回余额
}
function colculateRunway() returns(uint){
return this.balance / salary; //返回余额能够发放工资的次数
}
function hasEnoughFund() returns(bool){
return this.colculateRunway() > 0; //限制能够发放薪资的次数大于0次
}
function getPaid(){
if(msg.sender != frank){
revert(); //如果合约调用者不是frank 那么直接抛出异常
}
uint nextPayDay = lastPayday + payDuration; //如果重复使用一样的运算 第一是会浪费算力,还会浪费钱
if( nextPayDay > now){
revert(); //没到支付薪水时间
}
lastPayday = nextPayDay;
frank.transfer(salary);
}
}
8、错误检测
- assert(bool) 使用在程序运行时
- require(bool) 使用在程序输入时
9、多员工薪酬智能合约实例
pragma solidity ^0.4.22;
contract Pay{
uint constant payDuration = 10 seconds; //发放薪资的周期
address owner;
uint salary ; //工资总额
address employee ; //frank的账户地址
uint lastPayday;
//构造函数名要和合约名字一样
function pay(){
owner = msg.sender;
}
function updateEmployee(address e,uint s){
require(msg.sender == owner);//如果函数调用者不是当前owner,直接抛异常
if(employee != 0x0){
uint pament =salary * (now - lastPayday)/payDuration;
employee.transfer(pament);
}
employee = e;
salary = s * 1 ether;
lastPayday = now;
}
function addFund() payable returns(uint){
return this.balance; //返回余额
}
function colculateRunway() returns(uint){
return this.balance / salary; //返回余额能够发放工资的次数
}
function hasEnoughFund() returns(bool){
return this.colculateRunway() > 0; //限制能够发放薪资的次数大于0次
}
function getPaid(){
//如果合约调用者必须是employee 那么直接抛出异常
require(msg.sender == employee);
uint nextPayDay = lastPayday + payDuration; //如果重复使用一样的运算 第一是会浪费算力,还会浪费钱
assert(nextPayDay < now);//没到支付薪水时间
lastPayday = nextPayDay;
employee.transfer(salary);
}
}
数组:
- 静态数组(uint[5] A) 定义好了就不能改变数组的长度
- 动态数组(uint[] B)
方法:length 查看数组长度
push 只能用于动态数组
11、数据存储机制
- storage
- memory
- calldata
强制
--状态变量:storage
--function输入参数:calldata
默认:
--function返回参数:memory
--本地变量:storage
规则
相同存储空间变量父子
--传递reference(evm上的地址空间)
不同存储空间变量赋值
--拷贝
12、数据结构优化
Mapping
- 类似与map(C++),dict(python)
- key(bool,int,address,string)
- value(任何类型)
- mapping(address=>Employee) employees
- 只能做成员变量,不能做本地局部变量
Mapping底层实现
- 不使用数组+链表,不需要扩容
- hash函数keccak256hash,在storage上储存,理论上无限大的hash表
- 无法naiive的遍历整个mapping
- 赋值employees[key] = value
- 取值 value = employees[key]
- value是引用,在storage上存储,可以直接修改
- 当key不存在,value= type's default
13、可视度及合约继承
- public 公共的 谁都可见
- private 只有当前合约可见
- external 只有外部调用可见
- internal 外部调用不可见,内部和子类可见
- 状态变量:public,internal,private
- 默认internal
- public:自动定义取值函数
14、modifier
modifier onlyOwner{
_; 如果_;放在前面 那么require(msg.sender == owner);就要放在下次调用的return之前
require(msg.sender == owner);
}