Lập trình blockchain phần 4: Ngôn ngữ lập trình Java

3 phần trước bạn đã biết về cách lập trình blockchain với C++, JavaScript, Python. Mục đích của bài hướng dẫn này là giúp bạn xây dựng một cái nhìn toàn cảnh về cách con người có thể phát triển công nghệ blockchain bằng ngôn ngữ Java.

Ngôn ngữ lập trình Java

Trong hướng dẫn này, nhiệm vụ chính sẽ là:

  • Tạo 'blockchain' cơ bản (rất) cơ bản.
  • Thực hiện một proof of work đơn giản (khai thác hệ thống).
  • Tìm hiểu những khả năng của blockchain.

(Với điều kiện bạn có một sự hiểu biết cơ bản về lập trình hướng đối tượng).

Cần lưu ý rằng blockchain được tạo trong bài viết này chỉ đơn thuần giúp làm rõ các khái niệm và giúp bạn đọc hiểu thêm về blockchain.

Cài đặt

Bài viết sẽ sử dụng Java nhưng bạn sẽ có thể làm tương tự trong bất kỳ ngôn ngữ OOP nào. Bài viết sẽ sử dụng Eclipse nhưng bạn cũng có thể sử dụng bất kỳ trình soạn thảo văn bản ưa thích mới nào.

Bạn sẽ cần:

  • Java và JDK.(duh) đã được cài đặt
  • Eclipse (hoặc một IDE/Trình soạn thảo văn bản khác).

Tuy nhiên, bạn có thể dùng thư viện GSON của google. Điều này sẽ cho phép bạn biến một đối tượng thành Json \o/. Đó là một thư viện cực kỳ hữu ích mà sẽ tiếp tục được sử dụng như các công cụ tương tự khác. Nếu không muốn, bạn vui lòng sử dụng một phương pháp thay thế.

Trong Eclipse, tạo một dự án Java (file> new>). Giả sử đặt tên dự án là “noobchain” và tạo một Class mới cùng tên (NoobChain).

Tạo một dự án Java

Bây giờ bạn đã sẵn sàng để tạo blockchain rồi!

Tạo Blockchain

Blockchain chỉ là một chuỗi hay danh sách các khối. Mỗi khối trong blockchain sẽ có chữ ký số (Digital Signature) của riêng nó, chứa chữ ký số của khối trước đó và có một số dữ liệu (ví dụ, dữ liệu này có thể là các giao dịch).

Tạo blockchain

Hash = Digital Signature

Mỗi khối không chỉ chứa hàm hash của khối trước đó, mà còn chứa hash của chính nó (được tính từ giá trị previous hash). Nếu dữ liệu của khối trước đó bị thay đổi thì giá trị hash của khối trước đó sẽ thay đổi (vì nó được tính toán một phần bởi dữ liệu) và sẽ ảnh hưởng đến tất cả các hash của các khối đó sau đó. Tính toán và so sánh các hash cho ta biết liệu một blockchain có hợp lệ hay không.

Điều đó có nghĩa là, thay đổi bất kỳ dữ liệu nào trong danh sách này, sẽ thay đổi chữ ký số và phá vỡ chuỗi.

Vì vậy, Firsts cho phép tạo ra lớp Block tạo nên blockchain:

import java.util.Date;
public class Block {
public String hash;
public String previousHash;
private String data; //our data will be a simple message.
private long timeStamp; //as number of milliseconds since 1/1/1970.
//Block Constructor.
public Block(String data,String previousHash ) {
this.data = data;
this.previousHash = previousHash;
this.timeStamp = new Date().getTime();
}
}

Như bạn thấy, Block cơ bản chứa một String hash (giữ chữ ký số). Biến previousHash chứa dữ liệu hash và chuỗi của khối trước đó để giữ dữ liệu khối.

Tiếp theo chúng ta sẽ cần tìm cách để tạo chữ ký số.

Có rất nhiều thuật toán mã hóa mà bạn có thể chọn, tuy nhiên SHA256 là phù hợp nhất với ví dụ này. Chúng ta có thể nhập

java.security.MessageDigest

để truy cập thuật toán SHA256.

Cần sử dụng SHA256 sau đó xuống dòng để cho phép tạo ra một phương thức trợ giúp tiện dụng trong một lớp 'tiện ích' StringUtil mới:

import java.security.MessageDigest;
public class StringUtil {
//Applies Sha256 to a string and returns the result.
public static String applySha256(String input){
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
//Applies sha256 to our input,
byte[] hash = digest.digest(input.getBytes("UTF-8"));
StringBuffer hexString = new StringBuffer(); // This will contain hash as hexidecimal
for (int i = 0; i < hash.length; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if(hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
catch(Exception e) {
throw new RuntimeException(e);
}
}
}

Đừng lo lắng quá nhiều nếu bạn không hiểu nội dung của phương thức trợ giúp này. Tất cả những gì bạn cần biết là nó lấy một chuỗi và áp dụng thuật toán SHA256, rồi trả về chữ ký được tạo ra dưới dạng một chuỗi.

Bây giờ hãy sử dụng applySha256 helper, tại một phương thức mới trong lớp Block, để tính toán giá trị hash. Cần phải tính toán hash từ tất cả các phần của khối. Vì vậy, khối này sẽ bao gồm previousHash, datatimeStamp:

public String calculateHash() {
String calculatedhash = StringUtil.applySha256(
previousHash +
Long.toString(timeStamp) +
data
);
return calculatedhash;
}

cũng như cho phép thêm phương thức này vào Block constructor:

public Block(String data,String previousHash ) {
this.data = data;
this.previousHash = previousHash;
this.timeStamp = new Date().getTime();
this.hash = calculateHash(); //Making sure we do this after we set the other values.
}

Một số thử nghiệm

Lớp NoobChain chính cho phép tạo ra một số khối và xuất các hash ra màn hình để thấy rằng mọi thứ đang hoạt động tốt.

Khối đầu tiên được gọi là khối genesis, và bởi vì không có khối trước đó nên chúng ta sẽ chỉ nhập “0” làm previous hash.

public class NoobChain {
public static void main(String[] args) {
Block genesisBlock = new Block("Hi im the first block", "0");
System.out.println("Hash for block 1 : " + genesisBlock.hash);
Block secondBlock = new Block("Yo im the second block",genesisBlock.hash);
System.out.println("Hash for block 2 : " + secondBlock.hash);
Block thirdBlock = new Block("Hey im the third block",secondBlock.hash);
System.out.println("Hash for block 3 : " + thirdBlock.hash);
}
}

Kết quả sẽ trông giống như sau:

Kết quả đầu ra

Mỗi khối bây giờ có chữ ký số của riêng nó dựa trên thông tin và chữ ký của khối trước đó.

Hiện tại, blockchain không có nhiều khối, vì vậy hãy lưu trữ các khối trong ArrayList và cũng nhập gson để coi nó như là Json.

import java.util.ArrayList;
import com.google.gson.GsonBuilder;
public class NoobChain {
public static ArrayList<Block> blockchain = new ArrayList<Block>();
public static void main(String[] args) {
//add our blocks to the blockchain ArrayList:
blockchain.add(new Block("Hi im the first block", "0"));
blockchain.add(new Block("Yo im the second block",blockchain.get(blockchain.size()-1).hash));
blockchain.add(new Block("Hey im the third block",blockchain.get(blockchain.size()-1).hash));
String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
System.out.println(blockchainJson);
}
}

Bây giờ, kết quả hiển thị sẽ giống với những gì chúng ta mong đợi ở một blockchain.

Tiếp theo, hãy tìm cách để kiểm tra tính toàn vẹn của blockchain.

Tạo phương thức Boolean isChainValid() trong lớp NoobChain. Nó sẽ lặp qua tất cả các khối trong chuỗi và so sánh các hash. Phương pháp này sẽ cần phải kiểm tra biến hash thực tế có bằng với hash được tính toán và hash của khối trước có bằng với biến previousHash không.

public static Boolean isChainValid() {
Block currentBlock;
Block previousBlock;
//loop through blockchain to check hashes:
for(int i=1; i < blockchain.size(); i++) {
currentBlock = blockchain.get(i);
previousBlock = blockchain.get(i-1);
//compare registered hash and calculated hash:
if(!currentBlock.hash.equals(currentBlock.calculateHash()) ){
System.out.println("Current Hashes not equal");
return false;
}
//compare previous hash and registered previous hash
if(!previousBlock.hash.equals(currentBlock.previousHash) ) {
System.out.println("Previous Hashes not equal");
return false;
}
}
return true;
}

Mọi thay đổi đối với các khối của blockchain sẽ khiến phương thức này trả về false.

Các nút mạng bitcoin chia sẻ blockchain của chúng và chuỗi dài nhất hợp lệ sẽ được mạng chấp nhận. Vậy điều gì ngăn chặn ai đó giả mạo dữ liệu trong một khối cũ sau đó tạo ra một blockchain hoàn toàn mới? Proof of work (bằng chứng hoạt động). Hệ thống Proof of work Hashcash proof of work có nghĩa là phải mất nhiều thời gian và công sức tính toán để tạo ra các khối mới. Do đó kẻ tấn công sẽ tốn nhiều công sức tính toán khi kết hợp các khối.

Khai thác các khối

Bạn sẽ phải yêu cầu miner (người đào) thực hiện proof-of-work bằng cách thử các giá trị biến khác nhau trong khối cho đến khi giá trị hash bắt đầu bằng một số xác định, bắt đầu từ 0.

Hãy thêm một int, gọi là nonce vào phương thức calculateHash() và phương thức mineBlock():

import java.util.Date;
public class Block {
public String hash;
public String previousHash;
private String data; //our data will be a simple message.
private long timeStamp; //as number of milliseconds since 1/1/1970.
private int nonce;
//Block Constructor.
public Block(String data,String previousHash ) {
this.data = data;
this.previousHash = previousHash;
this.timeStamp = new Date().getTime();
this.hash = calculateHash(); //Making sure we do this after we set the other values.
}
//Calculate new hash based on blocks contents
public String calculateHash() {
String calculatedhash = StringUtil.applySha256(
previousHash +
Long.toString(timeStamp) +
Integer.toString(nonce) +
data
);
return calculatedhash;
}
public void mineBlock(int difficulty) {
String target = new String(new char[difficulty]).replace('\0', '0'); //Create a string with difficulty * "0"
while(!hash.substring( 0, difficulty).equals(target)) {
nonce ++;
hash = calculateHash();
}
System.out.println("Block Mined!!! : " + hash);
}
}

Trong thực tế mỗi miner sẽ bắt đầu lặp lại từ một điểm ngẫu nhiên, một số miner có thể thử số ngẫu nhiên cho nonce. Những giải pháp khó hơn sẽ yêu cầu integer.MAX_VALUE nhiều hơn, miner lúc này có thể thử thay đổi timestamp.

Phương thức mineBlock() chứa int được đặt tên là difficulty, đây là số lượng số bắt đầu từ 0 mà chúng phải giải quyết. Độ khó thấp như 1 hoặc 2 có thể được giải quyết gần như ngay lập tức trên hầu hết các máy tính, nên hãy nâng lên mức khoảng 4-6 để thử nghiệm. Tại thời điểm bài viết, độ khó Litecoin là khoảng 442.592.

Giờ ta thêm độ khó làm biến tĩnh vào lớp NoobChain:

public static int difficulty = 5;

Nên cập nhật lớp NoobChain để kích hoạt phương thức mineBlock() cho mỗi khối mới. Các Boolean isChainValid() cũng kiểm tra xem mỗi khối có một hash đã được giải quyết (bằng cách đào) hay không.

import java.util.ArrayList;
import com.google.gson.GsonBuilder;
public class NoobChain {
public static ArrayList<Block> blockchain = new ArrayList<Block>();
public static int difficulty = 5;
public static void main(String[] args) {
//add our blocks to the blockchain ArrayList:
blockchain.add(new Block("Hi im the first block", "0"));
System.out.println("Trying to Mine block 1... ");
blockchain.get(0).mineBlock(difficulty);
blockchain.add(new Block("Yo im the second block",blockchain.get(blockchain.size()-1).hash));
System.out.println("Trying to Mine block 2... ");
blockchain.get(1).mineBlock(difficulty);
blockchain.add(new Block("Hey im the third block",blockchain.get(blockchain.size()-1).hash));
System.out.println("Trying to Mine block 3... ");
blockchain.get(2).mineBlock(difficulty);
System.out.println("\nBlockchain is Valid: " + isChainValid());
String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
System.out.println("\nThe block chain: ");
System.out.println(blockchainJson);
}
public static Boolean isChainValid() {
Block currentBlock;
Block previousBlock;
String hashTarget = new String(new char[difficulty]).replace('\0', '0');
//loop through blockchain to check hashes:
for(int i=1; i < blockchain.size(); i++) {
currentBlock = blockchain.get(i);
previousBlock = blockchain.get(i-1);
//compare registered hash and calculated hash:
if(!currentBlock.hash.equals(currentBlock.calculateHash()) ){
System.out.println("Current Hashes not equal");
return false;
}
//compare previous hash and registered previous hash
if(!previousBlock.hash.equals(currentBlock.previousHash) ) {
System.out.println("Previous Hashes not equal");
return false;
}
//check if hash is solved
if(!currentBlock.hash.substring( 0, difficulty).equals(hashTarget)) {
System.out.println("This block hasn't been mined");
return false;
}
}
return true;
}
}

Kết quả hiển thị sẽ như sau:

Khai thác các khối

Đào mỗi khối sẽ mất một chút thời gian! (khoảng 3 giây). Bạn nên thử thay đổi các giá trị độ khó khác nhau để xem nó ảnh hưởng đến thời gian cần thiết để đào mỗi khối như thế nào.

Nếu ai đó giả mạo dữ liệu trong hệ thống blockchain:

  • Blockchain sẽ không hợp lệ
  • Sẽ không thể tạo ra một blockchain dài hơn.
  • Các blockchain trung thực trong mạng sẽ có lợi thế về thời gian trong chuỗi dài nhất.

Một blockchain giả mạo sẽ không thể bắt kịp chuỗi dài hơn và hợp lệ, trừ khi chúng có tốc độ tính toán lớn hơn tất cả các nút khác trong mạng kết hợp lại (có thể bằng một máy tính lượng tử trong tương lai hay gì đó).

Blockchain cơ bản đã hoàn tất rồi! Hãy ghi nhớ những điều sau về Blockchain của bạn:

  • Được tạo thành từ các khối lưu trữ dữ liệu.
  • Có một chữ ký số kết nối các khối của bạn với nhau.
  • Yêu cầu bằng chứng proof of work để xác nhận các khối mới.
  • Có thể kiểm tra xem dữ liệu trong đó có hợp lệ và có bị thay đổi không.

Xem thêm:

Thứ Năm, 05/07/2018 18:55
31 👨 1.773
0 Bình luận
Sắp xếp theo