精通以太坊-智能合约和Solidity

七、智能合约和Solidity

7.1 什么是智能合约

数字化的承诺,运行在EVM中。

特点:

  • 不可改变
  • 有确定性:每次输出是相同的

7.2 智能合约的生命周期

合约的地址由合约的创建交易在创建账户和随机数时生成。

智能合约并没有对应的私钥。

智能合约仅在被其他交易调用时执行。

不存在并发执行——EVM可认为是一台单线程计算机。

交易是原子的,若程序出错,则回滚之前所有操作,依旧会扣除gas。

合约不能更改,但可以通过执行SELFDESTRUCT的EVM字节码来删除,删除会提供gas退款。

SELFDESTRUCT需要开发者编写,否则无法删除。

7.3 以太坊高级编程语言

EVM高度隔离且极其简单。

智能合约的编程语言应极力避免任何可能的副作用。

Solidity为指令式编程语言。

7.4 使用Solidity编写智能合约

Solidity项目主要产出为Solidity编译器和ABI接口标准

7.5 以太坊合约的应用程序二进制接口

ABI是向机器指令层面编码和解码并传送数据的主要方式。

用JSON格式表示,包含描述函数和事件的数组。

应用与合约的交互完全依赖于ABI和应用实例部署的以太坊地址。

7.6 使用Solidity进行编程

预定义的全局变量和函数

Solidity基本数据类型:

  1. 布尔型(bool)
  2. 整数型(int, uint)
  3. 固定浮点数(fixed, ufixed):ufixed32x2表示该变量有32bit,小数点后有2位
  4. 地址address,有成员函数balance, transfer…
  5. 字节数组,从bytes1到bytes32,有固定和动态的区别
  6. 枚举,enum name{}
  7. 数组
  8. 结构体,struct name{}
  9. 映射,mapping(key_type=>value_type)
  10. 时间单位
  11. 以太币单位

触发合约执行的交易(msg)的属性:

  1. msg.sender:发起合约调用的地址
  2. msg.value:以太币数量
  3. msg.gas:当前可用gas数量
  4. msg.data:调用时传入的数据
  5. msg.sig:函数选择器

交易(tx)的属性:

  1. tx.gasprice:调用交易的gas价格
  2. tx.origin:发起交易的外部账户的地址

block的属性:

  1. block.blockhash(blockNumber):指定区块的哈希值,仅限于当前区块之前不超过256个区块
  2. block.coinbase:当前区块的矿工地址
  3. block.difficulty:POW的难度
  4. block.gaslimit:最大gas数量
  5. block.number:当前区块编号
  6. block.timestamp:当前区块的时间戳

address的属性:

  1. address.balance:地址余额
  2. address.transfer(amount):转出一定以太币
  3. address.send(amount):类似transfer
  4. address.call(payload)
  5. address.callcode(payload)
  6. address.delegatecall()

内建函数:

  1. addmod(), mulmod()
  2. sha256(), sha3()等等hash函数
  3. ecrecover,获得签名地址
  4. selfdestruct(recipient),删除合约并将剩余以太币转到recipient
  5. this,当前账户以太坊地址

合约定义

其他对象:

  1. interface
  2. library:只被部署一次

函数调用范围:

  1. public:可被交易,其他合约和合约内部调用
  2. external:类似public,不能内部调用除非指明this
  3. internal:只能被当前合约及其子合约内部调用
  4. private:只能被当前合约调用

函数都是可见的。

函数的行为:

  1. constant和view:不修改任何状态
  2. pure:不会在区块链中读取or写入任何数据
  3. payable:接收外部支付

构造函数constructor和自毁函数selfdestruct

函数修饰符modifier:_的地方会被修饰符的代码代替

继承is:contract 子合约 is 父合约1,父合约2 {}

错误处理

如果条件不满足则触发错误并且中止合约的执行:

  1. assert用于判断输出条件为真的情况
  2. require用来判断输入

立即中止合约执行并把状态回滚:

  1. revert
  2. throw已被淘汰

事件

当交易完成后,无论成功与否,都会生成一个交易收据,收据中包含由事件生成的日志。

关键字:

  1. indexed
  2. emit:将数据写入日志

调用其他合约

import引入合约文件

new实例化合约

可以添加已存在的实例,但很危险

call和delegatecall

这里给了调用合约的例子,值得看一下。

与gas有关的注意事项

如果gas耗尽,将触发以下事件:

  1. 抛出“out of gas”异常
  2. 恢复状态
  3. 消耗gas

避免消耗过多gas:

  1. 避免动态大小的数组
  2. 避免调用其他合约
  3. 使用estimateGas估计gas开销

疑惑

  1. 合约没有私钥,那要怎么使用其地址上的以太币?
  2. msg.sig是什么,有什么用?
  3. address.call是什么,有什么用?
  4. 假如我以简单的难度快速的算出了多个区块,别人算出了一个高难度的区块,那这时候主链怎么选择?
  5. interface例子?
  6. 事件indexed有什么用?
  7. 怎么理解添加已存在的实例?
  8. 使用Solidity进行编程这节需要重读