PHP 创建区块链

简介: 区块链是一个 不可变的、有序的 被称为块的记录链。它们可以包含交易、文件或任何您喜欢的数据。但重要的是,他们用哈希 一起被链接在一起

云栖号:https://yqh.aliyun.com
第一手的上云资讯,不同行业精选的上云企业案例库,基于众多成功案例萃取而成的最佳实践,助力您上云决策!

前话

提供一个思路帮助你了解区块链基础运作,文本并不是一个完整的区块链,希望你能举一反三

源码:ar414-com/phpblock

记住

区块链是一个 不可变的、有序的 被称为块的记录链。它们可以包含交易、文件或任何您喜欢的数据。但重要的是,他们用哈希 一起被链接在一起

需要准备什么?

  • php5.6+

1、Block 区块

块是什么样的?

每个块都有一个索引,一个时间戳(Unix时间戳),一个事务列表, 一个校验(工作证明算法生成的证明)前一个块的哈希

block = {
    'index': 2,
    'timestamp': 1506057125,
    'transactions': [
        {
            'sender': "8527147fe1f5426f9dd545de4b27ee00",
            'recipient': "a77f5cdfa2934df3954a5c7c7da5df1f",
            'amount': 5,
        }
    ],  
    'proof': 324984774000,
    'previous_hash': "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
}

在这一点上,一个 区块链 的概念应该是明显的 - 每个新块都包含在其内的前一个块的 哈希 。 这是至关重要的,因为这是 区块链 不可改变的原因:如果攻击者损坏 区块链 中较早的块,则所有后续块将包含不正确的哈希值。

新建一个Block类,区块链由N个区块组成,在区块链里,价值信息存储在区块之中。比如,比特币的区块存储交易记录,而交易记录是任何加密货币的核心。除此之外,区块里还包含有技术信息,比如它的版本号,当前的时间戳,以及上一个区块的哈希(Hash)。

<?php
/**
 * Created by PhpStorm.
 * User: ar414.com@gmail.com
 * Date: 2020/2/2
 * Time: 18:42
 */

class Block
{
    /**
     * @var integer 索引
     */
    private $index;

    /**
     * @var integer 时间戳
     */
    private $timestamp;

    /**
     * @var array 事务列表
     */
    private $transactions;

    /**
     * @var string 上一块的哈希值
     */
    private $previousHash;

    /**
     * @var integer 由工作证明算法生成的证明
     */
    private $proof;

    /**
     * @var string 当前块的哈希值
     */
    private $hash;

    /**
     * 通过调用方法返回新生成块的哈希
     * 防止外界改动
     * @return string
     */
    public function getHash()
    {
        return $this->hash;
    }

    public function __construct($index,$timestamp,$transactions,$previousHash,$proof)
    {
        $this->index        = $index;
        $this->timestamp    = $timestamp;
        $this->transactions = $transactions;
        $this->previousHash = $previousHash;
        $this->proof        = $proof;
        $this->hash         = $this->blockHash();
    }

    /**
     * 当前块签名
     * @return string
     */
    private function blockHash()
    {
        //我们必须确保这个字典(区块)是经过排序的,否则我们将会得到不一致的哈希值
        $blockArray = [
            'index' => $this->index,
            'timestamp' => $this->timestamp,
            'transactions' => $this->transactions,
            'proof'        => $this->proof,
            'previous_hash' => $this->previousHash
        ];
        $blockString = json_encode($blockArray);
        return hash('sha256',$blockString);
    }
}
  • index是当前块的索引
  • timestamp是当前块的生成时间
  • transactions是当前块的交易事务列表(有多个或一个交易)
  • previousHash是上一个区块的签名哈希
  • hash是当前区块的签名哈希
  • proof是当前区块的矿工工作量证明

proof

使用工作量证明(PoW)算法,来证明是如何在区块链上创建或挖掘新的区块。PoW 的目标是计算出一个符合特定条件的数字,这个数字对于所有人而言必须在计算上非常困难,但易于验证。这是工作证明背后的核心思想。

在比特币中,工作量证明算法被称为 Hashcash ,它和上面的问题很相似,只不过计算难度非常大。这就是矿工们为了争夺创建区块的权利而争相计算的问题。 通常,计算难度与目标字符串需要满足的特定字符的数量成正比,矿工算出结果后,就会获得一定数量的比特币奖励(通过交易)

2、创建一个区块链

我们要创建一个Blockchain类 ,他的构造函数创建了一个初始化的空列表(要存储我们的区块链)并且创建世纪快,以及初始化了事务列表。下面是我们这个类的实例:

Step 1:初始化区块列表并且创建创世块

    /**
     * @var array 区块列表
     */
    private $chain;

    /**
     * @var array 交易事务列表
     */
    private $currentTransactions;

    public function __construct()
    {
        $this->chain = [$this->createGenesisBlock()];
        $this->currentTransactions = [];
    }

     /**
     * 创建创世块
     * @return array
     */
    private function createGenesisBlock()
    {
        $block = [
            'index' => 1,
            'timestamp' => time(),
            'transactions' => [

            ],
            'proof' => 100,
            'previous_hash' => '0000000000000000000000000000000000000000000000000000000000000000',//参考BTC的第一个创世块
        ];
        $block['hash'] = (new Block($block['index'],$block['timestamp'],$block['transactions'],$block['previous_hash'],$block['proof']))->getHash();
        return $block;
    }

Step 2:新增交易事务

创建一笔新的交易到交易事务列表中等待新区块打包,每次生成新区块后清空列表

    /**
      * 新增交易事务
      * @param $senderPrivateKey
      * @param $senderAddress
      * @param $recipientAddress
      * @param $amount
      * @return bool
      */
     public function createTransaction($senderPrivateKey,$senderAddress,$recipientAddress,$amount)
     {
         $row = [
             'from'   => $senderAddress,
             'to'     => $recipientAddress,
             'amount' => $amount,
             'timestamp' => time()
         ];
         //TODO 私钥签名(就像支票签名)
         //TODO 区块链节点可以用发送者的签名来推导出公钥,再通过公钥验签并对比数据
         $this->currentTransactions[] = $row;
         return true;
     }

Step 3:创建新区块

当前示例创建新区快操作只能由挖矿成功的矿工操作,挖矿讲解在Step4

    /**
     * 增加新区块
     * @param int $proof
     * @return bool
     */
    public function addBlock(int $proof)
    {
        //上一个区块的信息
        $preBlockInfo = $this->chain[count($this->chain)-1];
        //验证工作证明
        if($this->checkProof($proof,$preBlockInfo['proof']) == false){
            return false;
        }
        //TODO 奖励矿工(在交易事务中)
        $block = [
            'index'        => count($this->chain) + 1,
            'timestamp'    => time(),
            'transactions' => $this->currentTransactions,
            'proof'        => $proof,
            'previous_hash' => $preBlockInfo['hash'],
            'hash'         => ''
        ];
        $block['hash'] = (new Block($block['index'],$block['timestamp'],$block['transactions'],$block['previous_hash'],$block['proof']))->getHash();
        //新增区块
        $this->chain[] = $block;
        //重置交易事务
        $this->currentTransactions = [];
        return true;
    }

        /**
         * 校验算力
         * @param string $proof
         * @param string $preProof
         * @return bool
         */
        private function checkProof(string $proof,string $preProof)
        {
            $string = $proof.$preProof;
            $hash   = hash('sha256',$string);
            if(substr($hash,0,4) == '0000'){
                return true;
            }else{
                return false;
            }
        }

Step 4:挖矿

挖矿正是神奇所在,它很简单,做了一下三件事:

  1. 计算工作量证明 PoW
  2. 通过新增一个交易授予矿工(自己)一个币
  3. 构造新区块并将其添加到链中

在比特币中,工作量证明算法被称为 Hashcash ,它和上面的问题很相似,只不过计算难度非常大。这就是矿工们为了争夺创建区块的权利而争相计算的问题。 通常,计算难度与目标字符串需要满足的特定字符的数量成正比,矿工算出结果后,就会获得一定数量的比特币奖励(通过交易)

让我们来实现一个相似 PoW 算法

找到一个数字 P ,使得它与前一个区块的 Proof 拼接成的字符串的 Hash 值以 4 个零开头。
    /**
     * 挖矿
     * @return void
     */
    public function mine()
    {
//        while (true)
//        {
            $proof = 0;
            //最新区块
            $blockInfo = $this->chain[count($this->chain)-1];
            $preProof  = $blockInfo['proof'];
            while (true)
            {
                $string = $proof.$preProof;
                $hash   = hash('sha256',$string);
                if(substr($hash,0,4) == '0000'){
                    //增加新区块
                    $this->addBlock($proof);
                    break;
                }
                $proof++;
            }

//        }
    }

Step 5:运行测试

$blockChainObj = new Blockchain();

//增加事务
$blockChainObj->createTransaction('','8527147fe1f5426f9dd545de4b27ee00',
    'a77f5cdfa2934df3954a5c7c7da5df1f',1);

//开启挖矿(挖到则生成新区块)
$blockChainObj->mine();

//查看当前区块列表
$blockList = $blockChainObj->getChainList();
var_dump($blockList);

//结果:
$ php Blockchain.php
array(2) {
  [0]=>
  array(6) {
    ["index"]=>
    int(1)
    ["timestamp"]=>
    int(1580717292)
    ["transactions"]=>
    array(0) {
    }
    ["proof"]=>
    int(100)
    ["previous_hash"]=>
    string(64) "0000000000000000000000000000000000000000000000000000000000000000"
    ["hash"]=>
    string(64) "567b2848f3ff87a614b3ba5ddc13389d4d7440699b1857935412561721d86d05"
  }
  [1]=>
  array(6) {
    ["index"]=>
    int(2)
    ["timestamp"]=>
    int(1580717292)
    ["transactions"]=>
    array(1) {
      [0]=>
      array(4) {
        ["from"]=>
        string(32) "8527147fe1f5426f9dd545de4b27ee00"
        ["to"]=>
        string(32) "a77f5cdfa2934df3954a5c7c7da5df1f"
        ["amount"]=>
        int(1)
        ["timestamp"]=>
        int(1580717292)
      }
    }
    ["proof"]=>
    int(28)
    ["previous_hash"]=>
    string(64) "567b2848f3ff87a614b3ba5ddc13389d4d7440699b1857935412561721d86d05"
    ["hash"]=>
    string(64) "3a599c88ddd60fb25605df33d33b19252117c3d7d0e70c66dbc45ed81ab295a9"
  }
}

Setp5:完整代码ar414-com/phpblock

云栖号在线课堂,每天都有产品技术专家分享
立即加入圈子:https://c.tb.cn/F3.Z8gvnK
与专家面对面,及时了解课程最新动态!

原文发布时间:2020-03-17
本文作者:ar414
本文来自:“阿里云云栖社区”,了解相关信息可以关注“阿里云云栖社区

目录
相关文章
|
9月前
|
存储 JSON 供应链
使用PHP构建区块链应用程序
区块链技术作为一种去中心化的分布式账本系统,已经引起了广泛的关注。它具有安全、透明、可追溯等特点,被广泛应用于加密货币、供应链管理、身份验证等领域。本文将介绍如何使用PHP构建一个简单的区块链应用程序,并提供相应的代码实现、运行结果和解读。
139 0
|
11月前
|
区块链 PHP
区块链多渠道分销系统开发特色讲解及源码示例(php版)
区块链多渠道分销系统是指使用区块链技术来实现多个渠道的销售管理和分销的系统。这种系统通常具有以下特点:
|
存储 供应链 安全
景蓝交易所源码php区块链交易所源码/币币/法币/合约交易/配资上币/带搭建教程
景蓝交易所源码php区块链交易所源码/币币/法币/合约交易/配资上币/带搭建教程
景蓝交易所源码php区块链交易所源码/币币/法币/合约交易/配资上币/带搭建教程
|
供应链 监控 安全
开源PHP区块链数字货币交易平台
开源PHP区块链数字货币交易平台
开源PHP区块链数字货币交易平台
|
Shell PHP
关于php创建扩展的一个坑:找不到skeleton
关于php创建扩展的一个坑:找不到skeleton
77 0
关于php创建扩展的一个坑:找不到skeleton
|
PHP Windows
php windows多进程,php windows创建多进程,
php windows多进程,php windows创建多进程,
501 0
|
PHP 数据库
PHP面试题:单例模式,创建mysqli数据库链接的单例对象
PHP面试题:单例模式,创建mysqli数据库链接的单例对象
196 0
|
PHP
PHP面试题:请写一段程序,在服务器创建一个文件fruit.dat,将试题3中得到的数组写入到改文件中,然后写一段程序从文件中读取并还原数组@author zhuwenqiong
PHP面试题:请写一段程序,在服务器创建一个文件fruit.dat,将试题3中得到的数组写入到改文件中,然后写一段程序从文件中读取并还原数组@author zhuwenqiong
105 0
|
PHP
你知道怎么在PHP中创建可选参数吗?
在上一篇《玩转PHP之快速生成二维码》中给大家介绍了怎么通过PHP快速生成二维码,感兴趣的朋友可以学习了解一下~ 本文的主题内容则是“如何在PHP中创建可选参数”? 有的人可能要问什么是“可选参数”? 可选参数就是指即使没有传递任何东西也不会阻止函数工作的参数,通俗一点的说法就是指有默认值的就是可选参数。
186 0