智能合约的主要结构:
pragma solidity ^0.4.22; //编译器版本
import 'filename" as fname; 引有其他文件
import “./x” as x
//… 单行注释
/…/ 多行注释
/**…*/ 文档注释
contract Name{} //定义合约名称,和文件名称一至
function name() public {} 定义函数,可执行代码单元
constructor() public{} 构造函数,只在创建合约时执行一次。常用来初始化地址变量。
event name(address from, address to, uint amount); 定义事件,from A to B amount,用于获取当前发生的事件。用于函数触发使用。
modifier onlySeller(){} //声明一个修改器
function abort() public onlySeller {} //修改器的使用
struct Voter{ //结构类开定义 ,一个结构内包含多个变量。
unit a;
bool b;
address c;
uint d;}
enum State {a,b,c} //枚举类型
状态变量会被永久存储在合经的存储空间里
数据类型 | 数据类型 | 关键字 | 数据类型 | 数据类型 | 关键字 |
---|---|---|---|---|---|
布尔类型 | Boolean | bool | 十六进制常量 | Hexadecimal Literal | bytes(n) |
整型 | Integer | int8……int256 | 枚举 | Enum | enum name{} |
定长浮点型 | Fixed Point Number | 函数类型 | Function Type | ||
定长字节数组 | Fixed-size Byte Array | byte……bytes32 | 地址类型 | Addres | |
有理数和整型常量 | Rational and Integer Literal | - | 地址常量 | Address Literal | |
字符串常量 | StringLiteral | string |
bool类型 常量值为true 和false
支持的运算符:
运算符 | 表达式 | 运算符 | 表达式 | 运算符 | 表达式 |
---|---|---|---|---|---|
逻辑非 | ! | 逻辑与 | && | 逻辑或 | || |
不等于 | != | 等于 | == |
integer类型
整型 int8,int16,int32…int256 数字以8步进,默认int256
无符号类型uint,同上,默认为uint256
支持的运算符:
运算符类型 | 表达式 |
---|---|
比较运算符 | <=、 < 、== 、!= 、>= 、> (返回布尔值) |
位运算符 | &、 | 、^(异或)、 ~(位取反) |
算术运算符 | +、-、*、/、% (取余)、**(幂)、<<(左位移)、>>(右位移) |
赋值运算符 | +=、-=、*=、/=、%=、|=、&=、^=、++、– |
定长字节数组
byte 表示bytes1,以步长为1递增至bytes32,定长字节数组常来代替字符串
bytesx 0<=k
有理数和整型常量
表达式中直接出现的数字常量
十六进制
以 hex开头
bytes3 a =hex"aabb"
地址类型:
address name; //地址变量,160位,不允许算术操作
地址类型成员变量:balance 和 transfer
地址调用:
.balance (uint256):地址类型余额
.transfer(uint256 amount):向地址发送amount费用,失败抛出异常,消耗2300gas
.send(uint256 amount) returns (bool):向地址发送amount费用,失败为false,消耗2300gas
.call(...) returns (bool):发出低级函数 CALL,失败时返回 false,发送所有可用 gas,可调节。
.callcode(...) returns (bool):发出低级函数 CALLCODE,失败时返回 false,发送所有可用 gas,可调节。
.delegatecall(...) returns (bool):发出低级函数 DELEGATECALL,失败时返回 false,发送所有可用 gas,可调节。
string name; //字符串变量
bytes32 //定长数组,消耗gas更少
函数
function () {internal|external} [pure|constant|view|payable] [returns ()]
数组
memary 内存
不能修改长度,
storage 存储
.length 修改数组长度
push 增加元素到数据末尾,返回值为新的长度
数据类型 | 数据类型 | 关键字 |
---|---|---|
数组 | Array | |
结构体 | Struct | |
映射 | Mapping |
struct 结构体,自定义类型,可以使用基本类型外,还可以使用数组,结构体,映射作为成员
struct Name{
bool mybool;
uint myInt;
customType[] cts; //自定义结构体类型。
mapping(string=>customType) indexs;
}
mapping(address=> unit) name; #虚拟化(key=>value)键值对变量,不能遍历。
view 函数
保证不修改状态
constant 是 view 的别名,
Getter 方法被标记为 view
编译器没有强制 view 方法不能修改状态
修饰函数可让合约接收转账
下面的语句被认为是修改状态:
修改状态变量 | 产生事件 | 创建其它合约 | 使用 调用任何没有标记为 view 或者 pure 的函数 |
---|---|---|---|
通过调用发送以太币 | selfdestruct | 使用低级调用 | 使用包含特定操作码的内联汇编 |
pure 函数
承诺不读取或修改状态
只可以修饰函数,该函数内,无法读/写状态变量
除了上面解释的状态修改语句列表之外,以下被认为是从状态中读取:
读取状态变量 | 访问 this.balance 或者 .balance | 使用包含某些操作码的内联汇编 |
---|---|---|
调用任何未标记为 pure 的函数 | 访问 block,tx, msg 中任意成员 (除 msg.sig 和 msg.data 之外) |
Fallback 函数
合约可以有一个未命名的函数。这个函数不能有参数也不能有返回值。 如果在一个到合约的调用中,没有其他函数与给定的函数标识符匹配(或没有提供调用数据),那么这个函数(fallback 函数)会被执行。
除此之外,每当合约收到以太币(没有任何数据),这个函数就会执行。此外,为了接收以太币,fallback 函数必须标记为 payable。 如果不存在这样的函数,则合约不能通过常规交易接收以太币。
在这样的上下文中,通常只有很少的 gas 可以用来完成这个函数调用(准确地说,是 2300 gas),所以使 fallback 函数的调用尽量廉价很重要。 请注意,调用 fallback 函数的交易(而不是内部调用)所需的 gas 要高得多,因为每次交易都会额外收取 21000 gas 或更多的费用,用于签名检查等操作。
具体来说,以下操作会消耗比 fallback 函数更多的 gas:
写入存储
创建合约
调用消耗大量 gas 的外部函数
发送以太币
pragma solidity ^0.4.0;
contract Test {
// 发送到这个合约的所有消息都会调用此函数(因为该合约没有其它函数)。
// 向这个合约发送以太币会导致异常,因为 fallback 函数没有 `payable` 修饰符
function() public { x = 1; }
uint x;
}
// 这个合约会保留所有发送给它的以太币,没有办法返还。
contract Sink {
function() public payable { }
}
contract Caller {
function callTest(Test test) public {
test.call(0xabcdef01); // 不存在的哈希
// 导致 test.x 变成 == 1。
// 以下将不会编译,但如果有人向该合约发送以太币,交易将失败并拒绝以太币。
// test.send(2 ether);
}
}
可见性:
external 外部函数,this访问
public 公开函数,函数默认可见性
internal 内部函数,状态变量默认可见性
private 私有函数,当前合约,不支持继承
关键字 | 注释 |
---|---|
payable | ? |
uint | 定义无符号整数默认为uint256 |
memory | 内存,函数参数数据位置默认值 |
storage | 存储,局部变量的数据位置默认 |
calldata | 只读块,外部函数的参数的数据位置被强制指定 |