Go区块链从0到1:区块持久化、命令行交互

简介:

到目前为止,我们实现了一个简单的区块链基础模型,建立了工作量证明的机制。本文将与大家一起实现区块链的持久化存储,以及实现一个简单的命令行对区块链进行操作。我们先忽略区块链“分布式”的特征,专注实现其数据库的特征。

数据库:

目前为止,我们没有数据库,我们将区块链存在内存中。对于实现的区块,我们再次使用,不能和别人分享该区块,因此我们要实现区块链的持久化。

比特币白皮书中并没有指定特定的数据库类型,它取决于开发者的选择,在实际使用中比特币使用leveldb作为数据库。大家来了解一种新的数据库:

BoltDB:

1.简单

2.使用go语言

3.不需要启动服务

4.满足我们需要的数据结构需求

From the BoltDB’s README on Github:

Bolt is a pure Go key/value store inspired by Howard Chu’s LMDB project. The goal of the project is to provide a simple, fast, and reliable database for projects that don’t require a full database server such as Postgres or MySQL.

Since Bolt is meant to be used as such a low-level piece of functionality, simplicity is key. The API will be small and only focus on getting values and setting values. That’s it.

简单的key/value,api专注于setting和getting。

需要注意的是,boltDB存储二进制类型数据,因此为了存储区块,我们必须进行序列化,我们使用golibarary中的encoding/gob作为序列化和反序列化函数。

数据库结构:

我们参考比特币的存储结构(将区块链数据分为两个bucket):

1.blocks区块存储区块链中区块的元数据。

2.chainstate 存储链的状态,存储未话费交易输出和一些元数据。

在blocks区,其key/value结构如下:

1.'b' + 32位区块哈希 作为区块的索引

2.'f' + 4位文件句柄 -> 文件信息记录

3.'l' -> 4位文件句柄  ->上一个区块的文件信息

4.'R' -> 1位布尔型: 是否在索引中

5.'F' + 1位标记长度 + 标记名 -> 1 byte boolean: various flags that can be on or off

6.'t' + 32位交易哈希 -> 交易记录

在chainstate区,其key/value结构如下:

1.'c' + 32位交易哈希 -> 本次交易的未花费交易输出

2.'B' -> 32位交易哈希: 到目前为止未消费交易的区块哈希

由于,我们本文并不实现交易,同时我们不分开文件存储,所以数据库总的区块结构可以简化为:

1.32位区块哈希>区块结构(序列化的)

2.‘l’>上一个区块的哈希

序列化:

由于boltDB只能存储[]byte类型数据,为了存储区块数据,我们需要实现序列化接口。我们使用go libarary中提供的encoding/gob函数实现区块的序列化。

另外我们需要一个函数,将db中的block反序列化为Block结构,以再次读取。

持久化:

从NewBlockChain函数开始,新建了一个BlockChain实例,并且将GeneiusBlock加入其中。

持久化步骤如下:

1.打开一个数据文件

2.检查是否该文件是否有保存的区块链信息

3.如果存在区块链信息:新建一个区块链实例,设置该区块链tip指向db中存储的区块链的最后一个区块哈希

4.如果不存在区块链:

        1.新建区块链实例

        2.存储在数据库中

        3.将创世区块的哈希作为最后一个区块哈希

        4.新建一个区块链实例,tip指向创世区块

同时我们需要更新区块的结构如下:

type BlockChainstruct {

        tip []byte

        db  *bolt.DB

}

接下来我们需要更新AddBlock方法:

现在我们实现了添加新区块的功能,但是出现一个问题,我们无法获取已经保存的区块链的信息。因此,我们需要增加新的功能,从db中读取区块链信息。

查看区块链:

至此为止,所有的区块均存储在数据库中,我们可以重新打开区块链文件新增区块。但是我们缺少一个重要功能,一次浏览每个区块的内容。

BoltDB提供api可以循环一个bucket中内容,但是其key是字节排序的,我们希望按区块添加的顺序依次打印区块信息。由于我们不希望一次将所有区块的信息加载入内存,因此需要实现一个迭代功能。

CLI:

目前,我们实现了NewBlockChain、AddBlock方法,现在就开始实现简单的命令行操作方法吧。

1.blockchain_go AddBlock "A pays B two yuan"

2.blockchain_go PrintChain

所有的命令行操作方法,我们都由CLI struct实现。

该结构的命令行由Run方法维护输入。

其中,os.Args返回参数中,第一个参数返回为可执行命令文件路径:

例如: C://goblock/main.exe  addblock -data test

上述命令使用os.Args返回参数数组,os.Args[0]为C://goblock/main.exe,os.Args[1]为addblock,os.Args[2]为data,os.Args[3]为test。具体的使用可查看flag包用法,后文会介绍。

到目前为止,我们实现了命令行向区块db中添加区块,以及查看区块信息的功能。

你可能感兴趣的:(Go区块链从0到1:区块持久化、命令行交互)