Objective
On the basis of the previous "golang-Blockchain learning 01", we have increased our blockchain workload proof.
Knowledge points
1, Blockchain proofofwork (proof of workload) concept, because everyone wants to generate blocks to get rewards, for the sake of fairness, we stipulate that to successfully generate a block must complete the task of the specified difficulty. That is, whoever completes the task with the specified difficulty will successfully generate a chunk. First set aside an egg, combined with an example of the workload proof will be summarized at the end of the text.
Golang to achieve a simple workload proof
1, define a workload difficulty. For example, the hash value of the required chunk must be 0 in front of the five bits. That is, hash similar: 00000xxxxxxxxxxx style.
2, add a nonce variable in the block structure, by constantly modifying the value of the nonce, constantly calculate the entire area of the hash value, until the above requirements can be met.
3. code example
Create a Proofofwork.go file. Define a structure for proof of work
type ProofOfWork struct { block *Block // 即将生成的区块对象 target *big.Int //生成区块的难度}
Create an instantiated proof of work structure.
const targetBits = 20func NewProofOfWork(b *Block) *ProofOfWork { target := big.NewInt(1) //难度:target=10的18次方(即要求计算出的hash值小于这个target) target.Lsh(target, uint(256-targetBits)) pow := &ProofOfWork{b, target} return pow}
Algorithm for calculating hash value
func (pow *ProofOfWork) Run() (int, []byte) { var hashInt big.Int var hash [32]byte nonce := 0// 从0自增 fmt.Printf("Mining the block containing \"%s\"\n", pow.block.Data) // 循环从nonce=0一直计算到nonce=2的64次方的值,知道算出符合要求的hash值 for nonce < maxNonce { // 准备计算hash的数据 data := pow.prepareData(nonce) hash = sha256.Sum256(data)// 计算hash fmt.Printf("\r%x", hash) hashInt.SetBytes(hash[:]) // 难度证明 if hashInt.Cmp(pow.target) == -1 { break// 符合 } else { nonce++// 不符合继续计算 } } fmt.Printf("\n\n") return nonce, hash[:]}
Preparing data
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}
Attachment
Formula on the code. List of all code files.
/lession02/src/coin/main.go
package mainimport ( "fmt" "core" "strconv")func main() {fmt.Printf("%d\n",uint(256-20)) bc := core.NewBlockChain() bc.AddBlock("send 1 btc to Ivan") bc.AddBlock("send 2 btc to Ivan") for _, block := range bc.Blocks { fmt.Printf("PrevBlockHash:%x\n", block.PrevBlockHash) fmt.Printf("Data:%s\n", block.Data) fmt.Printf("Hash:%x\n", block.Hash) fmt.Printf("TimeStamp:%d\n", block.TimeStamp) fmt.Printf("Nonce:%d\n", block.Nonce) pow := core.NewProofOfWork(block) fmt.Printf("Pow is %s\n", strconv.FormatBool(pow.Validate())) println() }}
/lession02/src/core/block.go
package coreimport ( "time" "strconv" "bytes" "crypto/sha256")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{}, 0} pow := NewProofOfWork(block) block.Nonce, block.Hash = pow.Run() return block}func (b *Block) SetHash() { strTimeStamp := []byte(strconv.FormatInt(b.TimeStamp, 10)) headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, strTimeStamp}, []byte{}) hash := sha256.Sum256(headers) b.Hash = hash[:]}func NewGenesisBlock() *Block { return NewBlock("Genesis Block", []byte{})}
/lession02/src/core/blockchain.go
package coretype BlockChain struct { Blocks []*Block}func (bc *BlockChain) AddBlock(data string) { preBlock := bc.Blocks[len(bc.Blocks)-1] newBlock := NewBlock(data, preBlock.Hash) bc.Blocks = append(bc.Blocks, newBlock)}func NewBlockChain() *BlockChain { return &BlockChain{[]*Block{NewGenesisBlock()}}}
/lession02/src/core/proofofwork.go
Package Coreimport ("math" "Math/big" "FMT" "crypto/sha256" "bytes") var (maxnonce = math). MaxInt64) Const Targetbits = 20type proofofwork struct {block *block target *big. Int}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), Inttohe X (Int64 (targetbits)), Inttohex (Int64 (Nonce)),}, []byte{}) return Data}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. Printf ("\ 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}
/lession02/src/core/utils.go
package coreimport ( "bytes" "encoding/binary" "log" "crypto/sha256")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[:]}