廢話不多說,開始跟我用golang搭建個迷你區塊鍊:
首先,引入包:
package main
import (
"bytes"
"crypto/sha256"
"encoding/binary"
"fmt"
"math"
"math/big"
"time"
)
設定一些常量,工作量證明難度系數dif,搜尋上界INT64_MAX:
const (
dif = 20
INT64_MAX = math.MaxInt64
)
然後我們設計一個簡單的區塊體和區塊鍊體,每個區塊呢有前個區塊哈希,本區塊哈希,資料,鍊長,時間戳和随機數:
type Block struct {
PrevHash []byte
Hash []byte
Data string
Height int64
Timestamp int64
Nonce int
}
type BlockChain struct {
Blocks []Block
}
實作一段工作量證明函數,這個工作量證明呢以後聊共識算法會細講的,也就是這裡實作了不可篡改(reigns最近被raft血虐的,TAT):
func IntToHex(num int64) []byte {
buff := new(bytes.Buffer)
err := binary.Write(buff, binary.BigEndian, num)
if err != nil {
panic(err)
}
return buff.Bytes()
}
func ProofOfWork(b Block, dif int) ([]byte, int) {
target := big.NewInt(1)
target.Lsh(target, uint(256-dif))
nonce := 0
for ; nonce < INT64_MAX; nonce++ {
check := bytes.Join(
[][]byte{b.PrevHash,
[]byte(b.Data),
IntToHex(b.Height),
IntToHex(b.Timestamp),
IntToHex(int64(nonce))},
[]byte{})
hash := sha256.Sum256(check)
var hashInt big.Int
hashInt.SetBytes(hash[:])
if hashInt.Cmp(target) == -1 {
return hash[:], nonce
}
}
return []byte(""), nonce
}
然後呢這段函數實作生成創世塊,也就是鍊頭啦:
func GenesisBlock(data string) BlockChain {
var bc BlockChain
bc.Blocks = make([]Block, 1)
bc.Blocks[0] = Block{
PrevHash: []byte(""),
Data: data,
Height: 1,
Timestamp: time.Now().Unix(),
}
bc.Blocks[0].Hash, bc.Blocks[0].Nonce = ProofOfWork(bc.Blocks[0], dif)
return bc
}
這段呢是生成新的區塊,也就是俗稱的挖礦,當然了真實的挖礦可比這個複雜多了:
func GenerateBlock(bc *BlockChain, data string) {
prevBlock := bc.Blocks[len(bc.Blocks)-1]
block := Block{
PrevHash: prevBlock.Hash,
Data: data,
Height: prevBlock.Height + 1,
Timestamp: time.Now().Unix(),
}
block.Hash, block.Nonce = ProofOfWork(block, dif)
bc.Blocks = append(bc.Blocks, block)
}
再寫個列印區塊函數:
func Print(bc BlockChain) {
for _, i := range bc.Blocks {
fmt.Printf("PrevHash: %x\n", i.PrevHash)
fmt.Printf("Hash: %x\n", i.Hash)
fmt.Println("Block's Data: ", i.Data)
fmt.Println("Current Height: ", i.Height)
fmt.Println("Timestamp: ", i.Timestamp)
fmt.Println("Nonce: ", i.Nonce)
}
}
好啦,各個函數都寫完了,不多不少99行

。
寫個main函數看看吧~
來,reigns開始挖礦,先挖個創世塊,給alice轉賬2刀,然後再給alice轉3刀,看看這幾次次操作怎麼記錄在區塊鍊中吧:
func main() {
blockchain := GenesisBlock("i am reigns")
GenerateBlock(&blockchain, "send 2$ to alice")
GenerateBlock(&blockchain, "send 3$ to alice")
Print(blockchain)
}
輸出結果:
由于創世塊沒有前面的區塊,是以他的PrevHash就是空,記錄給alice轉賬2刀的這個區塊,它的PrevHash就是創世塊了,後面的以此類推,得到一個不可篡改鍊。
也可以發現啊,區塊生成并不是一下子執行完成的,三個區塊用了接近7秒鐘,這就是工作量證明算法起的作用了,防止惡意節點不勞而獲,每個新的區塊都需要付出一定計算力才能得到,當然這裡沒有設定很高的困難度(dif = 20),也沒有根據時間動态增加難度,比特币網絡中一般設定的挖礦難度都需要10分鐘左右的,想想2009年的10分鐘和2019的10分鐘,難度提了多少~
怎麼樣,是不是了解了區塊鍊的基本結構呢,當然了成熟的鍊使用的資料存儲結構肯定不會是一個字元串,比如比特币用的是默克爾樹,交易也不會這麼随便就成功,都需要依靠一個叫做智能合約的東東進行限制的。