<golang>简单区块链的实现(带POW挖矿系统)

版权声明:本文为作者原创,如需转载,请注明出处
https://blog.csdn.net/weixin_42940826

前言

在IT界,2018最火的热词相必就是区块链了,C++和GO是目前最适合区块链开发的两种语言,所以咱们学GO的肯定得学一点区块链的知识,但是区块链涉及太多密码学,金融学、p2p网络等知识了,从哪里切入呢,今天我们就从用go实现一条带有模拟挖矿系统的简单区块链。


代码分析

三大模块
代码还是比较简单清晰的,主要有三个模块,Block模块、BlockChain模块、POW模块即挖矿模块。
运行流程

  • 首先从定义一个区块开始,一个区块中包含的信息有区块信息,时间戳,前区块哈希值,现区块哈希值,经过挖矿后得到的哈希碰撞值等等。
  • 接着我们开启一个切片用来存放一个个区块,但是第一个区块是比较特殊的,我们称之为创世区块,在真实的比特币中,第一个区块是由创始人中本聪挖矿所得,没有前哈希值,所以这里我们直接将第一个创世区块创建添加到区块切片中。
  • 然后给到一个添加区块的方法,用户添加区块信息后,经过POW挖矿系统才能成功添加到区块链上。

有了大概的运行流程接下来再来看代码就会轻松很多了。


代码

package main

import (
	"math/big"
	"bytes"
	"encoding/binary"
	"crypto/sha256"
	"fmt"
	"time"
)

//Block模块
type Block struct {
	Version uint64		//版本号
	MerkelRoot []byte	//这是一个默克尔数,这里先默认为空
	TimeStamp string 	//时间戳
	Difficulty uint64	//难度值
	Nonce uint64		//挖矿所找到的随机数
	PrevBlockHash []byte//前区块哈希值
	Data []byte			//插入的数据
	Hash []byte			//当前区块哈希值
}

//给到一个创建新区块的方法
func newBlock(data,prehash []byte)*Block  {
	block:=Block{
		Version:00,
		MerkelRoot:[]byte{},
		TimeStamp:time.Now().Format("2006-15:04:05"),
		Difficulty:difficulty,
		Data:data,
		PrevBlockHash:prehash,
	}
	//需要被挖矿之后才能创建区块,所以调用挖矿函数
	pow:=NewPOW(&block)
	nonce,hash:=pow.Mine()
	//挖矿结束,得到哈希碰撞值
	block.Nonce=nonce
	block.Hash=hash
	return &block
}

//Blockchain模块
const gnnesinfo="1996年9月2日,一代伟人诞生了" 

//给到一个区块链结构
type Blockchain struct {
	blocks []*Block
}
//将创世区块加入区块链,并返回一条可供操作的区块链
func NewblockChain()*Blockchain  {
	var bc Blockchain
	block:=newBlock([]byte(gnnesinfo),[]byte{})
	bc.blocks=append(bc.blocks,block)
	return &bc
}

//给到一个增加区块的方法
func (this *Blockchain)Addblock(data []byte)  {
		lastblockhash:=this.blocks[len(this.blocks)-1].Hash
		block:=newBlock(data,lastblockhash)
		this.blocks=append(this.blocks,block)
}

//遍历,打印所有
func (this *Blockchain)PrintAll()  {
	for i,v:=range this.blocks {
		fmt.Printf("=========区块高度%d=========\n",i)
		fmt.Printf("Version : %d\n", v.Version)
		fmt.Printf("PrevBlockHash : %x\n", v.PrevBlockHash)
		fmt.Printf("Hash : %x\n", v.Hash)
		fmt.Printf("MerkleRoot : %x\n", v.MerkelRoot)
		fmt.Printf("TimeStamp : %s\n", v.TimeStamp)
		fmt.Printf("Difficuty : %d\n", v.Difficulty)
		fmt.Printf("Nonce : %d\n", v.Nonce)
		fmt.Printf("Data : %s\n", v.Data)
	}
}

//pow挖矿模块
const difficulty=24

//POW挖矿结构需要两个参数,一个是所需挖矿的区块,另一个是挖矿成功所需目标数字
type ProofOfWork struct {
	target *big.Int
	block *Block
}

//给到一个根据难度值得到哈希碰撞目标值的函数
func Gettargetint()*big.Int  {
	targetint:=big.NewInt(1)
	targetint.Lsh(targetint,256-difficulty)
	return targetint
}

//创建挖矿的方法
func NewPOW(block *Block)*ProofOfWork  {
	var this ProofOfWork
	this.block=block
	targetint:=Gettargetint()
	this.target=targetint
	return &this
}
//一个用来将uint64转化为字符切片的小函数,方便接下来的转化
func uint2byte(num uint64)[]byte  {
	var buff bytes.Buffer
	binary.Write(&buff,binary.BigEndian,&num)
	return buff.Bytes()
}

//挖矿的准备工作,将其他字符组合起来之后求其哈希值
func (pow *ProofOfWork)PreparetoMine(nonce uint64)[]byte {
	info:=[][]byte{
		pow.block.PrevBlockHash,
		pow.block.Data,
		uint2byte(nonce),
		uint2byte(pow.block.Version),
		uint2byte(pow.block.Difficulty),
		[]byte(pow.block.TimeStamp),
		pow.block.MerkelRoot,
	}
	allinfo:=bytes.Join(info,[]byte{})
	hash:=sha256.Sum256(allinfo)
	return hash[:]
}

//pow挖矿方法,返回两个参数,一个是碰撞成功的数字nonce,另一个是当前区块哈希值
func (pow *ProofOfWork)Mine()(uint64,[]byte)  {
	var nonce uint64
	//nonce从0开始穷举,直到出现哈希值小于给到的目标值
	var hash []byte
	for  {
		hash=pow.PreparetoMine(nonce)
		var hashint big.Int
		hashint.SetBytes(hash)
		//对比哈希值是否小于目标值,小于则成功退出
		if hashint.Cmp(pow.target)==-1 {
			break
		}
		//不小于则继续穷举
		nonce++
	}
	return nonce,hash
}

//调用
func main()  {
bc:=NewblockChain()
bc.Addblock([]byte("welcometo"))
bc.Addblock([]byte("mycsdnblog"))
bc.PrintAll()
}

以上就是一个微型的区块链了,虽然看起来很简单,但是对于理解比特币、区块链还是有不少帮助的。


若是感兴趣或者不屑一顾的大牛们可以戳我的githubGO语言实现比特币系统,是这个小区块链的升级版本,并且将持续维护更新,加入了命令行功能、UTXO转账机制,bolt数据库存储、钱包等,更加接近真正的比特币系统

也欢迎各位给我留言,共同学习: )

猜你喜欢

转载自blog.csdn.net/weixin_42940826/article/details/83934629