iT邦幫忙

0

實作輕量級區塊鏈 (二):實作工作量證明與難度調整

  • 分享至 

  • xImage
  •  

昨天我們成功實作了區塊鏈的基礎資料結構,但如果你有實際執行昨天的程式碼,會發現 addBlock() 幾乎是在一瞬間就執行完畢並把區塊推入陣列中了。

在真實的分散式網路中,如果任何人都能在一秒內產生幾千幾萬個區塊,整個網路會立刻被垃圾區塊塞爆(這在資安上類似於一種 DoS 攻擊),且各個節點之間也無法有足夠的時間來同步最新的鏈狀態。

因此,我們需要一個機制來「故意拖慢」區塊產生的速度,這就是中本聰在比特幣中引入的工作量證明 (Proof of Work, PoW),俗稱「挖礦」。今天我們就要在程式碼中加入這個機制。

核心概念:Nonce 與難度 (Difficulty)
要怎麼讓電腦「刻意花時間」呢?區塊鏈的做法是設定一個數學難題。
我們要求產生的區塊 Hash 值,開頭必須包含特定數量的 0(例如:0000x...)。

但我們知道,只要區塊內的資料固定,算出來的 Hash 值就永遠是固定的。為了改變 Hash 的結果,我們必須在區塊中加入一個隨機應變的變數,這個變數就叫做 Nonce (Number used once)。礦工必須不斷更改 Nonce 的值,直到算出來的 Hash 剛好符合難度要求為止。

實作:修改 Block 類別
打開昨天的程式碼,我們需要對 Block 類別進行升級:加入 nonce,並實作 mineBlock 方法。
'''
const SHA256 = require('crypto-js/sha256');

class Block {
constructor(index, timestamp, data, previousHash = '') {
this.index = index;
this.timestamp = timestamp;
this.data = data;
this.previousHash = previousHash;
this.nonce = 0; // 新增:初始值設為 0
this.hash = this.calculateHash();
}

calculateHash() {
    // 新增:把 nonce 也加入 Hash 計算的字串中
    return SHA256(this.index + this.previousHash + this.timestamp + JSON.stringify(this.data) + this.nonce).toString();
}

// 新增:挖礦方法
mineBlock(difficulty) {
    // 產生一個長度為 difficulty 的字串,內容全是 '0'
    // 例如 difficulty 為 4,target 就是 '0000'
    const target = Array(difficulty).join("0");

    // 迴圈不斷執行,直到目前的 Hash 前面幾碼符合 target
    while (this.hash.substring(0, difficulty) !== target) {
        this.nonce++; // 更改 Nonce 值
        this.hash = this.calculateHash(); // 重新計算 Hash
    }

    console.log(`區塊開採成功!Hash: ${this.hash}, 嘗試次數: ${this.nonce}`);
}

}
'''

實作:修改 Blockchain 類別
接著,我們要告訴 Blockchain 目前的「難度」是多少,並在加入區塊前要求先進行挖礦。
'''
class Blockchain {
constructor() {
this.chain = [this.createGenesisBlock()];
this.difficulty = 4; // 新增:設定難度,數字越大越難算
}

// ... (保留原本的 createGenesisBlock, getLatestBlock, isChainValid 方法)

addBlock(newBlock) {
    newBlock.previousHash = this.getLatestBlock().hash;
    
    // 改變:不再直接計算 hash,而是呼叫 mineBlock 強制電腦去算數學題
    // newBlock.hash = newBlock.calculateHash(); 
    newBlock.mineBlock(this.difficulty);

    this.chain.push(newBlock);
}

}
'''

測試 PoW 機制
現在,讓我們再次執行我們的程式碼,看看會發生什麼事:
'''
let myIoTChain = new Blockchain();

console.log("正在開採區塊 1...");
myIoTChain.addBlock(new Block(1, "2026-09-22", { amount: 4 }));

console.log("正在開採區塊 2...");
myIoTChain.addBlock(new Block(2, "2026-09-23", { amount: 8 }));
'''

終端機輸出預期結果:
你會發現,程式不再是瞬間印出結果了。電腦風扇可能會轉一下,過了幾秒鐘後才印出:
'''
正在開採區塊 1...
區塊開採成功!Hash: 00008c2a... , 嘗試次數: 45892
正在開採區塊 2...
區塊開採成功!Hash: 0000b91e... , 嘗試次數: 120531
'''

透過實作 PoW,我們成功地掌握了區塊鏈的產塊節奏。這就是為什麼駭客很難竄改過去的區塊——因為一旦他改了其中一個區塊,他不只要重新計算那個區塊的 Hash,還要「重新挖出」後續所有區塊的工作量證明!在算力不如整個網路的情況下,這是根本做不到的。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言