写在前面:
本文目的:使用go语言,实现简单的区块结构,并通过pow共识算法将区块存储在区块链上,结构如下图
Prehash :上一个区块的hash值,通过它将两个区块串联起来,以后遍历区块也要用到,同时也保证了区块的有效性与安全性 Timestamp:区块产生的时间 Data:区块上的记录,交易 Hash:当前区块的hash 注:这只是一个简单的区块结构,具体结构还要根据区块的作用来定义属性
实现一个区块
定义一个结构体
type Block struct {
//时间戳
Timestame int64
//交易数据
Data []byte
//上一个区块hash
Prehash []byte
//区块hash
Hash []byte
}
创建一个区块
根据文章开头的区块链结构,要创建一个区块需要传入上一个区块的hash值Prehash和交易数据Data,区块Hash需要通过将区块内所有数据通过sha256算法,计算得到
func CreateBlock(data string,preHash []byte)(*Block) {
timestame := time.Now().Unix()
block := &Block{Timestame:timestame,Data:[]byte(data),Prehash:preHash}
//区块hash由timestame,data,prehash值拼接后的值,sha256加密后得到的值
block.SetHash()
return block
}
计算Hash值
func (block *Block) SetHash() {
//时间戳转byte数组
timestameBytes := []byte(strconv.FormatInt(block.Timestame,10))
//将区块转byte数组
blockData := bytes.Join([][]byte{
timestameBytes,
block.Data,
block.Prehash},[]byte{})
//计算hash值
hash := sha256.Sum256(blockData)
block.Hash = hash[:]
}
注:实际上这里的Hash值是需要通过pow共识算法计算的,这里只是为了创建区块,暂时先这么写,下面再添加pow算法
在main()函数中执行下面的代码,创建一个区块
func main() {
var preHash = [32]byte{}
block := BLC.CreateBlock("zhqBlock1",preHash[:])
block.PrintBlock()
}
输出结果:
实现区块链
上面创建区块时,有一个问题就是区块的PreHash,是我手动添加的,这肯定是不对的,但是区块链的第一个区块是没有PreHash的,所以这第一个区块和其他区块相比有些特别,我们称它为创世区块
,创世区块需要特别处理,preHash值设为0
创建创世区块
func CreateGenesisBlock()*Block {
//长度为32bits的byte数组,刚好256位与sha256得到的hash值长度对应
var preHash = [32]byte{}
block := CreateBlock("genesis block",preHash[:])
return block
}
区块链结构体
type Blockchain struct {
//链上所有数据应该是保存到本地数据库中,暂时先用切片简单实现
blocks []*Block
}
创建区块链对象
func CreateGenesisBlockchain()(*Blockchain) {
//创建创世区块
block := CreateGenesisBlock()
//创建区块链
blc := new(Blockchain)
blc.blocks = append(blc.blocks,block)
return blc
}
创建区块链的同时创建了创世区块
向区块链中添加区块:首先要有交易数据Data,其次上一个区块的hash即PreHash。Data是收到的交易数据,PreHash是区块链上最后一个区块的Hash值即blockchain.blocks[len(blockchain.blocks)-1].hash
func (blc *Blockchain) Addblock(data string) {
//获取链上最后一个区块的hash值
lastBlock := blc.blocks[len(blc.blocks)-1]
//将最后一个区块的hash值,传给新区块,做为prehash
block := CreateBlock(data,lastBlock.Hash)
blc.blocks = append(blc.blocks,block)
}
在main()中执行
func main() {
//创建区块链
blc := BLC.CreateGenesisBlockchain()
//添加新区块
blc.Addblock("first block")
//添加新区块
blc.Addblock("second block2")
//打印区块链
blc.PrintBlockchain()
}
运行结果;
结果中可以看到上一个区块的hash与下一个区块的preHash是对应的
添加pow共识算法
首先修改一下Block结构体,新增属性Nonce,挖矿时通过不断累加Nonce值来找到有效的hash值
type Block struct {
//时间戳
Timestame int64
//交易数据
Data []byte
//上一个区块hash
Prehash []byte
//区块hash
Hash []byte
//
Nonce int64
}
设置挖矿难度
const kTargetDifficult = 16
修改SetHash()方法,找到一个有效的hash值
//挖矿
func PandingHash(block *Block) {
for {
//将区块转byte数组
timestameBytes := []byte(strconv.FormatInt(block.Timestame,10))
nonce := []byte(strconv.FormatInt(block.Nonce,10))
blockData := bytes.Join([][]byte{
timestameBytes,
block.Data,
block.Prehash,
nonce},[]byte{})
hash := sha256.Sum256(blockData)
fmt.Printf("\r%x",hash)
//判断hash是否有效
if IsValidHash(hash[:]) {
//找到有效hash,跳出循环
block.Hash = hash[:]
fmt.Println()
break
}else {
//hash值无效,累加nonce,继续挖矿
block.Nonce++
}
}
}
//判断hash是否合法
func IsValidHash(hash []byte)bool {
target := big.NewInt(1)
target.Lsh(target,256-kTargetDifficult)
var hashInt big.Int
hashInt.SetBytes(hash)
if target.Cmp(&hashInt)== 1 {
return true
}
return false
}
运行结果:
今天就到这里,这篇是通过数组维护区块链,下一篇介绍通过BoltDB来维护区块链
下载demo https://github.com/sweetMegan/PubliceChain1