[
  {
    "path": ".gitignore",
    "content": "node_modules\n.DS_Store"
  },
  {
    "path": "Block.js",
    "content": "class Block {\n  constructor (index, previousHash, timestamp, data, hash, nonce) {\n    this.index = index;\n    this.previousHash = previousHash;\n    this.timestamp = timestamp;\n    this.data = data;\n    this.hash = hash;\n    this.nonce = nonce;\n  }\n\n  static get genesis() {\n    return new Block(\n      0,\n      \"0\",\n      1508270000000,\n      \"Welcome to Blockchain Demo 2.0!\",\n      \"000dc75a315c77a1f9c98fb6247d03dd18ac52632d7dc6a9920261d8109b37cf\",\n      604\n    );\n  }\n}\n\nmodule.exports = Block;"
  },
  {
    "path": "Blockchain.js",
    "content": "const Block = require(\"./Block.js\");\nconst crypto = require(\"crypto\");\n\nclass Blockchain {\n  constructor() {\n    this.blockchain = [Block.genesis];\n    this.difficulty = 3;\n  }\n\n  get() {\n    return this.blockchain;\n  }\n\n  get latestBlock() {\n    return this.blockchain[this.blockchain.length - 1];\n  }\n\n  isValidHashDifficulty(hash) {\n    for (var i = 0; i < hash.length; i++) {\n      if (hash[i] !== \"0\") {\n        break;\n      }\n    }\n    return i >= this.difficulty;\n  }\n\n  calculateHashForBlock(block) {\n    const { index, previousHash, timestamp, data, nonce } = block;\n    return this.calculateHash(\n      index,\n      previousHash,\n      timestamp,\n      data,\n      nonce\n    );\n  }\n\n  calculateHash(index, previousHash, timestamp, data, nonce) {\n    return crypto\n      .createHash(\"sha256\")\n      .update(index + previousHash + timestamp + data + nonce)\n      .digest(\"hex\");\n  }\n\n  mine(data) {\n    const newBlock = this.generateNextBlock(data);\n    try {\n      this.addBlock(newBlock);\n    } catch(err) {\n      throw err;\n    }\n  }\n\n  generateNextBlock(data) {\n    const nextIndex = this.latestBlock.index + 1;\n    const previousHash = this.latestBlock.hash;\n    let timestamp = new Date().getTime();\n    let nonce = 0;\n    let nextHash = this.calculateHash(\n      nextIndex,\n      previousHash,\n      timestamp,\n      data,\n      nonce\n    );\n\n    while (!this.isValidHashDifficulty(nextHash)) {\n      nonce = nonce + 1;\n      timestamp = new Date().getTime();\n      nextHash = this.calculateHash(\n        nextIndex,\n        previousHash,\n        timestamp,\n        data,\n        nonce\n      );\n    }\n\n    const nextBlock = new Block(\n      nextIndex,\n      previousHash,\n      timestamp,\n      data,\n      nextHash,\n      nonce\n    );\n\n    return nextBlock;\n  }\n\n  addBlock(newBlock) {\n    if (this.isValidNextBlock(newBlock, this.latestBlock)) {\n      this.blockchain.push(newBlock);\n    } else {\n      throw \"Error: Invalid block\";\n    }\n  }\n\n  isValidNextBlock(nextBlock, previousBlock) {\n    const nextBlockHash = this.calculateHashForBlock(nextBlock);\n\n    if (previousBlock.index + 1 !== nextBlock.index) {\n      return false;\n    } else if (previousBlock.hash !== nextBlock.previousHash) {\n      return false;\n    } else if (nextBlockHash !== nextBlock.hash) {\n      return false;\n    } else if (!this.isValidHashDifficulty(nextBlockHash)) {\n      return false;\n    } else {\n      return true;\n    }\n  }\n\n  isValidChain(chain) {\n    if (JSON.stringify(chain[0]) !== JSON.stringify(Block.genesis)) {\n      return false;\n    }\n\n    const tempChain = [chain[0]];\n    for (let i = 1; i < chain.length; i = i + 1) {\n      if (this.isValidNextBlock(chain[i], tempChain[i - 1])) {\n        tempChain.push(chain[i]);\n      } else {\n        return false;\n      }\n    }\n    return true;\n  }\n\n  isChainLonger(chain) {\n    return chain.length > this.blockchain.length;\n  }\n\n  replaceChain(newChain) {\n    if (this.isValidChain(newChain) && this.isChainLonger(newChain)) {\n      this.blockchain = JSON.parse(JSON.stringify(newChain));\n    } else {\n      throw \"Error: invalid chain\";\n    }\n  }\n}\n\nmodule.exports = Blockchain;\n"
  },
  {
    "path": "LICENSE.ISC.txt",
    "content": "ISC License\n\nCopyright (c) 2017, Sean Han\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n"
  },
  {
    "path": "Messages.js",
    "content": "const messageType = require(\"./message-type.js\");\nconst {\n  REQUEST_LATEST_BLOCK,\n  RECEIVE_LATEST_BLOCK,\n  REQUEST_BLOCKCHAIN,\n  RECEIVE_BLOCKCHAIN,\n  REQUEST_TRANSACTIONS,\n  RECEIVE_TRANSACTIONS\n} = messageType;\n\nclass Messages {\n  static getLatestBlock() {\n    return {\n      type: REQUEST_LATEST_BLOCK\n    };\n  }\n\n  static sendLatestBlock(block) {\n    return {\n      type: RECEIVE_LATEST_BLOCK,\n      data: block\n    };\n  }\n\n  static getBlockchain() {\n    return {\n      type: REQUEST_BLOCKCHAIN\n    };\n  }\n\n  static sendBlockchain(blockchain) {\n    return {\n      type: RECEIVE_BLOCKCHAIN,\n      data: blockchain\n    };\n  }\n}\n\nmodule.exports = Messages;"
  },
  {
    "path": "P2p.js",
    "content": "const wrtc = require(\"wrtc\");\nconst Exchange = require(\"peer-exchange\");\nconst p2p = new Exchange(\"Blockchain Demo 2.0\", { wrtc: wrtc });\nconst net = require(\"net\");\nconst messageType = require(\"./message-type.js\");\nconst {\n  REQUEST_LATEST_BLOCK,\n  RECEIVE_LATEST_BLOCK,\n  REQUEST_BLOCKCHAIN,\n  RECEIVE_BLOCKCHAIN,\n  REQUEST_TRANSACTIONS,\n  RECEIVE_TRANSACTIONS\n} = messageType;\nconst Messages = require(\"./Messages.js\");\n\nclass PeerToPeer {\n  constructor(blockchain) {\n    this.peers = [];\n    this.blockchain = blockchain;\n  }\n\n  startServer(port) {\n    const server = net\n      .createServer(socket =>\n        p2p.accept(socket, (err, conn) => {\n          if (err) {\n            throw err;\n          } else {\n            this.initConnection.call(this, conn);\n          }\n        })\n      )\n      .listen(port);\n  }\n\n  discoverPeers() {\n    p2p.getNewPeer((err, conn) => {\n      if (err) {\n        throw err;\n      } else {\n        this.initConnection.call(this, conn);\n      }\n    });\n  }\n\n  connectToPeer(host, port) {\n    const socket = net.connect(port, host, () =>\n      p2p.connect(socket, (err, conn) => {\n        if (err) {\n          throw err;\n        } else {\n          this.initConnection.call(this, conn);\n        }\n      })\n    );\n  }\n\n  closeConnection() {\n    p2p.close(err => {\n      throw err;\n    });\n  }\n\n  broadcastLatest() {\n    this.broadcast(Messages.sendLatestBlock(this.blockchain.latestBlock));\n  }\n\n  broadcast(message) {\n    this.peers.forEach(peer => this.write(peer, message));\n  }\n\n  write(peer, message) {\n    peer.write(JSON.stringify(message));\n  }\n\n  initConnection(connection) {\n    this.peers.push(connection);\n    this.initMessageHandler(connection);\n    this.initErrorHandler(connection);\n    this.write(connection, Messages.getLatestBlock());\n  }\n\n  initMessageHandler(connection) {\n    connection.on(\"data\", data => {\n      const message = JSON.parse(data.toString(\"utf8\"));\n      this.handleMessage(connection, message);\n    });\n  }\n\n  initErrorHandler(connection) {\n    connection.on(\"error\", err => {\n      throw err;\n    });\n  }\n\n  handleMessage(peer, message) {\n    switch (message.type) {\n      case REQUEST_LATEST_BLOCK:\n        this.write(peer, Messages.sendLatestBlock(this.blockchain.latestBlock));\n        break;\n      case REQUEST_BLOCKCHAIN:\n        this.write(peer, Messages.sendBlockchain(this.blockchain.get()));\n        break;\n      case RECEIVE_LATEST_BLOCK:\n        this.handleReceivedLatestBlock(message, peer);\n        break;\n      case RECEIVE_BLOCKCHAIN:\n        this.handleReceivedBlockchain(message);\n        break;\n      default:\n        throw \"Received invalid message.\";\n    }\n  }\n\n  handleReceivedLatestBlock(message, peer) {\n    const receivedBlock = message.data;\n    const latestBlock = this.blockchain.latestBlock;\n\n    if (latestBlock.hash === receivedBlock.previousHash) {\n      try {\n        this.blockchain.addBlock(receivedBlock);\n      } catch(err) {\n        throw err;\n      }\n    } else if (receivedBlock.index > latestBlock.index) {\n      this.write(peer, Messages.getBlockchain());\n    } else {\n      // Do nothing.\n    }\n  }\n\n  handleReceivedBlockchain(message) {\n    const receivedChain = message.data;\n    \n    try {\n      this.blockchain.replaceChain(receivedChain);\n    } catch(err) {\n      throw err;\n    }\n  }\n}\n\nmodule.exports = PeerToPeer;\n"
  },
  {
    "path": "README.md",
    "content": "<h1 align=\"center\">\n  <br>\n  <a href=\"https://blockchaindemo.io\" rel=\"noopener noreferrer\" target=\"_blank\"><img src=\"https://raw.githubusercontent.com/seanseany/blockchain/master/logo.png\" width=\"200\"></a>\n  <br>\n    <a href=\"https://blockchaindemo.io\" rel=\"noopener noreferrer\" target=\"_blank\">Blockchaindemo.io</a>\n  <br>\n</h1>\n\n<h4 align=\"center\">Code for learning the blockchain data structure</h4>\n\n<br>\n\n## 📦 Installation\n\nTo install this application, you'll need\n[Node.js](https://nodejs.org/en/download/) 7+ (which comes with\n[npm](http://npmjs.com)) installed on your computer. From your command line:\n\n#### Source\n\nYou'll need [Git](https://git-scm.com) to run the project from source. From your\ncommand line:\n\n```bash\n# Clone this repository\n$ git clone https://github.com/seanseany/blockchain\n\n# Go into the repository\n$ cd blockchain\n\n# Install dependencies\n$ npm install\n\n# Run the app\n$ npm start\n```\n\n## ℹ️ FAQ\n\n#### When or why I would use this?\n\nYou should use this if you want to build a bitcoin wallet, payment processor, or\nbitcoin merchant portal in javascript. You might also be interested in why\ndecentralized networks or p2p applications are useful, or what advantages they\nhave; this project seems like a good way to learn about that.\n\n#### What is the block chain actually for?\n\nThe blockchain is for authorizing payments of a cryptocurrency between two peers\nwithout the need for a centralized 3rd party approving of the transaction. There\nare other uses of the blockchain which are more in line with the second point,\ndigital signatures, but they are secondary to the main purpose of peer to peer\ntransfer of value. Bitcoin is blockchain's killer app.\n\n#### Why the hell should I care about the blockchain?\n\nBlockchain facilitates trade over a network. Imagine a metal as scarce as gold\nwith a magical property of \"can be transported over a communications channel\".\nThis has implications with respect to individual rights, the world economy, and\nthe way we monetize and transfer value at a level higher than bartering directly\nfor goods.\n\nLately people are distancing themselves from the proof-of-work concept and are\nusing blockchain to describe only the mechanism of signing a transaction as\nverification of sending an amount. Change \"sending an amount\" to almost anything\nelse - authorizing a change in a ruleset, casting a vote for a politician,\nverifying a point of IoT data is authentic. Now add in the concept of a\npeer-to-peer network to this and you've eliminated a middleman that once\nexisted, thereby improving the efficiency and reducing cost. In these cases,\n\"blockchain\" refers to the structuring of a program or database in such a way\nthat it has no central point of failure while still providing all of the\nfeatures expected. For example, augur and gnosis are decentralized prediction\nmarkets. Ethereum has implemented smart contracts which enable decentralized\nrelease of funds based on a gambling outcome.\n"
  },
  {
    "path": "cli.js",
    "content": "\nconst P2p = require(\"./P2p.js\");\nconst Blockchain = require(\"./Blockchain.js\");\nconst blockchain = new Blockchain();\nconst p2p = new P2p(blockchain);\n\nfunction cli(vorpal) {\n  vorpal\n  .use(welcome)\n  .use(connectCommand)\n  .use(discoverCommand)\n  .use(blockchainCommand)\n  .use(peersCommand)\n  .use(mineCommand)\n  .use(openCommand)\n  .delimiter('blockchain →')\n  .show()\n}\n\nmodule.exports = cli;\n\n// COMMANDS\nfunction welcome(vorpal) {\n  vorpal.log(\"Welcome to Blockchain CLI!\");\n  vorpal.exec(\"help\");\n}\n\nfunction connectCommand(vorpal) {\n  vorpal\n  .command('connect <host> <port>', \"Connect to a new peer. Eg: connect localhost 2727\")\n  .alias('c')\n  .action(function(args, callback) {\n    if(args.host && args.port) {\n      try {\n        p2p.connectToPeer(args.host, args.port);\n      } catch(err) {\n        this.log(err);\n      }\n    }\n    callback();\n  })\n}\n\nfunction discoverCommand(vorpal) {\n  vorpal\n  .command('discover', 'Discover new peers from your connected peers.')\n  .alias('d')\n  .action(function(args, callback) {\n    try {\n      p2p.discoverPeers();\n    } catch(err) {\n      this.log(err);\n    }\n    callback();\n  })\n}\n\nfunction blockchainCommand(vorpal) {\n  vorpal\n    .command('blockchain', 'See the current state of the blockchain.')\n    .alias('bc')\n    .action(function(args, callback) {\n      this.log(blockchain)\n      callback();\n    })\n}\n\nfunction peersCommand(vorpal) {\n  vorpal\n    .command('peers', 'Get the list of connected peers.')\n    .alias('p')\n    .action(function(args, callback) {\n      p2p.peers.forEach(peer => {\n        this.log(`${peer.pxpPeer.socket._host} \\n`)\n      }, this)\n      callback();\n    })\n}\n\nfunction mineCommand(vorpal) {\n  vorpal\n    .command('mine <data>', 'Mine a new block. Eg: mine hello!')\n    .alias('m')\n    .action(function(args, callback) {\n      if (args.data) {\n        blockchain.mine(args.data);\n        p2p.broadcastLatest(); \n      }\n      callback();\n    })\n}\n\nfunction openCommand(vorpal) {\n  vorpal\n    .command('open <port>', 'Open port to accept incoming connections. Eg: open 2727')\n    .alias('o')\n    .action(function(args, callback) {\n      if (args.port) {\n        if(typeof args.port === 'number') {\n          p2p.startServer(args.port);\n          this.log(`Listening to peers on ${args.port}`);\n        } else {\n          this.log(`Invalid port!`);\n        }\n      }\n      callback();\n    })\n}"
  },
  {
    "path": "index.js",
    "content": "#!/usr/bin/env node\nconst vorpal = require('vorpal')();\nvorpal.use(require('./cli.js'));"
  },
  {
    "path": "message-type.js",
    "content": "const messageType = {\n  REQUEST_LATEST_BLOCK: 0,\n  RECEIVE_LATEST_BLOCK: 1,\n  REQUEST_BLOCKCHAIN: 2,\n  RECEIVE_BLOCKCHAIN: 3,\n};\n\nmodule.exports = messageType;"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"blockchain-cli\",\n  \"version\": \"2.0.0\",\n  \"description\": \"Blockchain command-line interface\",\n  \"main\": \"index.js\",\n  \"engines\": {\n    \"node\": \"7.0.0\",\n    \"npm\": \"3.10.8\"\n  },\n  \"scripts\": {\n    \"start\": \"node ./index.js\",\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"peer-exchange\": \"^2.2.0\",\n    \"vorpal\": \"^1.12.0\",\n    \"wrtc\": \"0.0.63\"\n  }\n}\n"
  }
]