区块链数据如何持久化--博尔特数据库的运用以及之前代码工程的改造

347 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

区块链数据如何持久化

第一篇文章:juejin.cn/post/710982… 接上文:juejin.cn/post/711056… 为了让区块链数据持久化,我们不再使用切片来存储区块链信息,而是将区块链数据存放在DB里,因此,Blockchain的生成过程中需要增加读写数据库的操作

我们应该怎么做

将区块链的每一个区块用hash作为key,区块数据作为val存储在bucket中,此外,始终用‘last’作为key记录最新区块的hash

1、Blockchain结构调整

//db文件名
const dbFile = "blockchain.db"

//数据库bucket名
const blocksBucket = "blocks"

// 区块链:一个区块的指针数组
type Blockchain struct {
	//记录最新块hash值
	tip []byte
	//存放区块链的db
	db *bolt.DB
}

2、借助gob对区块数据进行编码

gob使用时需要使用NewEnocder生成编码器encoder,然后使用encoder编码区块内存数据就可以了

// 序列化区块
func (b *Block) Serialize() []byte {
	var result bytes.Buffer

	//编码器
	encoder := gob.NewEncoder(&result)
	//编码
	encoder.Encode(b)
	return result.Bytes()
}

3、修改Blockchain方法

在获取bucket时,如果为空,代表创世块操作,代码中使用了两次Put,第一次是记录hash与数据,第二次是记录最新块的hash值,key为"last"

// 创建区块链结构,初始化只有创世块
func NewBlockchain() *Blockchain {
	var tip []byte
	//1.打开数据库文件
	db, _ := bolt.Open(dbFile, 0600, nil)
	//2.更新数据库
	db.Update(func(tx *bolt.Tx) error {
		//2.1 获取bucket
		buck := tx.Bucket([]byte(blocksBucket))
		if buck == nil {
			//2.2.1 第一次使用,创建创世块
			fmt.Println("No existing blockchain found. Creating a new one...")
			genesis := NewGenesisBlock()
			//2.2.2 区块数据编码
			block_data := genesis.Serialize()
			//2.2.3 创建新bucket,存入区块信息
			bucket, _ := tx.CreateBucket([]byte(blocksBucket))
			bucket.Put(genesis.Hash, block_data)
			bucket.Put([]byte("last"), genesis.Hash)
			tip = genesis.Hash

		} else {
			//2.3 不是第一次使用,之前有块
			tip = buck.Get([]byte("last"))
		}
		return nil
	})
	//3. 记录Blockchain 信息
	return &Blockchain{tip, db}
}

4、修改添加区块的方法

增加区块的核心思想是打开数据库,获取最新的tip值,之后创建新的区块,并将其保存在数据库中。

// 向区块链结构上增加一个区块
func (bc *Blockchain) AddBlock(data string) {
	var tip []byte
	//1. 获取tip值,此时不能再打开数据库文件,要用区块的结构
	bc.db.View(func(tx *bolt.Tx) error {
		buck := tx.Bucket([]byte(blocksBucket))
		tip = buck.Get([]byte("last"))
		return nil
	})
	//2. 更新数据库
	bc.db.Update(func(tx *bolt.Tx) error {
		buck := tx.Bucket([]byte(blocksBucket))
		block := NewBlock(data, tip)
		//将新区块放入db
		buck.Put(block.Hash, block.Serialize())
		buck.Put([]byte("last"), block.Hash)
		//覆盖tip值
		bc.tip = block.Hash
		return nil
	})
}

5、总结

此时,区块链持久化就已经完成了,目前挖矿运转良好,但是区块链遍历还有一点问题。