比特币:基于交易的账本(transaction-based ledger)
比特币中是用的基于交易的账本,这种模式下,系统中并没有显示的记录每个账户上有多少钱,要根据UTXO里的信息推算,包括想知道这个人一共总资产有多少个比特币,就算一下这个人的所有账户,就他有私钥的那些账户在UTXO里面一共有多少个币就可以了。
好处是隐私保护比较好,你有多少钱,可能连你自己都说不清楚,那别人就更不清楚了。
但是这样就带来一个问题,就他使用上比较别扭,跟我们的日常体验不太一样。
比如:A要转给B10BTC,A要说明这10个币的来源,其中七个币是前面这个交易中收到的,另外三个币是之前另外一个交易收到的,证明币的来源的合法性。这和我们平时去银行的体验是不太一样的,银行是你存钱的时候要说明钱的来源,下次花钱的时候是不用说明每一笔钱是从哪儿来的。
另外一个比较别扭的地方,你在前面交易中收到一笔输出/收到一些币,将来要花的时候,必须要一次性都花出去,不能只花一部分。如果只花一部分,会出现什么情况?剩下的7个比特币会当做交易费给花出去了,这个时候,矿工就会很高兴了,但是你不高兴。
这个时候应该转回给自己,如下图
很多比特币钱包可以自动生成接收余额的地址,每次交易换一个新地址,也是有利于隐私保护的,但同样跟我们的日常生活习惯不太一样。比如说,银行当中,别人转给你十万块钱,你要把三万块钱转出去,剩下七万块钱就不用管,就放在账户上就行了。问题在于比特币系统中,没有显示的维护账户的交易概念。
以太坊:基于账户的账本(account-based ledger)
以太坊采用的是基于账户的模型,这种模型跟银行账户是比较相似的,系统中要显示的记录,每个账户上有多少个以太币。
比如:A转给B10ETH,这个交易的合法性只要检查一下A账户上有没有足够的钱就行了。比如A账户上有一百个以太币,要转10个给B,这就没问题,不用说明这100个以太币中是具体把哪十个转给了B,不用说明币的来源/来自之前哪个交易。将来B要转给C三个以太币也是可以的,不用把剩下的转给他自己,因为有显示余额的概念,所以剩下的币就直接放在账户上就行了。
用于说明币的来源的哈希指针也不用了。
double spending attack(双花攻击)--- 比特币中的问题
- 花钱的人不诚实,以前花过的钱想再花一次
基于账户模式的好处是对double spending attack有天然的防御作用,因为不用管币的来源,每花掉一次钱,就从你的账户上扣掉,花两次就扣两次。
replay attack (重放攻击) --- 以太坊中的问题
- 收钱的人不诚实,别人已经给他转过钱了,他想再转一次
A把转账交易A->B(10ETH)发布到网络上,过一段时间之后,这个交易被写到区块链里了,A就以为转账交易完成了。假设B是有恶意的,把这个交易在网上重新广播一遍,其他节点以为是个新的转账就把A的钱扣了2次。
解决方案:
加一个计数器(nonce),记录一下这个账户有史以来一共发布过多少交易,然后转账的时候,计数器(nonce)要成为交易内容的一部分,一起包含进去,都是受到发布交易的签名的保护的。
比如:A->B(10ETH),A一共发布过20个交易,这是是21个,所以写上nonce=21,然后整个内容写上A的签名,如下图
然后把上图这个交易发布到网上,因为有签名的保护,所以nonce的值,别人是改不了的。系统中的每个节点维护A这个状态,不仅要维护A账户上的钱balance,还要维护nonce的值,一开始nonce=0,每次收到A发布的一个交易,nonce+1。
比如:一开始的时候,A这个节点一开始的nonce=20,然后现在发布一个交易,这个节点一看,这个交易来了,是合法的,这个交易是可以执行的,同时更新一下,nonce=21。以后如果有人重放这个交易,这个节点一看,这个nonce已经是21了,已经被执行过了,就不会再执行一遍了。
以太坊账户的分类
以太坊中有两类账户:外部账户、合约账户。
externally owned account(外部账户)
外部账户是由公私钥控制的,本地产生一个公私钥对,私钥掌握账户的控制权(类似于比特币中的账户),也叫普通账户。
状态:
balance(账户余额)
nonce(计数器)
smart contract account(合约账户)
合约账户不是通过公私钥对控制的。
balance(账户余额)
nonce(计数器)
code(代码)
storage(相关状态-存储,包括每个变量的取值)
一个合约可以调用另外一个合约,所以要通过nonce值记录一下调用的次数。
合约账户不能主动发起一个交易,以太坊中的一个规定,所有的交易只能由外部账户发起,外部账户发起一个交易如果调用了一个合约账户,这个合约账户可以发送一个message调用另外一个合约,但是他不能自己品平白发起一个交易。
合约账户的调用
创建一个合约会返回一个地址,知道这个合约的地址,就可以调用这个合约,调用的过程当中状态会发生变化,代码(code)不会变,存储(storage)会变。
为什么要设计这样一种新的账户模式?
以太坊的创始人叫Vitalik,是个19岁的小孩,他当初创建以太坊的时候,比特币已经有比较成熟的代码可以作为参考,他为什么不用比特币已有的代码,而要另弄一套?
为什么不直接在比特币系统设计上改进,比如改出块时间、mining puzzle,为什么非要改账户体系?
比特币基于交易模型的一个好处是隐私保护,但是以太坊要支持的智能合约。
智能合约要求参与者有比较稳定的身份。
这跟日常生活当中是比较类似的,比如说,你跟某个人签个合同,如果说你跟他签合同的时候,他是一个身份,签完之后,他身份变了,你找不到了,那这就有问题了,也有可能突然冒出了另外一个人,说他当初就是跟你一块签合同的,只不过换了一个身份,这就给合同的执行带来一些困难。将来出现纠纷的时候,你也是需要知道这个合同当初是跟谁签的。
现在有人提出来用智能合约实现一些金融衍生品(financial derivative)。
比如期权/期货,往合约里投一笔钱,预测未来的价格走势,如果预测正确,给你一些收益,把钱还给你。但问题是,如果你投钱的这个账户,投完钱就变了,那到时候怎么把钱还给你呢?
这个不光是对于外部账户有这个问题。合约账户的问题就更严重了,如果你投钱投到一个合约账户,投完之后地址变了,找不到就麻烦了。
所以以太坊创建这个系统的时候,考虑了过去的一些已有的模型的利弊得失,最终没有采用比特币中基于交易的模式,而是采用了基于账户模式。
这个从目前的状况来看,还是比较合适的一个决策,就以太坊的账户是希望保持稳定的,无论是个人账户还是合约账户,如果你有隐私保护的需要,同样可以创建很多个账户,根据情况使用不同的账户进行不同的交易。