您的位置:首页 > 编程语言 > Go语言

创建区块链之v2实现pow(ProofOfWork工作量证明)

2018-10-25 00:30 771 查看

block.go

package main

import (
"time"
)

//定义块结构
type Block struct{
Version int64
PrevBlockHash []byte
Hash []byte
TimeStamp int64
TargetBits  int64
Nonce int64
MerKelRoot []byte

Data []byte
}

//设定创建块的方法
func NewBlock(data string, prevBlockHash []byte) *Block{
block := &Block{
Version:1,
PrevBlockHash:prevBlockHash,
//Hash:
TimeStamp:time.Now().Unix(),
TargetBits:10,
Nonce:0,
MerKelRoot:[]byte{},
Data:[]byte(data),
}
//block.SetHash() //设置区块的哈希值--->>> v2中来自工作量证明
pow := NewProofOfWork(block)
nonce, hash := pow.Run()
block.Hash = hash
block.Nonce = nonce
return block
}

// 添加哈希值---->> v2中来自pow
//func (block *Block)SetHash(){
//  tmp := [][]byte{
//      //实现int类型转换为byte类型的工具函数
//      IntToByte(block.Version),
//      block.PrevBlockHash,
//      IntToByte(block.TimeStamp),
//      block.MerKelRoot,
//      IntToByte(block.Nonce),
//      block.Data,
//  }
//  //将区块的各个字段链接成一个切片,使用【】byte{}进行链接,目的是避免污染源区块的信息
//  data := bytes.Join(tmp,[]byte{})
//
//  //对区块进行sha256哈希算法,返回值为[32]byte数组,不是切片
//  hash := sha256.Sum256(data)
//  block.Hash = hash[:]//由数组转换为切片
//}

// 创世块的创建,它的钱一个去魁岸的哈希值为空
func NewGenesisBlock() *Block{
return NewBlock("Genesis Block!",[]byte{})
}

blockchain.go

package main

import "os"

//定义区块链条
type  BlockChain struct{
blocks []*Block
}

// 创建区块链,并且添加创世块
func NewBlockChain() *BlockChain{
return &BlockChain{[]*Block{
NewGenesisBlock(),
}}
}

//添加区块
func (bc *BlockChain)AddBlock(data string){
//简单校验
if len(bc.blocks) <= 0 {
os.Exit(1)
}

//根据上一区块,创建新的区块
lastblock := bc.blocks[len(bc.blocks)-1]
prevBlockHash := lastblock.Hash
block := NewBlock(data, prevBlockHash)

//添加到区块链当中
bc.blocks = append(bc.blocks, block)
}

utils

package main

import (
"bytes"
"encoding/binary"
"fmt"
"os"
)

func IntToByte(num int64)[]byte{
var buffer  bytes.Buffer
err := binary.Write(&buffer, binary.BigEndian, num)
//if err != nil{
//  fmt.Println("IntToByte err occur:",err)
//  os.Exit(1)
//}
CheckErr(err)
return buffer.Bytes()
}

func CheckErr(err error){
if err != nil{
fmt.Println("err occur:",err)
os.Exit(1)
}
}

proofOfWork.go

package main

import (
"math/big"
"bytes"
"math"
"crypto/sha256"
"fmt"
)

const targetBits = 24 //假定难度值

type ProofOfWork struct{
block  *Block
targetBit  *big.Int

}

func NewProofOfWork(block *Block) *ProofOfWork{
var IntTarget = big.NewInt(1)   // 假定值
//000000000000000000000000000000001 初始值
//100000000000000000000000000000000 十进制
//000000000100000000000000000000000 十进制
//000001000000000000000000000000000 十六进制 目标哈希值
//0000000a0000000000001234560000000 实际值

IntTarget.Lsh(IntTarget, uint(256- targetBits))
return &ProofOfWork{block,IntTarget}
}

func (pow *ProofOfWork)PrepareRawData(nonce int64) []byte{
block := pow.block //获取需要处理的区块

tmp := [][]byte{
//实现int类型转换为byte类型的工具函数
IntToByte(block.Version),
block.PrevBlockHash,
IntToByte(block.TimeStamp),
block.MerKelRoot,
IntToByte(nonce),

IntToByte(targetBits), //添加难度值
block.Data,
}
//将区块的各个字段链接成一个切片,使用【】byte{}进行链接,目的是避免污染源区块的信息
data := bytes.Join(tmp,[]byte{})

return data
}

func (pow *ProofOfWork)Run()(int64, []byte){

var nonce int64
var hash [32]byte
var HashInt big.Int

fmt.Println("Begin Minng ...")
fmt.Printf("target hash : %x\n", pow.targetBit.Bytes())
for nonce < math.MaxInt64{
data := pow.PrepareRawData(nonce)
hash = sha256.Sum256(data) //取出来后是字符串

HashInt.SetBytes(hash[:]) //将byte值转换为大的数字

// 比较哈希值
if HashInt.Cmp(pow.targetBit) == -1{
fmt.Printf("Found Hash:%x\n", hash)
break
}else{
nonce ++
}
}
return nonce, hash[:]
}

//提供外部校验的方法
func (pow *ProofOfWork)IsValid()bool{
data :=pow.PrepareRawData(pow.block.Nonce)
hash := sha256.Sum256(data)
var IntHash big.Int

IntHash.SetBytes(hash[:])
return  IntHash.Cmp(pow.targetBit) == -1
}

main.go

package main

import "fmt"

func main(){
bc := NewBlockChain()
bc.AddBlock("班长转给老师一枚比特币")
bc.AddBlock("班长又转给老师一枚比特币")

for i, block := range bc.blocks
5b4
{
fmt.Println("====block num:", i)
fmt.Printf("Data:%s\n", block.Data)
fmt.Println("Version:",block.Version)

fmt.Printf("PrevHash:%x\n",block.PrevBlockHash)
fmt.Printf("Hash:%x\n",block.TimeStamp)
fmt.Printf("TimeStamp:%d\n",block.TimeStamp)
fmt.Printf("MerKel:%x\n",block.MerKelRoot)
fmt.Printf("Nonce:%d\n",block.Nonce)
//
pow := NewProofOfWork(block)
fmt.Printf("IsvALID:%v\n",pow.IsValid())
}

}

最终运行的效果如下所示:

Begin Minng ...
target hash : 010000000000000000000000000000000000000000000000000000000000
Found Hash:00000014312c76058b55905dbf9915019c484df5f64b9655d01985e050e16edd
Begin Minng ...
target hash : 010000000000000000000000000000000000000000000000000000000000
Found Hash:000000d3c28e9cff07f43949c6c6f23444c1beb7494aebb3be5cf74614e77f04
Begin Minng ...
target hash : 010000000000000000000000000000000000000000000000000000000000
Found Hash:0000004b9205eab846bcf921c952ea2a91e103a4c37170304c4e1bb85d32d73e
====block num: 0
Data:Genesis Block!
Version: 1
PrevHash:
Hash:5bd09d11
TimeStamp:1540398353
MerKel:
Nonce:26865217
IsvALID:true
====block num: 1
Data:班长转给老师一枚比特币
Version: 1
PrevHash:00000014312c76058b55905dbf9915019c484df5f64b9655d01985e050e16edd
Hash:5bd09d35
TimeStamp:1540398389
MerKel:
Nonce:6908425
IsvALID:true
====block num: 2
Data:班长又转给老师一枚比
2230
特币
Version: 1
PrevHash:000000d3c28e9cff07f43949c6c6f23444c1beb7494aebb3be5cf74614e77f04
Hash:5bd09d42
TimeStamp:1540398402
MerKel:
Nonce:70302967
IsvALID:true
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  go 区块链 pow
相关文章推荐