比特币被称为区块链1.0,以太坊被称为区块链2.0
以太坊针对BTC出现的问题进行了改进
- | 比特币 | 以太坊 |
---|---|---|
出块时间 | 10min | 约15秒 |
共识机制 | 工作量证明 | GHOST协议 |
挖矿算法 | mining puzzle | memory hard 将来会使用权益证明代替工作量证明 |
以太坊还增加了对智能合约的支持。
BTC实现了去中心化的货币, 以太坊的还实现了去中心化的合约支持
智能合约的应用场景, 如果合同的参与方来自世界各地,没有一个统一的司法管辖权,如果我们通过实现写好的程序代码,每个人都只能按照这个规则来执行,这是一种比较好的解决方案,即使合同参与方在一个司法管辖权,合同的维护也费时费力,打官司花好多时间和精力,也不一定赢。智能合约的好处是一旦合约发布到区块链,谁都不能改,只能按照智能合约的规则来做事。
BTC系统没有账户的概念,转账需要提供前一笔交易的来源,有多少钱需要你提供私钥去UTFO里面查询合计。交易没有没有找零机制,这种方式的好处是隐私保护好,缺点是不符合常规,以太坊有账户的概念,可以显示账户余额。
有账户的好处是天然防御double speeding attach
,缺点是replay attach
。
举例来说 A转给B 10ETH
过了几十秒数据写入区块链,B又在网络中广播一次,这样B就能获得20ECH
。以太坊在交易的时候增加交易次数nonce
,转账时交易次数要成为交易内容的一部分,受交易者的签名保护。
ETH系统中有两种账户
为什么以太坊不使用BTC得基于交易的账户模型?
因为ETH要支持合约账户,合约的地址不能改变。
ETH要维护 账户地址 addr
到 state
之间的映射。要使用什么数据结构呢?
直观的方式是 hash表
,如果不考虑hash碰撞
,插入和修改都很方面。
但是要保证数据不可篡改,就需要使BTC状态的二叉树结构和hash签名 即 Merkle Tree
, 这样如果一个账户的改动代价非常大。Merkle Tree
没有提供查找和插入的快捷方法。
因为每次交易只是更改少量用户状态,所以更新的局部性很重要
以太坊使用的是一种MPT结构
。它是一种树结构, 我们先看一下Trie Tree
的结构,比如有如下几个单词排列成Trie Tree
结构
这种结构的好处是
但缺点是链越长 查找内存的次数就越多,效率越低
需要对路径进行压缩 Patricia Tree
这种结构在路径key值稀疏的情况下路径压缩效果才好。以太坊中的地址是 这是一个非常大的数字,之所以要设计这么大的地址,是因为账户是本地产生的,这样可以有效的解决hash碰撞问题
MPT
是 Merkle Patricia Tree
的缩写, Merkle
即把普通指针换成了hash指针,前一节说过Merkle Tree
的特点是只要跟节点Merkle Tree Hash
不变,任何节点都不能篡改。
以太坊中用的的是修改的MPT
即Modified Merkle Patricia Tree
看一个ETF状态树的例子(注意,为了简化模式地址使用7位表示)
每次发布一个区块时,这些树的有一些节点会发生变化,这些改变不是在原地改的,而是新建分支,原来的状态其实是保存下来的
下图是两个相邻区块有个账户状态发生变动后的MPT
上图可以看出这是一个合约账户(因为有代码),交易次数发生变化,余额发生变化,其他都没有变化。
系统中每个全节点需要维护的不是一个MPT 而是每次出现一个区块都去新建一个MPT,但这个MPT绝大部分节点都是复用的,只有少数有改动的节点是新建的。
为什么保留历史状态,而不是原地修改?
因为ETC系统每隔10几秒就产生一个新区块,由于分布式网络的延迟,很容易出现分叉的情况,有了历史状态就可以快速回滚,沿着主线去挖矿。
可以根据交易信息回滚啊?
以太坊中还有合约账户,合约账户是可以编程的,是图灵完备的语言,没办法根据结果逆向推到出初始状态。
状态树保存的是 (key,value) 键值对, 账户的状态是经过序列化存储到状态树当中的。序列化使用的是RLP Recursive Length Prefix
,它的特点是极简主义,只支持一种数据结构nested array of bytes
,难的事情都交给应用层去做
交易树和收据树也是使用MPT结构, 状态树的key是账户地址,交易树和收据树的key是发布区块中的序号, 这个序号是发布区块的那个节点决定的。
交易树和收据树有什么用呢? 一个用途是提供证明某个交易打包到某个区块里, 收据树证明某个收据的执行结果打包到某个区块里
以太坊中引入 bloom filter
数据结构提供复杂查询的操作,它包含在块头里。 如查询过去十天与智能合约相关的操作。 bloom filter
可以证明没有就是没有, 有未必真有,通过bloom filter
可以更快速过滤绝大部分没有的区块,再从剩下的每个区块,再次使用bloom filter
过滤可能的交易或收据。
以太坊可以看作是交易驱动的状态机, 状态转移必须是确定的,因为所有的全节点都需要同步状态,要保持状态一致
转账的地址可以不存在吗?
这个是可能的,以太坊和比特币都一样创建账户的时候是不知道的,只有交易后其他节点才会这道这个账户的存在。
状态树与交易树、收据树的区别是,状态树保存全部的状态,为什么状态树不能像交易树、收据树一样只保存与当前交易有关用户的状态呢?这样可以大幅度削减每隔节点状态树的大小。
这是不可以的,因为查找一个用户状态将变得非常复杂,极端情况你可能要找到创世纪块中,才发现这个账户不存在
以太坊的出块事件是BTC的四十倍约15s出块,对于以太坊来说15s的出块造成分叉是常态,因为别的节点还没有接收到你的消息继续在挖当前区块,等到收到消息时可能已经挖出了区块,那么这对共识机制有什么挑战呢?
BTC的方案时作废,毕竟10分钟使得分叉很少,如果以太坊也按照这个方案,假设两个小的个体矿工和一个大矿主同时挖到一个区块,一方面大矿主的矿机会更靠近以太网网络中心,另一方面其他矿工会站队大矿主,因为大矿主更要可能挖出下一个区块,对其他矿工来说站队大矿主收益最大,这是很严重的不成正比的收益,如果整个挖矿都集中到几个大矿主手里,不利于以太网的问题。而BTC系统使用的是p2p Overlay Network
所有网络节点都是平等的,不存在网络上的优势。
所以以太坊引入叔父节点的概念,侄子招安叔父,侄子和叔父都能获得奖励。这里的叔父并非仅仅指父亲的兄弟,也包括爷爷的兄弟,爷爷的爷爷的兄弟。
一个侄子最多招安两个叔父,侄子获得的出块奖励,最近的叔父获得的出块奖励,最多追溯7代,叔父的奖励是递减的, 叔父没有交易费,不过这个也不重要,因为与BTC一样出块奖励远大于交易费。如果叔父后面还有节点将得不到任何奖励,这是为了鼓励出现分叉尽早合并,另外也是为了增加分叉攻击的代价。
以太坊的奖励机制与BTC一样有两部分
以太坊的出块奖励没有规定每四年减半,前一篇文章说过,总量固定的东西也有坏处。
BTC的挖矿算法总的来说是比较成功的,经受住了时间检验。但是挖矿专业化广为诟病,很多人呼吁应该one CPU, one vote
,所以之后的加密货币在设计mining puzzle
时,通过增加对内存的访memory hard mining puzzle
来抗 ASIC芯片化。
此外挖矿算法还需要 “求解困难验证容易“ 。这个在BTC中,假设A挖到矿,经历了无数次的调整nonce
和coinbase
的加密计算,然后发布到BTC网络,别的矿工只需要一次加密计算即可验证。 在以太坊中也是类似的,只是一次加密过程需要使用大量内存来缓冲中间计算结果。
以太坊的挖矿算法也有难度调节,比较复杂,有以下几点
1/2048
。具体算法如果感兴趣可以看一下这个视频
据说去年9月份以太坊已经完成从工作量证明到权益证明的转换。
权益证明的思路是,谁的币多,谁的话语权多,大家一起投票决定谁来挖矿,投票是类似摇骰子的过程,这样保证话语权少的矿工也能参与挖矿。
如果一个矿工拥有的币最多,那么他每次都有最高的概率挖到矿,这也是不公平的,所有有的加密货币要求,你投入的币要锁定一段时间,等到挖出多少个块以后才能使用。
这样又会有人两边下注(当出现分叉时),因为暂时落后的一个分支也有可能成为主链,两边下注的好处是挖矿的机会增加了,而锁币减少了。
所以权益证明引入了验证者,
2/3
以上的验证者支持才算有效。权益证明的好处
那么为什么以太坊一开始不使用权益证明?
主要是权益证明挖矿算法不成熟,基于工作量证明的BTC挖矿算法已经运行很多年没有问题。
什么是智能合约?
智能合约是运行在区块链上的一段代码,代码的逻辑定义了合约的内容。
下面一张图总结了区块链运行原理和智能合约所在位置
拿竞拍来举例子,你想搞一个竞拍,你的写一个Solidity
程序,然后发布到区块链中,别人怎么知道你这个合约,你需要线下宣传。
智能合约的帐户保存了合约当前的运行状态
Solidity是智能合约最常用的语言,语法上与JavaScript很接近,合约中每行代码的执行都要消耗汽油费。
前面介绍账户的时候说过,合约账务服务直接发起交易,必须外部账户调用,外部账户调用智能合约有两种方式。
智能合约的创建和运行
智能合约运行在EVM(Ethereum Virtual Machine)上
以太坊是一个交易驱动的状态机
另外智能合约的交易具有原子性,遇到异常会回滚本次所有操作。
智能合约发布后,所有矿工必须先执行职能合约再挖矿
执行了智能合约消耗很多时间,结果挖矿失败有补偿吗?
没有任何补偿,这对挖矿慢的矿工比较吃亏
你不给我汽油费我就不验证,直接同步你的状态继续挖下一个矿不就可以了吗?
如果这种风气蔓延会危害区块链的安全,没人验证,挖到矿的矿工补救可以胡作非为了吗?
如果你不去验证,不去更新本地的三棵树,以后就没办法挖矿了
执行错误的交易也要发不到区块链上,不然汽油费扣不掉
智能合约不支持多线程,多线程对内存访问顺序不同,执行结果可能不同。因为要保证状态一致,所以不支持多线程.
智能合约如何保证程序的正确性?万一有人想搞破坏写个死循环怎么办?
因为Solidity
是图灵完备的语言,没有办法保证你的程序正确性,以太坊的机制是将程序的正确性推给创建合约的人,每行代码的执行都需要消耗汽油费,不同的指令消耗的汽油费不同,如果程序运行失败,汽油费是不退的,这样创建合约的人就不会瞎搞。
如果有bug确实不能改,只能重新发布一个合约, 如果合约已经运行,这其实是很麻烦,因为创建合约的人要需要严格的测试。
DAO 去中心化的自治组织
The DAO 基于众筹的去中心化组织,它的本质是运行在以太坊上的智能合约。你想投资什么,你可以把以太币发给这个智能合约,The DAO会给你代币,需要投资哪个项目是大家投票决定的,你手中的代币越多,投票权重就越大,最后如果有了收益,按智能合约的规章制度进行分配。
如果小部分人的投资项目得不到认可怎么办?比如有一个小众化项目,这一小部分人可以用拆分的方法从The DAO里面独立出来,成立自己的子资金,叫 child DAO
,将代币在转换会以太币,再转入他们要投资的项目了。这也是投资者取回收益的唯一方式。
民主制度并不是绝对的少数服从多数,而是也要尊重少数人的选择的权利。这在当时被称为伟大的尝试,引起了很大的兴奋,它从2016年5月份开始众筹,一个月时间就筹集到了价值1.5亿美元的以太币(这是当时的价格,现在肯定以太币更值钱),这个效率比很多众筹网站效率高很多。
遗憾的是 The DAO 只存活了三个月,问题就出在TheDAO这个程序有bug。 正确的做法应该是先清零再转账,黑客就是利用这个漏洞(重入攻击),转走了The DAO 的钱。拆分有7天的讨论期,28天的锁定期,正是这个28天给了以太坊社区采用补救措施的时间。但这也导致了以太坊的分裂
一部分人认为应该回滚这次交易,还有一部分人认为不应该回滚,以太坊本身程序没问题,是以太坊上的运行的一个智能合约有漏洞,以太坊有那么多的智能合约,出了问题就会滚,那不就乱套了吗?那你还怎么说什么不可篡改的去中心化的账本?
由于这个事件影响很大,大家应该听过“大而不能倒”, 以太坊社区采取补救措施,两步走 先锁定这些账户, “凡事与TheDao这个基金相关的账户不允许任何交易” 。这是一个软分叉,假设升级协议的矿工为集合A,未升级协议的矿工为集合B,那么 集合A中有人挖到矿 集合B中的矿工都认,相反集合B中有人挖到矿,集合A中的矿工不认, 最后大家都会升级协议,系统中不会存在永久分叉。
遗憾的是升级后的软件又有"bug",因为没有认可这笔交易,所以没有收汽油费,看似很合理,结果黑客又利用这个漏洞发布大量非法交易,浪费矿工的时间,升级了协议的矿工受不了又退回之前的版本,软分叉失败了,这时候形势比较严峻了,剩余时间也不多了。
以太坊社区又推出了一个硬分叉的方案,通过升级软件协议,将 TheDao这个智能合约涨上的钱转移到另一个智能合约上,新的智能合约只有一个功能退钱。这样做争议很大,以太坊社区采用投票的方案,大部分人支持硬分叉,也升级了软件版本。
但是故事并没有结束,当初那些反对硬分叉的矿工并没有放弃,他们认为,一方面投票的人不多,另一方面投票就能说明问题吗?大多说人的意见一定是正确的吗?中国有很多人买不起药,把那些富豪的钱给平分了,可以吗?所以有一些矿工还在旧链上继续挖,这些人坚持根正苗红纯而又纯的去中心化,那些人都是高修正主义,过一段时间后交易所开始支持旧链上的货币ETC。
由于分叉前使用的都是同一个套账本这回导致重放攻击,后来给这两条链增建了 Chain ID 区分
刚刚查了下ETC目前还存活,ETC为了存活设计了通缩模型(每四年出块减半),尽管如此它相对于ETH这些年价格几乎没有增长。
反思:智能合约不可篡改的弊端
智能合约是用来写控制逻辑的,不适合存储(汽油费很贵),只有那些在互不信任的实体之间建立共识的操作才适合写在智能合约里。
本文作者:郭敬文
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!