真正理解區塊鏈底層原理的方法就是寫一個底層,UTXO 模型區塊鏈的開發難度還是比較簡單的,等開發完後再去嘗試一下基於 account 模型的。
什麼是區塊鏈以及 UTXO 模型和 account 模型等問題我就不在這裡寫了,網上的資料有很多,跟著寫之前可以先去了解一下區塊鏈的基礎知識。
開發環境:goland+go1.20
該項目 github 地址:lighteningchain
mirror 地址:lighteningchain(1)
創建項目#
使用 goland 創建項目,取名為 lighteningchain,並使用go mod init lighteningchain
初始化項目
區塊結構#
每個區塊應該包含頭部(head)信息用於總結性的描述這個區塊,然後在區塊的數據存放區(body)中存放要保存的重要數據
首先定義區塊結構體和區塊鏈的結構體
type Block struct {
Timestamp int64
Hash []byte //區塊hash值就是其ID
PrevHash []byte
Data []byte
}
type BlockChain struct {
Blocks []*Block
}
計算哈希#
有了結構體後,區塊的哈希計算也是必不可少的
func (b *Block) SetHash() {
information := bytes.Join([][]byte{Int64ToByte(b.Timestamp), b.PrevHash, b.Data}, []byte{})
hash := sha256.Sum256(information) //軟體包sha256 實現 FIPS 180-4 中定義的 SHA224 和 SHA256 哈希算法。
b.Hash = hash[:]
}
func Int64ToByte(num int64) []byte {
var buf = make([]byte, 8)
binary.BigEndian.PutUint64(buf, uint64(num))
return buf
}
information 變量是將區塊的各項屬性串聯之後的字節串。bytes.Join 可以將多個字節串連接,第二個參數是將字節串連接時的分隔符,這裡設置為 [] byte {} 即為空。
創建區塊和區塊鏈#
好了,區塊鏈的準備工作完成,下面就要開始創建區塊並將它們連在一起。
首先定義區塊創建函數
func CreateBlock(prevhash []byte, data []byte) *Block {
block := Block{time.Now().Unix(), []byte{}, prevhash, data}
block.SetHash() //所有數據添加好後再計算hash
return &block
}
可是每個區塊都要鏈接上一個區塊的 hash,那第一個區塊怎麼辦?這時就需要創世區塊。
func GenesisBlock() *Block {
genesisWords := "HelloWorld!"
return CreateBlock([]byte{}, []byte(genesisWords))
}
把創建好的區塊添加到區塊鏈上
func (bc *BlockChain) AddBlock(data string) {
newBlock := CreateBlock(bc.Blocks[len(bc.Blocks)-1].Hash, []byte(data))
bc.Blocks = append(bc.Blocks, newBlock)
}
這下整個區塊鏈就搭建好了,下面我們運行試試。對了,不要忘記初始化。
func CreateBlockChain() *BlockChain {
myBlockchain := BlockChain{}
myBlockchain.Blocks = append(myBlockchain.Blocks, GenesisBlock())
return &myBlockchain
}
main 函數編寫運行測試區塊鏈#
接下來我們就可以運行區塊鏈了,我們自己編寫幾個實例加進去然後輸出看看:
func main() {
blockchain := CreateBlockChain()
time.Sleep(time.Second)
blockchain.AddBlock("This is first Block after Genesis")
time.Sleep(time.Second)
blockchain.AddBlock("This is second!")
time.Sleep(time.Second)
blockchain.AddBlock("Awesome!")
time.Sleep(time.Second)
for num, block := range blockchain.Blocks {
fmt.Printf("number:%d Timestamp: %d\n", num, block.Timestamp)
fmt.Printf("number:%d hash: %x\n", num, block.Hash)
fmt.Printf("number:%d Previous hash: %x\n", num, block.PrevHash)
fmt.Printf("number:%d data: %s\n", num, block.Data)
}
}
點擊運行,輸出如下:
number:0 Timestamp: 1677568251
number:0 hash: 5af650b22cc85f225c2c42850714be9466408025dfec7191436d7efa7a716433
number:0 Previous hash:
number:0 data: HelloWorld!
number:1 Timestamp: 1677568252
number:1 hash: 3b2eafc41f8c0bd319fd2e7fd44ff2d15215ab931e6a599dc83b60f055653cb8
number:1 Previous hash: 5af650b22cc85f225c2c42850714be9466408025dfec7191436d7efa7a716433
number:1 data: This is first Block after Genesis
number:2 Timestamp: 1677568253
number:2 hash: 1be2cf3334f59a54a33e9c28957ecb836f17d731f6731bc7540066f99c2338c7
number:2 Previous hash: 3b2eafc41f8c0bd319fd2e7fd44ff2d15215ab931e6a599dc83b60f055653cb8
number:2 data: This is second!
number:3 Timestamp: 1677568254
number:3 hash: 460d954e05c98774b58426372f61997bed92ce7b4e2effb749b7bc2f0c19bdf3
number:3 Previous hash: 1be2cf3334f59a54a33e9c28957ecb836f17d731f6731bc7540066f99c2338c7
number:3 data: Awesome!
Process finished with the exit code 0
一切正常!
總結#
本章搭建了一個最簡易的區塊鏈,主要是加深對於區塊和區塊鏈數據結構的認識。可以看出來,此項目目前並不符合高內聚低耦合思想,因此下一章將對此進行優化,並引入 POW(工作量證明)共識機制。