区块链概念 That You Must Know 第四期(3)

第四期 简介go语言下挖矿难度的代码实现(3)

卡酷少

Wechat:13260325501

经过之前所有的铺垫,这一期我们将对难度的代码实现作出简单演示。(以下是在不考虑近期各机构对于区块存储信息改进的情况下。对于区块信息的调整,有比如“隔离验证”等方法。暂时不了解没有关系,本期并不涉及这点。之后随着学习的深入,我们会一一介绍给大家。)

本期我们将对上期图二中几项信息给出示例,然后代码模拟难度的实现。

区块里的哈希是如何产生的?

  • 如第四期(1)篇里讲到的,每个区块里包含了index,current hash,previous hash,timestamp,data,nounce等信息。current hash,就是将剩下的其他信息拼接成字符串,然后将这个字符串进行哈希的结果。正如上一个区块的当前哈希也是由它之前的区块的这些信息哈希生成的。
  • 其中,nounce作为计算机穷举的随机数,不断变化,形成字符串的变化,产生了不同的哈希值。这个哈希值不断去匹配现阶段的哈希难度。当nounce值取到某数,并使之形成的哈希值匹配上了当前的有效哈希难度,哈希碰撞就成功了。
  • 以下为代码实现

哈希sha256

  • 先给出代码
/*
代码逻辑:
    第一步:导入crypto/sha256库
    第二步:声明字符串
    第三步:sha256.New()创建一个对象
    第四步:将字符串转换为字节数组
    第五步:使用对象调用write方法
    第六步:first.Sum(nil) 返回hash值
*/

package main

import (
    //第1步
    "crypto/sha256"
    "fmt"
    "bytes"
)

func main() {
    //第2步
    const input1 = "199778A - > B 100"
    //第3步
    first := sha256.New()
    //第4步
    //第5步
    first.Write([]byte(input1))
    //第6步
    fmt.Printf("%x\n", first.Sum(nil))


    const input2 = "Hello"
    second := sha256.New()
    second.Write([]byte(input2))
    fmt.Printf("%x\n", second.Sum(nil))


    //输出两个哈希是否相等,bytes.Equal()
    fmt.Println(bytes.Equal(first.Sum(nil), second.Sum(nil)))

}
  • ==sha256== 输出结果:
0000e1343c8d9ec8a8996f0c1c8d1f9f1d954a750c3db5525205f401c516222d
185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
false

Process finished with exit code 0
  • 其中一些函数大家一定急于了解,但这些函数的封装过于艰深,我们在此不作深究。主要的是大家要记住四个关键步骤3,4,5,6,并熟练使用。其中包括以下几点:
  1. ==sha256.New()== 有返回值,需要声明变量并接收。且它的返回值一个是哈希对象,而且是一个指针对象。它可以调用一些方法,其中有write方法。——第3步
  2. 哈希对象调用 ==obj.Write()== 方法是需要传参,且参数类型为字节数组。所以涉及到要将哈希的字符串先转化为 ==[ ]byte== 类型——第4步第5步
  3. 哈希对象调用 ==first.Sum(nil)== 方法返回哈希值,方法有参数且参数固定为==nil==;可以声明变量接收或者直接输出。——第6步

关于哈希难度的判断

  • 要写出挖矿难度的完整代码,其中有一环节必须要解决。那就是如何判断哈希难度是否是有效的呢?下面我们先给出代码
/*
代码逻辑:
(我们将代码)
    第一步:声明一个随机取的哈希值,来在之后测验isValidDifficulty是否有效
    第二步:设置当前哈希难度,difficulty
    第三步:写入一个循环来迭代匹配哈希值对应位置的值,查看是否这个位置是否是哈希难度要求的值
    第四步:打印对这个哈希值的判断
*/

package main

import "fmt"

func main() {
    h := "0000e1343c8d9ec8a8996f0c1c8d1f9f1d954a750c3db5525205f401c516222d"
    //h1 := "0033e1343c8d9ec8a8996f0c1c8d1f9f1d954a750c3db5525205f401c516222d"
    //h2 := "0003e1343c8d9ec8a8996f0c1c8d1f9f1d954a750c3db5525205f401c516222d"
    difficulty := 4
    var i int
    for i = 0; i < len(h); i++ {
        if h[i] != '0' {
            break
        }
    }
    fmt.Print( i >= difficulty)
}
  • h 运行结果
true
Process finished with exit code 0
  • h1 运行结果
false
Process finished with exit code 0
  • h2 运行结果
false
Process finished with exit code 0
  • 于是我们将代码封装一下,使它看起来更清晰,更便于调用。
package main

import "fmt"

func main() {
    h := "0000e1343c8d9ec8a8996f0c1c8d1f9f1d954a750c3db5525205f401c516222d"
    fmt.Println(isValidHashDifficulty(h, 4))
}

func isValidHashDifficulty(h string, difficulty int) bool {
    b := len(h) // 64
    var i int
    for i = 0; i < b; i++ {
        if h[i] != '0' {
            break
        }
    }
    return i >= difficulty
}
  • 下一篇给出完整代码
    原文作者:kakushao
    原文地址: https://segmentfault.com/a/1190000014817254
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞