当前位置:   article > 正文

Go语言实现区块链(三)_go语言海鲜区块链系统的数据库 csdn

go语言海鲜区块链系统的数据库 csdn

一、保存区块链

为了能够永久保存区块链数据,这里引入bolt数据库。

(1)改写BlockChain结构体

  1. type BlockChain struct {
  2. //Blocks []*Block // 保存所有区块
  3. Db *bolt.DB
  4. Tail []byte // 最后区块的hash
  5. }

(2)改写NewBlockChain方法,把创世块数据以及最后区块的哈希写入数据库中。

  1. const dbName = "blockchain.db"
  2. const bucketName = "bucket"
  3. const last = "lastBlockHash"
  4. // 创建方法
  5. func NewBlockChain() *BlockChain {
  6. /*// 创建创世块
  7. genericBlock := NewBlock([]byte(genesisInfo), []byte{})
  8. // 创建BlockChain
  9. bc := BlockChain{[]*Block{genericBlock}}
  10. return &bc*/
  11. var db *bolt.DB
  12. var lastHash []byte
  13. // 1. 打开数据库
  14. db, err := bolt.Open(dbName, 0600, nil)
  15. if err != nil {
  16. panic("bolt.Open err!")
  17. }
  18. db.Update(func(tx *bolt.Tx) error {
  19. // 2. 打开抽屉Bucket
  20. bucket := tx.Bucket([]byte(bucketName))
  21. // 3. 如果Bucket是否为nil,则创建一个Bucket
  22. if bucket == nil {
  23. bucket, err = tx.CreateBucket([]byte(bucketName))
  24. if err != nil {
  25. panic("tx.CreateBucket err!")
  26. }
  27. // 创建创世块
  28. genericBlock := NewBlock([]byte(genesisInfo), []byte{})
  29. // 把创世块保存在bucket中
  30. bucket.Put(genericBlock.Hash, genericBlock.Serialize())
  31. // 把创世块的hash保存在last中
  32. bucket.Put([]byte(last), genericBlock.Hash)
  33. // 记录lastHash
  34. lastHash = genericBlock.Hash
  35. } else {
  36. // 4. 如果Bucket不为nil,记录lastHash
  37. lastHash = bucket.Get([]byte(last))
  38. }
  39. return nil
  40. })
  41. return &BlockChain{db, lastHash}
  42. }

(3)定义序列化和反序列化函数

  1. // 序列化block
  2. func (block *Block) Serialize() []byte {
  3. // 创建Encoder
  4. var buffer bytes.Buffer
  5. encoder := gob.NewEncoder(&buffer)
  6. // 加密操作
  7. err := encoder.Encode(block)
  8. if err != nil {
  9. panic("encoder.Encode err!")
  10. }
  11. return buffer.Bytes()
  12. }
  13. // 反序列化
  14. func Deserialize(data []byte) *Block {
  15. var block *Block
  16. var buffer bytes.Buffer
  17. _, err := buffer.Write(data)
  18. if err != nil {
  19. panic("buffer.Write err!")
  20. }
  21. // 创建Decoder
  22. decoder := gob.NewDecoder(&buffer)
  23. // 加密操作
  24. err = decoder.Decode(&block)
  25. if err != nil {
  26. panic("decoder.Decode err!")
  27. }
  28. return block
  29. }

(4)修改AddBlock方法,把新区块序列化后保存到数据库中,并且更新最后区块的哈希。

  1. // 添加区块
  2. func (bc *BlockChain) AddBlock(data string) {
  3. /*// 获取最后区块
  4. lastBlock := bc.Blocks[len(bc.Blocks)-1]
  5. // 创建一个新区块
  6. block := NewBlock([]byte(data), lastBlock.Hash)
  7. // 添加新区块
  8. bc.Blocks = append(bc.Blocks, block)*/
  9. // 获取最后区块hash
  10. lastHash := bc.Tail
  11. // 创建区块
  12. block := NewBlock([]byte(data), lastHash)
  13. // 更新操作
  14. bc.Db.Update(func(tx *bolt.Tx) error {
  15. bucket := tx.Bucket([]byte(bucketName))
  16. if bucket == nil {
  17. panic("bucket should not be nil!")
  18. }
  19. // 向bolt数据库添加新区块
  20. bucket.Put(block.Hash, block.Serialize())
  21. // 更新数据库的last
  22. bucket.Put([]byte(last), block.Hash)
  23. // 更新bc.Tail
  24. bc.Tail = block.Hash
  25. return nil
  26. })
  27. }

(5)修改main函数,把打印语句注释。

  1. func main() {
  2. bc := NewBlockChain()
  3. bc.AddBlock("1111")
  4. bc.AddBlock("2222")
  5. /*for i, block := range bc.Blocks {
  6. fmt.Println("======== block height : ", i, "=======")
  7. fmt.Printf("Version : %d\n", block.Version)
  8. fmt.Printf("PreHash : %x\n", block.PrevHash)
  9. fmt.Printf("MerKleRoot : %x\n", block.MerKleRoot)
  10. fmt.Printf("TimeStamp : %d\n", block.TimeStamp)
  11. fmt.Printf("Difficulty : %d\n", block.Difficulty)
  12. fmt.Printf("Nonce : %d\n", block.Nonce)
  13. fmt.Printf("Hash : %x\n", block.Hash)
  14. fmt.Printf("Data : %s\n", block.Data)
  15. }*/
  16. }

(6)编译运行,并查看数据库文件大小。

  1. > go build -o block.exe .
  2. > block
  3. > dir/a blockchain.db

 

二、遍历区块链

(1)定义迭代器结构体

  1. type BlockChainIterator struct {
  2. Db *bolt.DB
  3. Index []byte // 迭代器指针的索引值
  4. }

(2)提供创建方法

  1. // 创建迭代器
  2. func (bc *BlockChain) NewIterator() *BlockChainIterator {
  3. itr := BlockChainIterator{
  4. bc.Db,
  5. bc.Tail,
  6. }
  7. return &itr
  8. }

(3)定义迭代函数

  1. // 遍历上一个区块
  2. func (itr *BlockChainIterator) Prev() *Block {
  3. var block *Block
  4. itr.Db.View(func(tx *bolt.Tx) error {
  5. bucket := tx.Bucket([]byte(bucketName))
  6. if bucket == nil {
  7. panic("bucket shoud not be nil!")
  8. }
  9. // 获取最后区块
  10. blockBytes := bucket.Get(itr.Index)
  11. // 反序列化
  12. block = Deserialize(blockBytes)
  13. // 移动指针
  14. itr.Index = block.PrevHash
  15. return nil
  16. })
  17. return block
  18. }

(4)改写main函数

  1. func main() {
  2. bc := NewBlockChain()
  3. bc.AddBlock("1111")
  4. bc.AddBlock("2222")
  5. // 定义迭代器
  6. itr := bc.NewIterator()
  7. for {
  8. // 调用迭代器函数,返回当前block,并且向左移动
  9. block := itr.Prev()
  10. fmt.Println("========================")
  11. fmt.Printf("Version : %d\n", block.Version)
  12. fmt.Printf("PreHash : %x\n", block.PrevHash)
  13. fmt.Printf("MerKleRoot : %x\n", block.MerKleRoot)
  14. fmt.Printf("TimeStamp : %d\n", block.TimeStamp)
  15. fmt.Printf("Difficulty : %d\n", block.Difficulty)
  16. fmt.Printf("Nonce : %d\n", block.Nonce)
  17. fmt.Printf("Hash : %x\n", block.Hash)
  18. fmt.Printf("Data : %s\n", block.Data)
  19. // 退出条件
  20. if len(block.PrevHash) == 0 {
  21. break
  22. }
  23. }
  24. }

 

三、命令行

(1)定义命令行结构体

  1. type Cli struct {
  2. bc *BlockChain
  3. }

(2)定义Run函数,用于与用户进行交互。

  1. const Usage = `
  2. block addBlock --data DATA "添加新区块"
  3. block printChain "打印区块链"
  4. block getBalance --address ADDRESS "查询账户余额"
  5. block send FROM TO AMOUNT MINER DATA "由FROM给TO转AMOUNT个比特币,并指定MINER为矿工"
  6. block newWallet "创建一个钱包"
  7. block listAddress "列出所有钱包地址"
  8. `
  9. func (cli *Cli) Run() {
  10. args := os.Args
  11. if len(args) < 2 {
  12. fmt.Println(Usage)
  13. return
  14. }
  15. // 获取命令名称
  16. command := args[1]
  17. switch command {
  18. case "addBlock":
  19. if len(os.Args) == 4 && os.Args[2] == "--data" {
  20. data := os.Args[3]
  21. if data == "" {
  22. fmt.Println("data should not be empty!")
  23. return
  24. }
  25. cli.addBlock(data)
  26. }
  27. case "printChain":
  28. cli.PrintChain()
  29. default:
  30. fmt.Println(Usage)
  31. }
  32. }

(3)提供AddBlock函数

  1. // 添加区块
  2. func (cli *Cli) addBlock(data string) {
  3. cli.bc.AddBlock(data)
  4. }

(4)提供PrintChain函数

  1. // 打印区块
  2. func (cli *Cli) printChain() {
  3. bc := cli.bc
  4. // 定义迭代器
  5. itr := bc.NewIterator()
  6. for {
  7. // 调用迭代器函数,返回当前block,并且向左移动
  8. block := itr.Prev()
  9. fmt.Println("========================")
  10. fmt.Printf("Version : %d\n", block.Version)
  11. fmt.Printf("PreHash : %x\n", block.PrevHash)
  12. fmt.Printf("MerKleRoot : %x\n", block.MerKleRoot)
  13. fmt.Printf("TimeStamp : %d\n", block.TimeStamp)
  14. fmt.Printf("Difficulty : %d\n", block.Difficulty)
  15. fmt.Printf("Nonce : %d\n", block.Nonce)
  16. fmt.Printf("Hash : %x\n", block.Hash)
  17. fmt.Printf("Data : %s\n", block.Data)
  18. // 退出条件
  19. if len(block.PrevHash) == 0 {
  20. break
  21. }
  22. }
  23. }

(5)修改main函数

  1. func main() {
  2. bc := NewBlockChain()
  3. cli := Cli{bc}
  4. cli.Run()
  5. }

(6)创建运行脚本

  1. @del blockchain.db
  2. @go build -o block.exe .
  3. @block

 

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号