区块链第四章 工作量证明

代码结构:
在这里插入图片描述
./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情况下重新带入算法校验,如果结果和已知字符串是相同的,则证明字符串并非伪造。

猜你喜欢

转载自blog.csdn.net/weixin_43820665/article/details/108910897