简易区块链的搭建(2)——工作量证明

这篇具有很好参考价值的文章主要介绍了简易区块链的搭建(2)——工作量证明。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.原理与补充知识

1.big.Int 的一些常见方法和属性:

  • SetInt64(x int64):将一个 int64 类型的整数赋值给 big.Int

  • SetString(s string, base int):将一个字符串表示的整数按照指定的进制转换为 big.Int

  • SetBytes(x )(s string):讲一个字节型变量转换成big.Init
  • Add(x, y *big.Int) *big.Int:将两个 big.Int 相加,并返回结果。

  • Sub(x, y *big.Int) *big.Int:将一个 big.Int 减去另一个 big.Int,并返回结果。

  • Mul(x, y *big.Int) *big.Int:将两个 big.Int 相乘,并返回结果。

  • Div(x, y, z *big.Int) *big.Int:将一个 big.Int 除以另一个 big.Int,并返回商。

  • Mod(x, y, z *big.Int) *big.Int:将一个 big.Int 对另一个 big.Int 取模,并返回结果。

  • Cmp(y *big.Int) int:将 big.Int 与另一个 big.Int 比较,返回 -1、0 或 1,分别表示小于、等于或大于。

2.Target,nonce和PoW

target本质上是一个和SHA256生成哈希值一样大的整数

特殊的是这个数前几位都是0

我们要求,通过反复枚举nonce,生成一个小于target的数字。这样新产生的区块是成立的(即前面0个数大于等于)

这一过程被称为:工作量证明(PoW算法)

3.SHA256的充足性

sha256生成的哈希值256二进制位,有大约是1.157920892×10^77种可能

而我们要求一个区块链中的区块哈希值不能相同,这个算法产生的值重复的概率几乎为零

哪怕是满足target限制的hash值也是

2.源代码

package main
​
import (
    "bytes"
    "crypto/sha256"
    "encoding/binary"
    "fmt"
    "log"
    "math"
    "math/big"
    "time"
)
​
type Block struct {
    Timestamp int64
    Hash      []byte
    PrevHash  []byte
    Target    []byte 
    Nonce     int64  
    Data      []byte
}
​
const (
    Difficulty = 12
)
​
func (b *Block) GetTarget() []byte {
    target := big.NewInt(1)
    target.Lsh(target, uint(256-Difficulty))
    return target.Bytes()
}
​
func (b *Block) GetBase4Nonce(nonce int64) []byte {
    data := bytes.Join([][]byte{
        ToHexInt(b.Timestamp),
        b.PrevHash,
        ToHexInt(int64(nonce)),
        b.Target,
        b.Data,
    },
        []byte{},
    )
    return data
}
​
func (b *Block) FindNonce() int64 {
    var intHash big.Int
    var intTarget big.Int
    var hash [32]byte
    var nonce int64
    nonce = 0
    intTarget.SetBytes(b.Target)
​
    for nonce < math.MaxInt64 {
        data := b.GetBase4Nonce(nonce)
        hash = sha256.Sum256(data)
        intHash.SetBytes(hash[:])
        if intHash.Cmp(&intTarget) == -1 {
            break
        } else {
            nonce++
        }
    }
    return nonce
}
​
func (b *Block) ValidatePoW() bool {
    var intHash big.Int
    var intTarget big.Int
    var hash [32]byte
    intTarget.SetBytes(b.Target)
    data := b.GetBase4Nonce(b.Nonce)
    hash = sha256.Sum256(data)
    intHash.SetBytes(hash[:])
    if intHash.Cmp(&intTarget) == -1 {
        return true
    }
    return false
}
​
​
func Handle(err error) {
    if err != nil {
        log.Panic(err)
    }
}
​

func ToHexInt(num int64) []byte {
    buff := new(bytes.Buffer)
    err := binary.Write(buff, binary.BigEndian, num)
    Handle(err)
    return buff.Bytes()
}
​
type BlockChain struct {
    Blocks []*Block
}
​
func (bc *BlockChain) AddBlock(data string) {
    newBlock := CreateBlock(bc.Blocks[len(bc.Blocks)-1].Hash, []byte(data))
    bc.Blocks = append(bc.Blocks, newBlock)
}
​
func CreateBlockChain() *BlockChain {
    blockchain := BlockChain{}
    blockchain.Blocks = append(blockchain.Blocks, GenesisBlock())
    return &blockchain
}
​
func (b *Block) SetHash() {
    information := bytes.Join([][]byte{ToHexInt(b.Timestamp), b.PrevHash, b.Target, ToHexInt(b.Nonce), b.Data}, []byte{})
    hash := sha256.Sum256(information)
    b.Hash = hash[:]
}
​
func CreateBlock(prevhash, data []byte) *Block {
    block := Block{time.Now().Unix(), []byte{}, prevhash, []byte{}, 0, data}
    block.Target = block.GetTarget()
    block.Nonce = block.FindNonce()
    block.SetHash()
    return &block
}
​
func GenesisBlock() *Block {
    genesisWords := "Hello, blockchain!"
    return CreateBlock([]byte{}, []byte(genesisWords))
}
​
func main() {
    chain := CreateBlockChain()
    time.Sleep(time.Second)
    chain.AddBlock("After genesis, I have something to say.")
    time.Sleep(time.Second)
    chain.AddBlock("Leo Cao is awesome!")
    time.Sleep(time.Second)
    chain.AddBlock("I can't wait to follow his github!")
    time.Sleep(time.Second)
​
    for _, block := range chain.Blocks {
        fmt.Printf("Timestamp: %d\n", block.Timestamp)
        fmt.Printf("hash: %x\n", block.Hash)
        fmt.Printf("Previous hash: %x\n", block.PrevHash)
        fmt.Printf("nonce: %d\n", block.Nonce)
        fmt.Printf("data: %s\n", block.Data)
        fmt.Println("Proof of Work validation:", block.ValidatePoW())
    }
}

3.分块分析

1.导入包作用

import (
    "bytes"
    "crypto/sha256"
    "encoding/binary"
    "fmt"
    "log"
    "math"
​
    //提供了基本函数 π e登常量 等等计算功能
    //加密货币中的加密算法、共识机制和地址生成算法都可能涉及到数学运算
    "math/big"
    //这个包提供了大数运算的支持
    //加密货币中的椭圆曲线加密算法中经常需要处理大数
    //区块链中的一些计算可能涉及到非常大的数字,比如计算工作量证明的难度目标值
    "time"
)

2.区块包含元素作用

type Block struct {
    Timestamp int64
    Hash      []byte
    PrevHash  []byte
    Target    []byte
    //Target 字段通常用于表示工作量证明(Proof of Work,PoW)算法中的难度目标值。
    //在PoW算法中,矿工需要不断尝试不同的Nonce值,使得区块的哈希值小于或等于Target,以此来满足网络的难度要求
    //区块头中,Target字段表示了当前区块的目标哈希值,矿工需要通过不断调整Nonce值来寻找满足条件的哈希值,从而完成区块的挖掘工作
    Nonce int64
    //Nonce 字段是一个整数值,用于在PoW算法中尝试寻找有效哈希值的过程中进行递增或变化。
    //矿工通过调整Nonce值来产生不同的区块哈希,以尝试满足难度目标。
    Data []byte
}

3.难度

const (
    Difficulty = 12 //设置难度
)

difficulty 反映了矿工找到下一个有效区块的难易程度,难度随区块头目标Hash值(target)的变动而变动,target值越小,难度越大。

4.生成Target

// 在区块结构体(Block)中获取难度目标(Target)的字节数组表示。
func (b *Block) GetTarget() []byte {
    //区块头目标Hash值(target)  target值越小,难度越大
    target := big.NewInt(1)
    //NewInt 大整数对象是一种能够存储任意精度整数的数据类型,用于处理超出普通整数范围的大数字计算
    target.Lsh(target, uint(256-Difficulty))
    //Lsh 方法是左移操作,用于将 target 左移 256-Difficulty 位
    return target.Bytes()
}

如果我把区块链比作 设置挖矿目标和挖矿两个部分,那么这个GetTarget函数实现的是那个部分?

显然是设置难度文章来源地址https://www.toymoban.com/news/detail-857307.html

5.所有数据连成字节

// 将区块的时间戳(Timestamp)、前一个区块的哈希值(PrevHash)、给定的 nonce、挖矿目标值(Target)、以及区块数据(Data)连接成字节返回
func (b *Block) GetBase4Nonce(nonce int64) []byte {
    //(b *Block) 是一个方法接收器(receiver),它定义了一个方法 GetBase4Nonce() 与 Block 结构体相关联
    //指针类型接收器 意味着这个方法可以在 Block 类型的实例上被调用,并且可以修改这个实例的状态
    data := bytes.Join([][]byte{
        ToHexInt(b.Timestamp),
        b.PrevHash,
        ToHexInt(int64(nonce)),
        b.Target,
        b.Data,
    }, //字节切片被放置在一个外部的切片 [][]byte{} 中,以便稍后使用 bytes.Join 函数将它们连接起来,形成一个单独的字节切片
        []byte{},
    )
    return data
}

6.nonce枚举产生合法区块

func (b *Block) FindNonce() int64 {
    var intHash big.Int //哈希值
    //big.Int 是 Go 语言标准库 math/big 中的一个结构体类型,用于表示任意精度的整数
    var intTarget big.Int //要求挖矿大小target的值
    var hash [32]byte
    var nonce int64 //nonce变量,试图通过枚举来实现区块的创建PoW验证合法
    nonce = 0
    intTarget.SetBytes(b.Target)
​
    for nonce < math.MaxInt64 {
        // 将赋值语句放在函数体内部
        data := b.GetBase4Nonce(nonce)
        //调用函数, 传入nonce 返回一个包含所有数据的切片
        hash = sha256.Sum256(data)         //使用SHA-256 计算data切片的 哈希值
        intHash.SetBytes(hash[:])          //将 hash 数组转换为 big.Int 类型,并赋值给 intHash,准备与目标值进行比较
        if intHash.Cmp(&intTarget) == -1 { //big.Int 类型的方法 Cmp() 来比较两个大整数 intHash 和 intTarget 的大小
            break
        } else {
            nonce++
        }
    }
    return nonce
} //这个函数在创建block节点中用到
​

7.判断节点是否合法

// 通过hash和target的比较 判断节点是否合法
func (b *Block) ValidatePoW() bool {
    var intHash big.Int
    var intTarget big.Int
    var hash [32]byte
    intTarget.SetBytes(b.Target)
    //将字节数组 b.Target 的值设置给 intTarget 变量
    data := b.GetBase4Nonce(b.Nonce)
    hash = sha256.Sum256(data)
    intHash.SetBytes(hash[:])
    if intHash.Cmp(&intTarget) == -1 {
        return true
    }
    return false
}

8.处理错误

// 用于处理错误的通用函数 Handle(err error) 作用是在出现错误时,记录错误信息并终止程序的执行
func Handle(err error) {
    if err != nil {
        log.Panic(err)
    }
}

运行结果

go run main.go
​
​
Timestamp: 1711788684
hash: d21ec302d0aa322a933947b2020419e054627dbb0bf074d56deb42b862abedcb
Previous hash: 
nonce: 14124
data: Hello, blockchain!
Proof of Work validation: true
Timestamp: 1711788685
hash: 6f3c44e96d073df10d86ec1f2c609795cffea2d23220e42cec19c8bceedeb96d
Previous hash: d21ec302d0aa322a933947b2020419e054627dbb0bf074d56deb42b862abedcb
nonce: 270
data: This is the second blockchain. 
Proof of Work validation: true
Timestamp: 1711788686
hash: 84b859767f63568e9779ce3bee36d93b28a734b4611bca087b30040fdf158140
Previous hash: 6f3c44e96d073df10d86ec1f2c609795cffea2d23220e42cec19c8bceedeb96d
nonce: 463
data: We added Pow in it
Proof of Work validation: true
Timestamp: 1711788687
hash: 5ac063f26d47122350219560d39c8fff1f0187206244c5e75e1f7ddc0f4d9104
Previous hash: 84b859767f63568e9779ce3bee36d93b28a734b4611bca087b30040fdf158140
nonce: 2248
data: We learn Hash in a new way,more deeply.
Proof of Work validation: true
Timestamp: 1711788688
hash: 33b8604d40d2ac8f097fcb4ed8a76ef72bd37ae2959cec623ba880d1d6489cd5
Previous hash: 5ac063f26d47122350219560d39c8fff1f0187206244c5e75e1f7ddc0f4d9104
nonce: 246
data: Waiting forward to the next Line!
Proof of Work validation: true
​

到了这里,关于简易区块链的搭建(2)——工作量证明的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 竞赛python区块链实现 - proof of work工作量证明共识算法

    🔥 优质竞赛项目系列,今天要分享的是 python区块链实现 - proof of work工作量证明共识算法 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-senior/postgraduate 学长以比特币的结构向大家详解区块链的组成部分 previous hash

    2024年02月05日
    浏览(52)
  • 区块链中怎么惩罚虚假信息的矿工,工作量证明POW,共识算法

    目录 区块链中怎么惩罚虚假信息的矿工 工作量证明POW 什么是工作量证明? 现在出现了另一个问题:如果其他人偷看了小明的答案并且抢答了怎么办?  为什么区块可以安全广播? 共识算法 小结 1. 共识机制惩罚:矿工通过提交多个区块的作弊行为,扣除该矿工的所有抵押币

    2024年02月11日
    浏览(40)
  • 竞赛保研 python区块链实现 - proof of work工作量证明共识算法

    🔥 优质竞赛项目系列,今天要分享的是 python区块链实现 - proof of work工作量证明共识算法 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-senior/postgraduate 学长以比特币的结构向大家详解区块链的组成部分 previous hash

    2024年02月04日
    浏览(46)
  • 【毕设教程】python区块链实现 - proof of work工作量证明共识算法

    Hi,大家好,这里是丹成学长,今天向同学们介绍如何构建一个区块链系统作为毕设,区块链的原理 🧿 选题指导, 项目分享: https://gitee.com/dancheng-senior/project-sharing-1/blob/master/%E6%AF%95%E8%AE%BE%E6%8C%87%E5%AF%BC/README.md 学长以比特币的结构向大家详解区块链的组成部分 previous hash(前

    2024年01月21日
    浏览(46)
  • 挑战杯 python区块链实现 - proof of work工作量证明共识算法

    🔥 优质竞赛项目系列,今天要分享的是 python区块链实现 - proof of work工作量证明共识算法 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-senior/postgraduate 学长以比特币的结构向大家详解区块链的组成部分 previous hash

    2024年02月21日
    浏览(61)
  • 计算机竞赛python区块链实现 - proof of work工作量证明共识算法

    🔥 优质竞赛项目系列,今天要分享的是 python区块链实现 - proof of work工作量证明共识算法 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-senior/postgraduate 学长以比特币的结构向大家详解区块链的组成部分 previous hash

    2024年02月05日
    浏览(55)
  • 互联网加竞赛 python区块链实现 - proof of work工作量证明共识算法

    🔥 优质竞赛项目系列,今天要分享的是 python区块链实现 - proof of work工作量证明共识算法 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-senior/postgraduate 学长以比特币的结构向大家详解区块链的组成部分 previous hash

    2024年02月04日
    浏览(44)
  • eth入门之工作量证明 (POW)

    文档:工作量证明 (PoW) | ethereum.org 以太坊目前使用的共识协议被称为工作量证明 (PoW)。 这允许以太坊网络的节点就以太坊区块链上记录的所有信息的状态达成共识,并防止经济攻击。 接下来一年,工作量证明将被逐步淘汰,这有利于权益证明 (PoS) 的发展。 向权益证明 (Po

    2024年02月06日
    浏览(46)
  • 工作量证明在验证码中的实际应用

    工作量证明(Proof-of-Work,以下简称“PoW”)在维基百科的介绍中指一般要求用户进行一些耗时适当的复杂运算,并且答案能被服务方快速验算,以此耗用的时间、设备与能源做为担保成本,以确保服务与资源是被真正的需求所使用。 在实际生活中可以例举为:学生进行考试

    2024年01月15日
    浏览(82)
  • sass变量+函数,简化代码工作量

    2024年02月08日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包