Ethereum设计基础理论(二) 帐号和无UTXOs

张亚宁   |     |   2474 次阅读

原文:https://github.com/ethereum/wiki/wiki/Design-Rationale#accounts-and-not-utxos


比特币和它的很多衍生物,存储用户的余额都是基于未消费的交易输出 unspent tx outputs(UTXOs):整个系统的状态就是由UTXOs来组成(可以把它想象成“币”),这样每个币都有所有者和价值,每一个交易需要一个多个币,并创造出一个或多个币,它们依赖如下的验证约束:
1. 每个相关输入必须有效并且未花费
2. 每个交易必须有签名,并且符合每个输入的所有者的
3. 总的输入等于输出

用户的“余额”就是总的这些“币”,并且用户可以提供私钥来产生有效的签名。

(Image from https://bitcoin.org/en/developer-guide)

以太坊拒绝了这种方法,而采用了一种简单的办法:每个账户有一个balance状态,和以太坊特定的数据一样(code和内部storage),如果发送方有足够的余额支付,那么一个tx是有效的,发送方扣除金额,接受方记入金额。如果接受方还有代码,代码执行,内部状态可能还会变化,并且可能会发送额外的消息到其它账户,导致进一步的扣款和收款。

UTXOs的好处:
1. 高度的隐私:如果用户使用一个新地址来做交易,比较难把它和其他账户关联起来。这非常适用于货币,但是对于dapps就太武断,因为dapps经常会涉及到记录复杂的一系列用户状态,并不是像货币那样的简单的状态。
2. 潜在的扩展范式:UTXOs理论上更兼容特定的可扩展性范式,我们可以仅仅依靠一些币的所有者来维护Merkle proof的所有权,即使每个人包括所有者决定忘记这些数据,也只有所有者受害。在账户范式中,每一个丢失了Merkle tree对应一个账户部分的人,就不能处理影响到这个账户的操作,包括给它发送消息。尽管如此,非UTXO依赖的扩展范式也是存在的。

账户的好处:
1. 节省大量空间:例如,如果一个账户有5个UTXO,然后切换UTXO模式到账户模式可以减少的空间是(20 + 32 + 8) * 5 = 300 bytes(20 for the address, 32 for the txid and 8 for the value) 到 20 + 8 + 2 = 30 bytes (20 for the address, 8 for the value, 2 for a nonce(see below))。在实际中,可能没有这么多,因为账户需要存储在Patricia tree (see below) ,但是依然节省了大量空间。另外,交易可以变小(例如:以太坊100 bytes VS. 200-250 bytes比特币),因为每一个交易只需要一个引用,一个签名和产生一个输出。
2. 更大的替换性:因为这里没有区块链意义上的币,所以UTXO变得不符合实际,无论是技术上还是法律上,需要去建立红名单/黑名单计划,去区分币的来源。
3. 简单:容易编码和理解,尤其是一旦更复杂的脚本被引入。如果让所有的去中心化应用套用UTXO模式,本质上脚本来限制那种UTXO可以被消费,让脚本去执行包含消费的UTXO,这样的范式更复杂,而且丑陋。
4. 常量轻客户端引用:轻客户端可以在任何点引用所有和账户关联的数据,通过扫描状态树用特定的方法。在一个UTXO范式中,每个交易的引用变化,对于一个长期运行的dapps来讲,会造成特定的烦恼,如果采用上面讲的UTXO范式机制的话。

我们这样决定,因为我们要处理任意的状态和代码,帐户的优点要远远大于其他选择方案。另外,我们提到过“无特性”的原则,如果有人关心隐私,mixers和 coinjoin可以被内置通过在合约中加密数据包的方式。

账户范式的一个弱点是,为了防止重放攻击,每一个交易都必须需要一个“序号”,账户需要跟踪这个序号的使用,如果序号比最后一个序号大一就接受这个序号。这意味着,长期未使用的账号不能被账户状态剔除。一个简单的解决办法是,包含交易的块号,让他们在一段时间内避免重放,一旦每段周期过后再重置nonce。矿工或者其他用户可以“ping”未使用的账户来从状态中删除他们,作为协议一部分来全扫描是非常昂贵的。我们没有实现这个机制只是为了加速1.0的开发;在1.1或者后续的版本会有这样的系统。


译者注:关于更多tx的nonce的资料,有一个有趣的问题。
What happens when a transaction nonce is too high?

这是有人做的总结:
Summary

  • Transactions with too low a nonce get immediately rejected.
  • Transactions with too high a nonce get placed in the transaction pool queue.
  • I If transactions with nonces that fill the gap between the last valid nonce and the too high nonce are sent and the nonce sequence is complete, all the transactions in the sequence will get processed and mined.
  • When the geth instances are shut down and restarted, transactions in the transaction pool queue disappear.
  • The transaction pool queue will only hold a maximum of 64 transactions with the same From: address with nonces out of sequence.
  • The geth instance can be crashed by filling up the transaction pool queue with 64 transactions with the same From:
    • address with nonces out of sequence by, for example:Creating many accounts with a minimal amount of ethers (0.05 ETH in my tests)
    • Sending 64 transactions from each account with a large data payload
    • For the 4 Gb memory limit that I placed on my geth instance, 400 x 64 transactions with a payload of about 4,500 bytes would crash the geth instance (from my limited testing anyway).
    • These transactions with too high a nonce do NOT propagate to other nodes and crash other nodes on the Ethereum network.
  • The Ethereum World Computer cannot be brought down with transactions with too high a nonce. Good work, developers!

具体的实验方法可以参考链接:http://ethereum.stackexchange.com/questions/2808/what-happens-when-a-transaction-nonce-is-too-high

 
1 人喜欢