博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
区块链初始化与实现POW工作量证明
阅读量:5920 次
发布时间:2019-06-19

本文共 7603 字,大约阅读时间需要 25 分钟。

目录:

一.初始化区块链

1.代码结构

2. 定义区块结构与方法

3. 定义区块链结构与方法

4. 帮助库代码

5. 测试生成区块与初始化区块链

6. 测试代码

二. POW挖矿实现

1.代码结构

2. 定义pow算法实现

3. 修改区块的生成方式(从自定义到挖矿)

4. 测试代码,测试挖矿

5.验证区块有效性

一.初始化区块链

1. 代码结构

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

Block.go :定义区块结构与方法

BlockChain.go :定义区块链结构与方法

help.go :将常用代码块进行封装,形成帮助库

main.go:测试代码

2.定义区块结构与方法

package BLCimport (   "time"   "strconv"   "bytes"   "crypto/sha256")//定义区块type Block struct {   //1.区块高度,也就是区块的编号,第几个区块   Height int64   //2.上一个区块的Hash值   PreBlockHash []byte   //3.交易数据(最终都属于transaction 事务)   Data []byte   //4.创建时间的时间戳   TimeStamp int64   //5.当前区块的Hash值   Hash []byte   //6.Nonce 随机数,用于验证工作量证明   Nonce int64}//定义区块生成Hash的方法func (block *Block) SetHash() {   //1.将Height 转换为字节数组 []byte   heightBytes := IntToHex(block.Height)   //2.将TimeStamp 转换为字节数组 []byte   //2.1 将Int64的TimeStamp 转换成二进制   timeString := strconv.FormatInt(block.TimeStamp, 2)   //2.2 将二进制字符串转成字节数组   timeBytes := []byte(timeString)   //3.拼接所有属性,形成一个二维的byte数组   blockBytes := bytes.Join([][]byte{heightBytes, block.PreBlockHash, block.Data, timeBytes, block.Hash}, []byte{})   //4.生成Hash   hash := sha256.Sum256(blockBytes)   block.Hash = hash[:]}//1. 创建新的区块func NewBlock(data string, height int64, PreBlockHash []byte) *Block {   //创建区块   block := &Block{      height,      PreBlockHash,      []byte(data),      time.Now().Unix(),      nil,      0,   }   //设置Hash   block.SetHash()   return block}//2.生成创世区块func CreateGenesisBlock(data string) *Block {   return NewBlock(data, 1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})}

3.定义区块链与方法

package BLCtype BlockChain struct {   Blocks []*Block //存储有序的区块}func (blc *BlockChain)AddBlockChain(data string,height int64,preHash []byte){   //创建新区块   newBlock := NewBlock(data,height,preHash)   //往链中添加区块   blc.Blocks=append(blc.Blocks,newBlock)}//1.创建带有创世区块的区块链func CreateBlockChainWithGenesisBlock() *BlockChain {   //创建创世区块   genesisBlock := CreateGenesisBlock("Genesis Data..")   //返回区块链对象   return &BlockChain{[]*Block{genesisBlock}}}

4.帮助代码库

package BLCimport (   "bytes"   "encoding/binary"   "log")//将int64转换为字节数组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()}

5.测试代码

package mainimport (   "publicChain/BLC"   "fmt")func main() {   //创建创世区块   blockChain := BLC.CreateBlockChainWithGenesisBlock()   //创建新的区块   blockChain.AddBlockChain("Send $100 to Bruce", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)   blockChain.AddBlockChain("Send $200 to Apple", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)   blockChain.AddBlockChain("Send $300 to Alice", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)   blockChain.AddBlockChain("Send $400 to Bob", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)   fmt.Printf("创建的区块链为:\t%v\n", blockChain)   fmt.Printf("区块链存储的区块为:\t%v\n", blockChain.Blocks)   fmt.Printf("第二个区块的数据信息(交易信息)为:\t%v\n", string(blockChain.Blocks[1].Data))}

结果显示

二. POW挖矿实现

1.代码结构

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

多出的ProofOfWork.go用于实现挖矿

2. 定义pow算法实现

ProofOfWork.go

package BLCimport (   "math/big"   "bytes"   "crypto/sha256"   "fmt"   "time")type ProofOfWork struct {   Block  *Block   //当前要验证的区块   target *big.Int //大数存储,区块难度}//数据拼接,返回字节数组func (pow *ProofOfWork) prePareData(nonce int) []byte {   data := bytes.Join(      [][]byte{         pow.Block.PreBlockHash,         pow.Block.Data,         IntToHex(pow.Block.TimeStamp),         IntToHex(int64(targetBit)),         IntToHex(int64(nonce)),         IntToHex(int64(pow.Block.Height)),      },      []byte{},   )   return data}//256位Hash里面至少要有16个零0000 0000 0000 0000const targetBit = 16func (proofOfWork *ProofOfWork) Run(num int64) ([]byte, int64) {   //3.判断Hash的有效性,如果满足条件循环体   nonce := 0   var hashInt big.Int //存储新生成的hash值   var hash [32]byte   for {      //1. 将Block的属性拼接成字节数组      databytes := proofOfWork.prePareData(nonce)      //2.生成Hash      hash = sha256.Sum256(databytes)      fmt.Printf("挖矿中..%x\n", hash)      //3. 将hash存储至hashInt      hashInt.SetBytes(hash[:])      //4.判断hashInt是否小于Block里面的target      // Cmp compares x and y and returns:      //      //   -1 if x <  y      //    0 if x == y      //   +1 if x >  y      //需要hashInt(y)小于设置的target(x)      if proofOfWork.target.Cmp(&hashInt) == 1 {         //fmt.Println("挖矿成功", hashInt)         fmt.Printf("第%d个区块,挖矿成功:%x\n",num,hash)         fmt.Println(time.Now())         time.Sleep(time.Second * 2)         break      }      nonce ++   }   return hash[:], int64(nonce)}//创建新的工作量证明对象func NewProofOfWork(block *Block) *ProofOfWork {   /*1.创建初始值为1的target   0000 0001   8 - 2   */   target := big.NewInt(1)   //2.左移256-targetBit   target = target.Lsh(target, 256-targetBit)   return &ProofOfWork{block, target}}

3. 修改区块的生成方式(从自定义到挖矿)

Block.go

package BLCimport (   "time")//定义区块type Block struct {   //1.区块高度,也就是区块的编号,第几个区块   Height int64   //2.上一个区块的Hash值   PreBlockHash []byte   //3.交易数据(最终都属于transaction 事务)   Data []byte   //4.创建时间的时间戳   TimeStamp int64   //5.当前区块的Hash值   Hash []byte   //6.Nonce 随机数,用于验证工作量证明   Nonce int64}//1. 创建新的区块func NewBlock(data string, height int64, PreBlockHash []byte) *Block {   //创建区块   block := &Block{      height,      PreBlockHash,      []byte(data),      time.Now().Unix(),      nil,      0,   }   //调用工作量证明的方法,并且返回有效的Hash和Nonce值   //创建pow对象   pow := NewProofOfWork(block)   //挖矿验证   hash, nonce := pow.Run(height)   block.Hash = hash[:]   block.Nonce = nonce   return block}//2.生成创世区块func CreateGenesisBlock(data string) *Block {   return NewBlock(data, 1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})}

4. 测试代码,测试挖矿

main.go

package mainimport (   "publicChain/part2-工作量证明/BLC"   "fmt")func main() {   fmt.Println("开始挖矿")   //创建创世区块   blockChain := BLC.CreateBlockChainWithGenesisBlock()   //创建新的区块   blockChain.AddBlockChain("Send $100 to Bruce", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)   blockChain.AddBlockChain("Send $200 to Apple", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)   blockChain.AddBlockChain("Send $300 to Alice", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)   blockChain.AddBlockChain("Send $400 to Bob", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)   fmt.Printf("创建的区块链为:\t%v\n", blockChain)   fmt.Printf("区块链存储的区块为:\t%v\n", blockChain.Blocks)   fmt.Printf("第二个区块的数据信息(交易信息)为:\t%v\n", string(blockChain.Blocks[1].Data))   fmt.Printf("第二个区块的随机数为:\t%v\n", blockChain.Blocks[1].Nonce)}

测试结果

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

共计对五个区块进行挖矿,结果如上

5.验证区块有效性 

ProofOfWork.go

//判断挖矿得到的区块是否有效func (proofOfWork *ProofOfWork) IsValid() bool {   //1.proofOfWork.Block.Hash   //2.proofOfWork.Target   var hashInt big.Int   hashInt.SetBytes(proofOfWork.Block.Hash)   if proofOfWork.target.Cmp(&hashInt) == 1 {      return true   }   return false}

测试代码:

main.go

//通过POW挖出新的区块blockblock := BLC.NewBlock("Send $500 to Tom", blockChain.Blocks[len(blockChain.Blocks)-1].Height+1, blockChain.Blocks[len(blockChain.Blocks)-1].Hash)//手动将该区块添加至区块链中blockChain.Blocks = append(blockChain.Blocks, block)//创建一个工作量证明对象proofOfWork := BLC.NewProofOfWork(block)//判断该区块是否合法有效fmt.Println(proofOfWork.IsValid())

测试结果:

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1

第六个区块是我们新创建的区块,返回值为true,验证有效

参考资料:

区块链共识算法-POW: https://www.jianshu.com/p/b23cbafbbad2 

转载地址:http://ylnvx.baihongyu.com/

你可能感兴趣的文章
Linux系统启动流程详解
查看>>
通过源码解析 Node.js 中一个 HTTP 请求到响应的历程
查看>>
CodeIgniter的密码处理论
查看>>
Spring Cloud Config服务器
查看>>
测试人员必学的软件快速测试方法(二)
查看>>
Agora iOS SDK-快速入门
查看>>
LeetCode | Copy List with Random Pointer
查看>>
引入间接隔离变化(三)
查看>>
统一沟通-技巧-4-让国内域名提供商“提供”SRV记录
查看>>
cocos2d-x 3.0事件机制及用户输入
查看>>
比亚迪速锐F3专用夏季座套 夏天坐垫 四季坐套
查看>>
C++ 数字转换为string类型
查看>>
取证学习资料DVD
查看>>
Sublime Text 格式化代码快捷键
查看>>
疯狂的 Web 应用开源项目
查看>>
程序员全国不同地区,微信(面试 招聘)群。
查看>>
【干货】界面控件DevExtreme视频教程大汇总!
查看>>
前端重构实践(二) —— 模块化开发
查看>>
ssh 与 locale
查看>>
将Flash 嵌入WPF 程序
查看>>