300-BitCoin全攻略十一_数据库










11_BitCoin全攻略十一_数据库








我们引入bolt数据库
关于bolt数据库的使用入门,可以看一下我的另一篇博客

bolt数据库入门
https://blog.youkuaiyun.com/qq_33781658/article/details/87948815







1.我们使用一个bucket来存储所有的区块
2.bucket中的数据
	key: 区块hash值
	value: 区块的字节流(block转成字节流)
3.我们使用一个特殊的key记录上一个区块的hash值
	key: "lastHash"
	value: 最后一个区块的hash值
	每次添加区块之后
	就更新这个lastHash




我们先来看blockchain.go文件

type BlockChain struct {
	Blocks []*Block
}

我们现在的这个BlockChain结构体
里面放的是数组
现在我们要改成数据库存储了

type BlockChain struct {
	db *bolt.DB
}

我们再加一个属性
用来记录最后一个区块的hash值

type BlockChain struct {
	db *bolt.DB
	tail []byte
}




然后我们看NewBlockChain()方法
func NewBlockChain() *BlockChain {

	genesisInfo := []byte("Hello world! Hello blockchain!")
	genesisBlock := NewBlock(genesisInfo, []byte{})

	bc := BlockChain{
		Blocks: []*Block{genesisBlock},
	}

	return &bc
}


这里我们把创世区块放到数组里面
那么要修改成,把创始区块放到数据库里

const blockChainDB = "blockChain.db"
const blockBucket = "blockBucket"

func NewBlockChain() *BlockChain {

	var bc BlockChain
	genesisInfo := []byte("Hello world! Hello blockchain!")

	//创建db
	db, err := bolt.Open(blockChainDB, 0600, nil)
	if err != nil {
		panic(err)
	}

	//操作数据库
	db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(blockBucket))

		//第一次
		if b == nil {
			b, err = tx.CreateBucket([]byte(blockBucket))
			if err != nil {
				panic(err)
			}

			//将创世区块写入bucket
			genesisBlock := NewBlock(genesisInfo, []byte{})

			b.Put(genesisBlock.Hash, genesisBlock.toBytes())
			b.Put([]byte("lastHashKey"), genesisBlock.Hash)

			bc.tail = genesisBlock.Hash
		} else {
			lastHash := b.Get([]byte("lastHashKey"))
			bc.tail = lastHash
		}

		return nil
	})

	bc.db = db
	return &bc
}








然后我们来写一个Serialize方法
func (block Block) Serialize() []byte {
	
}
把block转换成字节流

然后还需要一个Deserialize方法反序列化
func Deserialize(data []byte) Block{

}
把字节流转换成Block



那么我们使用gob包来进行序列化和反序列化
func (b *Block) Serialize() []byte{
	var buffer bytes.Buffer
	encoder := gob.NewEncoder(&buffer)
	err := 	encoder.Encode(b)
	if err!=nil{
		panic(err)
	}

	return buffer.Bytes()
}

func Deserialize(data []byte) *Block{
	var block Block	
	decoder := gob.NewDecoder(bytes.NewReader(data))
	err := decoder.Decode(&block)
	if err!=nil{
		panic(err)
	}

	return &block
}
 







然后我们再改一下AddBlock方法
我们看一下

func (bc *BlockChain) AddBlock(data []byte) {

	//获取前一个区块
	lastBlock := bc.Blocks[len(bc.Blocks)-1]
	
	//获取前一个区块的hash值
	prevHash := lastBlock.Hash
	
	//创建当前区块
	newBlock := NewBlock(data, prevHash)
	
	//添加到区块链
	bc.Blocks = append(bc.Blocks, newBlock)
}



然后我们也修改成与数据库交互

func (bc *BlockChain) AddBlock(data []byte) bool {

	err := bc.db.Update(func(tx *bolt.Tx) error {

		b := tx.Bucket([]byte(blockBucket))
		if b == nil {
			fmt.Println("错误,bucket为空")
			os.Exit(1)
		}

		prevHash := bc.tail
		newBlock := NewBlock(data, prevHash)

		err := b.Put(newBlock.Hash, newBlock.Serialize())
		if err != nil {
			return err
		}
		err = b.Put([]byte(lastHashKey), newBlock.Hash)
		if err != nil {
			return err
		}

		bc.tail = newBlock.Hash
		return nil

	})

	if err != nil {
		return false
	}

	return true
}








然后我们看下完整代码

package main

import (
	"GolangDemo/blockchain/lib/bolt-master"
	"bytes"
	"encoding/gob"
	"fmt"
	"os"
)

type BlockChain struct {
	db   *bolt.DB
	tail []byte
}

func (bc *BlockChain) AddBlock(data []byte) bool {

	err := bc.db.Update(func(tx *bolt.Tx) error {

		b := tx.Bucket([]byte(blockBucket))
		if b == nil {
			fmt.Println("错误,bucket为空")
			os.Exit(1)
		}

		prevHash := bc.tail
		newBlock := NewBlock(data, prevHash)

		err := b.Put(newBlock.Hash, newBlock.Serialize())
		if err != nil {
			return err
		}
		err = b.Put([]byte(lastHashKey), newBlock.Hash)
		if err != nil {
			return err
		}

		bc.tail = newBlock.Hash
		return nil

	})

	if err != nil {
		return false
	}

	return true
}

const blockChainDB = "blockChain.db"
const blockBucket = "blockBucket"
const lastHashKey = "lastHashKey"

func NewBlockChain() *BlockChain {

	var bc BlockChain
	genesisInfo := []byte("Hello world! Hello blockchain!")

	//创建db
	db, err := bolt.Open(blockChainDB, 0600, nil)
	if err != nil {
		panic(err)
	}

	//操作数据库
	db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(blockBucket))

		//第一次
		if b == nil {
			b, err = tx.CreateBucket([]byte(blockBucket))
			if err != nil {
				panic(err)
			}

			//将创世区块写入bucket
			genesisBlock := NewBlock(genesisInfo, []byte{})

			b.Put(genesisBlock.Hash, genesisBlock.Serialize())
			b.Put([]byte(lastHashKey), genesisBlock.Hash)

			bc.tail = genesisBlock.Hash
		} else {
			lastHash := b.Get([]byte(lastHashKey))
			bc.tail = lastHash
		}

		return nil
	})

	bc.db = db
	return &bc
}

func (b *Block) Serialize() []byte {
	var buffer bytes.Buffer
	encoder := gob.NewEncoder(&buffer)
	err := encoder.Encode(b)
	if err != nil {
		panic(err)
	}

	return buffer.Bytes()
}

func Deserialize(data []byte) *Block {
	var block Block
	decoder := gob.NewDecoder(bytes.NewReader(data))
	err := decoder.Decode(&block)
	if err != nil {
		panic(err)
	}

	return &block
}









 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值