美文网首页PHP开发技术
使用PHP实现区块链(二) - 工作量证明

使用PHP实现区块链(二) - 工作量证明

作者: 我_记忆中的自己 | 来源:发表于2018-07-28 10:35 被阅读55次

列旭松

来自:Linux内核那些事(微信号:like_linux)

作者:列旭松,唯品会资深工程师,曾任职于YY语音,熟识PHP、C语言和Go语言。10年PHP开发经验,对PHP底层实现原理有较深理解。热衷于开源事业,开源过多个PHP相关的扩展,流行的PHP源码加密扩展(PHP-Beast)作者。另外,本人对分布式缓存系统(如Redis、Memcached)有较大的兴趣,喜欢钻研底层实现原理,《 PHP 核心技术与最佳实践》一书的作者。

1、前言

上一篇文章我们介绍了区块链的最基本数据结构-区块,而且还构建了一个最原始的区块链。但是现在我们很容易就可以向区块链中添加区块,这样有可能导致大量的区块在同时添加到区块链中,从而导致广播风暴。而且在分布式环境中,如果并发量太大会导致很多问题,例如拜占庭问题。

为了解决这个问题,比特币使用了工作量证明机制。

2、工作量证明

由于现在添加一个区块的成本很低,所以必须找到一个增加添加区块成本的方法,而在比特币中使用的是工作量证明,我们也效仿比特币使用工作量证明。

工作量证明(POW,Proof-of-Work)是一个用于阻止拒绝服务攻击和类似垃圾邮件等服务错误问题的协议,它在 1993 年被 Cynthia Dwork 和 Moni Naor 提出。

那么什么是工作量证明呢?其实很简单,就是找到一个符合某一规定的Hash值。例如我们规定区块的Hash值的前 20 个位必须为 0,要符合这样的区块才能添加到区块链中,那么工作量证明就是要找到符合这样规定的Hash值。

由于找到这样的Hash值是非常困难的,所以会给予找到合适Hash值的人相应奖励(比特币),找到符合规定Hash值的过程被称为“挖矿”,而挖矿的机器被称为“矿工”。

3、Hash值计算

如前面所说,我们需要找到一个符合规定的Hash值才能将区块添加到区块链中,而在我们的前一篇文章中计算区块Hash值的方法是直接序列化区块,然后使用SHA-256来计算其Hash值。那么有个问题是,区块的内容是不变的,所以计算出来的Hash值也是固定的,那么有什么办法来改变区块的Hash值呢?这里我们使用Hashcash 算法,步骤如下:

1. 取一些公开的数据(比如区块头)。

2. 给这个公开数据添加一个计数器。计数器默认从 0 开始。

3. 将数据和计数器组合到一起,获得一个Hash值。

4. 检查Hash值是否符合规定的条件:

   1) 如果符合条件,结束

   2) 如果不符合,增加计数器,重复步骤 3-4

可以看出这个是一个暴力计算的过程:改变计数器,计算新的Hash值,检查是否符合条件,直到找到符合条件的Hash值。

在 Hashcash 算法中,它的要求是“一个Hash值的前 20 位必须是 0”。条件越苛刻,找到符合条件的Hash值就越难。下图详细说明了这个过程:

在上图中,129022是计数器的值,而符合条件的Hash值是前 16 个位为 0 (上图中表现为Hash值的前4个字符为0)。

4、实现

上一篇文章中的Block对象的实现中,添加一个findBlockHash()的方法用于找到符合条件的Hash值:

class Block

{

    ...

    public $nonce;

    private function prepareData($nonce)

    {

        return json_encode([

            $this->prevHash,

            $this->timeStamp,

            $this->data,

            $nonce,

        ]);

    }

    public function findBlockHash()

    {

        $found = false;

        $condition = '0000'; // Hash值前N个字符必须等于$condition

        $condlength = strlen($condition);

        printf("Mining the block containing "%s" ", $this->data);

        for ($nonce = 0; $nonce < PHP_INT_MAX; $nonce++) {

            $data = $this->prepareData($nonce);

            $hash = hash('sha256', $data);

            printf(" %d: %s", $nonce, $hash);

            if (substr($hash, 0, $condlength) === $condition) {

                $found = true;

                break;

            }

        }

        print(" ");

        if ($found) {

            $this->nonce = $nonce;

            $this->hash = $hash;

        }

        return $found;

    }

}

在上面的代码中,我们为Block类添加了一个nonce的成员变量,用于记录计数器。而在findBlockHash()函数中,我们不断增加计数器的值,计算出Hash值,然后比较Hash值是否符合条件(前N个字符是否等于变量$condition)。如果找到合适的Hash值就退出循环,否则增加计数器的值计算下一个Hash值。而prepareData()方法用于序列化要计算Hash值的数据。

最后,我们在Block类的构造函数中调用findBlockHash()方法:

class Block

{

    ...

    public function __construct($prevHash, $data)

    {

        $this->prevHash = $prevHash;

        $this->timeStamp = time();

        $this->data = $data;

        $this->findBlockHash();

    }

    ...

}

现在我们来运行一下代码看看效果:

从运行结果可以看到,算出来的Hash值都符合我们规定的条件。当然,你可以修改更苛刻的条件来增加挖矿的难度。

最后还有一件事需要做,就是验证区块是否合法:

class Block

{

    ...

    public function validate()

    {

        $condition = '0000';

        $condlength = strlen($condition);

        $data = $this->prepareData($this->nonce);

        return substr(hash('sha256', $data), 0, $condlength) === $condition; 

    }

}

验证的方法很简单,就是计算出区块的Hash值,然后比较Hash值是否符合条件。然后我们在打印区块链的时候验证区块是否合法:

include('blockchain.php');

$bc = new Blockchain();

$bc->addBlock('This is block1');

$bc->addBlock('This is block2');

foreach ($bc->blocks as $block) {

    ...

    printf("PoW: %s ", $block->validate() ? 'true' : 'false');

    ...

}

运行代码查看结果:

结果符合我们的预期,代码在:https://github.com/liexusong/blockchain-php/tree/v2.0

相关文章

  • 使用PHP实现区块链(二) - 工作量证明

    列旭松 来自:Linux内核那些事(微信号:like_linux) 作者:列旭松,唯品会资深工程师,曾任职于YY语...

  • 使用JavaScript实现区块链

    BlockChain.js 使用javascript实现区块链,实现了 PoW工作量证明算法挖矿 P2P网络,挖到...

  • JS 实现区块链—工作量证明

    今天我们通过 js 实现一个区块链应用,帮助您更好地理解区块链技术原理 创建区块链 区块链验证 工作量证明防纂改 ...

  • Go实现区块链(二)---工作量证明

    1.前言 前面我们已经介绍了区块链基本原型,接下来我们实现一个简易版的工作量证明,也就是我们所说的挖矿。可能我们经...

  • Go区块链从0到1:区块持久化、命令行交互

    简介: 到目前为止,我们实现了一个简单的区块链基础模型,建立了工作量证明的机制。本文将与大家一起实现区块链的持久化...

  • 小巴成长记-区块链的共识机制(二)

    目前,区块链的共识机制主要有工作量证明、权益证明和最长链机制共识。工作量证明和权益证明我们之前有介绍过,现在我们来...

  • Python实现一个新币种

    简单区块链模型,实现了链式结构,创建区块,添加交易数据,共识算法(POW挖矿),分叉选择,工作量证明,多节点数据一...

  • 迷你区块链代码详解

    上一篇介绍了迷你区块链的实现过程,仔细阅读代码很容易掌握区块链中一些基本概念,如区块、哈希计算、工作量证明、共识算...

  • go公链实战0x01ProofOfWork

    上一节 我们用go语言实现了区块链的基础结构。今天来实现工作量证明。 区块新属性Nonce 我们先来看一下上节实现...

  • 区块链Demo

    刚接触区块链,百度了下,发现有人用Golang编写了一些区块链的链构建过程和工作量证明的代码,发现工作量证明的代码...

网友评论

    本文标题:使用PHP实现区块链(二) - 工作量证明

    本文链接:https://www.haomeiwen.com/subject/votomftx.html