BoltDB持久化操作

BoltDB有如下特性:

小而简约
使用Go实现
不需要单独部署

const dbName = "blockchain.db" 
const bkName = "blocks"

type Blockchain struct {
   tip [] byte  //存储最新区块的哈希值
   Db *bolt.DB //数据库
}

我们定义了两个常量,dbName用来存储数据库名称,bkName用来存储桶/表的名称,桶用来存储区块信息。
Blockchain 结构我们添加了 tip用来存储最新区块的哈希值。

数据序列化处理
使用BlotDB的前提就是,它的K-V都只能存储byte数组,所以我们要对Block结构进行序列化,然后读取到区块的时候我们还需反序列化。

序列化

func (b *Block) Serialize() []byte  {
	var result bytes.Buffer
	encoder:=gob.NewEncoder(&result)
	err :=encoder.Encode(b)
	if err!=nil{
		log.Panicf("serialize the block to byte failed %v \n",err)
	}
	return  result.Bytes()
}

反序列化

func DeserilizeBlock (blockBytes []byte) *Block{
   var block Block
   decoder:= gob.NewDecoder(bytes.NewReader(blockBytes))
   err:= decoder.Decode(&block)
   if err !=nil{
   	log.Panicf("deserialize the block to byte failed %v \n",err)
   }
   return  &block
}

持久化
写入DB
实现持久化,理所当然我们得从区块链中的创世区块开始,之前的方法(NewBlockchain)只实现了把创世区块添加到链中。
现在需要:
1.创建DB文件,并打开
2.创建桶
3.创世区块链序列化
4.把创世区块的Hash添加到DB中
5.把创世区块添加到链中

设定 block的k-v :
‘l’ -> 4-byte 文件编号: 最后一块文件的编号

func Blockchain_GenesisBlokc() *Blockchain {
   db, err := bolt.Open(dbName, 0600, nil)
   if err != nil {
   	log.Panicf("open the Dbfailed! %v\n", err)
   }
   //defer db.Close()
   var tip []byte //存储数据库中的区块哈希

   err = db.Update(func(tx *bolt.Tx) error {
   	b := tx.Bucket([]byte(bkName))
   	if b == nil {
   		b, err = tx.CreateBucket([]byte(bkName))
   		if err != nil {
   			log.Panicf("create the bucket [%s] failed! %v\n", bkName, err)
   		}
   	}
   	if b != nil {
   		genesisBlock := NewGenesisBlock()
   		//存储创世区块
   		err = b.Put(genesisBlock.Hash, genesisBlock.Serialize())
   		if err != nil {
   			log.Panicf("put the data of genesisBlock to Dbfailed! %v\n", err)
   		}
   		//存储最新区块链哈希
   		err = b.Put([]byte("l"), genesisBlock.Hash)
   		if err != nil {
   			log.Panicf("put the hash of latest block to Dbfailed! %v\n", err)
   		}
   		tip = genesisBlock.Hash
   	}
   	return nil
   })
   if err != nil {
   	log.Panicf("update the data of genesis block failed! %v\n", err)
   }
   return &Blockchain{tip, db}
}

改完链中创世区块后,然后我接着对链中区块的添加AddBlock进行改造。之前我们只是简单的把新的区块添加到链中,现在它需要做到:
1.打开桶
2.取出桶中最后一个区块的Hash
3.对Hash进行反序列化,得到最后一个区块信息
4.根据取出的信息,创建新的区块
5.把新的区块序列化存储到DB中

func (bc *Blockchain) AddBlock(data string) {
   err := bc.Db.Update(func(tx *bolt.Tx) error {
   	b := tx.Bucket([]byte(bkName))
   	if b != nil {
   		blockBytes := b.Get(bc.tip)
   		latest_block := DeserilizeBlock(blockBytes)
   		newBlock := NewBlock(latest_block.Index+1, data, latest_block.Hash)

   		err := b.Put(newBlock.Hash, newBlock.Serialize())
   		if nil != err {
   			log.Panicf("put the data of new block into Dbfailed! %v\n", err)
   		}
   		err = b.Put([]byte("l"), newBlock.Hash)
   		if nil != err {
   			log.Panicf("put the hash of the newest block into Dbfailed! %v\n", err)
   		}
   		bc.tip = newBlock.Hash
   	}

   	return nil
   })
   if nil != err {
   	log.Panicf("update the Dbof block failed! %v\n", err)
   }
}

读取区块
写入DB都改造好了,现在我们来实现读取

func (bc *Blockchain) PrintChain() {
	fmt.Println("——————————————打印区块链———————————————————————")
	var curBlock *Block
	var curHash []byte = bc.tip
	for {
		fmt.Println("—————————————————————————————————————————————")
		bc.Db.View(func(tx *bolt.Tx) error {
			b := tx.Bucket([]byte(bkName))
			if b != nil {
				blockBytes := b.Get(curHash)
				curBlock = DeserilizeBlock(blockBytes)

				fmt.Printf("\tHeigth : %d\n", curBlock.Index)
				fmt.Printf("\tTimeStamp : %d\n", curBlock.TimeStamp)
				fmt.Printf("\tPrevBlockHash : %x\n", curBlock.PrevBlockHash)
				fmt.Printf("\tHash : %x\n", curBlock.Hash)
				fmt.Printf("\tData : %s\n", string(curBlock.Data))
				fmt.Printf("\tNonce : %d\n", curBlock.Nonce)
			}
			return nil
		})
		// 判断是否已经遍历到创世区块
		var hashInt big.Int
		hashInt.SetBytes(curBlock.PrevBlockHash)
		if big.NewInt(0).Cmp(&hashInt) == 0 {
			break // 跳出循环
		}
		curHash = curBlock.PrevBlockHash
	}
}

运行

func main() {
	blockChain := BLC.Blockchain_GenesisBlokc()
	defer blockChain.Db.Close();
	blockChain.AddBlock("Send 100 btc to Jay")
	blockChain.AddBlock("Send 50 btc to Clown")
	blockChain.AddBlock("Send 20 btc to Bob")
	blockChain.PrintChain()
}

总结
本文实现了使用BoltDB,对数据进行持久化。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值