如何在 Node.js 中構建簡單的加密貨幣區塊鏈
已發表: 2022-03-10smashingCoin
幣。 試一試——它比你想像的要簡單!加密貨幣的空前興起及其支撐的區塊鏈技術已經席捲了世界——從十多年前作為一個學術概念的卑微開端到目前在各個行業中越來越多的採用。
區塊鏈技術因其增強去信任環境中的安全性、強制去中心化和提高流程效率的能力而受到廣泛關注。
傳統上,Python 一直是區塊鏈開發的事實上的編程語言。 然而,隨著這項令人驚嘆的技術的普及,開發選項也增加了——Node.js 並沒有落伍。
在本教程中,我將討論如何在 Node.js 中構建一個簡單的加密貨幣區塊鏈。 它不會太花哨,但足以幫助您了解區塊鏈的工作原理。
我將把這個簡單的加密貨幣稱為smashingCoin
。
如果您是一名 JavaScript 開發人員,想要跨入新興的加密貨幣領域,本文將為您提供入門所需的技能。 或者,如果您對加密貨幣世界的運作方式感到好奇,那麼本教程可能有助於回答您的一些問題。
推薦閱讀: Drew McLellan 理解子資源完整性
先決條件
要成功學習本教程,您需要具備以下條件:
- Node.js 安裝在您的機器上。 你可以在這裡下載;
- 代碼編輯器,例如 Visual Studio Code、Sublime Text 或任何其他。
讓我們開始吧…
什麼是區塊鏈?
區塊鍊是為比特幣和以太坊等數字貨幣提供動力的技術。 它是一種創新的分佈式公共分類賬技術,可維護不斷增長的記錄列表,稱為塊,這些記錄使用加密技術安全連接。
術語區塊鏈因其保存交易數據的方式而得名,即在彼此連接以創建鏈的塊中。 區塊鏈的規模隨著所進行交易數量的增加而增長。
任何有效的交易數據都會記錄到區塊鍊網絡中,該網絡受參與者規定的點對點規則的約束。 例如,這些數據可能包含區塊的“價值”,例如數字貨幣、交易記錄(例如各方交換商品和服務的時間)或權利特權,例如鍊記錄所有權信息的時間。
除了交易數據,每個區塊可能包含自己的加密哈希(唯一標識符或數字足跡)、自己的 nonce 值(在加密計算中使用一次的任意隨機數)、前一個區塊的哈希和最近的時間戳經驗證的交易。
由於每個新塊都應該指向前一個塊,如果將一個塊併入鏈中而沒有包含最後一個塊的正確哈希,則可能會使整個區塊鏈無效。 這種不變性是區塊鏈安全的關鍵。
此外,通常會應用各種類型的共識協議來維護區塊鏈的真實性。 共識確保所有參與者都同意網絡驗證的交易。
例如,常用的共識協議是工作量證明,其目的是識別一個數字,在完成一定量的計算工作後,找到一個複雜數學問題的解決方案。
證明工作的主要思想是區塊鍊網絡中的任何參與者都應該發現這個數字難以識別但易於驗證。 因此,它阻止了垃圾郵件和篡改區塊鏈結構的行為。
在大多數加密貨幣的情況下,向區塊鏈添加新區塊需要求解一個複雜的數學方程,隨著區塊鏈的增長,難度會隨著時間的推移而增加。 因此,任何通過解決這個問題證明他們已經完成工作的人都會在被稱為“挖礦”的過程中獲得數字貨幣的補償。
如何創建塊
現在,在介紹了區塊鏈技術及其工作原理之後,讓我們看看如何將這些概念應用於創建區塊。 如前所述,區塊是相互鏈接以形成區塊鏈的東西。
為了創建smashingCoin
貨幣,我將使用在ES6 中引入的JavaScript 類。
準備好?
讓我們把手弄髒……
這是CryptoBlock
類的代碼:
const SHA256 = require('crypto-js/sha256'); class CryptoBlock{ constructor(index, timestamp, data, precedingHash=" "){ this.index = index; this.timestamp = timestamp; this.data = data; this.precedingHash = precedingHash; this.hash = this.computeHash(); } computeHash(){ return SHA256(this.index + this.precedingHash + this.timestamp + JSON.stringify(this.data)).toString(); } }
正如您在上面的代碼中所見,我創建了CryptoBlock
類並向其添加了constructor()
方法——就像在任何其他 JavaScript 類中所做的一樣。 然後,為了初始化其屬性,我將以下參數分配給constructor
方法:
index | 它是一個唯一編號,用於跟踪整個區塊鏈中每個區塊的位置。 |
timestamp | 它記錄每個已完成事務的發生時間。 |
data | 它提供有關已完成交易的數據,例如發件人詳細信息、收件人詳細信息和交易數量。 |
precedingHash | 它指向區塊鏈中前一個區塊的哈希值,這對於維護區塊鏈的完整性很重要。 |
此外,我使用computeHash
方法根據其屬性計算塊的哈希,如上面的數據所示。
如您所見,我導入了 crypto-js JavaScript 庫並使用其crypto-js/sha256
模塊來計算每個塊的哈希值。 由於模塊返回一個數字對象,我使用toString()
方法將其轉換為字符串。
要將 crypto-js 庫添加到您的項目中,請轉到終端並運行以下命令以使用npm
安裝它:
npm install --save crypto-js
運行上述命令後,包含庫和其他基本文件的節點模塊目錄將添加到您的項目文件夾中。
如何創建區塊鏈
如前所述,區塊鏈技術基於所有區塊相互鏈接的概念。 所以,讓我們創建一個CryptoBlockchain
類來負責處理整個鏈的操作。 這是橡膠將與道路相遇的地方。
CryptoBlockchain
類將使用完成不同任務的輔助方法來維護區塊鏈的操作,例如創建新塊並將它們添加到鏈中。
這是CryptoBlockchain
類的代碼:
class CryptoBlockchain{ constructor(){ this.blockchain = [this.startGenesisBlock()]; } startGenesisBlock(){ return new CryptoBlock(0, "01/01/2020", "Initial Block in the Chain", "0"); } obtainLatestBlock(){ return this.blockchain[this.blockchain.length - 1]; } addNewBlock(newBlock){ newBlock.precedingHash = this.obtainLatestBlock().hash; newBlock.hash = newBlock.computeHash(); this.blockchain.push(newBlock); } }
讓我談談構成CryptoBlockchain
類的每個輔助方法的作用。
1.構造方法
此方法實例化區塊鏈。 在構造函數中,我創建了區塊blockchain
屬性,它引用了一個塊數組。 請注意,我向它傳遞了startGenesisBlock()
方法,該方法在鏈中創建了初始塊。
2. 創建創世塊
在區塊鏈中,創世塊是指在網絡上創建的第一個塊。 每當一個塊與鏈的其餘部分集成時,它應該引用前一個塊。
相反,在這個初始塊的情況下,它沒有任何前面的塊可以指向。 因此,創世塊通常被硬編碼到區塊鏈中。 這樣,可以在其上創建後續塊。 它的索引通常為 0。
我使用startGenesisBlock()
方法來創建創世塊。 請注意,我使用precedingHash
創建的CryptoBlock
類創建了它,並傳遞了index
、 timestamp
、 data
和 previousHash 參數。
3. 獲取最新區塊
獲取區塊鏈中的最新區塊有助於確保當前區塊的哈希指向前一個區塊的哈希——從而保持鏈的完整性。
我使用了obtainLatestBlock()
方法來檢索它。
4.添加新塊
我使用addNewBlock()
方法將新塊添加到鏈中。 為了做到這一點,我將新塊的前一個哈希值設置為鏈中最後一個塊的哈希值——從而確保鍊是防篡改的。
由於每次新計算都會改變新塊的屬性,因此再次計算其加密哈希非常重要。 更新其哈希後,新塊被推入區塊鏈數組。
實際上,由於已經放置了幾項檢查,因此向區塊鏈添加新塊並不容易。 儘管如此,對於這種簡單的加密貨幣,足以證明區塊鏈的實際運作方式。
測試區塊鏈
現在,讓我們測試我們的簡單區塊鏈,看看它是否有效。
這是代碼:
let smashingCoin = new CryptoBlockchain(); smashingCoin.addNewBlock(new CryptoBlock(1, "01/06/2020", {sender: "Iris Ljesnjanin", recipient: "Cosima Mielke", quantity: 50})); smashingCoin.addNewBlock(new CryptoBlock(2, "01/07/2020", {sender: "Vitaly Friedman", recipient: "Ricardo Gimenes", quantity: 100}) ); console.log(JSON.stringify(smashingCoin, null, 4));
正如您在上面的代碼中看到的,我創建了CryptoBlockchain
類的一個新實例並將其命名為smashingCoin
。 然後,我使用一些任意值將兩個塊添加到區塊鏈中。 在data
參數中,我使用了一個對象並添加了發件人詳細信息、收件人詳細信息和交易數量。
如果我在終端上運行代碼,這是我得到的輸出:
這就是smashingCoin
的樣子! 它是一個包含區塊blockchain
屬性的對象,它是一個包含鏈中所有塊的數組。 如上圖所示,每個區塊都引用了前一個區塊的哈希值。 例如,第二個塊引用了第一個塊的哈希。 在測試並看到我們的區塊鏈有效之後,讓我們添加更多功能來增強smashingCoin
的功能。
如何驗證區塊鏈的完整性
如前所述,區塊鏈的一個關鍵特徵是,一旦將一個塊添加到鏈中,就不能在不破壞鏈其餘部分的完整性的情況下對其進行更改。
因此,為了驗證區塊鏈的完整性,我將在CryptoBlockchain
類中添加一個checkChainValidity()
方法。
哈希對於確保區塊鏈的有效性和安全性至關重要,因為區塊內容的任何更改都將導致產生全新的哈希,並使區塊鏈失效。
因此, checkChainValidity()
方法將使用if
語句來驗證每個塊的哈希是否已被篡改。 從第一個創建的塊開始,它將遍歷整個區塊鏈並檢查其有效性。 請注意,由於創世塊是硬編碼的,因此不會被檢查。
此外,該方法將驗證每兩個連續塊的哈希是否相互指向。 如果區塊鏈的完整性沒有受到損害,則返回 true; 否則,如果出現任何異常,則返回 false。
這是代碼:
checkChainValidity(){ for(let i = 1; i < this.blockchain.length; i++){ const currentBlock = this.blockchain[i]; const precedingBlock= this.blockchain[i-1]; if(currentBlock.hash !== currentBlock.computeHash()){ return false; } if(currentBlock.precedingHash !== precedingBlock.hash) return false; } return true; }
如何添加工作證明
如前所述,工作量證明是用於增加挖礦難度或向區塊鏈添加新區塊的概念。
在smashingCoin
的情況下,我將使用一種簡單的算法來阻止人們輕鬆生成新塊或向區塊鏈發送垃圾郵件。
因此,在CryptoBlock
類中,我將添加另一個名為proofOfWork().
本質上,這個簡單的算法識別一個數字,作為difficulty
屬性傳遞,這樣每個塊的哈希都包含對應於這個difficulty
級別的前導零。
確保每個塊的哈希以difficulty
級別中設置的零數量開始,這需要大量的計算能力。 難度級別越高,挖掘新區塊所需的時間就越多。
此外,我將為每個散列塊添加一個隨機nonce
值,以便在重新散列時仍然可以滿足難度級別限制。
這是代碼:
proofOfWork(difficulty){ while(this.hash.substring(0, difficulty) !==Array(difficulty + 1).join("0")){ this.nonce++; this.hash = this.computeHash(); } }
而且,這是更新後的computeHash()
方法,其中包含nonce
變量:
computeHash(){ return SHA256(this.index + this.precedingHash + this.timestamp + JSON.stringify(this.data)+this.nonce).toString(); }
另外,為了在新塊的生成中實現工作量證明機制,我將把它包含在addNewBlock()
方法中:
addNewBlock(newBlock){ newBlock.precedingHash = this.obtainLatestBlock().hash; //newBlock.hash = newBlock.computeHash(); newBlock.proofOfWork(this.difficulty); this.blockchain.push(newBlock); }
包起來
以下是使用 Node.js 構建smashingCoin
加密貨幣的完整代碼:
const SHA256 = require("crypto-js/sha256"); class CryptoBlock { constructor(index, timestamp, data, precedingHash = " ") { this.index = index; this.timestamp = timestamp; this.data = data; this.precedingHash = precedingHash; this.hash = this.computeHash(); this.nonce = 0; } computeHash() { return SHA256( this.index + this.precedingHash + this.timestamp + JSON.stringify(this.data) + this.nonce ).toString(); } proofOfWork(difficulty) { while ( this.hash.substring(0, difficulty) !== Array(difficulty + 1).join("0") ) { this.nonce++; this.hash = this.computeHash(); } } } class CryptoBlockchain { constructor() { this.blockchain = [this.startGenesisBlock()]; this.difficulty = 4; } startGenesisBlock() { return new CryptoBlock(0, "01/01/2020", "Initial Block in the Chain", "0"); } obtainLatestBlock() { return this.blockchain[this.blockchain.length - 1]; } addNewBlock(newBlock) { newBlock.precedingHash = this.obtainLatestBlock().hash; //newBlock.hash = newBlock.computeHash(); newBlock.proofOfWork(this.difficulty); this.blockchain.push(newBlock); } checkChainValidity() { for (let i = 1; i < this.blockchain.length; i++) { const currentBlock = this.blockchain[i]; const precedingBlock = this.blockchain[i - 1]; if (currentBlock.hash !== currentBlock.computeHash()) { return false; } if (currentBlock.precedingHash !== precedingBlock.hash) return false; } return true; } } let smashingCoin = new CryptoBlockchain(); console.log("smashingCoin mining in progress...."); smashingCoin.addNewBlock( new CryptoBlock(1, "01/06/2020", { sender: "Iris Ljesnjanin", recipient: "Cosima Mielke", quantity: 50 }) ); smashingCoin.addNewBlock( new CryptoBlock(2, "01/07/2020", { sender: "Vitaly Friedman", recipient: "Ricardo Gimenes", quantity: 100 }) ); console.log(JSON.stringify(smashingCoin, null, 4));
如果我在終端上運行代碼,這是我得到的輸出:
如上圖所示,哈希現在以四個零開頭,這與工作量證明機制中設置的難度級別相對應。
結論
而已! 這就是您可以使用 Node.js 構建簡單的加密貨幣區塊鏈的方式。
當然, smashingCoin
加密貨幣遠未完成。 事實上,如果你在不做更多改進的情況下發布它,它就不太可能滿足當前市場對安全、可靠和直觀的數字貨幣的需求——讓你成為唯一使用它的人!
儘管如此,我希望本教程為您提供了一些基本技能,讓您在激動人心的密碼世界中涉足。
如果您有任何意見或問題,請在下方發布。
更多資源
- “區塊鏈 101”,CoinDesk
- “比特幣:點對點電子現金系統”,中本聰,Bitcoin.org