赞
踩
为了能够永久保存区块链数据,这里引入bolt数据库。
(1)改写BlockChain结构体
- type BlockChain struct {
- //Blocks []*Block // 保存所有区块
- Db *bolt.DB
- Tail []byte // 最后区块的hash
- }
(2)改写NewBlockChain方法,把创世块数据以及最后区块的哈希写入数据库中。
- const dbName = "blockchain.db"
- const bucketName = "bucket"
- const last = "lastBlockHash"
-
- // 创建方法
- func NewBlockChain() *BlockChain {
- /*// 创建创世块
- genericBlock := NewBlock([]byte(genesisInfo), []byte{})
- // 创建BlockChain
- bc := BlockChain{[]*Block{genericBlock}}
- return &bc*/
-
- var db *bolt.DB
- var lastHash []byte
-
- // 1. 打开数据库
- db, err := bolt.Open(dbName, 0600, nil)
- if err != nil {
- panic("bolt.Open err!")
- }
- db.Update(func(tx *bolt.Tx) error {
- // 2. 打开抽屉Bucket
- bucket := tx.Bucket([]byte(bucketName))
- // 3. 如果Bucket是否为nil,则创建一个Bucket
- if bucket == nil {
- bucket, err = tx.CreateBucket([]byte(bucketName))
- if err != nil {
- panic("tx.CreateBucket err!")
- }
- // 创建创世块
- genericBlock := NewBlock([]byte(genesisInfo), []byte{})
- // 把创世块保存在bucket中
- bucket.Put(genericBlock.Hash, genericBlock.Serialize())
- // 把创世块的hash保存在last中
- bucket.Put([]byte(last), genericBlock.Hash)
- // 记录lastHash
- lastHash = genericBlock.Hash
- } else {
- // 4. 如果Bucket不为nil,记录lastHash
- lastHash = bucket.Get([]byte(last))
- }
- return nil
- })
- return &BlockChain{db, lastHash}
- }
(3)定义序列化和反序列化函数
- // 序列化block
- func (block *Block) Serialize() []byte {
- // 创建Encoder
- var buffer bytes.Buffer
- encoder := gob.NewEncoder(&buffer)
- // 加密操作
- err := encoder.Encode(block)
- if err != nil {
- panic("encoder.Encode err!")
- }
- return buffer.Bytes()
- }
-
- // 反序列化
- func Deserialize(data []byte) *Block {
- var block *Block
- var buffer bytes.Buffer
- _, err := buffer.Write(data)
- if err != nil {
- panic("buffer.Write err!")
- }
- // 创建Decoder
- decoder := gob.NewDecoder(&buffer)
- // 加密操作
- err = decoder.Decode(&block)
- if err != nil {
- panic("decoder.Decode err!")
- }
- return block
- }
(4)修改AddBlock方法,把新区块序列化后保存到数据库中,并且更新最后区块的哈希。
- // 添加区块
- func (bc *BlockChain) AddBlock(data string) {
- /*// 获取最后区块
- lastBlock := bc.Blocks[len(bc.Blocks)-1]
- // 创建一个新区块
- block := NewBlock([]byte(data), lastBlock.Hash)
- // 添加新区块
- bc.Blocks = append(bc.Blocks, block)*/
-
- // 获取最后区块hash
- lastHash := bc.Tail
- // 创建区块
- block := NewBlock([]byte(data), lastHash)
- // 更新操作
- bc.Db.Update(func(tx *bolt.Tx) error {
- bucket := tx.Bucket([]byte(bucketName))
- if bucket == nil {
- panic("bucket should not be nil!")
- }
- // 向bolt数据库添加新区块
- bucket.Put(block.Hash, block.Serialize())
- // 更新数据库的last
- bucket.Put([]byte(last), block.Hash)
- // 更新bc.Tail
- bc.Tail = block.Hash
- return nil
- })
- }
(5)修改main函数,把打印语句注释。
- func main() {
- bc := NewBlockChain()
- bc.AddBlock("1111")
- bc.AddBlock("2222")
-
- /*for i, block := range bc.Blocks {
- fmt.Println("======== block height : ", i, "=======")
- fmt.Printf("Version : %d\n", block.Version)
- fmt.Printf("PreHash : %x\n", block.PrevHash)
- fmt.Printf("MerKleRoot : %x\n", block.MerKleRoot)
- fmt.Printf("TimeStamp : %d\n", block.TimeStamp)
- fmt.Printf("Difficulty : %d\n", block.Difficulty)
- fmt.Printf("Nonce : %d\n", block.Nonce)
- fmt.Printf("Hash : %x\n", block.Hash)
- fmt.Printf("Data : %s\n", block.Data)
- }*/
- }
(6)编译运行,并查看数据库文件大小。
- > go build -o block.exe .
- > block
- > dir/a blockchain.db
(1)定义迭代器结构体
- type BlockChainIterator struct {
- Db *bolt.DB
- Index []byte // 迭代器指针的索引值
- }
(2)提供创建方法
- // 创建迭代器
- func (bc *BlockChain) NewIterator() *BlockChainIterator {
- itr := BlockChainIterator{
- bc.Db,
- bc.Tail,
- }
- return &itr
- }
(3)定义迭代函数
- // 遍历上一个区块
- func (itr *BlockChainIterator) Prev() *Block {
- var block *Block
- itr.Db.View(func(tx *bolt.Tx) error {
- bucket := tx.Bucket([]byte(bucketName))
- if bucket == nil {
- panic("bucket shoud not be nil!")
- }
- // 获取最后区块
- blockBytes := bucket.Get(itr.Index)
- // 反序列化
- block = Deserialize(blockBytes)
- // 移动指针
- itr.Index = block.PrevHash
- return nil
- })
- return block
- }
(4)改写main函数
- func main() {
- bc := NewBlockChain()
- bc.AddBlock("1111")
- bc.AddBlock("2222")
-
- // 定义迭代器
- itr := bc.NewIterator()
- for {
- // 调用迭代器函数,返回当前block,并且向左移动
- block := itr.Prev()
- fmt.Println("========================")
- fmt.Printf("Version : %d\n", block.Version)
- fmt.Printf("PreHash : %x\n", block.PrevHash)
- fmt.Printf("MerKleRoot : %x\n", block.MerKleRoot)
- fmt.Printf("TimeStamp : %d\n", block.TimeStamp)
- fmt.Printf("Difficulty : %d\n", block.Difficulty)
- fmt.Printf("Nonce : %d\n", block.Nonce)
- fmt.Printf("Hash : %x\n", block.Hash)
- fmt.Printf("Data : %s\n", block.Data)
-
- // 退出条件
- if len(block.PrevHash) == 0 {
- break
- }
- }
- }
(1)定义命令行结构体
- type Cli struct {
- bc *BlockChain
- }
(2)定义Run函数,用于与用户进行交互。
- const Usage = `
- block addBlock --data DATA "添加新区块"
- block printChain "打印区块链"
- block getBalance --address ADDRESS "查询账户余额"
- block send FROM TO AMOUNT MINER DATA "由FROM给TO转AMOUNT个比特币,并指定MINER为矿工"
- block newWallet "创建一个钱包"
- block listAddress "列出所有钱包地址"
- `
-
- func (cli *Cli) Run() {
- args := os.Args
- if len(args) < 2 {
- fmt.Println(Usage)
- return
- }
- // 获取命令名称
- command := args[1]
- switch command {
- case "addBlock":
- if len(os.Args) == 4 && os.Args[2] == "--data" {
- data := os.Args[3]
- if data == "" {
- fmt.Println("data should not be empty!")
- return
- }
- cli.addBlock(data)
- }
- case "printChain":
- cli.PrintChain()
- default:
- fmt.Println(Usage)
- }
- }
(3)提供AddBlock函数
- // 添加区块
- func (cli *Cli) addBlock(data string) {
- cli.bc.AddBlock(data)
- }
(4)提供PrintChain函数
- // 打印区块
- func (cli *Cli) printChain() {
- bc := cli.bc
- // 定义迭代器
- itr := bc.NewIterator()
- for {
- // 调用迭代器函数,返回当前block,并且向左移动
- block := itr.Prev()
- fmt.Println("========================")
- fmt.Printf("Version : %d\n", block.Version)
- fmt.Printf("PreHash : %x\n", block.PrevHash)
- fmt.Printf("MerKleRoot : %x\n", block.MerKleRoot)
- fmt.Printf("TimeStamp : %d\n", block.TimeStamp)
- fmt.Printf("Difficulty : %d\n", block.Difficulty)
- fmt.Printf("Nonce : %d\n", block.Nonce)
- fmt.Printf("Hash : %x\n", block.Hash)
- fmt.Printf("Data : %s\n", block.Data)
-
- // 退出条件
- if len(block.PrevHash) == 0 {
- break
- }
- }
- }
(5)修改main函数
- func main() {
- bc := NewBlockChain()
- cli := Cli{bc}
- cli.Run()
- }
(6)创建运行脚本
- @del blockchain.db
- @go build -o block.exe .
- @block
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。