Version 2

  1. Define a structural ProofOfWork

    block

The target

  1. Provides a way to create PoW

    NewProofOfWork (parameters)

  2. Provides a method to calculate the hash value

    Run()

  3. Provide a check function

    IsValid()

Directory structure

block.go

package main

import (
   "time"
)

A. Block header: 6 fields b. Block body: The string represents data */
/ / block
type Block struct {
   Version int64   / / version
   PerBlockHash []byte // The hash value of the previous block
   Hash []byte // The hash value of the current block is used to simplify the code
   MerKelRoot []byte  // Meckelgen
   TimeStamp int64  / / time
   Bits int64  / / difficulty value
   Nonce int64 / / random value

/ / block
   Data []byte  // Transaction information
}

/* Provides a method to create blocks NewBlock(parameter) */
func NewBlock(data string ,prevBlockHash []byte) *Block {
   var block Block
   block = Block{
      Version:      2,
      PerBlockHash: prevBlockHash,
      //Hash: []byte{}, // The block does not store the Hash value. The node accepts the block and calculates it independently and stores it locally.
      MerKelRoot:   []byte{},
      TimeStamp:    time.Now().Unix(),
      Bits:         targetBits,
      Nonce:        0,
      Data:         []byte(data),
   }
   // block.sethash () // Fill the Hash
   PoW:= NewProofOfWork(&block)
   nonce , hash :=PoW.Run()
   block.Nonce=nonce
   block.Hash=hash
   return &block
}

/* func (block * block) SetHash() {func Join(s [][]byte, sep []byte) []byte tmp :=[][]byte{ IntToByte(block.Version), block.PerBlockHash, block.MerKelRoot, IntToByte(block.TimeStamp), IntToByte(block.Bits), IntToByte(block.Nonce), } data:= bytes.join (TMP,[]byte{}) // Compute the hash hash := sha256.sum256 (data) block.hash = hash[:] // Variable slice} */


/ / founding block
func NewGensisBlock(a) *Block{
   return NewBlock("Genesis Block!"And []byte{})}Copy the code

blockChain.go

package main


/* 1. Define a BlockChain structure BlockChain Block array */
type BlockChain struct {
   blocks []*Block
}

/* 2. Provide a way to create BlockChain() NewBlockChain() */
func NewBlockChain(a) *BlockChain {
   block := NewGensisBlock()
   return &BlockChain{blocks:[]*Block{block}}  // Create a blockchain with only one element and initialize it
}
/* 3. Provide a method to add blocks AddBlock(parameter) */

func (bc *BlockChain)AddBlock(data string)  {
   PerBlockHash := bc.blocks[len(bc.blocks)- 1].Hash  // The hash of this block is the hash of the previous block
   block := NewBlock(data,PerBlockHash)
   bc.blocks = append(bc.blocks,block)
}
Copy the code

proofOfWork.go

package main

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

/* 1. Define a structure of ProofOfWork target value */
type ProofOfWork struct {
   block *Block
   target *big.Int   / / the target
}
/* 2. Provide a method to create PoW NewProofOfWork(parameter) */
const targetBits = 24 

func NewProofOfWork(block *Block) *ProofOfWork {  // Proof of work
   target := big.NewInt(1)  / / 000... 001
   target.Lsh(target,uint(256-targetBits))  // Move 1 to the left //ox00000010000000.. 00
   pow:=ProofOfWork{
      block:  block,
      target: target,
   }
   return &pow
}

func (pow *ProofOfWork) PrepareData(nonce int64) []byte {
   Func Join(s [][]byte, sep []byte) []byte
   block := pow.block
   tmp :=[][]byte{
      IntToByte(block.Version),
      block.PerBlockHash,
      block.MerKelRoot,
      IntToByte(block.TimeStamp),
      IntToByte(block.Bits),
      IntToByte(block.Nonce),
   }
   data:=bytes.Join(tmp,[]byte{})    // Then calculate the hash
   return data
}

/* 2. Provide a method to calculate the hash value Run() */

func (pow *ProofOfWork)Run(a) (int64And []byte) {
    /* Pseudocode for nonce {hash := sha256(block_data+nonce) if (hash) < pow.target{flag=1}else{flag=0}} return nonce,hash[:] * /
   //1
   //2. Convert the hash value to big.int
   var hash [32]byte
   var nonce int64 = 0
   var hashInt big.Int
   fmt.Println("Start digging!)
   fmt.Printf("Difficulty target hash: %x\n" ,pow.target.Bytes())
   for nonce < math.MaxInt64  {
      data:=pow.PrepareData(nonce)
      hash = sha256.Sum256(data)
      // Cmp compares x and y and returns:
      //
      // -1 if x < y
      // 0 if x == y
      // +1 if x > y
      //
      hashInt.SetBytes(hash[:])
      if hashInt.Cmp(pow.target) == - 1 {
         fmt.Printf("Found ,nonce :%d ,hash :%x \n",nonce,hash)
      }else {
         //fmt.Printf("Not Found ,current nonce :%d ,hash :%x \n",nonce,hash)
         nonce++
      }
   }
   return nonce,hash[:]
}
/* 3. Provide a validation function IsValid() */

func (pow *ProofOfWork)IsValid(a) bool{
   var hashInt big.Int
   data := pow.PrepareData(pow.block.Nonce)
   hash:=sha256.Sum256(data)
   hashInt.SetBytes(hash[:])
   return hashInt.Cmp(pow.target) == - 1  // If it is -1, it is found

}
Copy the code

utils.go

package main

import (
   "bytes"
   "encoding/binary"
   "fmt"
   "os"
)

func IntToByte(num int64) []byte {
   //func Write(w io.Writer, order ByteOrder, data interface{}) error {
   var buffer bytes.Buffer
   err := binary.Write(&buffer, binary.BigEndian, num)
   CheckErr("IntToByte",err)
   return buffer.Bytes()
}

func CheckErr(position string,err error) {
   iferr ! =nil {
      fmt.Println("error ,pos:",position,err)
      os.Exit(1)}}Copy the code

main.go

package main

import "fmt"

func main(a) {
   bc := NewBlockChain()
   bc.AddBlock("A send B 1BTC")
   bc.AddBlock("B send C 1BTC")
   for _,block := range bc.blocks {
      fmt.Printf("Version : %d\n",block.Version)
      fmt.Printf("PerBlockHash : %x\n",block.PerBlockHash)
      fmt.Printf("Hash : %x\n",block.Hash)
      fmt.Printf("MerKelRoot : %x\n",block.MerKelRoot)
      fmt.Printf("TimeStamp : %d\n",block.TimeStamp)
      fmt.Printf("Bits : %d\n",block.Bits)
      fmt.Printf("Nonce : %d\n",block.Nonce)
      fmt.Printf("Data : %s\n",block.Data)
      fmt.Printf("IsVaild : %v\n",NewProofOfWork(block).IsValid())
   }
}
Copy the code

The results of

structure