PHP也能实现区块链?

PHP也能实现区块链?

区块链兄弟

百家号07-2018:21

区块链兄弟社区,区块链技术专业问答先行者,中国区块链技术爱好者聚集地

 

作者:列旭松

来源: 高可用架构

原文链接:http://t.cn/RgjsJ1i

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文约3000字+,阅读(观看)需要19分钟

 

 

作者简介:列旭松,唯品会资深工程师,曾任职于YY语音,熟识PHP、C语言和Go语言。10年PHP开发经验,对PHP底层实现原理有较深理解。热衷于开源事业,开源过多个PHP相关的扩展,流行的PHP源码加密扩展(PHP-Beast)作者。另外,本人对分布式缓存系统(如Redis、Memcached)有较大的兴趣,喜欢钻研底层实现原理,《 PHP 核心技术与最佳实践》一书的作

引言

什么是区块链?官方的解释是:区块链是一个分布式记账系统,是藉用密码学串接并保护其内容的串连交易记录(又称区块)。每一个区块包含了前一个区块的加密散列、对应的时间戳记以及交易数据(通常用默克尔树算法计算的散列值表示),这样的设计使得区块内容具有难以被篡改的特性。用区块链所串接的分布式账本能让两方有效率地纪录交易,且此交易可永久被查验。

 

但这个解释对于初学者来说太抽象了,所以接下来我们将会使用PHP来实现一个简易的区块链来加深对区块链的理解。

 

区块

大家应该玩过成语接龙,规则是这样:我先说一个成语“人山人海”,下一个玩家需要使用我说的成语的最后一个字作为下一个成语的开头,就是说需要使用“海”这个字作为新成语的开头,这时就可以接一个“海阔天空”。

 

而区块链的形式有点像成语接龙,就是下一个区块必须使用上一个区块的Hash值作为凭据来生成下一个区块。如下图:

 

 

这样做的好处是:从任意一个区块开始都可以通过前一个区块的Hash值可以不断的追溯整条区块链,直到创世区块(也就是区块链的第一个区块)。如果有人恶意攻击,也必须更改整条区块链的数据。但是计算Hash值是一个耗时的操作,所以要更改整条区块链的数据基本是不可能达到,这就保证了区块链的安全性。

 

下面我们使用PHP代码来定义区块:

 

class Block {public $prevHash; public $hash; public $timeStamp; public $data;}

 

字段解释

prevHash前一个区块的Hash值

hash当前区块的Hash值

timeStamp区块生成的时间戳

data区块保存的数据

 

prevHash、hash和timeStamp这几个字段在区块链中被称为区块头,区块的Hash值使用SHA-256算法计算。计算方法如下:

class Block {... public function setBlockHash() { $data = serialize($this);$this->hash = hash('sha256', $data); }}

 

首先我们使用serialize()函数把整个区块序列化,然后使用hash()函数计算区块的Hash值,并赋值给hash字段。

 

区块对象的构造函数如下:

 

class Block {... public function __construct($prevHash, $data) { $this->prevHash = $prevHash; $this->timeStamp = time(); $this->data = $data;$this->setBlockHash(); }}

 

另外我们提供一个获取区块Hash值的方法:

 

class Block{... public function getBlockHash() { return $this->hash; }}

 

区块链

前面说了,区块链就是按照一定的规则连接起来的区块,连接的规则就是下一个区块的区块头中必须包含前一个区块的Hash值。我们编写一个区块链对象来保存整条区块链,代码如下:

 

include('block.php');class Blockchain{public $blocks = [];}

 

区块链对象内部使用了一个数组来保存所有的区块,现阶段我们还没有使用到数据库来保存区块链,所以现在只需要把区块链保存在内存即可。

 

向区块链添加一个新的区块代码如下:

 

include('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值,而且随着区块链的创建被创建,代码如下:

 

include('block.php');class Blockchain{... public function __construct() { $this->blocks[] = new Block('', 'Genesis Block'); }}

 

创世区块并不需要包含前一个区块的Hash值,所以在创建创世区块时把前一个区块的Hash值设置为空。

 

OK!我们的简易区块链已经完成了,现在来测试一下我们的代码吧:

 

include('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");}

 

我们来运行一下测试代码,运行结果如下:

 

 

很好,结果符合我们的预期。

 

总结

本文只是实现了一个最简易的区块链,离完整的区块链还有非常远的距离。在我们现在的实现中存在很多不足,如:添加一个区块的成本很低,没有实现分布式,不能保存到本地磁盘(重启机器数据就会丢失)等,接下来的教程将会不断完善这些问题。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值