- vừa được xem lúc

Phát triển Blockchain với PHP

0 0 25

Người đăng: Hưng Duy

Theo Viblo Asia

Năm 2021 chắc hẳn là một năm bùng nổ của Blockchain, khi người người nhà nhà làm Blockchain, game NFT, Token.... Vậy nếu Blockchain được phát triển trên ngôn ngữ PHP thì sao?

Blockchain là gì?

Blockchain (hay gọi là cuốn sổ cái) là hệ thống cơ sở dữ liệu cho phép lưu trữ và truyền tải các khối thông tin (block). Chúng được liên kết với nhau nhờ mã hóa. Các khối thông tin này hoạt động độc lập và có thể mở rộng theo thời gian. Chúng được quản lý bởi những người tham gia hệ thống chứ không thông qua đơn vị trung gian. Nghĩa là khi một khối thông tin được ghi vào hệ thống Blockchain thì không có cách nào thay đổi được. Chỉ có thể bổ sung thêm khi đạt được sự đồng thuận của tất cả mọi người.

Tạo một block

Chúng ta sẽ khởi tạo 1 class có tên là Block, Class này sẽ làm nhiệm vụ mã hóa toàn bộ dữ liệu vào thành 1 chuỗi khóa

<?php class Block
{ public $index; //index là key của 1 block public $previousHash; // đây là hash của block trước public $timeHash; // là thời gian mã hóa của block public $data; // data là của block ( nội dung transaction chẳng hạn ) public $hash; // hash của block này public function __construct($index = 0, $previousHash = '', $timeHash = '', $data = '') { $this->index = $index; $this->previousHash = $previousHash; $this->timeHash = $timeHash; $this->data = $data; $this->hash = $this->execHash(); } public function execHash() { if(is_array($this->data)) { $dataContent = json_encode($this->data); } else { $dataContent = $this->data; } return hash('sha256', $this->index . $this->previousHash . $dataContent . $this->timeHash); }
} 

Tiếp đến chúng ta tạo một class Blockchain

<?php namespace App\Services; use Carbon\Carbon; class BlockChain extends Block
{ public $chain = array(); public function __construct() { $this->chain[] = $this->createGenesisBlock(); parent::__construct(); } public function createGenesisBlock() { return new Block(0000,'the first', Carbon::now()->format('d/m/Y H:i:s'), ['from' => 'hunghd', 'to' => 'hunghd2', 'amount'=> 3000]); } private function getLatestBlock() { return $this->chain[(count($this->chain) - 1)]; } public function addBlock($index, $timeHash, $data) { $previousHash = $this->getLatestBlock()->hash; $newBlock = new Block($index, $previousHash, $timeHash, $data); $this->chain[] = $newBlock; } } 

Ở đây mình sẽ tạo 1 block khi có 1 data truyền vào. Giả dụ data là 1 transaction hunghd gửi tiền cho hunghd2 thì lúc này mình sẽ tạo ra 1 Block mới. Block này là block đầu tiên thế nên index = 0 , previousHash = 'the first'. Và khi có thêm transaction hunghd2 gửi cho hunghd3 thì block tiếp theo sẽ có previousHash = mã hash của block trước đó. Từ đó cứ thêm transaction mới được thêm vào sẽ tạo ra thêm 1 block mới nối với các trước đó. Từ đó chúng ta có một blockchain cơ bản. Đây là code kết quả khi mình chạy thêm block:

$bl = new \App\Services\BlockChain();
$bl->addBlock(1, Carbon::now()->format('d/m/Y H:i:s'), ['from' => 'hunghd2', 'to' => 'hunghd3', 'amount'=> 4000]);
$bl->addBlock(2, Carbon::now()->format('d/m/Y H:i:s'), ['from' => 'hunghd3', 'to' => 'hunghd4', 'amount'=> 5000]);
$bl->addBlock(3, Carbon::now()->format('d/m/Y H:i:s'), ['from' => 'hunghd4', 'to' => 'hunghd', 'amount'=> 6000]);
array:4 [▼ 0 => App\Services\Block {#1578 ▼ +index: 0 +previousHash: "the first" +timeHash: "10/12/2021 11:23:14" +data: array:3 [▼ "from" => "hunghd" "to" => "hunghd2" "amount" => 3000 ] +hash: "ff0525def6dcb4ad33d5784f37c88e3ca7ac356c1ac186ae13796b756faf9a05" } 1 => App\Services\Block {#1579 ▼ +index: 1 +previousHash: "ff0525def6dcb4ad33d5784f37c88e3ca7ac356c1ac186ae13796b756faf9a05" +timeHash: "10/12/2021 11:23:14" +data: array:3 [▼ "from" => "hunghd2" "to" => "hunghd3" "amount" => 4000 ] +hash: "3b67c70f4e22032a7d4d0d2d0252b7b41f7ea218bfb199e647d16e4e9398f18c" } 2 => App\Services\Block {#1580 ▼ +index: 2 +previousHash: "3b67c70f4e22032a7d4d0d2d0252b7b41f7ea218bfb199e647d16e4e9398f18c" +timeHash: "10/12/2021 11:23:14" +data: array:3 [▼ "from" => "hunghd3" "to" => "hunghd4" "amount" => 5000 ] +hash: "ceabfe6fe846ea0ad4b44cabfebbdd1c5694d33247eba5f95210dd6d738ccadf" } 3 => App\Services\Block {#1581 ▼ +index: 3 +previousHash: "ceabfe6fe846ea0ad4b44cabfebbdd1c5694d33247eba5f95210dd6d738ccadf" +timeHash: "10/12/2021 11:23:14" +data: array:3 [▼ "from" => "hunghd4" "to" => "hunghd" "amount" => 6000 ] +hash: "c77a07b3e0f8987c95310f82546237e541191a05f940dc4e9d2ca04e5c8ad3be" }
]

Kiểm tra chain bị thay đổi hay không

Chúng ta đã tạo được một chain ở phía trên nhưng nếu giờ hacker muốn thay đổi 1 block bất kỳ trong chain thì sẽ như nào? Nếu mà dễ dàng thay đổi thế thì block chain đã không được thịnh hành như bây giờ rồi. Để ngăn chặn việc đó thì mình sẽ phải kiểm tra tính của chain như sau đó là lấy previousHash === hash trước đó.

public function inValidBlock() { for ($i = 1; $i < count($this->chain); $i++) { $currentBlock = $this->chain[$i]; $previousBlock = $this->chain[$i - 1]; if ($currentBlock->hash !== $currentBlock->execHash()) { return false; } if ($currentBlock->previousHash !== $previousBlock->hash) { return false; } } return true; }

Giờ mình sẽ thử thay đổi 1 block ( thay đôi data hoặc hash ) trong chain sẽ có kết quả như sau:

$bl = new \App\Services\BlockChain(); $bl->addBlock(1, Carbon::now()->format('d/m/Y H:i:s'), ['from' => 'hunghd2', 'to' => 'hunghd3', 'amount'=> 4000]); $bl->addBlock(2, Carbon::now()->format('d/m/Y H:i:s'), ['from' => 'hunghd3', 'to' => 'hunghd4', 'amount'=> 5000]); $bl->addBlock(3, Carbon::now()->format('d/m/Y H:i:s'), ['from' => 'hunghd4', 'to' => 'hunghd', 'amount'=> 6000]); $bl->chain[2]->data = [ 'from' => 'hunghd3', 'to' => 'hunghd', 'amount' => 5000 ]; $bl->chain[2]->hash = $bl->chain[2]->execHash(); $bl->invalid = $bl->inValidBlock();

Ở đây thấy mã hash của block thứ 2 đã bị thay đổi mà block thứ 3 đã lưu lại mã hash của block thứ 2 trước khi thay đổi. Nên kết quả kiểm tra là false

Proof-of-work

Nhưng thực tế, hashpreviousHash khi mọi người có thể thay đổi dữ liệu 1 block rồi thay previousHashhash của các block sau là vẫn tạo được một chain hợp lệ và chúng ta cũng muốn người dùng cùng phải đồng thuận (consensus) về một lịch sử duy nhất của chain. Và proof-of-work ra đời để giải quyết vấn đề này.

Nếu bạn muốn sửa đổi 1 block trước đó, bạn sẽ phải mine lại toàn bộ các block sau nó. Nó yêu cầu quét một giá trị bắt đầu bằng một số số 0 nhất định khi được hash. Giá trị được gọi là giá trị nonce, số bit 0 đứng đầu được gọi là difficulty. Bằng cách tăng độ khó việc khai thác, đồng nghĩa rằng việc mine sẽ ngày càng khó hơn. Chúng ta có thể làm hệ thống này bằng cách tạo method mine

Giờ class Block mình sẽ code cuối cùng như này:

<?php class Block
{ public $index; public $previousHash; public $timeHash; public $data; public $hash; public $mineVar; public function __construct($index = 0, $previousHash = '', $timeHash = '', $data = '') { $this->index = $index; $this->previousHash = $previousHash; $this->timeHash = $timeHash; $this->data = $data; $this->hash = $this->execHash(); $this->mineVar = 0; } public function execHash() { if(is_array($this->data)) { $dataContent = json_encode($this->data); } else { $dataContent = $this->data; } return hash('sha256', $this->index . $this->previousHash . $dataContent . $this->timeHash . $this->mineVar ); } public function mine($difficulty) { while (!str_starts_with($this->execHash(), str_repeat('0', $difficulty))) { $this->mineVar++; $this->hash = $this->execHash(); } return $this->mineVar; }
} 

Trong class Blockchain cũng cần bổ sung code như này:

<?php use Carbon\Carbon; class BlockChain extends Block
{ public $chain = array(); public $difficulty; public function __construct($difficulty) { $this->chain[] = $this->createGenesisBlock(); $this->difficulty = $difficulty; parent::__construct(); } public function createGenesisBlock() { return new Block(0000,'the first', Carbon::now()->format('d/m/Y H:i:s'), ['from' => 'hunghd', 'to' => 'hunghd2', 'amount'=> 3000]); } private function getLatestBlock() { return $this->chain[(count($this->chain) - 1)]; } public function addBlock($index, $timeHash, $data) { $previousHash = $this->getLatestBlock()->hash; $newBlock = new Block($index, $previousHash, $timeHash, $data); $newBlock->mine($this->difficulty); $this->chain[] = $newBlock; } public function inValidBlock() { for ($i = 1; $i < count($this->chain); $i++) { $currentBlock = $this->chain[$i]; $previousBlock = $this->chain[$i - 1]; if ($currentBlock->hash !== $currentBlock->execHash()) { return false; } if ($currentBlock->previousHash !== $previousBlock->hash) { return false; } } return true; } } 

Ok!! Giờ chúng ta sẽ thử chạy xem sao

$bl = new \App\Services\BlockChain(4);
$bl->addBlock(1, Carbon::now()->format('d/m/Y H:i:s'), ['from' => 'hunghd2', 'to' => 'hunghd3', 'amount'=> 4000]);
$bl->addBlock(2, Carbon::now()->format('d/m/Y H:i:s'), ['from' => 'hunghd3', 'to' => 'hunghd4', 'amount'=> 5000]);
$bl->addBlock(3, Carbon::now()->format('d/m/Y H:i:s'), ['from' => 'hunghd4', 'to' => 'hunghd', 'amount'=> 6000]);

Kết quả chúng ta sẽ có các block có số nonce như mong muốn. Để tăng độ khó là 5 số 0 thì mình chỉ cần thay đổi difficulty = 5.

array:4 [▼ 0 => App\Services\Block {#1578 ▼ +index: 0 +previousHash: "the first" +timeHash: "10/12/2021 11:58:04" +data: array:3 [▶] +hash: "f636898ed8e8d5ddf3db99134694921a491ebd1fc80a1b4d3eb28f8d2c7e9ed5" +mineVar: 0 } 1 => App\Services\Block {#1579 ▼ +index: 1 +previousHash: "f636898ed8e8d5ddf3db99134694921a491ebd1fc80a1b4d3eb28f8d2c7e9ed5" +timeHash: "10/12/2021 11:58:04" +data: array:3 [▶] +hash: "00001c87474ccbf7cc6ef4eefa0fd4499989583716f41e6373e70a1e1b89585b" +mineVar: 13413 } 2 => App\Services\Block {#1580 ▼ +index: 2 +previousHash: "00001c87474ccbf7cc6ef4eefa0fd4499989583716f41e6373e70a1e1b89585b" +timeHash: "10/12/2021 11:58:04" +data: array:3 [▶] +hash: "0000dd0d602d647ac6e3aa4d6672073c5d229a0f2a2a12322c11b18661751639" +mineVar: 25881 } 3 => App\Services\Block {#1581 ▼ +index: 3 +previousHash: "0000dd0d602d647ac6e3aa4d6672073c5d229a0f2a2a12322c11b18661751639" +timeHash: "10/12/2021 11:58:04" +data: array:3 [▶] +hash: "00008ae256d9ccb10c578dc77629e89c3f2bf4cc4a146758b5c57e284d9fef86" +mineVar: 5349 }
]

Tuy nhiên bài viết này mang tính cơ bản nên sẽ sử dụng proof-of-work. Trên thực tế công nghệ này đã lỗi thời chậm chạp, tốn tài nguyên và có hại cho môi trường nên các platform hiện nay thường sử dụng proof-of-stake.

Đây là bài viết dựa trên sự tìm hiểu của cá nhân mình nên có nhiều sai sót mong được mọi người đóng góp thêm!!!

Nguồn tham khảo

  1. https://viblo.asia/p/tu-tao-blockchain-trong-60-dong-code-javascript-1VgZvQN1KAw
  2. https://www.youtube.com/watch?v=TlW5KqOKWoQ
  3. http://ilook.asia/thu-thuat/phat-trien-blockchain-voi-php-83.html

Bình luận

Bài viết tương tự

- vừa được xem lúc

[Blockchain] Road to Bitcoin

. Chắc mọi người hẳn đã không còn xa lạ gì với anh chàng tỷ phú đã ném vỡ cửa kính ô tô nhà mình cùng với siêu năng lực điều khiển vật giá chỉ bằng lời nói, người đã đẩy định giá Bitcoin trên thị trường vượt ngưỡng 50K dolar/coin với những bài twitter để đời . .

0 0 44

- vừa được xem lúc

Khi Ethereum có chi phí giao dịch quá đắt đỏ - Tương lai cho layer2 ?

Với sự phát triển như vũ bão của Blockchain, ETH dường như đang quá tải và hệ quả là chi phí Gas đã lên đến 1000Gwei, phí để tạo những transaction phức tạp đã xấp xỉ 500$ . Và một giải pháp cứu cánh cho các sản phẩm Defi trên ETH chính là Layer2, và trong nhiệm vụ lần này Matic đang thể hiện khả năn

0 0 73

- vừa được xem lúc

Blockchain với Java - Tại sao không?

Cuộc cách mạng công nghiệp 4.0 ra đời kéo theo nhiều sự thay đổi và xu hướng mới được hình thành. Riêng đối với lĩnh vực CNTT cũng không nằm ngoài vùng ảnh hưởng mạnh mẽ. Chính làn sóng 4.

0 0 78

- vừa được xem lúc

Phân loại và tầm quan trọng của các node trong mạng blockchain

Trước khi đi vào phân loại và nêu rõ được tầm quan trọng của các node trọng mạng blockchain thì mình xin được trích dẫn khái niệm về blockchain từ Wikipedia như sau:. .

0 1 46

- vừa được xem lúc

Code Smart Contract bằng Assembly ?

Introduction. Hồi còn học trong ghế nhà trường bộ môn lập trình tốn nhiều não nhất của mình là code assembly. Nôm na thì bất cứ ngôn ngữ bậc cao nào như C , Go, Java,... được sinh ra để người dễ hiểu và dễ code , tuy nhiên chúng đều sẽ được compiled down xuống assembly một ngôn ngữ bậc thấp để máy h

0 0 43

- vừa được xem lúc

Dextool - Công cụ phân tích Decentralized Exchange tuyệt vời

. Trend Defi mặc dù đã bớt nhiệt nhưng những sản phẩm nổi bật của làn sóng này mang lại thì vẫn rất được người dùng ưa chuộng. Đặc biệt là các nền tảng Decentralized Exchange, tiêu biểu là Uniswap, SushiSwap, 1inch Exchange, FalconSwap,... Nhưng khi đã sử dụng các nền tảng DEx này mà không biết đến

0 0 92