LaravelZero 从零实现区块链(一)基本原型

前言

学习区块链有些时间了,根据大佬的文章用Go也实现了一遍,但作用一名web码农,平时用的最多的还是PHP,所以打算用PHP再搞一搞,当是复习了。

本教程基于LaravelZero(因为构建命令行省事儿:stuck_out_tongue: )简单构建一个属于你的区块链,如果你有一些区块链的前置知识那就最好不过啦。

项目仓库在这儿 php-blockchain,欢迎star。水平有限,如有错误之处,也欢迎指出。

初始化

  1. 根据 LaravelZero 文档,先创建一个项目,确保能顺利跑起来。
  2. 在app目录下创建 Services 文件夹,咱们的代码都写在这里面。

区块链是什么

简单来说,区块链是一个提供了拜占庭容错、并保证了最终一致性的分布式数据库;从数据结构上看,它是基于时间序列的链式数据块结构;从节点拓扑上看,它所有的节点互为冗余备份;从操作上看,它提供了基于密码学的公私钥管理体系来管理账户。

组成区块链的核心技术主要有

  1. P2P 网络协议
  2. 分布式一致性算法
  3. 加密签名算法
  4. 账户与存储模型

在本文中,我们将利用数组来存储区块,来实现区块链的基本原型。

区块

在区块链中,真正存储有效信息的是区块(block)。

那就创建一个区块,在 App/Services 目录新建一个 Block.php。

<?php

namespace App\Services;

use Carbon\Carbon;

class Block
{
    /**
     * 当前时间戳,也就是区块创建的时间
     * @var int $timestamp
     */
    public $timestamp;

    /**
     * 区块存储的信息,也就是交易
     * @var string $data
     */
    public $data;

    /**
     * 前一个块的哈希,即父哈希
     * @var string $prevBlockHash
     */
    public $prevBlockHash;

    /**
     * 当前块的哈希 
     * @var string $hash
     */
    public $hash;
}

在比特币中,区块的结构主要有如下信息:

Field Purpose Size(Bytes)
Block Size 区块大小 4
Block Header 区块头 80
Transaction Counter 交易计数器 1~9
Transactions 交易 -

区块头的主要结构:

字段 描述 大小
Version 版本号 4
hashPrevBlock 256位的父区块Hash 32
hashMerkleRoot 256位的交易默克尔树Hash 32
Time 时间戳 4
Bits 本区块工作量证明算法的难度目标 4
Nonce 随机数 4

其中交易(Transactions)也就是我们创建的 data 字段;而其他字段(prevBlockHash,timestamp)在比特币中由专门的数据结构,即区块头存储;另外为了方便,我们还加上了当前块的 hash 字段,在比特币中是没有直接存储当前块的哈希的。

为了方便,我们就不单独实现区块头了,而是所有数据都放在一起,这样我们就创建了一个简单的区块。

下面我们来完善区块的创建:
Block.php


    public function __construct(string $data, string $prevBlockHash)
    {
        $this->prevBlockHash = $prevBlockHash;
        $this->data = $data;
        $this->timestamp = time();
        $this->hash = $this->setHash();
    }

    public function setHash(): string
    {
        return hash('sha256', implode('', [$this->timestamp, $this->prevBlockHash, $this->data]));
    }

区块链

本质上,区块链就是一个有着特定结构的数据库,是一个有序,每一个块都连接到前一个块的链表。也就是说,区块按照插入的顺序进行存储,每个块都与前一个块相连。这样的结构,能够让我们快速地获取链上的最新块,并且高效地通过哈希来检索一个块。

有了区块,下面让我们来实现区块链。在基本原型阶段,我们用数组来存放区块结构。新建一个文件 BlockChain.php

<?php
namespace App\Services;

class BlockChain
{
    /**
     * @var Block[] $blocks
     */
    public $blocks;

    public function __construct(Block $block)
    {
        $this->blocks[] = $block;
    }

    // 加入一个块到区块链中
    public function addBlock(string $data)
    {
        $prevBlock = $this->blocks[count($this->blocks) - 1];
        $newBlock = new Block($data, $prevBlock->hash);
        $this->blocks[] = $newBlock;
    }
}

addBlock() 方法使我们有了向链中添加区块的能力,但是还没完,在添加区块以前,区块链中应该存在一个创世区块。

    // 初始化创世区块
    public static function NewGenesisBlock()
    {
        $block = new Block('Genesis Block', '');

        return new BlockChain($block);
    }

大功告成,下面让我们来测试一下!

$bc = BlockChain::NewGenesisBlock();
$bc->addBlock('i am 2 block');
$bc->addBlock('i am 3 block');
dd($bc->blocks);

结果如下:

array:3 [
  0 => App\Services\Block {#155
    +timestamp: 1587700797
    +data: "Genesis Block"
    +prevBlockHash: ""
    +hash: "e0ecf169c2ea5143743438fd91778ca6cdff1c870120c784f836650cfaaaff38"
  }
  1 => App\Services\Block {#153
    +timestamp: 1587700797
    +data: "i am 2 block"
    +prevBlockHash: "e0ecf169c2ea5143743438fd91778ca6cdff1c870120c784f836650cfaaaff38"
    +hash: "c33a37e9708a2871c6b03fd2f6468081edb4e96d911c7227ad84271d9c4f8b6d"
  }
  2 => App\Services\Block {#160
    +timestamp: 1587700797
    +data: "i am 3 block"
    +prevBlockHash: "c33a37e9708a2871c6b03fd2f6468081edb4e96d911c7227ad84271d9c4f8b6d"
    +hash: "de300a998179bfeeb3ea60be3f49e205f8552b8ab9d506a76d847f0ba9d93646"
  }
]

NICE!
至此,我们就完成了区块链基本原型的实现,就下来我们会尝试构建出工作量证明系统。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 1

大佬,p2p网络怎么弄麽?

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!