弁言
什么是区块链?官方的阐明是:区块链是一个分布式记账系统,是藉用密码学串接并保护其内容的串连交易记录(又称区块)。每一个区块包含了前一个区块的加密散列、对应的韶光戳记以及交易数据(常日用默克尔树算法打算的散列值表示),这样的设计使得区块内容具有难以被窜改的特性。用区块链所串接的分布式账本能让两方有效率地记录交易,且今生意营业可永久被查验。
但这个阐明对付初学者来说太抽象了,以是接下来我们将会利用PHP来实现一个大略单纯的区块链来加深对区块链的理解。
区块
大家该当玩过针言接龙,规则是这样:我先说一个针言“人上人海”,下一个玩家须要利用我说的针言的末了一个字作为下一个针言的开头,便是说须要利用“海”这个字作为新针言的开头,这时就可以接一个“夸夸其言”。
而区块链的形式有点像针言接龙,便是下一个区块必须利用上一个区块的Hash值作为凭据来天生下一个区块。如下图:
这样做的好处是:从任意一个区块开始都可以通过前一个区块的Hash值可以不断的追溯整条区块链,直到创世区块(也便是区块链的第一个区块)。如果有人恶意攻击,也必须变动整条区块链的数据。但是打算Hash值是一个耗时的操作,以是要变动整条区块链的数据基本是不可能达到,这就担保了区块链的安全性。
下面我们利用PHP代码来定义区块:
<phpclass Block {public $prevHash;public $hash;public $timeStamp;public $data;}
字段阐明prevHash前一个区块的Hash值hash当前区块的Hash值timeStamp区块天生的韶光戳data区块保存的数据
prevHash、hash和timeStamp这几个字段在区块链中被称为区块头,区块的Hash值利用SHA-256算法打算。打算方法如下:
<phpclass Block {...public function setBlockHash {$data = serialize($this);$this->hash = hash('sha256', $data);}}
首先我们利用serialize函数把全体区块序列化,然后利用hash函数打算区块的Hash值,并赋值给hash字段。
区块工具的布局函数如下:
<phpclass Block {...public function __construct($prevHash, $data) {$this->prevHash = $prevHash;$this->timeStamp = time;$this->data = $data;$this->setBlockHash;}}
其余我们供应一个获取区块Hash值的方法:
<?phpclass Block{...public function getBlockHash{return $this->hash;}}
区块链
前面说了,区块链便是按照一定的规则连接起来的区块,连接的规则便是下一个区块的区块头中必须包含前一个区块的Hash值。我们编写一个区块链工具来保存整条区块链,代码如下:
<?php
include('block.php');class Blockchain{public $blocks = ;}
区块链工具内部利用了一个数组来保存所有的区块,现阶段我们还没有利用到数据库来保存区块链,以是现在只须要把区块链保存在内存即可。
向区块链添加一个新的区块代码如下:
<?phpinclude('block.php');class Blockchain{...public function addBlock($data){$prevBlock = $this->blocks[count($this->blocks)-1];$this->blocks = new Block($prevBlock->getBlockHash, $data);}}
由于天生新区块必须包含前一个区块的Hash值,以是在添加新区块时须要获取区块链中末了一个区块作为新区块的前一个区块,然后把前一个区块的Hash包含到新区块的区块头中。
可能聪明的读者会创造,在区块链刚创建时并没有任何区块,那么添加新区块时拿哪个区块作为前一个区块呢?答案便是创世区块。创世区块不用包含前一个区块的Hash值,而且随着区块链的创建被创建,代码如下:
<?phpinclude('block.php');class Blockchain{...public function __construct{$this->blocks = new Block('', 'Genesis Block');}}
创世区块并不须要包含前一个区块的Hash值,以是在创建创世区块时把前一个区块的Hash值设置为空。
OK!
我们的大略单纯区块链已经完成了,现在来测试一下我们的代码吧:
<?phpinclude('blockchain.php');$bc = new Blockchain;$bc->addBlock('This is block1');$bc->addBlock('This is block2');foreach ($bc->blocks as $block) {printf(\"大众PrevHash: %s\n\公众, $block->prevHash);printf(\"大众Hash: %s\n\公众, $block->hash);printf(\"大众Data: %s\n\"大众, $block->data);printf(\公众\n\公众);}
我们来运行一下测试代码,运行结果如下:
很好,结果符合我们的预期。
总结
本文只是实现了一个最大略单纯的区块链,离完全的区块链还有非常远的间隔。在我们现在的实现中存在很多不敷,如:添加一个区块的本钱很低,没有实现分布式,不能保存到本地磁盘(重启机器数据就会丢失)等,接下来的教程将会不断完善这些问题。