区块链,工作证明(pow)代码+原理golang版剖析

author author     2022-10-26     464

关键词:

介绍

在之前的文章中,我们构建了一个非常简单的数据结构,这是块链数据库的本质。 而且我们可以用它们之间的链式关系向它添加区块:每个区块与前一个链接。 唉,然而在现实中添加一个区块添加到链是艰巨的工作。

工作证明

块链的一个关键思想是,必须通过工作证明才能将数据放入其中。这是一个艰巨的工作,使块链安全和一致。此外,这笔辛苦的工作也得到了奖励(这是人们获得采矿硬币的方式)。

这种机制与现实生活中的机制非常相似:人们必须工作获酬劳励并维持生命。在网络中,网络的一些参与者(矿工)努力维持网络,为其添加新的块,并为他们的工作获得奖励。作为其工作的结果,块以安全的方式并入到块链中,这保持了整个块链数据库的稳定性。值得注意的是,完成工作的人必须证明这一点。

这个整体“努力工作和证明工作价值”机制被称为工作证明。这很难因为它需要很多的计算能力:即使是高性能的计算机也不能很快的完成。此外,这项工作的难度不时增加,以保持新的块率每小时大约6个块。在比特币,这样的工作的目标是找到一个块的哈希,满足一些要求。这是散列,作为证明。因此,找到证据是实际工作。

最后要注意的事情。工作证明算法必须满足要求:做完工作不易完成,证明工作容易完成。证明通常交给非工作者,所以对他们来说,验证它不应该花太多的时间。

哈希算法加密

在本文中,我们将讨论哈希值。 如果你熟悉这个概念,你可以跳过这个部分。

哈希是获取指定数据的哈希值的过程。 哈希值是对其计算的数据的唯一表示。 哈希函数是一个获取任意大小的数据并产生固定大小的哈希的函数。 以下是哈希的一些主要功能:

  • 原始数据无法从哈希值恢复。 因此,散列不是加密。

  • 数据只能有一个哈希值,散列是唯一的。

  • 更改输入数据中的一个字节将导致完全不同的散列。

技术分享图片

哈希函数被广泛用于检查数据的一致性。在区块链中,使用哈希来保证块的一致性。 哈希算法的输入数据包含前一个块的哈希值,从而使得已经生成的链难以修改之前产生的区块(或至少相当困难):必须重新计算其后的所有块的哈希值。

哈希现金 、 Hashcash

比特币使用Hashcash,哈希现金的发明最初是为防止电子邮件垃圾邮件而开发的。它可以分为以下几个步骤:

  1. 获取公开的数据(在电子邮件的情况下,它是接收者的电子邮件地址;在比特币的情况下,它是块标题)。

  2. 添加一个计数器。计数器从0开始。

  3. 获取数据+计数器组合的散列。

  4. 检查哈希值是否符合要求。

    1. 如果满足要求,结束过程。

    2. 如果不满足要求,增加计数器并重复步骤3和4。

因此,这是一个强力算法:您更改计数器,计算一个新的哈希,检查它,增加计数器,计算哈希等。这就是为什么它在计算上是昂贵的。

现在让我们看看一个哈希必须满足的要求。在原来的Hashcash实现中“哈希的前20位必须是零”。然而在比特币中,哈希要求是不时进行调整的,因为尽管计算能力随着时间的推移而增加,越来越多的矿工加入网络,因此设计必须每10分钟生成一个块

为了演示这个算法,我从前面的例子中获取了数据(“我喜欢甜甜圈”),并发现一个以0个零字节开头的哈希:

编写代码

程序员小提醒:go和python都是不用加分号的语言

好的,我们完成了理论,让我们编写代码! 首先,我们来定义挖掘的难度:

const targetBits = 24

In Bitcoin, “target bits” is the block header storing the difficulty at which the block was mined. We won’t implement a target adjusting algorithm, for now, so we can just define the difficulty as a global constant.

24 is an arbitrary number, our goal is to have a target that takes less than 256 bits in memory. And we want the difference to be significant enough, but not too big, because the bigger the difference the more difficult it’s to find a proper hash.

在比特币中,“目标位(target bit)”是存储块被挖掘的困难的块头。 我们现在不会实现目标调整算法,所以我们可以将难度定义为全局常数

24是一个任意数字,我们的目标是在内存中占用少于256位的目标。 而且我们希望差异足够大,但不要太大,因为差异越大,找到合适的哈希越难。

type ProofOfWork struct 
    block  *Block 
    target *big.Int //定义目标位


func NewProofOfWork(b *Block) *ProofOfWork 
    target := big.NewInt(1)
    target.Lsh(target, uint(256-targetBits))  //左移256个 target bits位

    pow := &ProofOfWorkb, target

    return pow

这里创建保存指向块的指针的工作证明结构和指向目标的指针。 “目标”是上一段所述要求的另一个名称。 我们使用一个大整数,因为我们将哈希与目标进行比较:我们将哈希转换为一个大整数,并检查它是否小于目标。

big: https://golang.org/pkg/math/big/

在新的工作证明的函数中,我们初始化一个值为1的big.Int,并将其左移256个 - targetBits位。 256是SHA-256哈希的长度,以比特为单位,它是我们要使用的SHA-256散列算法。 目标的十六进制表示为:

0x10000000000000000000000000000000000000000000000000000000000

它在内存中占用29个字节。 这是与以前的例子中的哈希的比较:

0fac49161af82ed938add1d8725835cc123a1a87b1b196488360e58d4bfb51e3
0000010000000000000000000000000000000000000000000000000000000000
0000008b0f41ec78bab747864db66bcb9fb89920ee75f43fdaaeb5544f7f76ca

第一个哈希(以“我喜欢甜甜圈”计算)大于目标,因此它不是有效的工作证明。 第二个哈希(以“我喜欢甜甜圈ca07ca”计算)小于目标,因此这是一个有效的证明。

您可以将目标视为范围的上限:如果数字(哈希)低于边界,则它是有效的,反之亦然。 降低边界将导致有效数量减少,因此找到有效数量所需的工作更加困难。

现在,对数据进行哈希处理。

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

我们只是将块区域与目标和随机数合并。 nonce这里是从上面的Hashcash描述的计数器,这是加密术语。

好的,所有的准备工作都完成了,我们来实现PoW算法的核心:

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) // SHA-256加密
        fmt.Printf("\r%x", hash)
        hashInt.SetBytes(hash[:])  // 讲hash转换成Big Integer

        if hashInt.Cmp(pow.target) == -1 
            break
         else 
            nonce++
        
    
    fmt.Print("\n\n")

    return nonce, hash[:]

首先,我们初始化变量:hashInt是哈希的整数表示; nonce是柜台。 接下来,我们运行一个“无限”循环:它受限于maxNonce,它等于math.MaxInt64; 这样做是为了避免可能的随机数溢出。 虽然我们的PoW实施的难度太低,以至于防止溢出,但最好是进行此检查,以防万一。

在循环中我们:

  • 准备数据

  • 用SHA-256进行哈希。

  • 将散列转换为大整数。

  • 将整数与目标进行比较。

现在我们可以删除BlockSetHash方法并修改NewBlock函数:

func NewBlock(data string, prevBlockHash []byte) *Block 
    block := &Blocktime.Now().Unix(), []byte(data), prevBlockHash, []byte, 0
    pow := NewProofOfWork(block)
    nonce, hash := pow.Run()

    block.Hash = hash[:]
    block.Nonce = nonce

    return block

Here you can see that nonce is saved as a Block property. This is necessary because nonce is required to verify a proof. The Blockstructure now looks so:

type Block struct 
    Timestamp     int64
    Data          []byte
    PrevBlockHash []byte
    Hash          []byte
    Nonce         int

验证工作证明

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

主函数代代码再次检查

func main() 
    ...

    for _, block := range bc.blocks 
        ...
        pow := NewProofOfWork(block)
        fmt.Printf("PoW: %s\n", strconv.FormatBool(pow.Validate()))
        fmt.Println()
    

结论

我们的块链是一个更接近其实际架构的一步:添加块现在需要努力工作,因此挖掘是可能的。 但是它仍然缺乏一些关键的特征:块链数据库不是持久的,没有钱包,地址,交易,没有共识机制。 所有这些我们将在以后的文章中实现的,现在,开采开采!


创建区块链之v2实现pow(proofofwork工作量证明)(代码片段)

block.gopackagemainimport("time")//定义块结构typeBlockstructVersionint64PrevBlockHash[]byteHash[]byteTimeStampint64TargetBitsint64Nonceint64MerKelRoot[]byteData[]byte//设定创建块的方法funcNewBlock(datastring,pre 查看详情

区块链实现之pow分析(代码片段)

本代码的全部实现已在github上面同步开源,项目地址:linkPoW算法介绍工作量证明(ProofOfWork,简称POW),简单理解就是一份证明,用来确认你做过一定量的工作。监测工作的整个过程通常是极为低效的,而通... 查看详情

区块链技术与应用实验报告(实验八)(代码片段)

文章目录区块链技术与应用实验报告(实验八)关于作者作者介绍一、实验目的及要求二、实验原理简介三、实验环境四、实验步骤1.运行Goland界面2.实现区块的结构总结区块链技术与应用实验报告(实验八)关于作者作者介绍🍊... 查看详情

golang区块链开发002-初始化区块链与pow挖矿实现

目录:一.初始化区块链1.代码结构2.定义区块结构与方法3.定义区块链结构与方法4.帮助库代码5.测试生成区块与初始化区块链6.测试代码二.POW挖矿实现1.代码结构2.定义pow算法实现3.修改区块的生成方式(从自定义到挖矿)4.测试代码... 查看详情

工作量证明和挖矿(代码片段)

...难易度验证测试小结概览本章节我们将会在我们的玩具版区块链的基础上加入工作量证明(POW)的支持。在第一章节的版本中,任何人都都可以在没有任何工作量证明的情况下添加一个区块到区块链中。当我们引入工作量证明机制... 查看详情

区块链技术——工作量证明(代码片段)

...明**挖矿(计算or工作)**的结果会作为数据加入区块链成为一个区块,完成这个**工作**的人也会获得奖励(即挖矿获得比特币)。所以**挖矿**的过程是一种多劳多得的按劳分配模式,算力高, 查看详情

初识区块链

工作量证明(proofofwork)  区块链的一个关键是,为了保证安全稳定,要给它加一个门槛:即参与者想创建区块并加入区块链,必须证明自己完成了非常困难的工作,这就是"工作量证明",简称POW。可以理解为POW用于保持区块... 查看详情

经典共识pow的原理及实现(代码片段)

...用在防止拒绝服务攻击以及过滤垃圾邮件,现在成为区块链公链中最常见也是最有效的共识算法之一,当下最流行的比特币、以太坊等公链目前均使用PoW共识。​PoW是通过对一个复杂难题的求解,来保证区块链交易打... 查看详情

区块链实现之pow分析(代码片段)

...;1.建立ProofOfWork类,带有两个属性目标哈希,目标区块2.通过ProofOfWork类进行计算目标区块的哈希,并与目标哈希进行比较。3.若判定目标区块的哈希值小于目标哈希值,则完成工作量证明,进行广播,并上... 查看详情

区块链的共识机制是什么?

当我们讨论区块链的时候,经常会谈到共识机制。那么什么是共识机制?区块链为什么需要共识机制?区块链的共识机制有哪些?了解到这些不同共识机制的原理,才能进一步理解区块链的安全特性和不可篡... 查看详情

区块链入门到实战之区块链–工作量证明(代码片段)

目的:解决艰难的任务,获取记账能力。区块链中,每个人手上都有账本,每个人都可以记账,但怎么能让这些账本的内容保持一致,让大家都认这个账,就需要共识机制。人类社会中,通常的共识机制是,如果某个人能完成某... 查看详情

《区块链100问》第55集:工作量证明机制是什么?

...算约10分钟,才能算出一个满足条件的结果。该结果即“区块头”里包含的随机数。  工作量证明是指,如果矿工找到了一个满足条件的结果,我们便可 查看详情

什么是ethereumfair(ethf/etf)?

要点:1.EthereumFair旨在挽救工作量证明以太坊区块链的最重要特征。它是以太坊区块链的第一个分支,以响应切换到权益证明算法。2.EthereumFair声称保留了工作量证明共识算法,并希望在旧区块链上为矿工建立一个新... 查看详情

pow挖矿算法原理及其在比特币以太坊中的实现

...根据挖矿贡献的有效工作,来决定货币的分配。?比特币区块?  比特币区块由区块头和该区块所包含的交易列表组成。区块头大小为80字节,其构成包括:?  4字节:版本号  32字节:上一个区块的哈希值  32字节:交易... 查看详情

区块链主流共识算法

...迅速,概括起来就是求解难,验证容易。比特币是第一个区块链应用,同时也是最著名的应用之一,它所使用的共识机制就是 查看详情

毕设教程python区块链实现-proofofwork工作量证明共识算法(代码片段)

文章目录0前言1区块链基础1.1比特币内部结构1.2实现的区块链数据结构1.3注意点1.4区块链的核心-工作量证明算法1.4.1拜占庭将军问题1.4.2解决办法1.4.3代码实现2快速实现一个区块链2.1什么是区块链2.2一个完整的快包含什么2.3什么... 查看详情

区块链主流共识算法

...迅速,概括起来就是求解难,验证容易。比特币是第一个区块链应用,同时也是最著名的应用之一,它所使用的共识机制就是P 查看详情

《区块链100问》第54集:区块链的共识机制是什么?

在区块链系统当中,没有一个像银行一样的中心化记账机构,保证每一笔交易在所有记账节点上的一致性,即让全网达成共识至关重要。共识机制解决的就是这个问题。  目前主要的共识机制有工作量证明机制PoW和权益证明机... 查看详情