前話
瞭解區塊鏈基礎運作
什麼是區塊鏈?
區塊鏈是一個 不可變的、有序的 被稱為塊的記錄鏈。它們可以包含交易、檔案或任何您喜歡的資料。但重要的是,他們用雜湊 一起被連結在一起
需要準備什麼?
- php5.6+
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:挖礦
挖礦正是神奇所在,它很簡單,做了一下三件事:
- 計算工作量證明 PoW
- 透過新增一個交易授予礦工(自己)一個幣
- 構造新區塊並將其新增到鏈中
在比特幣中,工作量證明演算法被稱為 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"
}
}
Setp6:完整程式碼ar414-com/phpblock
本作品採用《CC 協議》,轉載必須註明作者和本文連結