Kiến trúc Blockchain – Tạo blockchain với bài toán PoW bằng javascript – Phần 2

■ Gợi nhớ

Trong bài viết trước, chúng ta đã làm quen với cấu trúc cơ bản của một Blockchain. Mình xem lại cấu trúc Blockchain cơ bản một xíu nhé. Đơn vị cấu thành nhỏ nhất trong blockchain là Block. Một Blockchain có nhiều Block nối với nhau. Mỗi Block sẽ chứa những thông tin cơ bản như index, prevHash, timestamp, data, hash. Như vậy, để tạo một Block mới gắn vào tiếp chuỗi Blockchain, thì chúng ta chỉ cần tạo 1 block gồm như thông tin như trên, trong đó, hash được tạo ra bằng thuật toán SHA. Sau đó, gắn block mới tạo vào chuỗi blockchain. Thật là đơn giản phải không ^^.

Bạn có thể xem lại phần 1 ở đây.

Nhưng đi sâu hơn một xíu trong thị trường tiền điện tử, điển hình như Bitcoin, chắc hẳn bạn cũng nghe loáng thoáng về máy đào coin, những máy đó phải giải thuật toán để xác nhận các transaction, giải xong bài toàn thì sẽ được thưởng bitcoin, độ khó đào coin ngày càng khó nên việc giải thuật toán cũng càng khó, v.v… Vậy với cái Blockchain cơ bản ở trong phần một mình đã trình bày, thì độ khó nằm đâu? phần thưởng cho máy đào nằm đâu? Cứ bình tĩnh, đọc tiếp phần dưới này nhé.

■ Blockchain với thuật toán Proof-of-Work

Trước tiên mình muốn đưa ra bài toán đơn giản cho dễ hiểu như vầy:
● Bài toán dạng 1: A bằng bao nhiêu?

1 + 2 + 3 + 4 + 5 = A

111 + 222 + 333 + 444 + 555 = A

● Bài toán dạng 2: A bằng bao nhiêu?

1 + 2 + 3 + 4 + A = 111

222 + A + 333 + 444 + 555 = 9999

● Bài toán dạng 3: A bằng bao nhiêu? Trong đó, B là một số tuỳ ý nhưng phải thoả điều kiện

4 + 5 + 8 + 9 + A  = B | với điều kiện B phải chia hết cho 3

11 + 22 + 33 + 44 + A  = B | với điều kiện chữ số đầu của B phải bằng 3

Trong 3 dạng toán trên, bạn có cảm nhận độ khó tăng dần không. Bài toán dạng một là một bài toàn dạng xuôi khá đơn giản. Nhưng đến bài toán thứ hai, thì bạn phải truy ngược lại để tìm số A. Đến dạng toán thứ 3 thì không những phải truy ngược lại mà còn kèm theo điều kiện. Vì vậy ai giải nhanh nhất sẽ là người chiến thắng và sẽ được thưởng.

Trong Blockchain có áp dụng thuật toán Proof-of-Work cũng vậy. Nhìn vào hình vẽ bên dưới, bạn sẽ thấy trong cấu trúc có thêm một param nonce. Nonce là một con số tuỳ ý, giống như số A trong bài toán ví dụ. Để hiểu rõ hơn bạn nhìn vào hình bên dưới nhé.

Khi có một Block mới muốn add vào Blockchain, Block đó sẽ được tạo ra với những tham số cơ bản và một số nonce. Lúc này, nonce và hash vẫn là ẩn số. Hash sẽ có công thức tính như sau:

hash = SHA256(index + prevHash + timestamp + JSON.stringify(data) + nonce); 

và hash tìm được phải thoả kiều kiện 2 chữ số đầu của hash phải bằng 00. Điều điện đó ta gọi nó là độ khó. Độ khó càng tăng khi ta thay đổi điều kiện thoả càng phức tạp.

Vd:

2 chữ số đầu của hash phải bằng dc => độ khó *

5 chữ số đầu của hash phải bằng dc48e => độ khó **

5 chữ số đầu của hash phải bằng dc48e2 chữ số cuối của hash phải bằng 00 => độ khó n* ^^

Để tìm ra hash thoả điều kiện, máy tính sẽ chạy liên tục công thức tính hash bằng SHA256 như trên với con số nonce nào đó. Nếu hash tìm ra không thoả, máy tính sẽ thay đổi số nonce khác rồi tính lại công thức cho đến khi hash tìm được thoả điều kiện. Sẽ có nhiều máy tính tham gia giải bài toán này. Máy tính nào tìm thấy con số nonce tạo ra hash thoả điều kiện đầu tiên sẽ là máy tính tính chiến thằng và sẽ được thưởng.

■ Blockchain với Demo

Viết thử cái demo để chạy xem nhé, cho dễ hình dung hơn.

Code toàn bộ ở đây nhé.

Dựa vào demo ở phần 1, chúng ta chỉnh sửa lại chút xíu nhé. Đầu tiên xem flowchart để  hình dung code chạy như thế nào nhé.

Đầu tiên, ví dụ có

address_1 gửi đến address_2 100 coin => là 1 transaction

address_3 gửi đến address_4 100 coin => là 1 transaction khác

những transaction sẽ vào hàng đợi, khi block mới được tạo, các transaction sẽ được bỏ vào block đóng vai trò là tham số data. Sau đó miner sẽ bắt đầu giải toán cho block mới đó bằng cách thay đổi con số nonce cho phù hợp để hash thoả điều kiện. Sau khi giải toán thành công, block đó sẽ đuọc add vào blockchain và 1 transaction mới được tạo để chuyển tiền thưởng cho miner.

Dựa vào code ở phần 1, code của chúng ta sẽ thêm như sau:

Định nghĩa thêm class Transaction

// định nghĩa thêm class transaction
// gồm các thông tin cần thiết:
// địa chỉ gửi, địa chỉ đến, số tiền, phí giao dịch
class Transaction{
    constructor(fromAddress, toAddress, amount, fee){
        this.fromAddress = fromAddress;
        this.toAddress = toAddress;
        this.amount = amount;
        this.fee = fee;
    }
}

Trong class Block, chúng ta thêm một tẹo như sau:

class Block {
    constructor(timestamp, transactions, previousHash = '') {
        this.previousHash = previousHash;
        this.timestamp = timestamp;
        this.transactions = transactions;
        this.hash = this.calculateHash();
        this.nonce = 0;        // <------- thêm nonce } calculatehash() { return sha256( this.previoushash + this.timestamp json.stringify(this.transactions) this.nonce <------- ).tostring(); hàm này sẽ chạy loop tìm con số để tạo hash thoả độ khó mineblock(difficulty) while (this.hash.substring(0, difficulty) !="=" array(difficulty 1).join("0")) this.nonce++; this.hash="this.calculateHash();" }< code>

Trong class Blockchain, sẽ thêm như sau:

class Blockchain{
    constructor() {
        this.chain = [this.createGenesisBlock()];
        // độ khó là 2 chữ số đầu của hash == 00 this.difficulty = 2;
        // list transaction đang chờ xác nhận
        this.pendingTransactions = [];  
        // phần thưởng
        this.miningReward;
    }
    //
    // sau khi giải được nonce cho block
    // miner sẽ được thưởng dựa vào fee chuyển của các transaction
    // trong block đã mine thành công
    getminingReward() {
      let reward = 0;
      for(const trans of this.pendingTransactions){
          reward += trans.fee;
      }
      return reward;
    }
    //
    minePendingTransactions(miningRewardAddress){
        // tạo block mới và mine tìm số nonce phù hợp
        let block = new Block(Date.now(), this.pendingTransactions, this.getLatestBlock().hash);
        block.mineBlock(this.difficulty);
        console.log('Block successfully mined!');
        this.chain.push(block);
        // tạo 1 transaction chuyển tiền thưởng 
        //cho address đã tham gia mine thành công
        var miningReward = Number(this.getminingReward())*0.8;
        this.pendingTransactions = [
            new Transaction(null, miningRewardAddress, miningReward, miningReward*0.1)
        ];
    }
    //
    // add transaction muốn xác nhận vào hàng đợi
    createTransaction(transaction){
        this.pendingTransactions.push(transaction);
    }
    //
    // đọc lại lịch sử các block trong chuỗi blockchain
    // tính toán số tiền hiện tại của address đó
    getBalanceOfAddress(address){
        let balance = 0;
        for(const block of this.chain){
            for(const trans of block.transactions){
                if(trans.fromAddress === address){
                    balance -= trans.amount;
                }
                if(trans.toAddress === address){
                    balance += trans.amount;
                }
            }
        }
        return balance;
    }
}

Còn lại giữ nguyên như code ở phần một nhé.

Chạy thử xem nhé

let landthCoin = new Blockchain();
landthCoin.createTransaction(new Transaction('address1', 'address2', 100, 10));
landthCoin.createTransaction(new Transaction('address2', 'address1', 50, 5));

console.log('\n Starting the miner...');
landthCoin.minePendingTransactions('landth-address');

console.log('\nBalance of landth is', landthCoin.getBalanceOfAddress('landth-address'));

console.log('\n Starting the miner again...');
landthCoin.minePendingTransactions('xaviers-address');

console.log('\nBalance of landth is', landthCoin.getBalanceOfAddress('landth-address'));

Kết quả sau khi chạy console sẽ in ra như sau:

 Starting the miner...
BLOCK MINED: 008b274d75d856de3911f9066b97e587c2d02b4b8b1a86fc4c7a13eca8739060
Block successfully mined!

Balance of landth is 0

 Starting the miner again...
BLOCK MINED: 00d687f3c63bfecc871217494e807306eb2d73e952087399a81820dfbd252504
Block successfully mined!

Balance of landth is 12

 ■ Tâm tư

Thật thú vị phải không? Nhưng hiện nay, độ khó để mine Bitcoin như các bạn cũng đã biết, ngày càng khó. Đòi hỏi các máy tính chạy để giải bài toán phải thật mạnh mẽ và phải chạy suốt ngày đêm. Chính vì điều đó đã gây ra vấn đề môi trường cho nhân loại. Điện tiêu thụ cho các máy đào ngốn không ít. Vì vậy cần tìm ra một cách giải toán mới mà đỡ tốn tiền chạy máy đào nhĩ. Và có lẽ thuật toán Proof-of-Stake (PoS) đang được cân nhắc và thay thế. Hiện nay, Bitcoin với PoS vẫn đang được chạy thí nghiệm. Bên cạnh đó, cũng có những Network mới ra đời sau này đã áp dụng PoS. Nhưng tất cả chỉ đang trong giai đoạn phân tích và test. Liệu PoS có thay thế PoW được không, chúng ta chờ đợi xem nhé.