1. 程式人生 > >最全 比特幣區塊鏈結構+程式碼

最全 比特幣區塊鏈結構+程式碼

  • 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%算力是一件很問難的事,況且我也相信,比特幣網路也不會允許任何一個節點達到這樣的能力的

好了就說這麼多吧,