Ethereum数据存储分析
第一部分看看geth客户端的整体结构
创建私链的时候已经指定创世块genesis.json都放在private-geth目录下,现在是已经挖矿过的目录。
Current里面的内容是MANIFEST-000007
~
进入真正的存放数据的目录private-geth/data/00
geth中保存的是区块链的相关数据
keystore中保存的是该链条中的用户信息
History记录历史信息
之前我们这个节点已经创建了两个账户,现在我们可以看到keystore里面有两个账户信息的文件
每个账户都由一对钥匙定义,一个私钥和一个公钥。账户以地址为索引,地址由公钥衍生而来,取公钥的最后 20个字节。每对私钥 /地址都编码在一个钥匙文件里。钥匙文件是JSON文本文件,可以用任何文本编辑器打开和浏览。钥匙文件的关键部分,账户私钥,通常用你创建帐户时设置的密码进行加密。钥匙文件的文件名格式为UTC。账号列出时是按字母顺序排列,但是由于时间戳格式,实际上它是按创建顺序排列。如果把秘钥丢了钥匙文件可以在以太坊节点数据目录的keystore子目录下找到,接下来我们进入一个keystore目录文件看看他的信息:
警告:记住密码并”备份钥匙文件”。为了从账号发送交易,包括发送以太币,你必须同时有钥匙文件和密码。确保钥匙文件有个备份并牢记密码,尽可能安全地存储它们。这里没有逃亡路径,如果钥匙文件丢失或忘记密码,就会丢失所有的以太币。没有密码不可能进入账号,也没有忘记密码选项。所以一定不要忘记密码。
接下来进入geth可以看到chaindata,lightchaindata,nodes目录
进入nodes(我们这条私链有三个节点,所以这里有三个ldb文件)
进入chaindata,区块链最后的本地存储都是以ldb文件
Lightchaindata是一个轻客户端的模式,该模式无需下载较大的以太坊区块链,免去了繁琐的流程
第二部分看看源码的结构
1 Core/types/block.Go
首先看到的是一个区块的结构
区块主要分为区块体和区块头,下面是去块体的结构,主要是交易列表和叔块列表
这是区块头的结构体
我们知道了一个区块的结构,那它是怎么存储的呢
区块和交易等数据最终都是存储在leveldb数据库中的,数据库的存储位置在datadir/geth/chaindata中,在core/database_util.go中封装了所有与区块存储和读取相关的代码,通过这些代码可以弄清楚区块、交易等数据结构在数据库中是如何存储的。
leveldb是一个key-value数据库,所有数据都是以键-值对的形式存储。key一般与hash相关,value一般是要存储的数据结构的RLP编码。区块存储时将区块头和区块体分开存储。
区块头的存储格式为:
headerPrefix + num (uint64 big endian) + hash -> rlpEncode(header)
其中key由区块头前缀、区块号(uint64大端格式)、区块hash构成,value是区块头的RLP编码。
区块体的存储格式为:
bodyPrefix + num (uint64 big endian) + hash -> rlpEncode(block body)
其中key由区块体前缀、区块号(uint64大端格式)