go区块链公链实战0x01ProofOfWork

上一节 我们用go语言实现了区块链的基础结构。今天来实现工作量证明。

区块新属性Nonce

我们先来看一下上节实现的区块结构:

type Block struct {
    //1.区块高度
    Height int64
    //2.上一个区块HAsh
    PrevBlockHash []byte
    //3.交易数据
    Data []byte
    //4.时间戳
    Timestamp int64
    //5.Hash
    Hash []byte
}

我们都知道一个合法区块的诞生其哈希值必须满足指定的条件,比特币采用的是工作量证明。我们这里用go开发的公链也采用POW一致性算法来产生合法性区块。

因此,区块必须不断产生哈希直到满足POW的哈希值产生才能添加到主链上成为合法区块。看看上图区块的基本结构,对于一个区块来说,1-4项属性都市固定,而区块哈希又是由这些属性拼接生成的。所以,要想让区块哈希能不断变化,必须引入一个变量Nonce。

引入Nonce后,就可以通过改变Nonce值来不断产生新的哈希值直到找到满足条件的哈希。

POW难度targetBits

前面用Python简单介绍过区块链中的挖矿概念,一般地,对于256位的哈希值来说设定挖矿条件的方式往往是:前多少位为0。targetBits便是用于指定目标哈希需满足的条件的,即计算的哈希值必须前targetBits位为0.

而对于一个256位的二进制串判断前多少位为0显得很繁琐,我们可以巧妙地通过位移运算将这一判断转换为一个数学问题。eg:

假设哈希值得位数为8,当前targetBits为2(256位亦然,用8举例是位数少便于描述),那么目标哈希值必须满足前两位都是0。从临界情况入手,当第2位不为0时的最小的数为0100 0000,只要小于这个数就是符合条件的哈希值。那么这些数是怎么找到的呢?

1.8位哈希值最小的非0值为0000 0001
2.该值左移8-targetBits位,0000 0001 << 6 = 0100 0000 = target
3.if hash < target 区块合法

Block结构完善

Nonce
type Block struct {
    //1.区块高度
    Height int64
    //2.上一个区块HAsh
    PrevBlockHash []byte
    //3.交易数据
    Data []byte
    //4.时间戳
    Timestamp int64
    //5.Hash
    Hash []byte
    //6.Nonce  符合工作量证明的随机数
    Nonce int64
}
新区块产生
//1.创建新的区块
func NewBlock(data string, height int64, prevBlockHash []byte) *Block {

    //创建区块
    block := &Block{
        Height:        height,
        PrevBlockHash: prevBlockHash,
        Data:          []byte(data),
        Timestamp:     time.Now().Unix(),
        Hash:          nil,
        Nonce:         0}

    //调用工作量证明返回有效的Hash
    pow := NewProofOfWork(block)
    hash, nonce := pow.Run()
    block.Hash = hash[:]
    block.Nonce = nonce

    fmt.Printf("\r%d-%x\n", nonce, hash)

    return block
}

ProofOfWork

基本结构
//期望计算的Hash值前面至少要有16个零
const targetBits = 16

type ProofOfWork struct {
    //求工作量的block
    Block *Block
    //工作量难度 big.Int大数存储
    target *big.Int
}
创建新的POW对象
//创建新的工作量证明对象
func NewProofOfWork(block *Block) *ProofOfWork {

    /**
    target计算方式  假设:Hash为8位,targetBit为2位
    eg:0000 0001(8位的Hash)
    1.8-2 = 6 将上值左移6位
    2.0000 0001 << 6 = 0100 0000 = target
    3.只要计算的Hash满足 :hash < target,便是符合POW的哈希值
    */

    //1.创建一个初始值为1的target
    target := big.NewInt(1)
    //2.左移bits(Hash) - targetBit 位
    target = target.Lsh(target, 256-targetBits)

    return &ProofOfWork{block, target}
}
哈希值的预选值
//拼接区块属性,返回字节数组
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)),
            IntToHex(int64(pow.Block.Height)),
        },
        []byte{},
    )

    return data
}
区块有效性验证
//判断当前区块是否有效
func (proofOfWork *ProofOfWork) IsValid() bool  {

    //比较当前区块哈希值与目标哈希值
    var hashInt big.Int
    hashInt.SetBytes(proofOfWork.Block.Hash)

    if proofOfWork.target.Cmp(&hashInt) == 1 {

        return true
    }

    return false
}
挖矿(产生有效的哈希值)
//运行工作量证明
func (proofOfWork *ProofOfWork) Run() ([]byte, int64) {

    //1.将Block属性拼接成字节数组

    //2.生成hash
    //3.判断Hash值有效性,如果满足条件跳出循环

    //用于寻找目标hash值的随机数
    nonce := 0
    //存储新生成的Hash值
    var hashInt big.Int
    var hash [32]byte

    for {
        //准备数据
        dataBytes := proofOfWork.prepareData(nonce)
        //生成Hash
        hash = sha256.Sum256(dataBytes)

        //\r将当前打印行覆盖
        //fmt.Printf("\r%x", hash)
        //存储Hash到hashInt
        hashInt.SetBytes(hash[:])
        //验证Hash
        if proofOfWork.target.Cmp(&hashInt) == 1 {

            break
        }
        nonce++
    }

    return hash[:], int64(nonce)
}

POW测试


package main

import (
    "chaors.com/LearnGo/publicChaorsChain/part2-ProofOfWork-Prototype/BLC"
    "fmt"
)

func main() {

    //genesisBlock := BLC.CreateGenesisBlock("Genenis Block")
    //创建带有创世区块的区块链
    blockchain := BLC.CreateBlockchainWithGensisBlock()
    //添加一个新区快
    blockchain.AddBlockToBlockchain("first Block",
        blockchain.Blocks[len(blockchain.Blocks)-1].Height,
        blockchain.Blocks[len(blockchain.Blocks)-1].Hash)
    blockchain.AddBlockToBlockchain("second Block",
        blockchain.Blocks[len(blockchain.Blocks)-1].Height,
        blockchain.Blocks[len(blockchain.Blocks)-1].Hash)
    blockchain.AddBlockToBlockchain("third Block",
        blockchain.Blocks[len(blockchain.Blocks)-1].Height,
        blockchain.Blocks[len(blockchain.Blocks)-1].Hash)
    fmt.Println(blockchain)
}

运行后,consle会不断打印计算出的Hash值,直到计算出的Hash值满足条件。当我们调整POW难度targetBits,会发现计算的时间有所改变。targetBits越大,挖矿难度越大,新区快产生的时间也就越久。

源代码在这,喜欢的朋友记得给个小star,或者fork.也欢迎大家一起探讨区块链相关知识,一起进步!

.
.
.
.

互联网颠覆世界,区块链颠覆互联网!

---------------------------------------------20180623 18:13
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容

  • 一、快速术语检索 比特币地址:(例如:1DSrfJdB2AnWaFNgSbv3MZC2m74996JafV)由一串...
    不如假如阅读 15,959评论 4 87
  • 简介 不管你们知不知道以太坊(Ethereum blockchain)是什么,但是你们大概都听说过以太坊。最近在新...
    Lilymoana阅读 3,892评论 1 22
  • 以前阳光的我,也有小小的心情。
    余念一生阅读 233评论 7 8
  • 让你病的人,给不了你药;给你药的人,舍不得你病 走错了路,要记得回头;爱错了人,要懂得放手。人心都是相对的,以真换...
    毅自由阅读 182评论 0 0
  • 1. 相对于其他嘻嘻哈哈,快乐幸福的孩子来说,啊能是不幸的。 很不幸。天生又聋又哑,有点智障。 但他也就那么活着。...
    娱情饭桶说阅读 557评论 7 24