区块链第四章 工作量证明

    科技2022-07-11  95

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

    Processed: 0.051, SQL: 8