// Simplified version of Blockchain Technology
/**
* To create digital signature (or hash) of the transaction
*/
class Block{
public function __construct( $index, $timestamp, $data, $prev_hash = ''){
$this->index = $index;
$this->timestamp = $timestamp;
$this->data = $data;
$this->prev_hash = $prev_hash;
$this->hash = $this->calculateHash();
}
// calculates the hash of the block
public function calculateHash(){
return hash('sha256', $this->index . $this->timestamp . json_encode( $this->data ) );
}
}
/**
* Stores the list of all transaction in an array.
* Contains the transaction detail of each block in the chain.
* Also has the hash to check if the data has been tampered.
*/
class Blockchain{
public static $index = 0;
public static $chain;
public function __construct(){
if( !isset(self::$chain) )
self::$chain = array( $this->genesisBlock() );
}
public function genesisBlock(){
return new Block(self::$index, time(), 'genesis block: 100', '0');
}
public function getLatestBlock(){
return end( self::$chain );
}
public function addBlock( $newBlock ){
$newBlock->prev_hash = $this->getLatestBlock()->hash;
$newBlock->hash = $newBlock->calculateHash();
array_push( self::$chain, $newBlock);
}
// checks the integrity of the blockchain
public function isChainValid(){
for( $i = 1; $i < count(self::$chain); $i++ ){
$currentBlock = self::$chain[$i];
$prevBlock = self::$chain[$i - 1];
if( $currentBlock->hash !== $currentBlock->calculateHash() ){
return false;
}
if( $currentBlock->prev_hash !== $prevBlock->hash ){
return false;
}
}
return true;
}
}
/**
* Allows to create multiple account.
* Initiates only single Blockchain.
* That Blockchain object is used to track all transactions.
*/
class Account{
// keeps track of unique user account number
public static $id = 101;
public static $Blockchain_obj;
public function __construct( $name, $balance ){
$this->name = $name;
$this->id = self::$id++;
$this->balance = $balance;
// makes sure only one instance of Blockchain exists
if( !isset(self::$Blockchain_obj) )
self::$Blockchain_obj = new Blockchain();
}
public function view_balance(){
return $this->name . ', your balance is: ' . $this->balance;
}
public function transfer( $another_account, $amount ){
$this->balance -= $amount;
Blockchain::$index++;
$data = array( 'To' => $another_account->id, 'amount' => $amount, 'transaction_type' => 'transfer' );
$block = new Block( Blockchain::$index, time(), $data );
$another_account->deposit( $amount );
return self::$Blockchain_obj->addBlock($block);
}
public function deposit( $amount ){
$this->balance += $amount;
}
private function withdraw( $amount ){
$this->balance -= $amount;
}
}
// create two random accounts
$account1 = new Account( 'John', 200 );
$account2 = new Account( 'Harry', 200 );
// simulate money transfer
$account1->transfer( $account2, 100 );
$account2->transfer( $account1, 50 );
// shows the new balance after transfer
var_dump($account1->view_balance());
var_dump($account2->view_balance());
// shows all the tractions until now
echo print_r( Blockchain::$chain, true );
/** checks if the data has been tinkered
* @returns true in this case
*/
var_dump( 'valid chain? ' . Account::$Blockchain_obj->isChainValid() );
// simulate data tampering
var_dump( Blockchain::$chain[1]->data = array( 'amount' => 20000 ) );
var_dump( Blockchain::$chain[1]->calculateHash() );
/** checks whether the chain is valid after tampering
* returns false cause the data was altered
*/
var_dump( 'valid chain? ' . Account::$Blockchain_obj->isChainValid() );
Output:
string(26) "John, your balance is: 150"
string(27) "Harry, your balance is: 250"
Array
(
[0] => Block Object
(
[index] => 0
[timestamp] => 1513702684
[data] => genesis block: 100
[prev_hash] => 0
[hash] => 09fa53c5a5c1b2f9e96a1715b658543612121dd13de3c39eeed761c1e0c39a45
)
[1] => Block Object
(
[index] => 1
[timestamp] => 1513702684
[data] => Array
(
[To] => 102
[amount] => 100
[transaction_type] => transfer
)
[prev_hash] => 09fa53c5a5c1b2f9e96a1715b658543612121dd13de3c39eeed761c1e0c39a45
[hash] => 03bbb054b83e2a029cf9517975338386e2e2e76050d8e970fc7ad83f30ce4453
)
[2] => Block Object
(
[index] => 2
[timestamp] => 1513702684
[data] => Array
(
[To] => 101
[amount] => 50
[transaction_type] => transfer
)
[prev_hash] => 03bbb054b83e2a029cf9517975338386e2e2e76050d8e970fc7ad83f30ce4453
[hash] => 846242260d96b36fafccc6c4232e42d975228d7439ff719f3e42b8aca39fac7d
)
)
string(27) "first check: valid chain? 1"
array(1) { ["amount"]=> int(20000) }
string(64) "5e4e2cd2a8fbd856e74e4eb45f5db55e07005f36c46c8dbc07babd9a5ae3cc86"
string(27) "second check: valid chain? "