PHP 创建区块链

作者: 9c1fd88cfd08 | 来源:发表于2020-02-03 16:23 被阅读0次

    前话

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

    源码:

    https://github.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

    相关文章

      网友评论

        本文标题:PHP 创建区块链

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