比特币的区块链架构主要围绕支持虚拟货币的实现,虽然它有一定的灵活性,但用来支撑虚拟货币以外的应用场景还显得非常局限。
近年来,区块链逐渐引起IT业界的关注,并逐渐成为独立于比特币的一个平台架构,其重要性越来越受到重视。
区块链2.0的概念也随之产生。
其核心理念是把区块链作为一个可编程的分布式信用基础设施,支撑智能合约应用,以与过去比特币区块链作为一个虚拟货币支撑平台区别开来。
具体说来就是,不仅仅把区块链作为一个去中心化的虚拟货币和支付平台,而是通过增加链上的扩展性功能,把区块链的技术范围扩展到支撑一个去中心化的市场。
交易内容可以包括房产的契约、权益及债务凭证、知识产权,甚至汽车、艺术品等。
区块链2.0提供一套新的协议(区块链2.0协议)支撑新型的去中心化应用。如果用互联网协议来做类比,区块链1.0就相当于TCP/IP协议,而区块链2.0就相当于HTTP、SMTP和FTP等高级协议。
甚至有把区块链1.0比做电话,而区块链2.0相当于智能电话的比喻。
在比特币后,出现很多被称为区块链2.0的平台,其中,最具代表性的是以太坊平台。下面简单介绍一下以太坊架构。以太坊的设计主要还是以比特币架构为基础。下面只对和比特币架构不同的账户设计和区块链设计主要方面做重点讨论。
1.账户设计
比特币没有账户的概念。每个用户的余额都是从他们在区块链上的UTXO计算出来的。以太坊则有两种类型的账户。
一种是外部所有账户(EOA),另一种是约(Contract)账户。
外部所有账户就是我们一般意义上的用户账户,它由私钥控制。
合约是一种特殊的可编程账户,合约存在以太坊区块链上,它是代码(它的功能)和数据(它的状态)的集合。
合约受代码控制并由外部所有账户激活。以太坊的设计是将区块链作为一个通用的管理对象状态转换的去中心化平台,账户就是有状态的对象。
外部所有账户的状态就是余额,而合约账户的状态可以是余额、代码执行情况,以及合约的存储。
以太坊网络的状态就是所有账户的状态,该状态由每个区块的交易来更新,同时需在全网形成共识。
用户和以太坊
用户和以太坊区块链的交互需要通过对账户的交易来实现。每个以太坊的外部所有账户由一对密钥定义,一个是私钥,一个是公钥。区块链的EOA账户由它们的地址来做索引。
取公钥的后20位作为地址,这和比特币的地址不一样。每个公私钥对被编码存放在一个密钥文件(Keyfile)中。
密钥文件采用JSON格式,可以用文本编辑器打开来看。
密钥文件的私钥都是用在建立账户时输入的口令来加密的。密钥文件存在以太坊节点的数据目录中的keystore子目录中。密钥文件需要经常备份,否则如果失掉密钥文件,账户里的以太币也就无法找回了。
合约账户可以执行图灵完备的计算任务,也可在合约账户之间传递消息,合约编译成以太坊虚拟机字节码(EthereumVirtual Machine Bytecode),并记录在区块链上。
外部所有账户可以通过发送交易到合约来实现对合同的调用。这需要提供几个参数。
例如EOA的地址、合约的地址,以及数据。数据部分包括需要调用的合约里的方法(method)以及其传递的参数。
这个需要用到Application Binary Interface(ABI)来作为传递数据的编码和解码的标准。
关于ABI的详细信息可以参考以太坊wiki网页https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI。
2.区块链设计
比特币采用Merkle树来将交易的哈希值按一定算法组成二叉树状结构,顶层节点的哈希值相当于整个交易清单的指纹,可以用来校验交易清单。
中本聪采用Merkle树设计,也是为了轻量级节点能通过SPV(简化支付验证)方式来方便地校验交易。
SPV不用下载整个交易清单,而是只需要区块报文头中交易清单顶层节点的哈希值,以及与自身节点相关的交易,然后可以通过向其他节点查询其他相邻交易,就可以完成对某个交易是否包含在区块链中某个区块的验证。
以太坊的区块链的每个区块不但保存着交易清单,还保存最新的状态。以太坊作为一个通用的区块链编程平台,引入了账户概念,由此它也带来更为复杂的校验和查询需求。
例如要查询账户的余额或判断一个账户是否存在,光用比特币的Merkle树就满足不了要求。因此以太坊采用Merkle Patricia树来实现对交易和状态的校验和查询。
下面看看交易和状态面临的问题。
以太坊的状态包含一个键值表(key-value map),其中键是地址,值是账户,里声明的变量,包括余额、随机数(nonce)、代码和账户的存储(存储也以一棵树的形式来组织)。
与交易数据只能增不能改不一样,账户的状态经常被改变,其余额、随机数经常变。另外,新的账户也经常被插入,键在存储里也被经常插入和删除。
因此Merkle树不适合这种情况,而需要一种可以在插入、更新和删除操作后快速计算新的树根哈希值,而不需要重新计算整棵树的数据结构。
同时,树的深度是有限的,即使在有攻击者试图通过故意发很多交易来尽量增加树的深度的情况下,不然一个攻击者可以通过操纵树的深度,以使得每个更新都变得非常慢,来对平台实施拒绝服务攻击。
还有一个要求是树的根哈希只是与树的数据有关,而与更新的顺序无关。
不同的更新顺序或者甚至重新计算整个树的根哈希值都不会改变树的根哈希值。Patricia树是符合这些要求的数据结构。
简单来说,以太坊的账户的状态由键值表(Key-Value Map)来表示,在Patricia树里,键被编码成向下访问树的路径。
在以太坊的Patricia里,每个节点有16个子节点,所以路径用十六进制来编码。
例如,键“dog”的十六进制编码是6461567,所以要访问键“dog”所对应的值,就必须先从根节点开始,向下到第6个节点,然后再由该节点向下到第4个节点,以此类推,一直到最后。
在区块链的区块报文头中,不像比特币那样仅仅存放一个交易清单的Merkle树根哈希值,而是存放了3个根哈希值。
一个是交易的Merkle根哈希值。
另外一个是状态的根哈希值。
还有一个是收据的根哈希值。
另外一个和比特币的不同是,以太坊的区块链中的每个区块保存区块链号和区块难度。