用Javasctipt程式碼簡單模擬解釋區塊鏈概念
本文試圖用簡單200行程式碼來解析區塊鏈的基本原理。
區塊鏈基本概念很簡單:它其實是一個分散式資料庫,維護一個不斷增長的有序的記錄列表。“區塊鏈”術語通常與諸如交易,智慧合約或加密貨幣等概念密切相關。涉及這麼多概念使得理解區塊鏈變成一個艱鉅的任務。這裡將通過一個稱為NaiveChain庫包使用200行的Javascript實現超簡單的blockchain。
第一個邏輯步驟是決定塊結構。為了使事情儘可能簡單,我們僅包含最必要的:index,timestamp,data,hash和previous hash。
必須在塊中找到前一個塊的Hash,以保持鏈的完整性,程式碼如下:
class Block { constructor(index, previousHash, timestamp, data, hash) { this.index = index; this.previousHash = previousHash.toString(); this.timestamp = timestamp; this.data = data; this.hash = hash.toString(); } }
塊Hash雜湊
塊需要實行Hash以保持資料的完整性。演算法使用SHA-256。應該注意,這個Hash與“ 挖掘 ” 無關,因為不需要解決Proof Of Work工作證明問題。
var calculateHash = (index, previousHash, timestamp, data) => { return CryptoJS.SHA256(index + previousHash + timestamp + data).toString(); };
為了生成一個塊,我們必須知道前一個塊的雜湊,並建立所需內容的其餘部分(=索引,雜湊,資料和時間戳),塊資料是由終端使用者提供的。
var generateNextBlock = (blockData) => { var previousBlock = getLatestBlock(); var nextIndex = previousBlock.index + 1; var nextTimestamp = new Date().getTime() / 1000; var nextHash = calculateHash(nextIndex, previousBlock.hash, nextTimestamp, blockData); return new Block(nextIndex, previousBlock.hash, nextTimestamp, blockData, nextHash); };
儲存塊
記憶體中的Javascript陣列用於儲存區塊鏈。區塊鏈的第一塊總是一個所謂的“基因塊genesis-block”,它是硬編碼的。
var getGenesisBlock = () =>{ return new Block(0,"0",1465154705,"my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7"); }; var blockchain=[getGenesisBlock()];
驗證塊的完整性
在任何指定時間,我們必須能夠驗證塊或塊鏈在完整性方面是否有效。特別是當我們從其他節點接收新塊,並必須決定是否接受他們時。
var isValidNewBlock = (newBlock, previousBlock) => { if (previousBlock.index + 1 !== newBlock.index) { console.log('invalid index'); return false; } else if (previousBlock.hash !== newBlock.previousHash) { console.log('invalid previoushash'); return false; } else if (calculateHashForBlock(newBlock) !== newBlock.hash) { console.log('invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash); return false; } return true; };
選擇最長的鏈
在指定時間鏈中應該總是隻有一個顯式塊。在衝突的情況下(例如,兩個節點都生成塊號72),我們選擇具有最長塊數的鏈。
var replaceChain = (newBlocks) => { if (isValidChain(newBlocks) && newBlocks.length > blockchain.length) { console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); blockchain = newBlocks; broadcast(responseLatestMsg()); } else { console.log('Received blockchain invalid'); } };
與其他節點通訊
節點的一個重要部分是與其他節點共享和同步區塊鏈。以下規則用於保持網路同步。
- 當節點生成新塊時,它將其廣播到網路
- 當節點連線到新的對等體時,它查詢最新的塊
- 當節點遇到具有大於當前已知塊的索引的塊時,它將塊新增到其當前鏈或查詢整個區塊鏈。
上圖是當節點服從所描述的協議時遵循的一些典型的通訊場景
不使用自動對等體發現。對等體的位置(= URL)就必須手動新增。
控制節點
使用者必須能夠以某種方式控制節點。這是通過設定HTTP伺服器來完成的。
var initHttpServer = () = > { var app = express(); app.use(bodyParser.json()); app.get('/blocks', (req, res) = > res.send(JSON.stringify(blockchain)) ) ; app.post('/mineBlock', (req, res) = > { var newBlock = generateNextBlock(req.body.data); addBlock(newBlock); broadcast(responseLatestMsg()); console.log('block added: ' + JSON.stringify(newBlock)); res.send(); }); app.get('/peers', (req, res) = > { res.send(sockets.map(s = > s._socket.remoteAddress + ':' + s._socket.remotePort) ); }); app.post('/addPeer', (req, res) = > { connectToPeers([req.body.peer]); res.send(); }); app.listen(http_port, () = > console.log('Listening http on port: ' + http_port) ); } ;
如程式碼所示,使用者能夠以以下方式與節點互動:
- 列出所有塊
- 建立由使用者提供內容的新塊
- 列出或新增對等體
控制節點的最直接的方法是例如使用Curl:
#get所有節點的塊
curl http://localhost:3001/blocks
架構
應該注意,一個節點實際上暴露了兩個Web伺服器:一個用於使用者控制節點(HTTP伺服器),一個用於節點之間的對等通訊(Websocket HTTP伺服器)
NaiveChain的主要元件
結論
NaiveChain是為了演示和學習區塊鏈而建立的。由於它沒有“ 挖掘 ”演算法(PoS的PoW),它不能在公共網路中使用。它仍然實現了功能區塊鏈的基本特徵。
您可以檢查ofollow,noindex" target="_blank">Github儲存庫 以獲取更多技術詳細資訊。