LaravelZero 从零实现区块链(一)基本原型
前言
学习区块链有些时间了,根据大佬的文章用Go也实现了一遍,但作用一名web码农,平时用的最多的还是PHP,所以打算用PHP再搞一搞,当是复习了。
本教程基于LaravelZero(因为构建命令行省事儿 )简单构建一个属于你的区块链,如果你有一些区块链的前置知识那就最好不过啦。
项目仓库在这儿 php-blockchain,欢迎star。水平有限,如有错误之处,也欢迎指出。
初始化
- 根据 LaravelZero 文档,先创建一个项目,确保能顺利跑起来。
- 在app目录下创建 Services 文件夹,咱们的代码都写在这里面。
区块链是什么
简单来说,区块链是一个提供了拜占庭容错、并保证了最终一致性的分布式数据库;从数据结构上看,它是基于时间序列的链式数据块结构;从节点拓扑上看,它所有的节点互为冗余备份;从操作上看,它提供了基于密码学的公私钥管理体系来管理账户。
组成区块链的核心技术主要有:
- P2P 网络协议
- 分布式一致性算法
- 加密签名算法
- 账户与存储模型
在本文中,我们将利用数组来存储区块,来实现区块链的基本原型。
区块
在区块链中,真正存储有效信息的是区块(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 协议》,转载必须注明作者和本文链接
大佬,p2p网络怎么弄麽?