1. 概述
以太坊中的出块时间缩短为十几秒,设计了基于gost的协议。以太坊中的mining puzzle是memory hard的,限制了ASIC的使用(ASIC resistance)。
proof of work –> proof of stake
Bitcoin: decentralized currency
Ethereum: decentrailized contract(去中心化的合约)
2. 以太坊账户
基于账户的模型(account-based ledger)
有余额的概念,转账交易时只需验证账户上是否有足够的余额,不用验证币的来源,对于double spending attack有天然的防御。
缺点: replay attack
a向b转10个币,写入区块链中,b又广播一次a向b转账的交易
防范:
1 | A -> B(10 ETH) |
nonce 为交易次数,每一个交易的nonce唯一
以太坊中有两类账户:
外部账户(externally owned account)
- 由公私钥对控制
- 属性:
balance(账户余额)
nonce(计数器)
合约账户(smart contract account)
- 特点:
一个合约可以调用其他合约,但合约账户不能主动发起交易 - 属性:
nonce
code
storage
- 特点:
3. 状态树
1 | 为了实现从账户地址到账户状态的映射 |
(key, value)
RLP:Recursive Length Prefix
3.1. trie(字典树)
特点:
- 每个节点的分支数目取决于key值中每个元素的取值范围(在以太坊中分叉数为17,因为是16进制,加上一位结束标志)
- tire的查找效率取决于key的长度,键值越长,查找需要访问内存的次数越多。(在以太坊中key的长度为40)
- 不会出现碰撞(只要地址不同就不可能碰撞)
- 插入顺序不影响树的结构
- 更新的局部性很好,只更新相关的分支
缺点:
- 浪费存储空间
3.2. Patricia trie(tree)
为了解决trie的存储浪费,同时提高查找效率,引入了pt
pt 是前缀树,对于字典树进行路径压缩。
注意:
在pt中新插入元素,原来压缩的路径可能会扩展开
3.3. MPT(Merkle Patricia tree)
使用哈希指针的pt
以太坊中使用的是 modified MPT
保存历史状态是为了支持回滚操作
blockheader代码:
block代码:
extblock代码:
4. 交易树和收据树
对于状态树来说,查找的键值就是账户的地址,对于交易树和收据树来说,查找的键值就是这个交易在发布的区块里的序号,交易的排列顺序是由发布这个区块的节点决定的。
区别:
交易树和收据树是只把当前发布的区块的交易组织起来的;而状态树是把系统中所有账户的状态都要包含进来,不管这个账户与当前的交易有没有关系。
每个区块的交易树和收据树都是独立的,他们是不会共享节点的,一个区块和另一个区块发布的交易本身我们也认为是独立的。
作用:
- 提供Merkel proof
- 查找过去n天产生与某个只能合约相关的交易
4.1. bloom filter
可以支持高效的查找,判断某个元素是否在某个集合中。
思想: 为集合计算出一个紧凑的摘要,哈希映射
缺点:
- 哈希碰撞(false positive)
- 不支持删除操作(哈希碰撞)
通过bloom filter可以过快速过滤掉无关的区块
以太坊的运行过程可以看做是一个交易驱动的状态机(transaction-driven state machine),状态的转换是确定的
5. GHOST 协议
在以太坊中出现分叉的情况更为常见
(uncle区块:当一个区块a被挖出时,感知到有相同的区块b被挖出,则b是c的uncle区块)被包含的uncle区块可获得7/8的出块奖励。
新区块如果包含一个uncle区块可以获得额外的1/32的出块奖励,一个新区块最多包含2个uncle block。
初代ghost协议存在的问题:
- 只能包含两个uncle区块
- 为了商业竞争,可能故意不包含uncle区块
修改协议:
- 祖父,曾祖父区块。。。都可以作为uncle区块,因为区块不太可能都是由同一个矿池挖出,所以会有其他区块包含uncle区块,使得uncle区块可以获得奖励。
- 以太坊中规定最多可以包含前6代的uncle区块,6代之前的不是uncle区块,或者说合法的uncle只有6个辈分。
- 对于当前块来讲,包含任意辈分的uncle,都能获得额外的1/32的出块奖励。
以太坊中有两种reward,block reward和gas fee,uncle block不能获得gas fee。gas fee与比特币中的交易费类似。
问题:
包含uncle block时要执行uncle block中的交易吗?
不检查uncle block中交易的合法性,值检查uncle是否符合挖矿难度如果分叉之后还跟着一串该怎么办?
如果每个都给奖励,会降低分叉攻击的成本。以太坊中规定只给第一个区块奖励。
6. 挖矿算法
挖矿是保证区块链安全的一个重要保障,所以我们可以说block chain is secured by mining.
但是比特币的挖矿算法后来出现了ASIC芯片,使得具有强算力的设备在挖矿上有更大的优势,这与去中心化的思想是背道而驰的。(只能专业的机器,普通的计算设备不能参与挖矿)
后来出现的加密货币的挖矿算法在设计的时候尽量降低对于ASIC的依赖,增加对内存的需求,即
ASIC resistance
memory hard mining puzzle
LiteCoin 就是基于这种思想的加密货币
6.1. LiteCoin
使用基于scrypt的mining puzzle
开设一个很大的数组,按照顺序填充一些伪随机数,使用seed填充第一个值,后一个值是有前一个值取哈希得到的。
求解puzzle时,读取A位置的数,根据他的取值算出下一个读取的位置,比如是B,以此类推。
问题:
- 对于轻节点不友好,验证和求解需要同样的内存
实际上litecoin的内存只有128k
6.2. 以太坊
以太坊使用memory hard的挖矿算法。
- 有两个数据集,小数据集16M cache,大数据集1G dataset(DAG)。大数据集是从小数据集中生成出来的。
- 小数据集是轻节点保存的
- 大数据集是挖矿节点使用的
- 这两个数据集是不断增大的
6.2.1. 伪代码
生成小数据集:
生成大数据集:
挖矿/验证函数:
挖矿函数:
全部函数:
6.3. 几点说明
以太坊实际上只有gpu挖矿,没有出现ASIC矿机,从这一点上讲是比较成功的。
以太坊构思从工作量证明转向权益证明,即POW->POS,但至今没有转变。
以太坊中使用了预挖矿(pre-mining)的过程,所谓预挖矿是指预留一些以太币给开发者。
7. 难度调整算法
与比特币的每隔2016个区块调整一次不同,以太坊是每隔区块都有可能调整难度。
难度调整算法:
以太坊发展的4个阶段:
拜占庭阶段调整挖矿难度具体代码实现:
8. 权益证明(proof of stake)
例如,根据持有币的多少来确定挖矿难度,持有币越多,挖矿难度越低,但这个设计会有问题,因为持有币多的人总会很容易挖到矿。所以有的加密货币要求投入的币会锁定一段时间。有时候叫做proof of deposit。
早期的权益证明会遇到两边下注的问题(nothing at stake)
在下面分支投入的币不会影响上面分支
8.1. Casper the Friendly Finality Gadget(FFG)
以太坊想要使用的权益证明
1 | 以太坊中引入了一个validator的概念: |
验证者参与这个过程:
- 如果验证者履行职责,可以得到相应的奖励
- 如果验证者有不良行为,要受到相应的惩罚
- 行政不作为(该投票不投票),扣除一部分保证金
- 乱投票(两边下注),没收保证金(销毁)
- 每个验证者有一定任期,任期满了之后有一定等待期,在等待期可以接受其他节点检举揭发对其惩处,如果等待期通过,则可以取回保证金和相应的奖励
9. 智能合约
- 智能合约是运行在区块链上的一段带密码,代码逻辑定义了合约内容
- 智能合约的账户保存了合约当前的运行状态
- balance: 当前余额
- nonce: 交易次数
- code:合约代码
- storage: 存储,数据结构是一颗MPT
- Solidity是智能合约最常用的语言,语法上与JavaScript很相近
9.1. 如何调用智能合约
调用智能合约与转账类似,例如A转账给B,若B是一个普通账户,则与比特币中的转账是相同的;若B是一个合约账户,这个转账实际上是发起对B合约的一次调用,具体调用的函数是在data域中说明的。
9.1.1. 外部账户调用
其中:
- TO CONTRACT ADDRESS: 是被调用的合约的地址
- 中间一行是调用的参数
汽油费是给发布这个区块的矿工的,汽油费如果不给的话,矿工不会把这个交易打包进入区块。
9.1.2. 一个合约调用另一个合约
由于以太坊中合约账户不能主动发起交易,所以在这个例子中应该还有一个外部账户,调用了合约B。
9.1.3. fallback 函数
9.2. 智能合约的创建和运行
9.3. 汽油费(gas fee)
死循环不可解,是一个Halting Problem
9.4. 错误处理
如果汽油费不够,则会引起回滚,但是已经消耗的汽油费不退,此举是为了防止恶意节点发起拒绝服务攻击。
9.5. 嵌套调用
9.6. 智能合约可以获得的区块信息
- block.blockhash(uint blockNumber) returns (bytes32) : 给定区块的哈希—仅对最近的256个区块有效而不包括当前区块
- block.coinbase(address):挖出当前区块的矿工地址
- block.difficulity(uint):当前区块难度
- block.gaslimit(uint):当前区块gas限额
- block.number(uint):当前区块好
- block.timestamp(uint):自unix epoch起始当前区块以秒计的时间戳。
9.7. 智能合约可以获得的调用信息
- msg.data(bytes):完整的calldata
- msg.gas(unit):剩余gas
- msg.sender(address):消息发送者(当前调用)
- msg.sig(bytes4):calldata的前4字节(也就是函数表示服)
- msg.value(uint):随消息发送的wei的数量
- now(uint):目前区块时间戳(block.timestamp)
- tx.gasprice(uint):交易的gas价格
- tx.origin(address):交易发起者(完全的调用链)
9.8. 地址类型
9.8.1. transfer vs. send vs. call
这三个函数都可以用于转账
- transfer和send 这两个是专门为了转账的函数,区别在于,transfer会导致连锁回滚;send不会导致连锁回滚
- call本意是用来调用函数的,也可以转账。也不会连锁回滚。把剩下的汽油都发过去
10. the Dao
DAO(Decentralized Autonomous Organization) 去中心化的自治组织
- 建立在代码的基础上的组织, 组织的规章制度写在代码里,通过区块链的共识协议维护规章制度的正常执行
DAC(Decentralized Autonomous Corporation)
the Dao: 2016年5月出现的一个致力于众筹投资的组织。使用以太币换取代币,由投入币的多少确定投票资格。收益的取回方式:split Dao,split直到子Dao中只有一个用户。
由于代码的漏洞,黑客发动了重入攻击。取走了很多以太币
这件事引起了轩然大波,在社区引发了激烈讨论,以太坊开发团队首先试图冻结与the Dao相关的交易,发布软件升级,实现软分叉,但由于升级的代码中不收取与the Dao相关交易的汽油费,导致产生了很多攻击。后又发布另一个版本的升级,实现硬分叉。以太坊分为了两个社区,旧链改为ETC,新链仍使用ETH.
10.1. 反思
- 关于智能合约的反思
Is smart contract really smart?
smart contract is anything but smart.Irrerocability is a double edged sword
Nothing is irrevovable(不可篡改)
Is solidity the right programming language?
what does decentralization mean?
对规则的修改需要用去中心化的方式来修改decentralized != distributed
11. 美链
当value很大时,amount可能会溢出,会导致体统上凭空出现很多代币。
12. 课程总结
- 中心化的组织也可以使用去中心化的支付方式
- 缺乏一种全球流通的货币
- 未来互联网的发展方向:支付渠道和信息渠道的统一
- 加密货币不应该与现有货币竞争
- 随着协议的改进,支付效率提高了很多
- 评价