上一節學習了基於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分別代表的是十六進...