基于java语言构建区块链——工作量证明

     2022-03-28     535

关键词:

技术分享图片
引言

在 上一篇 文章中,我们实现了区块链最基本的数据结构模型,添加区块以及和前一个区块连接在一起。但是,我们的实现方式非常简单,而真实的比特币区块链中,每一个区块的添加都是需要经过大量的计算才可以完成,这个过程就是我们熟知的挖矿。

工作量证明机制
区块链最关键的一个思想就是,必须进行大量且困难的计算工作才能将交易数据存放到区块链上。这种工作机制才能保证整个区块链数据的安全性和一致性。同时,完成这个计算工作的矿工会得到相应的Token奖励。

这套机制和我们的现实生活非常相似:我们必须努力工作来赚取报酬用以维持我们的生活。在区块链中,网络中的矿工们努力工作来维持区块链网络,为其添加区块,并且获得一定的Token奖励。作为他们工作的成果,一个区块以安全的方式被组合进了区块链中,这样就保证了整个区块链数据库的稳定性。还有一个必须要注意的是,某个矿工完成了计算工作的结果,还必须得到其他所有矿工的认同(证明是正确的),这样才算完成。

这一整套的计算和证明机制,就称为Proof-of-Work(工作量证明)。计算工作是非常非常困难的,因为它需要消耗大量的计算机算力资源,即使是性能非常高的计算机都不能非常快地计算出正确的结果。此外,随着时间的推移,这项计算工作的难度也会随之增加,目的是为了保证每小时6个新区块的出块率。在比特币中,这种工作的目标是找到满足某个特定要求的区块Hash(哈希值)。这个区块哈希值就是工作结果的一个证明。因此,计算工作的目的就是为了寻找到这个证明值。

最后要注意的是,计算出这个特定的Hash(哈希值)是非常困难的,但是别人来验证这个Hash值是否正确的时候,是非常简单的,一下子就能完成。

给大家推荐一个java内部学习群:725633148,进群找管理免费领取学习资料和视频。没有错就是免费领取!大佬小白都欢迎,大家一起学习共同进步!

Hashing

Hash:哈希 | 散列
我们来讨论一下Hashing(哈希),对这一块非常熟悉的朋友可以直接跳过这一段内容。

哈希是一种计算机算法,该算法能够计算出任意大小数据的哈希值,并且这个哈希值的长度是固定的,256bit。这个被计算出来的哈希值能够作为这个数据的唯一代表。哈希算法有几个关键的特性:

不可逆性。不能根据一个哈希值推导出原始数据。所以,哈希不是加密。
唯一性。每个数据有且仅有一个唯一的哈希值。
迥异性。原始数据一丁点的变化都将得到完全不一样的哈希值。
例如:

SHA256("wangwei1") ——> 1e898b7c9adaad86c20139a302ccd5277f81040cab68dc2aecfc684773532652
SHA256("wangwei2") ——> c9cc7417c17318c8aab448cc8ace24c53b6dcf350f5c5fd8e91cbc3b011a179d
哈希算法被广泛用于验证文件的一致性上。比如软件提供商通常会在安装包上附加一个检验码(checksums),当我们下载完一个软件安装包后,可以用哈希函数计算一下这个软件安装包的哈希值,然后再和软件安装包的检验码做个对比,就可以知道下载的安装包是否完整、是否有数据丢失。

在区块链中,哈希值用于保证区块的一致性。每一个区块被用于进行哈希计算的数据,都包含前一个区块链的哈希值,因此任何人想要修改区块的数据几乎是不可能的,他必须要把整个区块链中从创世区块到最新的区块的所有哈希值全部重新计算一遍。

你可以脑补一下这个工作量有多大,按照目前计算机的算力来看,几乎不可能
Hashcash
比特币的工作量证明是使用的是Hashcash算法,一种最初被用于反垃圾邮件的算法,它可以被拆解为以下几步:

获取某种公开可知的数据data(在邮件案例中,指的是收件人邮件地址;比特币案例中,指的是区块头)
添加一个计数器counter,初始值设置为0;
计算 data 与 counter拼接字符串的哈希值;
检查上一步的哈希值是否满足某个条件,满足则停止计算,不满足则 counter 加1,然后重复第3步和第4步,直到满足这个特定的条件为止。
这是一种粗暴的算法:你改变计数器,计算一个新的哈希值,检查它,增加计数器,计算一个新的哈希值,循环往复,这就是为什么它需要花费大量计算机算力资源的原因所在。

让我们来近距离看一下这个特定的条件指的是什么。在原始的Hashcash算法中,这个特殊的要求指的是计算出来的哈希值的前20bit必须全是零,

在比特币种,这种要求哈希值前面有多少个零打头的要求是随着时间的推移而不断调整的,这是出于设计的目的,尽管在计算机的算力会不断的提升和越来越多的矿工加入这个网络中的情况下,都要保证每10min生产一个区块。

我们演示一下这个算法,

计算字符串‘I like donuts‘的哈希值

SHA256("I like donuts")
——> f80867f6efd4484c23b0e7184e53fe4af6ab49b97f5293fcd50d5b2bfa73a4d0

拼接一个计数器值(ca07ca),再次进行Hash计算

SHA256("I like donutsca07ca")
——> 0000002f7c1fe31cb82acdc082cfec47620b7e4ab94f2bf9e096c436fc8cee06
这里的ca07ca是计数器值的十六进制,他表示的十进制值为13240266

即,从0开始,总共计算了13240266次,才计算出I like donuts这个数据的Hash值,满足前6位(3字节)全是零。
代码实现
思路:
1)每次区块被添加到区块链之前,先要进行挖矿(Pow)

2)挖矿过程中,产生的 Hash 值,如果小于难度目标值则添加进区块,否则继续挖矿,直到找到正确的Hash为止

3)最后,验证区块Hash是否有效
定义Pow类

/**

/**

  • 准备数据
  • <p>
  • 注意:在准备区块数据时,一定要从原始数据类型转化为byte[],不能直接从字符串进行转换
  • @param nonce
  • @return
    */
    private String prepareData(long nonce) {
    byte[] prevBlockHashBytes = {};
    if (StringUtils.isNoneBlank(this.getBlock().getPrevBlockHash())) {
    prevBlockHashBytes = new BigInteger(this.getBlock().getPrevBlockHash(), 16).toByteArray();
    }

    return ByteUtils.merge(
    prevBlockHashBytes,
    this.getBlock().getData().getBytes(),
    ByteUtils.toBytes(this.getBlock().getTimeStamp()),
    ByteUtils.toBytes(TARGET_BITS),
    ByteUtils.toBytes(nonce)
    );
    }
    参与Hash运算的如下几个信息:
    前一个区块(父区块)的Hash值;
    区块中的交易数据;
    区块生成的时间;
    难度目标;
    用于工作量证明算法的计数器
    详见:《精通比特币 (第二版)》第09章
    Pow算法

/**

  • 运行工作量证明,开始挖矿,找到小于难度目标值的Hash
  • @return
    */
    public PowResult run() {
    long nonce = 0;
    String shaHex = "";
    System.out.printf("Mining the block containing:%s ", this.getBlock().getData());

    long startTime = System.currentTimeMillis();
    while (nonce < Long.MAX_VALUE) {
    String data = this.prepareData(nonce);
    shaHex = DigestUtils.sha256Hex(data);
    if (new BigInteger(shaHex, 16).compareTo(this.target) == -1) {
    System.out.printf("Elapsed Time: %s seconds ", (float) (System.currentTimeMillis() - startTime) / 1000);
    System.out.printf("correct hash Hex: %s ", shaHex);
    break;
    } else {
    nonce++;
    }
    }
    return new PowResult(nonce, shaHex);
    }
    循环体里面主要以下四步:
    准备数据
    进行sha256运算
    转化为BigInter类型
    与target进行比较
    最后,返回正确的Hash值以及运算计数器nonce
    验证区块Hash有效性

/**

  • 验证区块是否有效
  • @return
    */
    public boolean validate() {
    String data = this.prepareData(this.getBlock().getNonce());
    return new BigInteger(DigestUtils.sha256Hex(data), 16).compareTo(this.target) == -1;
    }
    修改区块添加逻辑

/**

  • <p> 创建新区块 </p>
  • @param previousHash
  • @param data
  • @return
    */
    public static Block newBlock(String previousHash, String data) {
    Block block = new Block("", previousHash, data, Instant.now().getEpochSecond(), 0);
    ProofOfWork pow = ProofOfWork.newProofOfWork(block);
    PowResult powResult = pow.run();
    block.setHash(powResult.getHash());
    block.setNonce(powResult.getNonce());
    return block;
    }
    创建区块
    创建Pow算法对象
    执行Pow算法
    保存返回的Hash以及运算计数器
    测试运行

/**

  • 测试
  • @author wangwei
  • @date 2018/02/05
    */
    public class BlockchainTest {

    public static void main(String[] args) {

    Blockchain blockchain = Blockchain.newBlockchain();
    
    blockchain.addBlock("Send 1 BTC to Ivan");
    blockchain.addBlock("Send 2 more BTC to Ivan");
    
    for (Block block : blockchain.getBlockList()) {
        System.out.println("Prev.hash: " + block.getPrevBlockHash());
        System.out.println("Data: " + block.getData());
        System.out.println("Hash: " + block.getHash());
        System.out.println("Nonce: " + block.getNonce());
    
        ProofOfWork pow = ProofOfWork.newProofOfWork(block);
        System.out.println("Pow valid: " +  pow.validate() + "
    ");
    }

    }
    }

/**

  • 设定TARGET_BITS = 20,得到如下结果:
    */
    Mining the block containing:Genesis Block
    Elapsed Time: 2.118 seconds
    correct hash Hex: 00000828ee8289ef6381f297585ef8c952fde93fc2b673ff7cc655f699bb2442

Mining the block containing:Send 1 BTC to Ivan
Elapsed Time: 1.069 seconds
correct hash Hex: 00000a38c0d7f2ebbd20773e93770298aa8bc0cc6d85fca8756fe0646ae7fea5

Mining the block containing:Send 2 more BTC to Ivan
Elapsed Time: 4.258 seconds
correct hash Hex: 00000777f93efe91d9aabcba14ab3d8ab8e0255b89818cdb9b93cfa844ad0c7f

Prev.hash:
Data: Genesis Block
Hash: 00000828ee8289ef6381f297585ef8c952fde93fc2b673ff7cc655f699bb2442
Nonce: 522163
Pow valid: true

Prev.hash: 00000828ee8289ef6381f297585ef8c952fde93fc2b673ff7cc655f699bb2442
Data: Send 1 BTC to Ivan
Hash: 00000a38c0d7f2ebbd20773e93770298aa8bc0cc6d85fca8756fe0646ae7fea5
Nonce: 474758
Pow valid: true

Prev.hash: 00000a38c0d7f2ebbd20773e93770298aa8bc0cc6d85fca8756fe0646ae7fea5
Data: Send 2 more BTC to Ivan
Hash: 00000777f93efe91d9aabcba14ab3d8ab8e0255b89818cdb9b93cfa844ad0c7f
Nonce: 1853839
Pow valid: true
给大家推荐一个java内部学习群:725633148,进群找管理免费领取学习资料和视频。没有错就是免费领取!大佬小白都欢迎,大家一起学习共同进步!

总结
我们正在一步一步接近真实的区块链架构,本篇我们实现了挖矿机制,但是我们还有很多关键性的功能没有实现:区块链数据库的持久性、钱包、地址、交易、共识机制,这些我们后面一步一步来实现。


基于java语言构建区块链——基本原型

...事情,这样我们才能把握住这波时代趋势的红利。本文将基于Java语言构建简化版的blockchain,来实现数字货币。创建区块区块链是由包含交易信息的区块从后向前有序链接起来的数据结构。 查看详情

基于java实现的简单区块链

...言使用java创建第一个非常基本的区块链实现一个简单的工作量证明系统即挖矿创建区块 查看详情

基于go语言构建区块链:part1(代码片段)

...。本文将参考https://jeiwan.cc/tags/blockchain/教程,学习如何基于Go语言构建区块链。1、编程环境设置编程工具使用GoLand,前文已介绍软件安装经验。软件安装完成后,还需要设置工作路径“GOPATH”。在电脑上新建一个空白目录,然... 查看详情

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

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

用go构建一个区块链--part2:工作量证明(代码片段)

翻译的系列文章我已经放到了GitHub上:blockchain-tutorial,后续如有更新都会在GitHub上,可能就不在这里同步了。如果想直接运行代码,也可以cloneGitHub上的教程仓库,进入src目录执行make即可。在前面一文中,... 查看详情

用go构建一个区块链--part7:网络(代码片段)

...特性:匿名,安全,随机生成的地址;区块链数据存储;工作量证明系统;可靠地存储交易。尽管这些特性都不可或缺,但是仍有不足。能够使得这些特性真正发光发热,使得加密货币成为可能的,是网络(network)。如果实现... 查看详情

区块链之工作量证明

区块链之工作量证明在整个区块链中的作用新的区块依赖工作量证明算法(PoW)|ProofOfWork来构造理解PoW的目标是找出一个符合特定条件的数字,这个数字很难计算出来,但容易验证。这就是工作量证明的核心思想。示例代码fromha... 查看详情

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

...结构1.2实现的区块链数据结构1.3注意点1.4区块链的核心-工作量证明算法1.4.1拜占庭将军问题1.4.2解决办法1.4.3代码实现2快速实现一个区块链2.1什么是区块链2.2一个完整的快包含什么2.3什么是挖矿2.4工作量证明算法:2.5实现代... 查看详情

区块链工作量证明及哈希算法

什么是工作量证明:1、工作的结果作为数据加入区块链成为一个区块2、完成这个工作的人会获得奖励(这也就是通过挖矿获得比特币)3、整个“努力工作并进行证明”的机制,就叫工作量证明为什么采用哈希算法:1、不... 查看详情

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

...理。能正确使用编程语言搭建区块和区块链,并进行工作量证明实现。二、实验原理简介实验简介#工作量证明及哈希算法#工作量证明代码实现#区块链的工作量证明,主要是通过新的区块链依赖工作量证明算法(POW&#x... 查看详情

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

什么是工作量证明ProofOfWork,简称POW,即对工作量的证明。为什么要做工作量证明**挖矿(计算or工作)**的结果会作为数据加入区块链成为一个区块,完成这个**工作**的人也会获得奖励(即挖矿获得比特币... 查看详情

区块连游戏开发教程(代码片段)

...加到链中。这个决策过程催生了区块链的去中心化性质。工作量证明(PoW)、取证证明(PoS)和权威证明(PoA)是去中心化机制,通过这些机制&#x 查看详情

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

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

初识区块链

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

基于指针数组实现简单的区块链day(代码片段)

...区块容量1.12每秒成交量1.13单位二、其他基础知识2.1挖矿(工作量证明)2.2go演示挖矿2.3地址生成规则2.4base642.5交易三、模拟简单的区块链3.1创建简单的区块3 查看详情

使用javascript实现简单的区块链(签名+工作量证明机制)(代码片段)

//区块链blockchain//data之前区块的哈希值当前区块的哈希值:是由存储在区块里的信息算出来的(data+之前区块的哈希值)constsha256=require('./crypto-js/sha256')//区块classBlockconstructor(data)this.data=datathi 查看详情

用go构建一个区块链--part3:持久化和命令行接口(代码片段)

...行make即可。引言到目前为止,我们已经构建了一个有工作量证明机制的区块链。有了工作量证明ÿ 查看详情

投票证明:基于投票机制和联盟封锁链的高性能一致性协议

Title:投票证明:基于投票机制和联盟封锁链的高性能一致性协议Abstract:比特币引入了一种革命性的去中心化共识机制。然而,应用于公共区块链的比特币衍生共识机制不适合新兴联盟区块链的部署场景。我们提出了一种新的... 查看详情