PoW共识算法是一种基于算力的共识算法,我们需要在挖矿的过程当中找到其相应的解,从而获得“挖矿奖励”,但要找到这个解,并没有固定的算法,只能靠计算机随机的哈希碰撞,因此,PoW算法考验的并不是算法,而是算力的强弱。
什么是PoW算法
Proof-of-Work 简称 PoW,即为工作量证明。通过计算一个数值( nonce ),使得拼揍上交易数据后内容的 Hash 值满足规定的上限。在节点成功找到满足的Hash值之后,会马上对全网进行广播打包区块,网络的节点收到广播打包区块,会立刻对其进行验证。
工作量证明的优缺点
优点:完全去中心化,节点自由进出;
缺点:目前已经吸引全球大部分的算力,其它再用Pow共识机制的区块链应用很难获得相同的算力来保障自身的安全;挖矿造成大量的资源浪费;tps较小,不能满足大量交易的需求
实现 Proof-of-Work 共识机制
安装依赖软件
在安装好go的环境之后,本文通过使用GoLand编译代码并在Postman上进行实现
在goland中的terminal安装依赖软件
$ go get github.com/davecgh/go-spew/spew
$ go get github.com/gorilla/mux
$ go get github.com/joho/godotenv
其中 spew 是负责在控制台中格式化输出相应的结果
gorilla/mux 是编写web处理程序的流行软件包,用起来很方便
godotnev 通过这个依赖软件我们可以从我们项目的根目录中的 .env 文件中读取数据
这三个依赖用起来都非常方便,具体的使用方法在github当中都会有详细的介绍,在这里不赘述
实现 PoW 共识机制
首先,第一步,我们需要在项目的根目录下新建 .env文件,并在其中添加一行 ADDR=8080,端口大小可以任意修改,但许多人会在新建.env文件上出问题,.env文件新建的时候先新建为 .env.txt 文件,之后再进入powershell中输入ren .env.txt .env就修改成功了。这个文件会为后面在电脑上模拟pow实现的时候提供接入端口的数值,因此十分重要
第二步,新建 main.go 导入相应的包

定义区块

difficulty 代表难度系数,如果赋值为 1,则需要判断生成区块时所产生的 Hash 前缀至少包含1个 0,这是作为pow算法的主体,所有的算力都要用在计算满足当前难度的hash值,从而得到正确的结果,成功挖矿
Block 代表区块的结构体。
Index 是区块链中数据记录的位置
Timestamp 是自动确定的,并且是写入数据的时间
BPM 是每分钟跳动的次数,是你的脉率
Hash 是代表这个数据记录的SHA256标识符
PrevHash 是链中上一条记录的SHA256标识符
Difficulty 是当前区块的难度系数
Nonce 是 PoW 挖矿中符合条件的数字
Blockchain 是存放区块数据的集合
Message 是使用 POST 请求传递的数据
mutex 是为了防止同一时间产生多个区块
生成区块

newBlock 中的 PrevHash 存储的上一个区块的 Hash。
for 循环 通过循环改变 Nonce,然后选出符合相应难度系数的 Nonce。
isHashValid 判断 hash,是否满足当前的难度系数。如果难度系数是2,则当前hash的前缀有2个0。


验证区块

其中给出了三种不匹配的条件,1)前一个区块的index+1和当前区块的index不匹配
2)前一个区块的hash值和当前区块的hash值不匹配
3)再次对当前区块的hash值进行计算,和之前计算出来的不一样
web服务器


makeMuxRouter 主要定义路由处理,当收到 GET 请求,就会调用 handleGetBlockchain 方法。当收到 POST 请求,就会调用 handleWriteBlock 方法。
handleGetBlockchain 获取所有区块的列表信息。

handleWriteBlock 主要是生成新的区块。


主函数

godotenv.Load() 允许我们从 根目录的文件 .env 读取相应的变量。
genesisBlock 创建初始区块。
run() 启动 web 服务
启动web服务器
$ go run main.go
可以通过 Postman软件模拟网络请求。
通过 POST 访问 http://localhost:8080 可以添加新的区块信息。
在Postman中点击POST,之后输入“localhost:8080”,点击Body,选中raw,输入“{“BPM”:60}”,之后点击SEND按键,开始模拟区块生成的过程

在goland中就会一直出现hash值,并进行不停的计算,直到得到最终的“正确答案”
同样,我们还可以通过Postman中的GET按钮得到最终的所有的区块的结果

代码中的difficulty我们将其设置为5,但是我们可以将其设置为任何值来调整出块的难度,每一次的出块速度也可以在generateBlock当中进行调整,通过time.Sleep(time.Microsecond),我们可以设置为second或者其他参数,从而调整相隔两次计算的间隔时间。
以上就是关于PoW在go语言环境下的实现。
网友评论