目錄:
一.初始化區塊鏈
1.代碼結構
2. 定義區塊結構與方法
3. 定義區塊鏈結構與方法
4. 幫助庫代碼
5. 測試生成區塊與初始化區塊鏈
6. 測試代碼
二. POW挖礦實現
1.代碼結構
2. 定義pow算法實現
3. 修改區塊的生成方式(從自定義到挖礦)
4. 測試代碼,測試挖礦
5.驗證區塊有效性
一.初始化區塊鏈
1. 代碼結構

Block.go :定義區塊結構與方法
BlockChain.go :定義區塊鏈結構與方法
help.go :將常用代碼塊進行封裝,形成幫助庫
main.go:測試代碼
2.定義區塊結構與方法
package BLC
import (
"time"
"strconv"
"bytes"
"crypto/sha256"
)
//定義區塊
type Block struct {
//1.區塊高度,也就是區塊的編號,第幾個區塊
Height int64
//2.上一個區塊的Hash值
PreBlockHash []byte
//3.交易數據(最終都屬于transaction 事務)
Data []byte
//4.創建時間的時間戳
TimeStamp int64
//5.當前區塊的Hash值
Hash []byte
//6.Nonce 隨機數,用于驗證工作量證明
Nonce int64
}
//定義區塊生成Hash的方法
func (block *Block) SetHash() {
//1.將Height 轉換為字節數組 []byte
heightBytes := IntToHex(block.Height)
//2.將TimeStamp 轉換為字節數組 []byte
//2.1 將Int64的TimeStamp 轉換成二進制
timeString := strconv.FormatInt(block.TimeStamp, 2)
//2.2 將二進制字符串轉成字節數組
timeBytes := []byte(timeString)
//3.拼接所有屬性,形成一個二維的byte數組
blockBytes := bytes.Join([][]byte{heightBytes, block.PreBlockHash, block.Data, timeBytes, block.Hash}, []byte{})
//4.生成Hash
hash := sha256.Sum256(blockBytes)
block.Hash = hash[:]
}
//1. 創建新的區塊
func NewBlock(data string, height int64, PreBlockHash []byte) *Block {
//創建區塊
block := &Block{
height,
PreBlockHash,
[]byte(data),
time.Now().Unix(),
nil,
0,
}
//設置Hash
block.SetHash()
return block
}
//2.生成創世區塊
func CreateGenesisBlock(data string) *Block {
return NewBlock(data, 1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
}3.定義區塊鏈與方法
package BLC
type BlockChain struct {
Blocks []*Block //存儲有序的區塊
}
func (blc *BlockChain)AddBlockChain(data string,height int64,preHash []byte){
//創建新區塊
newBlock := NewBlock(data,height,preHash)
//往鏈中添加區塊
blc.Blocks=append(blc.Blocks,newBlock)
}
//1.創建帶有創世區塊的區塊鏈
func CreateBlockChainWithGenesisBlock() *BlockChain {
//創建創世區塊
genesisBlock := CreateGenesisBlock("Genesis Data..")
//返回區塊鏈對象
return &BlockChain{[]*Block{genesisBlock}}
}4.幫助代碼庫
package BLC
import (
"bytes"
"encoding/binary"
"log"
)
//將int64轉換為字節數組
func IntToHex(num int64) []byte {
buff := new(bytes.Buffer)
err := binary.Write(buff, binary.BigEndian, num)
if err != nil {
log.Panic(err)
}
return buff.Bytes()
}5.測試代碼
package main
import (
"publicChain/BLC"
"fmt"
)
func main() {
//創建創世區塊
blockChain := BLC.CreateBlockChainWithGenesisBlock()
//創建新的區塊
blockChain.AddBlockChain("Send $100 to Bruce", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)
blockChain.AddBlockChain("Send $200 to Apple", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)
blockChain.AddBlockChain("Send $300 to Alice", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)
blockChain.AddBlockChain("Send $400 to Bob", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)
fmt.Printf("創建的區塊鏈為:\t%v\n", blockChain)
fmt.Printf("區塊鏈存儲的區塊為:\t%v\n", blockChain.Blocks)
fmt.Printf("第二個區塊的數據信息(交易信息)為:\t%v\n", string(blockChain.Blocks[1].Data))
}結果顯示
二. POW挖礦實現
1.代碼結構

多出的ProofOfWork.go用于實現挖礦
2. 定義pow算法實現
ProofOfWork.go
package BLC
import (
"math/big"
"bytes"
"crypto/sha256"
"fmt"
"time"
)
type ProofOfWork struct {
Block *Block //當前要驗證的區塊
target *big.Int //大數存儲,區塊難度
}
//數據拼接,返回字節數組
func (pow *ProofOfWork) prePareData(nonce int) []byte {
data := bytes.Join(
[][]byte{
pow.Block.PreBlockHash,
pow.Block.Data,
IntToHex(pow.Block.TimeStamp),
IntToHex(int64(targetBit)),
IntToHex(int64(nonce)),
IntToHex(int64(pow.Block.Height)),
},
[]byte{},
)
return data
}
//256位Hash里面至少要有16個零0000 0000 0000 0000
const targetBit = 16
func (proofOfWork *ProofOfWork) Run(num int64) ([]byte, int64) {
//3.判斷Hash的有效性,如果滿足條件循環體
nonce := 0
var hashInt big.Int //存儲新生成的hash值
var hash [32]byte
for {
//1. 將Block的屬性拼接成字節數組
databytes := proofOfWork.prePareData(nonce)
//2.生成Hash
hash = sha256.Sum256(databytes)
fmt.Printf("挖礦中..%x\n", hash)
//3. 將hash存儲至hashInt
hashInt.SetBytes(hash[:])
//4.判斷hashInt是否小于Block里面的target
// Cmp compares x and y and returns:
//
// -1 if x < y
// 0 if x == y
// +1 if x > y
//需要hashInt(y)小于設置的target(x)
if proofOfWork.target.Cmp(&hashInt) == 1 {
//fmt.Println("挖礦成功", hashInt)
fmt.Printf("第%d個區塊,挖礦成功:%x\n",num,hash)
fmt.Println(time.Now())
time.Sleep(time.Second * 2)
break
}
nonce ++
}
return hash[:], int64(nonce)
}
//創建新的工作量證明對象
func NewProofOfWork(block *Block) *ProofOfWork {
/*1.創建初始值為1的target
0000 0001
8 - 2
*/
target := big.NewInt(1)
//2.左移256-targetBit
target = target.Lsh(target, 256-targetBit)
return &ProofOfWork{block, target}
}3. 修改區塊的生成方式(從自定義到挖礦)
Block.go
package BLC
import (
"time"
)
//定義區塊
type Block struct {
//1.區塊高度,也就是區塊的編號,第幾個區塊
Height int64
//2.上一個區塊的Hash值
PreBlockHash []byte
//3.交易數據(最終都屬于transaction 事務)
Data []byte
//4.創建時間的時間戳
TimeStamp int64
//5.當前區塊的Hash值
Hash []byte
//6.Nonce 隨機數,用于驗證工作量證明
Nonce int64
}
//1. 創建新的區塊
func NewBlock(data string, height int64, PreBlockHash []byte) *Block {
//創建區塊
block := &Block{
height,
PreBlockHash,
[]byte(data),
time.Now().Unix(),
nil,
0,
}
//調用工作量證明的方法,并且返回有效的Hash和Nonce值
//創建pow對象
pow := NewProofOfWork(block)
//挖礦驗證
hash, nonce := pow.Run(height)
block.Hash = hash[:]
block.Nonce = nonce
return block
}
//2.生成創世區塊
func CreateGenesisBlock(data string) *Block {
return NewBlock(data, 1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
}4. 測試代碼,測試挖礦
main.go
package main
import (
"publicChain/part2-工作量證明/BLC"
"fmt"
)
func main() {
fmt.Println("開始挖礦")
//創建創世區塊
blockChain := BLC.CreateBlockChainWithGenesisBlock()
//創建新的區塊
blockChain.AddBlockChain("Send $100 to Bruce", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)
blockChain.AddBlockChain("Send $200 to Apple", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)
blockChain.AddBlockChain("Send $300 to Alice", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)
blockChain.AddBlockChain("Send $400 to Bob", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)
fmt.Printf("創建的區塊鏈為:\t%v\n", blockChain)
fmt.Printf("區塊鏈存儲的區塊為:\t%v\n", blockChain.Blocks)
fmt.Printf("第二個區塊的數據信息(交易信息)為:\t%v\n", string(blockChain.Blocks[1].Data))
fmt.Printf("第二個區塊的隨機數為:\t%v\n", blockChain.Blocks[1].Nonce)
}測試結果

共計對五個區塊進行挖礦,結果如上
5.驗證區塊有效性
ProofOfWork.go
//判斷挖礦得到的區塊是否有效
func (proofOfWork *ProofOfWork) IsValid() bool {
//1.proofOfWork.Block.Hash
//2.proofOfWork.Target
var hashInt big.Int
hashInt.SetBytes(proofOfWork.Block.Hash)
if proofOfWork.target.Cmp(&hashInt) == 1 {
return true
}
return false
}測試代碼:
main.go
//通過POW挖出新的區塊block
block := BLC.NewBlock("Send $500 to Tom", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)
//手動將該區塊添加至區塊鏈中
blockChain.Blocks = append(blockChain.Blocks, block)
//創建一個工作量證明對象
proofOfWork := BLC.NewProofOfWork(block)
//判斷該區塊是否合法有效
fmt.Println(proofOfWork.IsValid())測試結果:

第六個區塊是我們新創建的區塊,返回值為true,驗證有效
參考資料:
區塊鏈共識算法-POW: https://www.jianshu.com/p/b23cbafbbad2
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。