Arno

Arno

使用golang從零開始搭建基於UTXO模型的區塊鏈(一、實現最簡易的區塊鏈)

真正理解區塊鏈底層原理的方法就是寫一個底層,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(工作量證明)共識機制。

參考資料#

Go Blockchain Tutorial Part 1: Hello, Blockchain

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。