定義一個工做量證實的結構ProofOfWork數組
blockapp
目標值ide
提供一個創造PoW的方法函數
NewProofOfWork(參數)區塊鏈
提供一個計算哈希值的方法ui
Run()spa
提供一個校驗函數code
IsValid()blog
結構目錄圖片
block.go
package main import ( "time" ) /* 1.定義一個區塊的結構Block a.區塊頭:6個字段 b.區塊體:字符串表示data */ //區塊 type Block struct { Version int64 //版本 PerBlockHash []byte //前一個區塊的hash值 Hash []byte //當前區塊的hash值,是爲了簡化代碼 MerKelRoot []byte //梅克爾根 TimeStamp int64 //時間抽 Bits int64 //難度值 Nonce int64 //隨機值 //區塊體 Data []byte //交易信息 } /* 提供一個建立區塊的方法 NewBlock(參數) */ func NewBlock(data string ,prevBlockHash []byte) *Block { var block Block block = Block{ Version: 2, PerBlockHash: prevBlockHash, //Hash: []byte{}, //區塊不存儲hash值,節點接受區塊後獨立計算並存儲在本地。 MerKelRoot: []byte{}, TimeStamp: time.Now().Unix(), Bits: targetBits, Nonce: 0, Data: []byte(data), } // block.SetHash() //填充Hash PoW:= NewProofOfWork(&block) nonce , hash :=PoW.Run() block.Nonce=nonce block.Hash=hash return &block } /* func (block *Block) SetHash() { // 源碼裏面是要傳二維切片 func Join(s [][]byte, sep []byte) []byte tmp :=[][]byte{ IntToByte(block.Version), block.PerBlockHash, block.MerKelRoot, IntToByte(block.TimeStamp), IntToByte(block.Bits), IntToByte(block.Nonce), } data:=bytes.Join(tmp,[]byte{}) //以後再計算hash hash := sha256.Sum256(data) block.Hash = hash[:] //變切片 } */ //創始塊 func NewGensisBlock() *Block{ return NewBlock("Genesis Block!",[]byte{}) }
blockChain.go
package main /* 1. 定義一個區塊鏈結構BlockChain Block數組 */ type BlockChain struct { blocks []*Block } /* 2. 提供一個建立BlockChain()的方法 NewBlockChain() */ func NewBlockChain() *BlockChain { block := NewGensisBlock() return &BlockChain{blocks:[]*Block{block}} //建立只有一個元素的區塊鏈,初始化 } /* 3. 提供一個添加區塊的方法 AddBlock(參數) */ func (bc *BlockChain)AddBlock(data string) { PerBlockHash := bc.blocks[len(bc.blocks)-1].Hash //這一個區塊的哈希是前一塊的哈希值 block := NewBlock(data,PerBlockHash) bc.blocks = append(bc.blocks,block) }
proofOfWork.go
package main import ( "bytes" "crypto/sha256" "fmt" "math" "math/big" ) /* 1. 定義一個工做量證實的結構ProofOfWork block 目標值 */ type ProofOfWork struct { block *Block target *big.Int //目標值 } /* 2. 提供一個創造PoW的方法 NewProofOfWork(參數) */ const targetBits = 24 func NewProofOfWork(block *Block) *ProofOfWork { //工做量證實 target := big.NewInt(1) //000....001 target.Lsh(target,uint(256-targetBits)) //將1向左移動 //ox00000010000000..00 pow:=ProofOfWork{ block: block, target: target, } return &pow } func (pow *ProofOfWork) PrepareData(nonce int64) []byte { // 源碼裏面是要傳二維切片 func Join(s [][]byte, sep []byte) []byte block := pow.block tmp :=[][]byte{ IntToByte(block.Version), block.PerBlockHash, block.MerKelRoot, IntToByte(block.TimeStamp), IntToByte(block.Bits), IntToByte(block.Nonce), } data:=bytes.Join(tmp,[]byte{}) //以後再計算hash return data } /* 2. 提供一個計算哈希值的方法 Run() */ func (pow *ProofOfWork)Run() (int64,[]byte) { /*僞代碼 for nonce { hash := sha256(block_data+nonce) if (hash) < pow.target{ flag=1 }else{ flag=0 } } return nonce,hash[:] */ //1.憑藉數據 //2.哈希值轉成big.Int類型 var hash [32]byte var nonce int64 = 0 var hashInt big.Int fmt.Println("開始挖礦了!") fmt.Printf("難度 target hash : %x\n" ,pow.target.Bytes()) for nonce < math.MaxInt64 { data:=pow.PrepareData(nonce) hash = sha256.Sum256(data) // Cmp compares x and y and returns: // // -1 if x < y // 0 if x == y // +1 if x > y // hashInt.SetBytes(hash[:]) if hashInt.Cmp(pow.target) == -1 { fmt.Printf("Found ,nonce :%d ,hash :%x \n",nonce,hash) }else { //fmt.Printf("Not Found ,current nonce :%d ,hash :%x \n",nonce,hash) nonce++ } } return nonce,hash[:] } /* 3. 提供一個校驗函數 IsValid() */ func (pow *ProofOfWork)IsValid() bool{ var hashInt big.Int data := pow.PrepareData(pow.block.Nonce) hash:=sha256.Sum256(data) hashInt.SetBytes(hash[:]) return hashInt.Cmp(pow.target) == -1 //若是是-1就是找到了就是 }
utils.go
package main import ( "bytes" "encoding/binary" "fmt" "os" ) func IntToByte(num int64) []byte { //func Write(w io.Writer, order ByteOrder, data interface{}) error { var buffer bytes.Buffer err := binary.Write(&buffer, binary.BigEndian, num) CheckErr("IntToByte",err) return buffer.Bytes() } func CheckErr(position string,err error) { if err != nil { fmt.Println("error ,pos:",position,err) os.Exit(1) } }
main.go
package main import "fmt" func main() { bc := NewBlockChain() bc.AddBlock("A send B 1BTC") bc.AddBlock("B send C 1BTC") for _,block := range bc.blocks { fmt.Printf("Version : %d\n",block.Version) fmt.Printf("PerBlockHash : %x\n",block.PerBlockHash) fmt.Printf("Hash : %x\n",block.Hash) fmt.Printf("MerKelRoot : %x\n",block.MerKelRoot) fmt.Printf("TimeStamp : %d\n",block.TimeStamp) fmt.Printf("Bits : %d\n",block.Bits) fmt.Printf("Nonce : %d\n",block.Nonce) fmt.Printf("Data : %s\n",block.Data) fmt.Printf("IsVaild : %v\n",NewProofOfWork(block).IsValid()) } }