持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情
区块链数据如何持久化
第一篇文章:https://juejin.cn/post/7109829091540336647 接上文:https://juejin.cn/post/7110563538078269477 为了让区块链数据持久化,我们不再使用切片来存储区块链信息,而是将区块链数据存放在DB里,因此,Blockchain的生成过程中需要增加读写数据库的操作
我们应该怎么做
将区块链的每一个区块用hash作为key,区块数据作为val存储在bucket中,此外,始终用‘last’作为key记录最新区块的hash
1、Blockchain结构调整
```go //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编码区块内存数据就可以了 ```go // 序列化区块 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" ```go // 创建区块链结构,初始化只有创世块 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 区块数据编码 blockdata := genesis.Serialize() //2.2.3 创建新bucket,存入区块信息 bucket, _ := tx.CreateBucket([]byte(blocksBucket)) bucket.Put(genesis.Hash, blockdata) 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值,之后创建新的区块,并将其保存在数据库中。 go // 向区块链结构上增加一个区块 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、总结
此时,区块链持久化就已经完成了,目前挖矿运转良好,但是区块链遍历还有一点问题。