区块链第四章 工作量证明

代码结构:
在这里插入图片描述
./coin/main.go

package main
import (
	"core"
	"fmt"
	"strconv"
)

func main(){
	bc:= core.NewBlockchain()

	bc.AddBlock("Send 1 BTC to Ivan")
	bc.AddBlock("Send 2 more BTC to Ivan")

	for _,block :=range bc.Blocks{
		fmt.Printf("Prev. hash:%x\n",block.PrevBlockHash)
		fmt.Printf("Data: %s\n",block.Data)
		fmt.Printf("Hash: %x\n",block.Hash)

		pow:=core.NewProofOfWork(block)
		fmt.Printf("PoW: %s\n",strconv.FormatBool(pow.Validate()))
		fmt.Println()
	}
}



./core/block.go

package core

import "time"

type Block struct{
	Timestamp 		int64 // 区块链创建时间戳
	Data      		[]byte //区块包含的数据
	PrevBlockHash 	[]byte //前一个区块的哈希值
	Hash 	  		[]byte //区块自身的哈希值,用于校验区块数据有效
	Nonce			int    //用于证明工作量
}
func NewBlock(data string,prevBlockHash []byte) *Block{
	//block := &Block{time.Now().Unix(),[]byte(data),prevBlockHash,[]byte{}}
	block := &Block{time.Now().Unix(),[]byte(data),prevBlockHash,[]byte{},0}
	pow := NewProofOfWork(block)
	nonce, hash := pow.Run()

	block.Hash = hash[:]
	block.Nonce = nonce
	return block
}

func NewGenesisBlock() *Block{
	return NewBlock("Genesis Block",[]byte{})
}


.core/blockchain.go

package core

type Blockchain struct{
	Blocks []*Block
}
func (bc *Blockchain)AddBlock(data string){
	prevBlock := bc.Blocks[len(bc.Blocks)-1]
	newBlock := NewBlock(data,prevBlock.Hash)
	bc.Blocks = append(bc.Blocks,newBlock)
}
func NewBlockchain() *Blockchain{
	return &Blockchain{[] *Block{NewGenesisBlock()}}
}

.core/proofofwork.go

package core

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

var (
	maxNonce = math.MaxInt64
)

const targetBits = 20

type ProofOfWork struct{
	block *Block
	target *big.Int
}

//新建一个NewProofOfWork的函数,并返回一个ProofOfWork
func NewProofOfWork(b *Block) *ProofOfWork{
	target := big.NewInt(1)
	target.Lsh(target,uint(256-targetBits)) //对比特位进行移位操作

	pow:= &ProofOfWork{b,target}

	return pow
}
func (pow *ProofOfWork) prepareData(nonce int) []byte{
	data := bytes.Join(
		[][]byte{
			pow.block.PrevBlockHash,
			pow.block.Data,
			IntToHex(pow.block.Timestamp),
			IntToHex(int64(targetBits)),
			IntToHex(int64(nonce)),
		},
		[]byte{},
		)

	return data
}
//运行一个pow
func (pow *ProofOfWork) Run() (int,[]byte){
	var hashInt big.Int
	var hash [32]byte
	nonce := 0

	fmt.Printf("Mining the block containing \"%s\"\n",pow.block.Data)
	for nonce< maxNonce {
		data := pow.prepareData(nonce)

		hash = sha256.Sum256(data)
		fmt.Printf("\r%x",hash)
		hashInt.SetBytes(hash[:])

		if hashInt.Cmp(pow.target) == -1 {
			break
		} else{
			nonce++
		}
	}
	fmt.Print("\n\n")

	return nonce,hash[:]
}

func  (pow *ProofOfWork) Validate() bool {
	var hashInt big.Int

	data := pow.prepareData(pow.block.Nonce)
	hash := sha256.Sum256(data)
	hashInt.SetBytes(hash[:])

	isValid := hashInt.Cmp(pow.target) == -1

	return isValid

}

.core/utils.go

package core

import (
	"bytes"
	"crypto/sha256"
	"encoding/binary"
	"log"
)

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()
}
func DataToHash(data []byte) []byte {
	hash :=sha256.Sum256(data)
	return hash[:]
}

这节课通过输入的语句和设置好的targetbits以及用于证明工作量的nonces来改变生成的Hash字符串。如果targetbits为12,字符串前面就有3个0,如果targetbits为20前面就有5个0。当nounce仅仅相差1时生成的字符串也是不同的。
而哈希校验则是在已知nonces情况下重新带入算法校验,如果结果和已知字符串是相同的,则证明字符串并非伪造。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拔牙不打麻药

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值