最全 比特幣區塊鏈結構+程式碼
阿新 • • 發佈:2019-01-29
-
1. 區塊鏈書籍和有用連結
首先,本人也是一週後在學習區塊鏈的路上,學習中將自己看過的有用的資訊就放在自己的GitHub上,方便自己複習好找
本人首頁:www.github.com/cancerts/study-blockchain-referrence 【點選】
裡面有我25本(寫部落格時)區塊鏈領域比較熱門的書籍,有PDF、mobi三種格式的,懂區塊鏈的自己取
- 2. 區塊鏈結構和程式碼(JavaScript)
- 3. 區塊鏈
區塊鏈是一種分散式賬本,運用了許多密碼學的技術來保證寫入賬本的資料安全,不被篡改,我們知道最初是沒有區塊鏈這個概念的,是從比特幣底層組織資料的形式中提出來的
- 4. 區塊
第一個區塊稱為創世區塊(Genesis block),區塊鏈中包含Index Timestamp Hash Previous Hash Data Nonce 區塊號 時間戳 sh256 前一個區塊的hash 輸入的內容 隨機值 程式碼:
class Block { constructor (index, previousHash, timestamp, data, hash, nonce) { this.index = index; this.previousHash = previousHash; this.timestamp = timestamp; this.data = data; this.hash = hash; this.nonce = nonce; } get genesis() { new Block( 0, "0", 1508270000000, "Welcome to Blockchain", "000dc75a315c77a1f9c98fb6247d03dd18ac52632d7dc6a9920261d8109b37cf", 604 ); } } module.exports = Block;
- 5. 索引
創世區塊區塊索引為0,下一個區塊為1,每增加一個區塊增加一,每一個區塊鏈的所以唯一代表一個區塊,可以更具索引查詢到相應的區塊資訊
- 6. 時間戳
區塊被建立的時間,用的是Linux時間表示方法,區塊根據時間戳進行排序
- 7. 雜湊
雜湊就是一段隨機值:000dc75a315c77a1f9c98fb6247d03dd18ac52632d7dc6a9920261d8109b37cf,根據輸入內容計算出
&&:相同的資料得到的hash值相同
&&:不同的資料得到完全不同的hash值
&&:hash很容易計算
&&:不能有hash值遞推出源資料
&&:一個數據很小的變化導致hash值的變化很大
- 8. 有效雜湊
有效雜湊指規定計算後hash值的最前面0的數量達到要求,0越多,那麼要找到正確的隨機值(nonce)計算出有效的hash就會越困難
程式碼:
// cosnt Block = reuqire("./Block.js"); // class Blockchain { // constructor() { // this.blockchain = [Block.genesis()]; this.difficulty = 20; // } // get() { ... } // get latestBlock() { ... } isValidHashDifficulty(hash) { for (var i = 0; i < hash.length; i++) { if (hash[i] !== "0") { break; }; } return i >= this.difficulty; } // }; // module.exports = Blockchain;
- 9. 計算區塊雜湊值
計算雜湊值就是輸入一段內容然後輸出一段固定長度的hash值來,用公式表示為:hash=f(data)
// const Block = require("./Block.js"); const crypto = require("crypto"); // class Blockchain { // constructor() { ... } // get() { ... } // get latestBlock() { ... } // isValidHashDifficulty(hash) { ... } calculateHashForBlock(block) { const { index, previousHash, timestamp, transactions, nonce } = block; return this.calculateHash( index, previousHash, timestamp, transactions, nonce ); } calculateHash(index, previousHash, timestamp, data, nonce) { return crypto .createHash("sha256") // SHA256 Hash Function .update(index + previousHash + timestamp + data + nonce) .digest("hex"); } // }; // module.exports = Blockchain;
- 10. 前一個區塊的雜湊
前一個區塊的雜湊就是前一個區塊計算出來的hash值,創世區塊hash值為0,因為沒有前一個區塊了
- 11. 資料
資料就是儲存在每一個區塊中的資料,可以值比特幣中的交易
- 12. 改變資料
區塊鏈中改變任何一個數據都會導致計算結果不一致,計算結果不一樣的內容是不會被記錄在區塊鏈的有效賬本中
- 13. 改變資料的影響
例如:當你建立了100和區塊了,當你改變第55個區塊鏈的內容後,將導致計算的雜湊值與後面的不一樣就會導致hash衝突,而且不能連結起來
- 14. 開採一個區塊
開採一個區塊就是將一段時間的交易資訊打包後,計算隨機值,找到後計算出的hash值小於給定的hash值
程式碼:
// const Block = require("./Block.js"); // const crypto = require("crypto"); // class Blockchain { // constructor() { ... } // get() { ... } // get latestBlock() { ... } // isValidHashDifficulty(hash) { ... } // calculateHashForBlock(block) { ... } // calculateHash(...) { ... } mine(data) { const newBlock = this.generateNextBlock(data); try { this.addBlock(newBlock); } catch (err) { throw err; }; } // }; // module.exports = Blockchain;
- 15. 隨機值
隨機值就是一個運用密碼學技術保證安全的一種做法,計算出的隨機值在比特幣網路中作為工作量證明,意思就是你計算出有效的隨機值,就說明你經過了很大的運算量,那麼你也會獲得相應的獎勵,隨著全網計算力的增加,尋找隨機值的難度也會相應的增加
程式碼:
// const Block = require("./Block.js"); // const crypto = require("crypto"); // class Blockchain { // constructor() { ... } // get() { ... } // get latestBlock() { ... } // isValidHashDifficulty(hash) { ... } // calculateHashForBlock(block) { ... } // calculateHash(...) { ... } // mine(data) { ... } generateNextBlock(data) { const nextIndex = this.latestBlock.index + 1; const previousHash = this.latestBlock.hash; let timestamp = new Date().getTime(); let nonce = 0; let nextHash = this.calculateHash( nextIndex, previousHash, timestamp, data, nonce ); while (!this.isValidHashDifficulty(nextHash)) { nonce = nonce + 1; timestamp = new Date().getTime(); nextHash = this.calculateHash( nextIndex, previousHash, timestamp, data, nonce ); } const nextBlock = new Block( nextIndex, previousBlock.hash, nextTimestamp, data, nextHash, nonce ); return nextBlock; } // }; // module.exports = Blockchain;
- 16. 開採一個新的區塊
開發一個新的區塊,就是找到滿足要求的隨機值,然後將找出的區塊新增在上一個區塊的後面,比特幣網路控制了每10分鐘出一個新的區塊,每挖出一個區塊,現在是獎勵:12.5+交易費用,用一個簡單的例子來解釋一下為什麼開採一個新的區塊稱為挖礦呢?我們都知道傳統的挖礦,就是從礦山裡挖出一些礦石,然後賣了就可以賺取很多的money,你只要挖到了礦,人家就會給你發很多錢,其實那個錢是中央銀行給你印的,在我們比特幣中,很多礦機在那麼計算隨機值,計算出就相當於挖到了一車的金子,以現在6-8千美金一枚比特幣,挖到一個區塊,就自動發行12.5個比特幣,一下子就可以為所欲為了,是不是很爽啊,人家說,70年代挖礦的人現在都成為百萬富翁了,那麼現在你還不挖礦,是不是家裡還有座金山呢?哈哈
- 17. 增加有效區塊
當你挖出一個有效的區塊來時,你就要將這個區塊加入到區塊鏈中去,在所有節點同步資料之前,還要進行資料的驗證,驗證一下你廣播的隨機值是不是真的,會不會騙我啊,我可是很老實的呀,要是發現,你很誠實沒有騙我,那麼我就在我的小本本上記上一個區塊,好,合作愉快
程式碼:
// const Block = require("./Block.js"); // const crypto = require("crypto"); // class Blockchain { // constructor() { ... } // get() { ... } // get latestBlock() { ... } // isValidHashDifficulty(hash) { ... } // calculateHashForBlock(block) { ... } // calculateHash(...) { ... } // mine(data) { ... } // generateNextBlock(data) { ... } // addBlock(newBlock) { ... } isValidNextBlock(nextBlock, previousBlock) { const nextBlockHash = this.calculateHashForBlock(nextBlock); if (previousBlock.index + 1 !== nextBlock.index) { return false; } else if (previousBlock.hash !== nextBlock.previousHash) { return false; } else if (nextBlockHash !== nextBlock.hash) { return false; } else if (!this.isValidHashDifficulty(nextBlockHash)) { return false; } else { return true; } } // }; // module.exports = Blockchain;
- 18. 點對點網路
點對點網路就是加入到區塊鏈網路中的每一個節點都要是平等的,可以進行通訊,保持相同的賬本資料
程式碼:
const wrtc = require('wrtc'); const Exchange = require('peer-exchange'); const p2p = new Exchange("Blockchain Demo 2.0", { wrtc: wrtc }); const net = require("net"); class PeerToPeer { constructor(blockchain) { this.peers = []; this.blockchain = blockchain; } startServer(port) { const server = net .createServer(socket => p2p.accept(socket, (err, conn) => { if (err) { throw err; } else { this.initConnection.call(this, conn); } }) ) .listen(port); } } module.exports = PeerToPeer;
- 19. 增加一個節點
比特幣網路是一個共有網路,任何人都可以加入併成其為節點
程式碼
// const wrtc = require('wrtc'); // const Exchange = require('peer-exchange'); // const p2p = new Exchange(...); // const net = require("net"); // class PeerToPeer { // constructor(blockchain) { ... } // startServer(port) { ... } discoverPeers() { p2p.getNewPeer((err, conn) => { if (err) { throw err; } else { this.initConnection.call(this, conn); } }); } // } // module.exports = PeerToPeer;
- 20. 節點的狀態
節點的狀態就是看看,這個節點有沒偷懶呀,新開採出來的區塊有沒有拿小本本把他記下來呀,當然,加入的節點都是很誠實的,你去看都記得可認真了
程式碼:
// const wrtc = require('wrtc'); // const Exchange = require('peer-exchange'); // const p2p = new Exchange(...); // const net = require("net"); // class PeerToPeer { // constructor(blockchain) { ... } // startServer(port) { ... } // discoverPeers() { ... } connectToPeer(host, port) { const socket = net.connect(port, host, () => p2p.connect(socket, (err, conn) => { if (err) { throw err; } else { this.initConnection.call(this, conn); } }) ); } closeConnection() { p2p.close(err => { throw err; }) } // } // module.exports = PeerToPeer;
- 21. 節點的資訊
加入到到網路中的節點,不是加入就沒有事情做了,還要檢查那個幾點有最新的資料,有的話自己也要記一下奧
程式碼:
// const wrtc = require('wrtc'); // const Exchange = require('peer-exchange'); // const p2p = new Exchange(...); // const net = require("net"); const messageType = { REQUEST_LATEST_BLOCK: 0, RECEIVE_LATEST_BLOCK: 1, REQUEST_BLOCKCHAIN: 2, RECEIVE_BLOCKCHAIN: 3, }; const { REQUEST_LATEST_BLOCK, RECEIVE_LATEST_BLOCK, REQUEST_BLOCKCHAIN, RECEIVE_BLOCKCHAIN, REQUEST_TRANSACTIONS, RECEIVE_TRANSACTIONS } = messageType; // class PeerToPeer { ... } // module.exports = PeerToPeer; class Messages { static getLatestBlock() { return { type: REQUEST_LATEST_BLOCK }; } static sendLatestBlock(block) { return { type: RECEIVE_LATEST_BLOCK, data: block }; } static getBlockchain() { return { type: REQUEST_BLOCKCHAIN }; } static sendBlockchain(blockchain) { return { type: RECEIVE_BLOCKCHAIN, data: blockchain }; } }
- 22. 節點之間的通訊
程式碼:
// const wrtc = require('wrtc'); // const Exchange = require('peer-exchange'); // const p2p = new Exchange(...); // const net = require("net"); // const messageType = { ... }; // const { ... } = messageType; // class PeerToPeer { // constructor(blockchain) { ... } // startServer(port) { ... } // discoverPeers() { ... } // connectToPeer(host, port) { ... } // closeConnection() { ... } broadcastLatest() { this.broadcast(Messages.sendLatestBlock(this.blockchain.latestBlock)); } broadcast(message) { this.peers.forEach(peer => this.write(peer, message)); } write(peer, message) { peer.write(JSON.stringify(message)); } initConnection(connection) { this.peers.push(connection); this.initMessageHandler(connection); this.initErrorHandler(connection); this.write(connection, Messages.getLatestBlock()); } initMessageHandler(connection) { connection.on("data", data => { const message = JSON.parse(data.toString("utf8")); this.handleMessage(connection, message); }); } initErrorHandler(connection) { connection.on("error", err => { throw err; }); } handleMessage(peer, message) { switch (message.type) { case REQUEST_LATEST_BLOCK: this.write(peer, Messages.sendLatestBlock(this.blockchain.latestBlock)); break; case REQUEST_BLOCKCHAIN: this.write(peer, Messages.sendBlockchain(this.blockchain.get())); break; case RECEIVE_LATEST_BLOCK: this.handleReceivedLatestBlock(message, peer); break; case RECEIVE_BLOCKCHAIN: this.handleReceivedBlockchain(message); break; default: throw "Received invalid message."; } } // } // module.exports = PeerToPeer; // class Messages { ... }
- 23. 增加一個節點和新增一個區塊
程式碼:
// const wrtc = require('wrtc'); // const Exchange = require('peer-exchange'); // const p2p = new Exchange(...); // const net = require("net"); // const messageType = { ... }; // const { ... } = messageType; // class PeerToPeer { // constructor(blockchain) { ... } // startServer(port) { ... } // discoverPeers() { ... } // connectToPeer(host, port) { ... } // closeConnection() { ... } // broadcastLatest() { ... } // broadcast(message) { ... } // write(peer, message) { ... } // initConnection(connection) { ... } // initMessageHandler(connection) { ... } // initErrorHandler(connection) { ... } // handleMessage(peer, message) { ... } handleReceivedLatestBlock(message, peer) { const receivedBlock = message.data; const latestBlock = this.blockchain.latestBlock; if (latestBlock.hash === receivedBlock.previousHash) { try { this.blockchain.addBlock(receivedBlock); } catch(err) { throw err; } } else if (receivedBlock.index > latestBlock.index) { this.write(peer, Messages.getBlockchain()); } else { // Do nothing. } } // } // module.exports = PeerToPeer; // class Messages { ... }
- 24. 增加一個節點和新增兩個區塊
程式碼:
// const wrtc = require('wrtc'); // const Exchange = require('peer-exchange'); // const p2p = new Exchange(...); // const net = require("net"); // const messageType = { ... }; // const { ... } = messageType; // class PeerToPeer { // constructor(blockchain) { ... } // startServer(port) { ... } // discoverPeers() { ... } // connectToPeer(host, port) { ... } // closeConnection() { ... } // broadcastLatest() { ... } // broadcast(message) { ... } // write(peer, message) { ... } // initConnection(connection) { ... } // initMessageHandler(connection) { ... } // initErrorHandler(connection) { ... } // handleMessage(peer, message) { ... } handleReceivedLatestBlock(message, peer) { // if (latestBlock.hash === receivedBlock.previousHash) { // ... } else if (receivedBlock.index > latestBlock.index) { this.write(peer, Messages.getBlockchain()); } else { // Do nothing. } } handleReceivedBlockchain(message) { const receivedChain = message.data; try { this.blockchain.replaceChain(receivedChain); } catch(err) { throw err; } } // } // module.exports = PeerToPeer; // class Messages { ... }
- 25. 最後講一下51%攻擊
51%攻擊指的是當每個人掌握了全網51%的算力後,他就可以更改賬本,變成最長鏈,但是掌握51%算力是一件很問難的事,況且我也相信,比特幣網路也不會允許任何一個節點達到這樣的能力的
好了就說這麼多吧,