创建区块链之v2实现pow(ProofOfWork工作量证明)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建区块链之v2实现pow(ProofOfWork工作量证明)相关的知识,希望对你有一定的参考价值。
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
", 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
", 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{
fmt.Println("====block num:", i)
fmt.Printf("Data:%s
", block.Data)
fmt.Println("Version:",block.Version)
fmt.Printf("PrevHash:%x
",block.PrevBlockHash)
fmt.Printf("Hash:%x
",block.TimeStamp)
fmt.Printf("TimeStamp:%d
",block.TimeStamp)
fmt.Printf("MerKel:%x
",block.MerKelRoot)
fmt.Printf("Nonce:%d
",block.Nonce)
//
pow := NewProofOfWork(block)
fmt.Printf("IsvALID:%v
",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:班长又转给老师一枚比特币
Version: 1
PrevHash:000000d3c28e9cff07f43949c6c6f23444c1beb7494aebb3be5cf74614e77f04
Hash:5bd09d42
TimeStamp:1540398402
MerKel:
Nonce:70302967
IsvALID:true
以上是关于创建区块链之v2实现pow(ProofOfWork工作量证明)的主要内容,如果未能解决你的问题,请参考以下文章