前话 了解区块链基础运作
什么是区块链? 区块链是一个 不可变的、有序的 被称为块的记录链。它们可以包含交易、文件或任何您喜欢的数据。但重要的是,他们用哈希 一起被链接在一起
需要准备什么? 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"
}
}
讨论