go公鏈實戰0x03資料持久化

2021-09-11 15:15:29 字數 4227 閱讀 1078

上一節學習了基於go語言的資料庫boltdb的基本使用,這一節用boltdb實現區塊鏈的資料持久化。

區塊鏈的資料主要集中在各個區塊上,所以區塊鏈的資料持久化即可轉化為對每乙個區塊的儲存。boltdb是kv儲存方式,因此這裡我們可以以區塊的雜湊值為key,區塊為value。

此外,我們還需要儲存最新區塊的雜湊值。這樣,就可以找到最新的區塊,然後按照區塊儲存的上個區塊雜湊值找到上個區塊,以此類推便可以找到區塊鏈上所有的區塊。

我們知道,boltdb儲存的鍵值對的資料型別都是位元組陣列。所以在儲存區塊前需要對區塊進行序列化,當然讀取區塊的時候就需要做反序列化處理。

沒什麼難點,都是借助系統方法實現。廢話少說上**。

序列化

//區塊序列化

func (block *block) serialize() byte

return result.bytes()

}複製**

反序列化
//區塊反序列化

func deserializeblock(blockbytes byte) *block

return block

}複製**

區塊鏈結構

之前定義的區塊鏈結構是這樣的:

type blockchain struct 

複製**

但是這樣的結構,每次執行程式區塊陣列都是從零開始建立,並不能實現區塊鏈的資料持久化。這裡的陣列屬性要改為boltdb型別的區塊資料庫,同時還必須有乙個儲存當前區塊鏈最新區塊雜湊的屬性。

type blockchain struct 

複製**

相關資料庫常量
//相關資料庫屬性

const dbname = "chaorsblockchain.db"

const blocktablename = "chaorsblocks"

const newestblockkey = "chnewestblockkey"

複製**

建立區塊鏈
//1.建立帶有創世區塊的區塊鏈

func createblockchainwithgensisblock() *blockchain

err = db.view(func(tx *bolt.tx) error

"%x", hash)

}return nil

})if err != nil

return blockchain

} //建立並開啟資料庫

db, err := bolt.open(dbname, 0600, nil)

if err != nil

err = db.update(func(tx *bolt.tx) error

} if b != nil

//儲存最新區塊hash

err = b.put(byte(newestblockkey), gensisblock.hash)

if err != nil

blockchain = &blockchain

} return nil

}) //更新資料庫失敗

if err != nil

return blockchain

}複製**

新增區塊

前面我們寫的這個方法為:

func (blc *blockchain) addblocktoblockchain(data string, height int64, prevhash byte)  

//5.更新資料庫裡最新區塊

err = b.put(byte(newestblockkey), newblock.hash)

if err != nil

//6.更新區塊鏈最新區塊

blc.tip = newblock.hash

} return nil

}) if err != nil

}複製**

區塊鏈遍歷
//3.遍歷輸出所有區塊資訊  --> 以後一般使用優化後的迭代器方法(見3.x)

func (blc *blockchain) printchain

() return nil

})if err != nil

var hashint big.int

hashint.setbytes(block.prevblockhash)

//遍歷到創世區塊,跳出迴圈 創世區塊雜湊為0

if big.newint(0).cmp(&hashint) == 0

curhash = block.prevblockhash }}

複製**

注意:

######time.unix(block.timestamp, 0).format("2006-01-02 15:04:05") golang這裡真是奇葩啊……時間戳格式化只能寫"2006-01-02 15:04:05",乙個數丟不能寫錯,不然你會」被穿越「的!!!據說這個日期是go語言的誕生日期,還真是傲嬌啊,生怕大家不知道嗎???

判斷區塊鏈資料庫是否存在

//判斷資料庫是否存在

func isdbexists(dbname string) bool

_, err := os.stat(dbname)

if err == nil

if os.isnotexist(err)

return

true

}複製**

對區塊鏈區塊的遍歷上面已經實現,但是還可以優化。我們不難發現區塊鏈的區塊遍歷類似於單向鍊錶的遍歷,那麼我們能不能製造乙個像鍊錶的next屬性似的迭代器,只要通過不斷地訪問next就能遍歷所有的區塊?

話都說到這份上了,答案當然是肯當的。

blockchainiterator

//區塊鏈迭代器

type blockchainiterator struct

複製**

next迭代方法
func (blciterator *blockchainiterator) next() *block 

return nil

}) if err != nil

return block

}複製**

怎麼用?

1.在blockchain類新增乙個生成當前區塊鏈的迭代器的方法

//生成當前區塊鏈迭代器的方法

func (blc *blockchain) iterator() *blockchainiterator

}複製**

2.修改之前的printchain方法
優化區塊鏈遍歷方法

func (blc *blockchain) printchain

() }

}複製**

是不是發現遍歷區塊的**相對簡潔了,這裡把資料庫訪問和區塊迭代的**分離到了blockchainiterator裡實現,也符合程式設計的單一職責原則。

() 複製**1.首次執行(這時不存在資料庫)

2.注釋掉三句addblocktoblockchain**,再次執行

這次我們並沒有新增區塊,所以列印區沒有挖礦的過程。但是列印的區塊是上次addblocktoblockchain新增的,說明區塊儲存成功了。

3.修改addblocktoblockchain段**,再次執行

blockchain.addblocktoblockchain("4th block")

blockchain.addblocktoblockchain("5th block")

複製**

我們看到,在原有區塊資訊不變的情況,新挖出的區塊成功新增到了區塊鏈資料庫中。說明我們的區塊鏈資料持久化實現成功了。

###網際網路顛覆世界,區塊鏈顛覆網際網路!

---------------------------------------------20180624 20:16

C 中 x與0x的區別

首先這兩個均表示16進製制,但是用法有所不同。x主要是用於字元的表示 如char ch xa 那麼ch這個字元所代表的是什麼呢?正如上面所說的 x代表的是16進製制,16進製制中的a在十進位制中代表10,那麼ch這個數就代表著序號為10的ascii碼所代表的字元,即 n換行符。0x雖然也代表十六進製...

VS2019報錯0x系列

在進行c 開發時候,由於野指標 空指標 未初始化記憶體等原因,很容易導致記憶體錯誤,並報出特定錯誤碼。google上對上述錯誤碼的解釋如下 0xcdcdcdcd created but not initialised 未初始化的堆記憶體 0xdddddddd deleted 引用的記憶體已經 物件被...

關於十六進製制0x

0x00.在程式設計中,以0x開始的資料表示16進製制。比如0x00表示十進位制中的0,0x01表示1。0x01.0x 是後面是十六進製制數字的標示,後面是數字的主題。比如0x01其實是 0x 主題部分01,就是十六進製制的01,也就是一。如果是0x0f,那表示就是15.因為a f分別代表的是十六進...