(三)编写智能合约

将使用Solidity编程语言创建一个Dapp用于证明在特定时间的存在、真实性和所有权,即证明一个文件在一个特定时间属于一个特定所有者

  • Solidity源文件布局
  • 理解Solidity的数据类型
  • 合约的特殊变量和函数
  • 控制结构
  • 合约的结构和功能
  • 编译和部署智能合约
3.1 Solidity 源文件

Solidity源文件使用的扩展名为.sol
MacOS部署Solidity

http://wiki.jikexueyuan.com/project/solidity-zh/installing-solidity.html

3.2 智能合约的结构

合约就像一个类,其中包含:状态变量、函数、函数修改器、事件、结构、枚举

合约还支持继承,通过在编译时备份代码来实现

合约同样支持多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//contract关键字声明一个合约
contract Sample {
//静态变量
uint 256 data;//声明data,包含一些数据
adddress owner;//声明owner 包含所有者的以太坊地址

//定义一个事件,用来通知客户端,一旦data变化,将触发这个事件
event logData(uint256 dataToLog);

//函数修改器,用于在执行一个函数之前自动检测条件
modifier onlyOwner() {
if (msg.sender != owner) throw;
_;
}

//construtor得到合约构造函数,在部署合约时,调用构造函数。用于初始化状态变量
function Sample(uint256 initData, address initOwner)
{
data = initData;
owner = initOwner;
}

//函数
function getData() returns (uint256 returnedData) {
return data;
}

function setData(uint256 newData) onlyOwner {
logData(newData);
data = newData;
}
}
3.3 数据位置

在Solidity中,根据情况的不同,变量可能不存储在内存和文件系统中。

对于复杂数据类型,例如字符串、数组和结构类型struct可以向类型中添加storage或者memory进行重写。

函数参数默认使用memory

本地变量默认使用storage

状态变量位置强制使用storage

数据位置很重要,因为他们会改变分配的行为:

  • storage变量和memory变量之间的分配总是创建一个独立的备份。但是如果分配是从memory存储的一种复杂类型到另一种复杂类型,则不创建备份
  • 到一个状态变量的分配总是创建一个独立的备份
  • 不能把memeory中存储的复杂类型分配给本地存储变量
  • 在分配状态变量给本地存储比阿尼量的情况下,本地存储变量指向状态变量,本地存储变量变为指针。
3.4 什么是不同的数据类型

Solidity是一种静态类型语言,变量存储的数据类型需要预先定义,所有变量默认值都是0

  • 布尔值

    最简单的数据类型,可以是true或者false

  • uint8,uint16,uint36…uint256分别用于存储无符号8、16、36位整数,同样还有int8,int16,int36…
  • ufixed和fixed代表分数,ufixed0x8,yfixed0x16用于存储未签名的8位、16位分数
  • address 用于存储最大20字节的值(16进制表示)用于存储以太坊地址

    address类型有两个属性balance和send。balance用于检测地址余额,send用于向地址发送以太币。send方法拿出需要转账数量的wei,并根据转账是否成功返回true或者false

3.4.1 数组类型

Solidity支持generic和byte两种数组类型,他们支持固定长度和动态长度两种数组,也支持多为数组

  • generic数组类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    contract sample {
    //动态长度数组
    int[] myArray = [0, 0];
    function sample(uint index, int value)
    {
    myArray[index] = value;

    int[] myArray2 = myArray;

    //固定长度数组
    uint24[3] memory myArray3 = [1, 2, 9999];

    uint8[2] myArray4 = [1, 2];
    }
    }
  • 数组有length属性,用户可以给length属性分型一个值,改变数组大小,但不可以在内存中改变数组大小,也不可以改变非动态数组大小

  • 如果想分文动态数组的未设置索引,会抛出异常
  • array,structs和map都不可以用作函数参数,也不可以用作函数返回值
3.4.2 字符串类型

在Solidity中,有两种方法创建字符串:使用bytes和string,byte用于创建原始字符串,string用于创建UTF-8字符串,字符串长度总是动态的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
contract sample {
string myString = "";
bytes myRawString;

function sample(string initString, bytes rawStringInit)
{
myString = initString;
string myString2 = myString;

//myString3存储在内存中
string memory myString3 = "ABCDR";
myString3 = 'sdsds';//改变myString3的值

myRawString = rawStringInit;
myRawString.length++;

}
}
3.4.3 结构类型

Solidity还支持结构类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
contract sample {
struct myStruct {
bool myBool;
string myString;
}
myStruct s1;
myStruct s2 = myStruct(true, "");

function sample(bool initBool, string initString)
{
s1 = myStruct(initBool, initString);
myStruct memory = myStruct(initBool, initString);
}
}

3.4.4 枚举类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
contract sample {
enum OS {windows, Linux, OSX, UNIX}
OS choice;

function sample(OS chosen)
{
choice = chosen;
}

function setLinuxOS()
{
choice = OS.Linux;
}

function getChoice() returns (OS chosenOS)
{
return choice;
}
}
3.4.5 mapping类型

mapping数据类型还是一个哈希表。只可以存在storage中,不存在memory中,因为他们是作为状态变量声明的。

可以认为mapping类型包含key/value对,不是实际存储key,而是存储key的keccak256哈希,用于查询value。

mapping类型没有长度,不可以分配给另个一个mapping

1
2
3
4
5
6
7
8
9
10
contrcat sample {
mapping (int => string) myMap;
function sample(int key, string value)
{
myMap[key] = value;

mapping (int => string) myMap2 = myMap;//myMap2是myMap的映射
}
}
如果想访问mapping不存在的key,返回的value为0
3.4.6 delete操作符

delete操作符可以用于任何变量,将其设置为默认值0;

如果对动态数组使用delete操作符,则删除所有元素,长度变为0

如果对于静态数组使用,则充值所有索引

对mapping类型使用,不发生任何作用,如果对mao的一个键使用,则会删除该键的值

1
2
3
4
function reset()
{
delete myArray;
}
3.5 控制结构
3.6 用new操作符创建合约
3.7 异常
3.8 外部函数调用
3.9 合约功能
3.10 库
3.11 返回多值
3.12 导入其他Solidity源文件
3.13 全局可用变量
3.14 以太币单位
3.15 存在、真实性和所有权合约
3.16 编译和部署合约
3.17 总结