區(qū)塊鏈是二十一世紀(jì)最具革命性的技術(shù)之一,它正在不斷成熟,它的諸多潛力正在逐步實(shí)現(xiàn)中。本質(zhì)上來看,區(qū)塊鏈只不過是一個(gè)分布式的數(shù)據(jù)庫。之所以區(qū)塊鏈獨(dú)特,是因?yàn)樗⒉皇且粋€(gè)私有數(shù)據(jù)庫,而是一個(gè)公開的數(shù)據(jù)庫,即,每一個(gè)使用它的人擁有這個(gè)數(shù)據(jù)庫的全部或者至少一部分。任何一個(gè)新的數(shù)據(jù)記錄,只能在多數(shù)數(shù)據(jù)庫持有者(維護(hù)者)的多數(shù)同意之后被加入數(shù)據(jù)庫。正因如此,區(qū)塊鏈?zhǔn)沟眉用茇泿乓约?a href="http://wenjunhu.com/v/" target="_blank">智能合約成為可能。
?
在這個(gè)系列文章中,我們將打造一個(gè)簡化版本的加密貨幣,它將基于一個(gè)簡化版本的區(qū)塊鏈實(shí)現(xiàn)。
區(qū)塊(Block)
讓我們先從區(qū)塊開始。在區(qū)塊鏈里,價(jià)值信息存儲在區(qū)塊之中。比如,比特幣的區(qū)塊存儲交易記錄,而交易記錄是任何加密貨幣的核心。除此之外,區(qū)塊里還包含有技術(shù)信息,比如它的版本號,當(dāng)前的時(shí)間戳,以及上一個(gè)區(qū)塊的哈希(Hash)。
在這篇文章中,我們所實(shí)現(xiàn)的并不是像比特幣那樣完整的區(qū)塊鏈,而是一個(gè)簡化版本的區(qū)塊鏈,它只含有最基本的核心信息。差不多是這樣:
type Block struct {
Timestamp int64
Data []byte
PrevBlockHash []byte
Hash []byte}
Timestamp 是當(dāng)前的時(shí)間戳(即,區(qū)塊被創(chuàng)建的時(shí)間),Data 是區(qū)塊中包含的價(jià)值信息,PrevBlockHash 存儲的是上一個(gè)區(qū)塊的哈希,而Hash 保存的是當(dāng)前區(qū)塊的哈希。在比特幣的標(biāo)配中,Timestamp、PrevBlockHash、Hash是區(qū)塊的頭部數(shù)據(jù)(Block headers),構(gòu)成一個(gè)單獨(dú)的數(shù)據(jù)結(jié)構(gòu);而交易記錄(Transactions,在我們這個(gè)版本中就是 Data),是另外一個(gè)單獨(dú)的數(shù)據(jù)結(jié)構(gòu)。而我們在這里為了簡化,把數(shù)據(jù)結(jié)構(gòu)混在了一起。
那我們?nèi)绾斡?jì)算哈希呢?計(jì)算哈希的方式是區(qū)塊鏈的重要特征之一,也正是這個(gè)特性使得區(qū)塊鏈如此安全。關(guān)鍵在于,計(jì)算哈希是一個(gè)計(jì)算起來很困難的工作,它需要時(shí)間,哪怕是在很快的計(jì)算機(jī)上(這就是為什么人們要買比 CPU 計(jì)算能力更強(qiáng)悍 GPU 甚至專門的 ASIC 芯片做礦機(jī)的 原因)。這是故意如此設(shè)計(jì)的,這么做的結(jié)果是,往區(qū)塊鏈(數(shù)據(jù)庫)里添加新的區(qū)塊(數(shù)據(jù))有一定的困難,以此保證一旦新的數(shù)據(jù)被加入,往后很難篡改。以后的文章里會進(jìn)一步討論并實(shí)現(xiàn)這個(gè)機(jī)制。
現(xiàn)在呢,我們只需要罷區(qū)塊里的各個(gè)字段關(guān)聯(lián)起來,并在此基礎(chǔ)上計(jì)算出一個(gè) SHA-256 哈希。讓我們調(diào)用一下 SetHash這個(gè)方法:
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[:]
}
接下來,依據(jù) Golang 的常用方式,我們將實(shí)現(xiàn)一個(gè)函數(shù),以便更簡單地創(chuàng)建區(qū)塊:
func NewBlock(data string, prevBlockHash []byte) *Block {
block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}}
block.SetHash() return block
}
就這么簡單。
區(qū)塊鏈(Blockchain)
現(xiàn)在,讓我們來實(shí)現(xiàn)區(qū)塊鏈。本質(zhì)上來看,區(qū)塊鏈只不過是一個(gè)特定結(jié)構(gòu)的數(shù)據(jù)庫,它是一個(gè)有序的,反向鏈接的列表(back-linked list)。這就意味著說,區(qū)塊是按照插入的順序排列的,每個(gè)區(qū)塊都鏈接到上一個(gè)區(qū)塊。這樣的結(jié)構(gòu),使得使用者可以很快地在區(qū)塊鏈中獲得最新的區(qū)塊,也可以很有效率地通過區(qū)塊的哈希獲得某個(gè)區(qū)塊。
在 Golang 中,這種結(jié)構(gòu)可以用數(shù)組(Array)與數(shù)圖(Map) 實(shí)現(xiàn):數(shù)組用來維護(hù)有序哈希(在 Go 語言中,數(shù)組是有序的);數(shù)圖(Map) 用來維護(hù) hash → block 對。不過,在我們的區(qū)塊鏈原型中,我們只需要數(shù)組就可以了,因?yàn)槲覀儠簳r(shí)不需要通過哈希獲取區(qū)塊。
type Blockchain struct {
blocks []*Block
}
這就是我們的第一個(gè)區(qū)塊鏈!我從來沒想到竟然會這么簡單!
現(xiàn)在,我們要想辦法往區(qū)塊鏈里添加區(qū)塊了:
func (bc *Blockchain) AddBlock(data string) {
prevBlock := bc.blocks[len(bc.blocks)-1]
newBlock := NewBlock(data, prevBlock.Hash)
bc.blocks = append(bc.blocks, newBlock)
}
這就完事兒了?或者……?
為了添加新的區(qū)塊,我們需要一個(gè)已經(jīng)存在的區(qū)塊,可現(xiàn)在我們的區(qū)塊鏈里面沒有任何區(qū)塊!于是,在任何區(qū)塊鏈中,應(yīng)該至少有一個(gè)區(qū)塊,這第一個(gè)區(qū)塊,被稱為“創(chuàng)始塊”(Genesis Block)。來,讓我們實(shí)現(xiàn)一個(gè)方法去創(chuàng)建這個(gè)“創(chuàng)始塊”:
func NewGenesisBlock() *Block { return NewBlock(“Genesis Block”, []byte{})
}
現(xiàn)在我們就可以創(chuàng)建一個(gè)函數(shù),用來創(chuàng)建一個(gè)已含有“創(chuàng)始塊”的區(qū)塊鏈了:
func NewBlockchain() *Blockchain { return &Blockchain{[]*Block{NewGenesisBlock()}}
}
讓我們來看看這區(qū)塊鏈?zhǔn)欠衲苡茫?/p>
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()
}
}
輸出結(jié)果是:
Prev. hash:
Data: Genesis Block
Hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168
Prev. hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168
Data: Send 1 BTC to Ivan
Hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1
Prev. hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1
Data: Send 2 more BTC to Ivan
Hash: 561237522bb7fcfbccbc6fe0e98bbbde7427ffe01c6fb223f7562288ca2295d1
(竟然)完工!
結(jié)論
我們創(chuàng)建了一個(gè)極簡的區(qū)塊鏈原型:它只不過是一個(gè)由區(qū)塊構(gòu)成的數(shù)組,每個(gè)區(qū)快鏈接指向上一個(gè)區(qū)塊。當(dāng)然,真正的區(qū)塊鏈遠(yuǎn)比這個(gè)復(fù)雜的多。在我們的區(qū)塊鏈里,添加一個(gè)新區(qū)塊非???,非常容易;但是在真正的區(qū)塊鏈中添加一個(gè)新的區(qū)塊需要更多的工作:在獲得添加區(qū)塊的允許之前要做很繁重的計(jì)算才行(這個(gè)過程被稱為工“作證明機(jī)制”,即,“Proof-of-Work”,POW)。并且,區(qū)塊鏈?zhǔn)且粋€(gè)沒有主權(quán)的分布式的數(shù)據(jù)庫。因此,任何一個(gè)新的區(qū)塊在被加入之前,必須經(jīng)過網(wǎng)絡(luò)中其它參與者的確認(rèn)與允許(這個(gè)機(jī)制被稱為“共識機(jī)制”,“Consensus”)…… 還有,我們的區(qū)塊鏈里,還沒有任何交易記錄呢!
評論
查看更多