区块存储
区块(Block)是以太坊的核心数据结构之一,Block包含Header和Body两部分。区块的存储是由leveldb完成的,leveldb的数据是以键值对存储的。
|
|
Blockchain管理所有的Block, 让其组成一个单向链表。Headerchain管理所有的Header,也形成一个单向链表, Headerchain是Blockchain里面的一部分 。
|
|
以太坊的数据库体系-Merkle-Patricia Trie(MPT), 它是由一系列节点组成的二叉树,在树底包含了源数据的大量叶子节点, 父节点是两个子节点的Hash值,一直到根节点。
|
|
|
|
Transaction是Body的重要数据结构,一个交易就是被外部拥有账户生成的加密签名的一段指令,序列化,然后提交给区块链。
在这里保存区块信息时,key一般是与hash相关的,value所保存的数据结构是经过RLP编码的。
在代码中,core/database_util.go中封装了区块存储和读取相关的代码。
在存储区块信息时,会将区块头和区块体分开进行存储。因此在区块的结构体中,能够看到Header和Body两个结构体。
区块头(Header)的存储格式为:
|
|
key是由区块头的前缀,区块号和区块hash构成。value是区块头的RLP编码。
区块体(Body)的存储格式为:
|
|
key是由区块体前缀,区块号和区块hash构成。value是区块体的RLP编码。
在database_util.go中,key的前缀可以区分leveldb中存储的是什么类型的数据。
|
|
database_util.go最开始就定义了所有的前缀。这里的注释详细说明了每一个前缀存储了什么数据类型。
database_util.go中的其他方法则是对leveldb的操作。其中get方法是读取数据库中的内容,write则是向leveldb中写入数据。
要讲一个区块的信息写入数据库,则需要调用其中的WriteBlock方法。
|
|
这里我们看到,将一个区块信息写入数据库其实是分别将区块头和区块体写入数据库。
首先来看区块头的存储。区块头的存储是由WriteHeader方法完成的。
|
|
这里首先对区块头进行了RLP编码,然后将区块号转换成为byte格式,开始组装key。
这里首先向数据库中存储了一条区块hash->区块号的键值对,然后才将区块头的信息写入数据库。
接下来是区块体的存储。区块体存储是由WriteBody方法实现。
|
|
WriteBody首先将区块体的信息进行RLP编码,然后调用WriteBodyRLP方法将区块体的信息写入数据库。key的组装方法如之前所述。
交易存储
交易主要在数据库中仅存储交易的Meta信息。
|
|
交易的Meta信息结构体如下:
|
|
这里,meta信息会存储块的hash,块号和块上第几笔交易这些信息。
交易Meta存储是以交易hash加交易的Meta前缀为key,Meta的RLP编码为value。
交易写入数据库是通过WriteTxLookupEntries方法实现的。
|
|
这里,在将交易meta入库时,会遍历块上的所有交易,并构造交易的meta信息,进行RLP编码。然后以交易hash为key,meta为value进行存储。
这样就将一笔交易写入数据库中。
从数据库中读取交易信息时通过GetTransaction方法获得的。
|
|
这个方法会首先通过交易hash从数据库中获取交易的meta信息,包括交易所在块的hash,块号和第几笔交易。
接下来使用块号和块hash获取从数据库中读取块的信息。
然后根据第几笔交易从块上获取交易的具体信息。
这里以太坊将交易的存储换成了新的存储方式,即交易的具体信息存储在块上,交易hash只对应交易的meta信息,并不包含交易的具体信息。
而以前的交易存储则是需要存储交易的具体信息和meta信息。
因此GetTransaction方法会支持原有的数据存储方式。