持续创作,加速成长!这是我参与「掘金日新计划 · 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、总结
此时,区块链持久化就已经完成了,目前挖矿运转良好,但是区块链遍历还有一点问题。