创建区块链之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\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{
        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:班长又转给老师一枚比特币
Version: 1
PrevHash:000000d3c28e9cff07f43949c6c6f23444c1beb7494aebb3be5cf74614e77f04
Hash:5bd09d42
TimeStamp:1540398402
MerKel:
Nonce:70302967
IsvALID:true

转载于:https://blog.51cto.com/13914991/2308617

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值