使用 Go 實作區塊鏈(一):建立基礎結構

前言

本文為「Building a Blockchain in Golang」教學影片的學習筆記。

建立專案

建立專案。

1
2
mkdir go-blockchain
cd go-blockchain

初始化 Go Modules。

1
go mod init github.com/memochou1993/go-blockchain

實作

建立一個 blockchain 資料夾。

1
mkdir blockchain

blockchain 資料夾建立一個 block.go 檔。

1
touch blockchain/block.go

block.go 檔中建立一個 Block 結構體,即「區塊」。

1
2
3
4
5
type Block struct {
Hash []byte // 雜湊值
Data []byte // 資料
PrevHash []byte // 前一個區塊的雜湊值
}

Block 結構體建立一個 DeriveHash() 方法,將當前區塊的資料與前一個區塊的雜湊值合併後,產生一個新的雜湊值作為當前區塊的雜湊值。

1
2
3
4
5
func (b *Block) DeriveHash() {
info := bytes.Join([][]byte{b.Data, b.PrevHash}, []byte{})
hash := sha256.Sum256(info)
b.Hash = hash[:]
}

建立一個 CreateBlock() 方法,接受一個字串型態的資料和前一個區塊的雜湊值作為參數,繼承前一個區塊的雜湊值,並回傳一個新的區塊。

1
2
3
4
5
func CreateBlock(data string, prevHash []byte) *Block {
block := &Block{[]byte{}, []byte(data), prevHash}
block.DeriveHash()
return block
}

建立一個 Genesis() 方法,回傳一個創世區塊。

1
2
3
func Genesis() *Block {
return CreateBlock("Genesis", []byte{})
}

blockchain 資料夾建立一個 blockchain.go 檔。

1
touch blockchain/blockchain.go

建立一個 BlockChain 結構體,即「區塊鏈」。

1
2
3
type BlockChain struct {
Blocks []*Block
}

BlockChain 結構體建立一個 AddBlock() 方法,接受一個字串型態的資料,使用前一個區塊的雜湊值建立一個新的區塊,並添加至區塊鏈中。

1
2
3
4
5
func (chain *BlockChain) AddBlock(data string) {
prevBlock := chain.Blocks[len(chain.Blocks)-1]
newBlock := CreateBlock(data, prevBlock.Hash)
chain.Blocks = append(chain.Blocks, newBlock)
}

建立一個 InitBlockChain() 方法,並回傳一個包括了創世區塊的新的區塊鏈。

1
2
3
func InitBlockChain() *BlockChain {
return &BlockChain{[]*Block{Genesis()}}
}

建立 main.go 檔。

1
touch main.go

main 方法中建立一個區塊鏈,並新增幾個區塊。

1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
chain := InitBlockChain()

chain.AddBlock("First Block after Genesis")
chain.AddBlock("Second Block after Genesis")
chain.AddBlock("Third Block after Genesis")

for _, block := range chain.Blocks {
fmt.Printf("Previous Hash: %x\n", block.PrevHash)
fmt.Printf("Data in Block: %s\n", block.Data)
fmt.Printf("Hash: %x\n", block.Hash)
}
}

執行程式。

1
go run main.go

顯示結果如下:

1
2
3
4
5
6
7
8
9
10
11
12
Previous Hash: 
Data in Block: Genesis
Hash: 81ddc8d248b2dccdd3fdd5e84f0cad62b08f2d10b57f9a831c13451e5c5c80a5
Previous Hash: 81ddc8d248b2dccdd3fdd5e84f0cad62b08f2d10b57f9a831c13451e5c5c80a5
Data in Block: First Block after Genesis
Hash: 50493b76a2b7bec8d33620d6310d5578b1dda079684405ed5e6bd55510146daf
Previous Hash: 50493b76a2b7bec8d33620d6310d5578b1dda079684405ed5e6bd55510146daf
Data in Block: Second Block after Genesis
Hash: 213e91a4ae1be45a651695ede0e75cba50818dce027dd4f0fe35742dc90158e1
Previous Hash: 213e91a4ae1be45a651695ede0e75cba50818dce027dd4f0fe35742dc90158e1
Data in Block: Third Block after Genesis
Hash: e22b76962d23ed3e327b9ababac19270b56c4d70d8878446609b13fa72ebc0e1

程式碼

參考資料