TiiL Tutorials
@TinhocTiiL

Ví dụ Lập trình Blockchain với Java

Trước hết, hiểu cách blockchain làm việc.

Các đơn vị cơ bản của blockchain là các blocks.  Mỗi block có thể gói một số lượng giao dịch (transactions) hoặc dữ liệu có giá trị khác:

3.1. Mining (đào) một Block

Chúng ta biểu diễn một block bởi một giá trị hash. Việc tạo giá trị hash cho một block được gọi là ĐÀO “mining” block. Việc đào một block thường tốn kém về mặt tính toán để thực hiện vì nó đóng vai trò như “proof of work”.

Hàm băm của một khối thường có những dữ liệu sau:

  • Về cơ bản, hash của một block bao gồm các giao dịch mà nó đóng gói
  • hash cũng có thể bao gồm cả nhãn thời gian (timestamp) khi tạo khối
  • It also includes a nonce, an arbitrary number used in cryptography
  • Cuối cùng, hash của khối hiện tại bao gồm cả hash của previous block

Nhiều nodes trên mạng có thể cạnh tranh để đào block tại cùng một thời điểm. Ngoại trừ việc tạo hash, các nodes cũng phải xác minh rằng các transactions đang được thêm vào block là hợp pháp.

3.2. Việc thêm một Block vào Blockchain

Trong khi việc “đào/khai thác” một khối rất tốn kém về mặt tính toán,  việc xác minh rằng một block có hợp pháp hay không thì tương đối dễ hơn nhiều. Tất cả các nodes trong mạng tham gia xác minh một khối mới được khai thác.

Do đó, một khối mới được khai thác được thêm vào blockchain dựa trên sự đồng thuận của các nút.

Hiện tại, có một số giao thức đồng thuận có sẵn mà chúng ta có thể sử dụng để xác minh. Các nút trong mạng sử dụng cùng một giao thức để phát hiện nhánh độc hại của chuỗi. Do đó, một nhánh độc hại ngay cả khi được giới thiệu sẽ sớm bị phần lớn các nút từ chối.

4. Blockchain cơ bản với Ngôn ngữ Java

4.1. Thực thi/Xây dựng một  Block

Đầu tiên, chúng ta cần định nghĩa một POJO đơn giản để lưu dữ liệu của block:

public class Block {
    private String hash;
    private String previousHash;
    private String data;
    private long timeStamp;
    private int nonce;
    // Hàm khởi tạo
    public Block(String data, String previousHash, long timeStamp) {
        this.data = data;
        this.previousHash = previousHash;
        this.timeStamp = timeStamp;
        this.hash = calculateBlockHash();
    }
    // Các getters và setters chính ở đây...
}
  • hash:  lưu giá trị hash của block, được tính tính toán dựa trên dữ liệu khác
  • previousHash: giá trị hash của block liền trước nó, phần quan trọng để xây dựng chuỗi (chain)
  • data: dữ liệu thực tế, bất kỳ thông tin nào có giá trị, vd như một hợp đồng -contract
  • timestamp:Thời gian tạo block này
  • nonce: một số tùy ý được sử dụng trong cryptograph

4.2. Tính toán giá trị Hash

Theo triên, việc tính toán sẽ được thực hiện thông qua một phương thức calculateBlockHash 

Một giá trị hash là đầu ra của một hàm băm (hash function). Một hash function ánh xạ dữ liệu đầu vào có kích thước tùy ý thành dữ liệu đầu tra có kích thước cố định. Ngoài ra, hàm băm là hàm một chiều (ta không thể suy ngược lại được dữ liệu đầu vào tư đầu ra của nó.

Sau đây là mã lệnh để tạo giá trị hash của một block  bằng Java:

public String calculateBlockHash() {
    String dataToHash = previousHash + Long.toString(timeStamp) 
      + Integer.toString(nonce) + data;
    MessageDigest digest = null;
    byte[] bytes = null;
    try {
        digest = MessageDigest.getInstance("SHA-256");
        bytes = digest.digest(dataToHash.getBytes(UTF_8));
    } catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
        logger.log(Level.SEVERE, ex.getMessage());
    }
    StringBuffer buffer = new StringBuffer();
    for (byte b : bytes) {
        buffer.append(String.format("%02x", b));
    }
    return buffer.toString();
}

Giải thích

  • Đầu tiên, chúng ta “nối” các thuộc tính của block thành một chuỗi, để tạo hash từ nó
  • sau đó, chúng ta tạo một instance SHA-256 hash function tử lớp thư viện MessageDigest
  • tiếp đến, chúng ta tạo hash value, (khi này đang ở byte array)
  • Cuối cùng, chung ta biển đổi về hex string ( vì một giá trị hash thường được biểu diễn ở chuỗi 32 số hệ 16

4.3. ĐÀO Block

Khai thác một khối nghĩa là giải quyết một công việc tính toán phức tạp cho khối. Trong khi việc tính gián giá trị băm của một khối là tương đối đơn giản, thì việc tìm kiếm giá trị băm bắt đầu với 5 số không thì ngược lại.

public String mineBlock(int prefix) {
    String prefixString = new String(new char[prefix]).replace('\0', '0');
    while (!hash.substring(0, prefix).equals(prefixString)) {
        nonce++;
        hash = calculateBlockHash();
    }
    return hash;
}

Let’s see what we trying to do here are:

  • We start by defining the prefix we desire to find
  • Then we check whether we’ve found the solution
  • If not we increment the nonce and calculate the hash in a loop
  • The loop goes on until we hit the jackpot

We’re starting with the default value of nonce here and incrementing it by one. But there are more sophisticated strategies to start and increment a nonce in real-world applications. Also, we’re not verifying our data here, which is typically an important part.

4.4. Let’s Run the Example

Now that we’ve our block defined along with its functions, we can use this to create a simple blockchain. We’ll store this in an ArrayList:

List<Block> blockchain = new ArrayList<>();
int prefix = 4;
String prefixString = new String(new char[prefix]).replace('\0', '0');

Additionally, we’ve defined a prefix of four, which effectively means that we want our hash to start with four zeroes.

Let’s see how can we add a block here:

@Test
public void givenBlockchain_whenNewBlockAdded_thenSuccess() {
    Block newBlock = new Block(
      "The is a New Block.", 
      blockchain.get(blockchain.size() - 1).getHash(),
      new Date().getTime());
    newBlock.mineBlock(prefix);
    assertTrue(newBlock.getHash().substring(0, prefix).equals(prefixString));
    blockchain.add(newBlock);
}

4.5. Blockchain Verification

How can a node validate that a blockchain is valid? While this can be quite complicated, let’s think about a simple version:

@Test
public void givenBlockchain_whenValidated_thenSuccess() {
    boolean flag = true;
    for (int i = 0; i < blockchain.size(); i++) {
        String previousHash = i==0 ? "0" : blockchain.get(i - 1).getHash();
        flag = blockchain.get(i).getHash().equals(blockchain.get(i).calculateBlockHash())
          && previousHash.equals(blockchain.get(i).getPreviousHash())
          && blockchain.get(i).getHash().substring(0, prefix).equals(prefixString);
            if (!flag) break;
    }
    assertTrue(flag);
}

So, here we’re making three specific checks for every block:

  • The stored hash of the current block is actually what it calculates
  • The hash of the previous block stored in the current block is the hash of the previous block
  • The current block has been mined
Avatar
https://khoacntt.ntu.edu.vn/giang-vien/mai-cuong-tho

một GV Đại học. TiiL đã phụ trách một số môn học như: Lập trình Java, Phát triển web với Java, Lập trình thiết bị di động, Lập trình hệ thống nhúng và IoT.

Comments are closed.