翻譯的系列文章我已經放到了 GitHub 上:blockchain-tutorial,後續如有更新都會在 GitHub 上,可能就不在這裡同步了。如果想直接運行代碼,也可以 clone GitHub 上的教程倉庫,進入 src 目錄執行 make 即可。 引言
Timestamp 是目前時間戳,也就是區塊建立的時間。 Data 是區Block Storage的實際有效資訊。 PrevBlockHash 儲存的是前一個塊的雜湊。 Hash 是當前塊的雜湊。 在比特幣技術規範中,Timestamp, PrevBlockHash, Hash 是區塊頭(block header),區塊頭是一個單獨的資料結構。而交易,也就是這裡的 Data, 是另一個單獨的資料結構。為了簡便起見,我把這兩個混合在了一起。
那麼,我們要如何計算雜湊呢。如何計算雜湊,是區塊鏈一個非常重要的部分。正是由於這個特性,才使得區塊鏈是安全的。計算一個雜湊,是在計算上非常困難的一個操作。即使在高速電腦上,也要花費不少時間 (這就是為什麼人們會購買 GPU 來挖比特幣) 。這是一個有意為之的架構設計,它故意使得加入新的區塊十分困難,因此可以保證區塊一旦被加入以後,就很難再進行修改。在本系列未來幾篇文章中,我們將會討論和實現這個機制。
目前,我們僅取了 Block 結構的一些欄位(Timestamp, Data 和 PrevBlockHash),並將它們相互串連起來,然後在串連後的結果上計算一個 SHA-256 的雜湊. 讓我們在 SetHash 方法中完成這個任務:
func (b *Block) SetHash() { timestamp := []byte(strconv.FormatInt(b.Timestamp, 10)) headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, timestamp}, []byte{}) hash := sha256.Sum256(headers) b.Hash = hash[:]} 1 2 3 4 5 6 7
接下來,按照 Golang 的慣例,我們會實現一個用於簡化建立一個區塊的函數:
func NewBlock(data string, prevBlockHash []byte) *Block { block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}} block.SetHash() return block} 1 2 3 4 5
這就是我們的第一個區塊鏈。我從來沒有想過它會是這麼容易。
現在,讓我們能夠給它添加一個塊:
func (bc *Blockchain) AddBlock(data string) { prevBlock := bc.blocks[len(bc.blocks)-1] newBlock := NewBlock(data, prevBlock.Hash) bc.blocks = append(bc.blocks, newBlock)} 1 2 3 4 5
完成。不過,真的就這樣了嗎。
為了加入一個新的塊,我們必須要有一個已有的塊,但是,現在我們的鏈是空的,一個塊都沒有。所以,在任何一個區塊鏈中,都必須至少有一個塊。這樣的塊,也就是鏈中的第一個塊,通常叫做創世塊(genesis block). 讓我們實現一個方法來建立一個創世塊:
func NewGenesisBlock() *Block { return NewBlock("Genesis Block", []byte{})} 1 2 3
現在,我們可以實現一個函數來建立有創世塊的區塊鏈:
func NewBlockchain() *Blockchain { return &Blockchain{[]*Block{NewGenesisBlock()}}} 1 2 3
來檢查一個我們的區塊鏈是否如期工作:
func main() { bc := NewBlockchain() bc.AddBlock("Send 1 BTC to Ivan") bc.AddBlock("Send 2 more BTC to Ivan") for _, block := range bc.blocks { fmt.Printf("Prev. hash: %x\n", block.PrevBlockHash) fmt.Printf("Data: %s\n", block.Data) fmt.Printf("Hash: %x\n", block.Hash) fmt.Println() }} 1 2 3 4 5 6 7 8 9 10 11 12 13
輸出:
Prev. hash:Data: Genesis BlockHash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168Prev. hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168Data: Send 1 BTC to IvanHash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1Prev. hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1Data: Send 2 more BTC to IvanHash: 561237522bb7fcfbccbc6fe0e98bbbde7427ffe01c6fb223f7562288ca2295d1 1 2 3 4 5 6 7 8 9 10 11