精通以太坊-智能合约和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基本数据类型:
- 布尔型(bool)
- 整数型(int, uint)
- 固定浮点数(fixed, ufixed):ufixed32x2表示该变量有32bit,小数点后有2位
- 地址address,有成员函数balance, transfer…
- 字节数组,从bytes1到bytes32,有固定和动态的区别
- 枚举,enum name{}
- 数组
- 结构体,struct name{}
- 映射,mapping(key_type=>value_type)
- 时间单位
- 以太币单位
触发合约执行的交易(msg)的属性:
- msg.sender:发起合约调用的地址
- msg.value:以太币数量
- msg.gas:当前可用gas数量
- msg.data:调用时传入的数据
- msg.sig:函数选择器
交易(tx)的属性:
- tx.gasprice:调用交易的gas价格
- tx.origin:发起交易的外部账户的地址
block的属性:
- block.blockhash(blockNumber):指定区块的哈希值,仅限于当前区块之前不超过256个区块
- block.coinbase:当前区块的矿工地址
- block.difficulty:POW的难度
- block.gaslimit:最大gas数量
- block.number:当前区块编号
- block.timestamp:当前区块的时间戳
address的属性:
- address.balance:地址余额
- address.transfer(amount):转出一定以太币
- address.send(amount):类似transfer
- address.call(payload)
- address.callcode(payload)
- address.delegatecall()
内建函数:
- addmod(), mulmod()
- sha256(), sha3()等等hash函数
- ecrecover,获得签名地址
- selfdestruct(recipient),删除合约并将剩余以太币转到recipient
- this,当前账户以太坊地址
合约定义
其他对象:
- interface
- library:只被部署一次
函数调用范围:
- public:可被交易,其他合约和合约内部调用
- external:类似public,不能内部调用除非指明this
- internal:只能被当前合约及其子合约内部调用
- private:只能被当前合约调用
函数都是可见的。
函数的行为:
- constant和view:不修改任何状态
- pure:不会在区块链中读取or写入任何数据
- payable:接收外部支付
构造函数constructor和自毁函数selfdestruct
函数修饰符modifier:_的地方会被修饰符的代码代替
继承is:contract 子合约 is 父合约1,父合约2 {}
错误处理
如果条件不满足则触发错误并且中止合约的执行:
- assert用于判断输出条件为真的情况
- require用来判断输入
立即中止合约执行并把状态回滚:
- revert
- throw已被淘汰
事件
当交易完成后,无论成功与否,都会生成一个交易收据,收据中包含由事件生成的日志。
关键字:
- indexed
- emit:将数据写入日志
调用其他合约
import引入合约文件
new实例化合约
可以添加已存在的实例,但很危险
call和delegatecall
这里给了调用合约的例子,值得看一下。
与gas有关的注意事项
如果gas耗尽,将触发以下事件:
- 抛出“out of gas”异常
- 恢复状态
- 消耗gas
避免消耗过多gas:
- 避免动态大小的数组
- 避免调用其他合约
- 使用estimateGas估计gas开销
疑惑
- 合约没有私钥,那要怎么使用其地址上的以太币?
- msg.sig是什么,有什么用?
- address.call是什么,有什么用?
- 假如我以简单的难度快速的算出了多个区块,别人算出了一个高难度的区块,那这时候主链怎么选择?
- interface例子?
- 事件indexed有什么用?
- 怎么理解添加已存在的实例?
- 使用Solidity进行编程这节需要重读