├── .gitignore ├── package.json ├── README.md └── dev ├── test.js ├── blockchain.js ├── block-explorer └── index.html └── networkNode.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "javaScript-blockchain", 3 | "version": "1.0.0", 4 | "description": "Learn Blockchain By Building Your Own In JavaScript", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "node_1": "nodemon --watch dev -e js dev/networkNode.js 3001 http://localhost:3001", 9 | "node_2": "nodemon --watch dev -e js dev/networkNode.js 3002 http://localhost:3002", 10 | "node_3": "nodemon --watch dev -e js dev/networkNode.js 3003 http://localhost:3003", 11 | "node_4": "nodemon --watch dev -e js dev/networkNode.js 3004 http://localhost:3004", 12 | "node_5": "nodemon --watch dev -e js dev/networkNode.js 3005 http://localhost:3005" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "body-parser": "^1.18.2", 18 | "express": "^4.16.3", 19 | "nodemon": "^1.17.3", 20 | "request": "^2.87.0", 21 | "request-promise": "^4.2.2", 22 | "sha256": "^0.2.0", 23 | "uuid": "^3.2.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learn Blockchain By Building Your Own In JavaScript 2 | 3 | This repository is the source code that accompanies a course on Udemy.com that teaches students how blockchain technology works by coding out their own blockchain prototype in javascript. 4 | 5 | The course is called **[Learn Blockchain By Building Your Own In JavaScript](https://www.udemy.com/build-a-blockchain-in-javascript/?couponCode=GHDISCOUNT)** and it can be found **[here](https://www.udemy.com/build-a-blockchain-in-javascript/?couponCode=GHDISCOUNT)**. 6 |

7 | JavaScript Blockchain Course 8 |
9 | 10 | ## Getting Started 11 | 12 | The first step in running this project is to run `npm install`. 13 | 14 | The rest of the steps can be found in the **[course](https://www.udemy.com/build-a-blockchain-in-javascript/?couponCode=GHDISCOUNT)**! 15 |
16 | 17 | ## Course Content 18 | 19 | In this course you will build out your very own **blockchain** and **decentralized blockchain network** using the javascript programming language. 20 | 21 | In this course you will learn all of the following concepts and your blockchain will have all of the following features: 22 | 23 | - A **proof of work** algorithm to secure the network. 24 | - **Hashing algorithms** to secure the data within the blockchain. 25 | - The ability to **mine (create) new blocks** that contain data. 26 | - The ability to **create transactions** and store them in blocks. 27 | - An **API/server** that will be used to interact with the blockchain from the internet. 28 | - It will be hosted on a **decentralized blockchain network**. 29 | - A **consensus algorithms** to verify that the network nodes have valid data and are synchronized. 30 | - A **broadcasting system** to keep the data in the blockchain network synchronized. 31 | - Many other awesome features!... 32 | 33 | When you have completed this course you will have built out **your own blockchain prototype in code**. You will have a thorough understanding of how blockchain technology actually works and why this technology is so **secure and valuable**. You will also have a deep understanding of how decentralized blockchain networks function and why decentralization is such an important feature for securing the blockchain. The whole process of **storing, securing, and validating data/transactions** on the blockchain will become very clear. 34 |



35 | ###### Copyright Disclaimer 36 | ###### The code in this repository is property of Eric Traub (owner). The code, all or portions of it, is not to be distributed in any way without written permission from the owner. The code is protected under United States copyright laws. -------------------------------------------------------------------------------- /dev/test.js: -------------------------------------------------------------------------------- 1 | const Blockchain = require('./blockchain'); 2 | const bitcoin = new Blockchain(); 3 | 4 | 5 | const bc1 = { 6 | "chain": [ 7 | { 8 | "index": 1, 9 | "timestamp": 1525295039150, 10 | "transactions": [], 11 | "nonce": 100, 12 | "hash": "0", 13 | "previousBlockHash": "0" 14 | }, 15 | { 16 | "index": 2, 17 | "timestamp": 1525295064849, 18 | "transactions": [], 19 | "nonce": 18140, 20 | "hash": "0000b9135b054d1131392c9eb9d03b0111d4b516824a03c35639e12858912100", 21 | "previousBlockHash": "0" 22 | }, 23 | { 24 | "index": 3, 25 | "timestamp": 1525295150900, 26 | "transactions": [ 27 | { 28 | "amount": 12.5, 29 | "sender": "00", 30 | "recipient": "555dc5d04e4c11e89b44174d1b876bbf", 31 | "transactionId": "64b4c6504e4c11e89b44174d1b876bbf" 32 | }, 33 | { 34 | "amount": 10, 35 | "sender": "NNFANSDFHYHTN90A09SNFAS", 36 | "recipient": "IUW099N0A90WENNU234UFAW", 37 | "transactionId": "881441704e4c11e89b44174d1b876bbf" 38 | }, 39 | { 40 | "amount": 20, 41 | "sender": "NNFANSDFHYHTN90A09SNFAS", 42 | "recipient": "IUW099N0A90WENNU234UFAW", 43 | "transactionId": "8c835b604e4c11e89b44174d1b876bbf" 44 | }, 45 | { 46 | "amount": 30, 47 | "sender": "NNFANSDFHYHTN90A09SNFAS", 48 | "recipient": "IUW099N0A90WENNU234UFAW", 49 | "transactionId": "92c6e7304e4c11e89b44174d1b876bbf" 50 | } 51 | ], 52 | "nonce": 59137, 53 | "hash": "0000c09685e31e57318e569b5fe3ca88ced727a29a0eb9cbea633e05056b4c29", 54 | "previousBlockHash": "0000b9135b054d1131392c9eb9d03b0111d4b516824a03c35639e12858912100" 55 | }, 56 | { 57 | "index": 4, 58 | "timestamp": 1525295192141, 59 | "transactions": [ 60 | { 61 | "amount": 12.5, 62 | "sender": "00", 63 | "recipient": "555dc5d04e4c11e89b44174d1b876bbf", 64 | "transactionId": "97fa3b804e4c11e89b44174d1b876bbf" 65 | }, 66 | { 67 | "amount": 40, 68 | "sender": "NNFANSDFHYHTN90A09SNFAS", 69 | "recipient": "IUW099N0A90WENNU234UFAW", 70 | "transactionId": "a5d523504e4c11e89b44174d1b876bbf" 71 | }, 72 | { 73 | "amount": 50, 74 | "sender": "NNFANSDFHYHTN90A09SNFAS", 75 | "recipient": "IUW099N0A90WENNU234UFAW", 76 | "transactionId": "a8b55fe04e4c11e89b44174d1b876bbf" 77 | }, 78 | { 79 | "amount": 60, 80 | "sender": "NNFANSDFHYHTN90A09SNFAS", 81 | "recipient": "IUW099N0A90WENNU234UFAW", 82 | "transactionId": "ab0347804e4c11e89b44174d1b876bbf" 83 | }, 84 | { 85 | "amount": 70, 86 | "sender": "NNFANSDFHYHTN90A09SNFAS", 87 | "recipient": "IUW099N0A90WENNU234UFAW", 88 | "transactionId": "ad9738d04e4c11e89b44174d1b876bbf" 89 | } 90 | ], 91 | "nonce": 16849, 92 | "hash": "00001f3f4e1635cc930cdc41a954d19bcf457eeba8bf6c7be7aa4fe1489e64d3", 93 | "previousBlockHash": "0000c09685e31e57318e569b5fe3ca88ced727a29a0eb9cbea633e05056b4c29" 94 | }, 95 | { 96 | "index": 5, 97 | "timestamp": 1525295206369, 98 | "transactions": [ 99 | { 100 | "amount": 12.5, 101 | "sender": "00", 102 | "recipient": "555dc5d04e4c11e89b44174d1b876bbf", 103 | "transactionId": "b08f1c104e4c11e89b44174d1b876bbf" 104 | } 105 | ], 106 | "nonce": 40153, 107 | "hash": "000067295fb567842799b887910fe31cc8ca7544ec15a000b65005f6ac50df21", 108 | "previousBlockHash": "00001f3f4e1635cc930cdc41a954d19bcf457eeba8bf6c7be7aa4fe1489e64d3" 109 | }, 110 | { 111 | "index": 6, 112 | "timestamp": 1525295212959, 113 | "transactions": [ 114 | { 115 | "amount": 12.5, 116 | "sender": "00", 117 | "recipient": "555dc5d04e4c11e89b44174d1b876bbf", 118 | "transactionId": "b90a6f704e4c11e89b44174d1b876bbf" 119 | } 120 | ], 121 | "nonce": 252386, 122 | "hash": "0000462c88b2814ebb930b13ac3c19dc698b2dca27b0c296e03f8a2ea104f74f", 123 | "previousBlockHash": "000067295fb567842799b887910fe31cc8ca7544ec15a000b65005f6ac50df21" 124 | } 125 | ], 126 | "pendingTransactions": [ 127 | { 128 | "amount": 12.5, 129 | "sender": "00", 130 | "recipient": "555dc5d04e4c11e89b44174d1b876bbf", 131 | "transactionId": "bcf84b704e4c11e89b44174d1b876bbf" 132 | } 133 | ], 134 | "currentNodeUrl": "http://localhost:3001", 135 | "networkNodes": [] 136 | }; 137 | 138 | 139 | 140 | 141 | console.log('VALID: ', bitcoin.chainIsValid(bc1.chain)); 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /dev/blockchain.js: -------------------------------------------------------------------------------- 1 | const sha256 = require('sha256'); 2 | const currentNodeUrl = process.argv[3]; 3 | const uuid = require('uuid/v1'); 4 | 5 | function Blockchain() { 6 | this.chain = []; 7 | this.pendingTransactions = []; 8 | 9 | this.currentNodeUrl = currentNodeUrl; 10 | this.networkNodes = []; 11 | 12 | this.createNewBlock(100, '0', '0'); 13 | }; 14 | 15 | 16 | Blockchain.prototype.createNewBlock = function(nonce, previousBlockHash, hash) { 17 | const newBlock = { 18 | index: this.chain.length + 1, 19 | timestamp: Date.now(), 20 | transactions: this.pendingTransactions, 21 | nonce: nonce, 22 | hash: hash, 23 | previousBlockHash: previousBlockHash 24 | }; 25 | 26 | this.pendingTransactions = []; 27 | this.chain.push(newBlock); 28 | 29 | return newBlock; 30 | }; 31 | 32 | 33 | Blockchain.prototype.getLastBlock = function() { 34 | return this.chain[this.chain.length - 1]; 35 | }; 36 | 37 | 38 | Blockchain.prototype.createNewTransaction = function(amount, sender, recipient) { 39 | const newTransaction = { 40 | amount: amount, 41 | sender: sender, 42 | recipient: recipient, 43 | transactionId: uuid().split('-').join('') 44 | }; 45 | 46 | return newTransaction; 47 | }; 48 | 49 | 50 | Blockchain.prototype.addTransactionToPendingTransactions = function(transactionObj) { 51 | this.pendingTransactions.push(transactionObj); 52 | return this.getLastBlock()['index'] + 1; 53 | }; 54 | 55 | 56 | Blockchain.prototype.hashBlock = function(previousBlockHash, currentBlockData, nonce) { 57 | const dataAsString = previousBlockHash + nonce.toString() + JSON.stringify(currentBlockData); 58 | const hash = sha256(dataAsString); 59 | return hash; 60 | }; 61 | 62 | 63 | Blockchain.prototype.proofOfWork = function(previousBlockHash, currentBlockData) { 64 | let nonce = 0; 65 | let hash = this.hashBlock(previousBlockHash, currentBlockData, nonce); 66 | while (hash.substring(0, 4) !== '0000') { 67 | nonce++; 68 | hash = this.hashBlock(previousBlockHash, currentBlockData, nonce); 69 | } 70 | 71 | return nonce; 72 | }; 73 | 74 | 75 | 76 | Blockchain.prototype.chainIsValid = function(blockchain) { 77 | let validChain = true; 78 | 79 | for (var i = 1; i < blockchain.length; i++) { 80 | const currentBlock = blockchain[i]; 81 | const prevBlock = blockchain[i - 1]; 82 | const blockHash = this.hashBlock(prevBlock['hash'], { transactions: currentBlock['transactions'], index: currentBlock['index'] }, currentBlock['nonce']); 83 | if (blockHash.substring(0, 4) !== '0000') validChain = false; 84 | if (currentBlock['previousBlockHash'] !== prevBlock['hash']) validChain = false; 85 | }; 86 | 87 | const genesisBlock = blockchain[0]; 88 | const correctNonce = genesisBlock['nonce'] === 100; 89 | const correctPreviousBlockHash = genesisBlock['previousBlockHash'] === '0'; 90 | const correctHash = genesisBlock['hash'] === '0'; 91 | const correctTransactions = genesisBlock['transactions'].length === 0; 92 | 93 | if (!correctNonce || !correctPreviousBlockHash || !correctHash || !correctTransactions) validChain = false; 94 | 95 | return validChain; 96 | }; 97 | 98 | 99 | Blockchain.prototype.getBlock = function(blockHash) { 100 | let correctBlock = null; 101 | this.chain.forEach(block => { 102 | if (block.hash === blockHash) correctBlock = block; 103 | }); 104 | return correctBlock; 105 | }; 106 | 107 | 108 | Blockchain.prototype.getTransaction = function(transactionId) { 109 | let correctTransaction = null; 110 | let correctBlock = null; 111 | 112 | this.chain.forEach(block => { 113 | block.transactions.forEach(transaction => { 114 | if (transaction.transactionId === transactionId) { 115 | correctTransaction = transaction; 116 | correctBlock = block; 117 | }; 118 | }); 119 | }); 120 | 121 | return { 122 | transaction: correctTransaction, 123 | block: correctBlock 124 | }; 125 | }; 126 | 127 | 128 | Blockchain.prototype.getAddressData = function(address) { 129 | const addressTransactions = []; 130 | this.chain.forEach(block => { 131 | block.transactions.forEach(transaction => { 132 | if(transaction.sender === address || transaction.recipient === address) { 133 | addressTransactions.push(transaction); 134 | }; 135 | }); 136 | }); 137 | 138 | let balance = 0; 139 | addressTransactions.forEach(transaction => { 140 | if (transaction.recipient === address) balance += transaction.amount; 141 | else if (transaction.sender === address) balance -= transaction.amount; 142 | }); 143 | 144 | return { 145 | addressTransactions: addressTransactions, 146 | addressBalance: balance 147 | }; 148 | }; 149 | 150 | 151 | 152 | 153 | 154 | 155 | module.exports = Blockchain; 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /dev/block-explorer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Block Explorer 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |

Block Explorer

17 |
18 |
19 |
20 |
21 |
22 |
23 | 24 |
25 |
26 | 31 |
32 | 37 |

38 | No data found for search. 39 |

40 |
41 |
42 |
43 |
44 |
45 | 46 | 47 |

Block

48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
Block Hash{{ block.hash }}
Index{{ block.index }}
Time Stamp{{ block.timestamp }}
Nonce{{ block.nonce }}
Previous Hash{{ block.previousBlockHash }}
Number Transactions{{ block.transactions.length }}
76 | 77 | 78 | 79 |

Transaction

80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 |
Sender{{ transaction.sender }}
Recipient{{ transaction.recipient }}
Amount{{ transaction.amount }}
96 | 97 | 98 | 99 |

Address

100 |

(Balance: {{ addressData.addressBalance }})

101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 |
SenderRecipientAmount
{{ transaction.sender }}{{ transaction.recipient }}{{ transaction.amount }}
117 | 118 | 119 |
120 |
121 |
122 | 123 | 176 | 177 | 218 | 219 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /dev/networkNode.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const bodyParser = require('body-parser'); 4 | const Blockchain = require('./blockchain'); 5 | const uuid = require('uuid/v1'); 6 | const port = process.argv[2]; 7 | const rp = require('request-promise'); 8 | 9 | const nodeAddress = uuid().split('-').join(''); 10 | 11 | const bitcoin = new Blockchain(); 12 | 13 | 14 | app.use(bodyParser.json()); 15 | app.use(bodyParser.urlencoded({ extended: false })); 16 | 17 | 18 | // get entire blockchain 19 | app.get('/blockchain', function (req, res) { 20 | res.send(bitcoin); 21 | }); 22 | 23 | 24 | // create a new transaction 25 | app.post('/transaction', function(req, res) { 26 | const newTransaction = req.body; 27 | const blockIndex = bitcoin.addTransactionToPendingTransactions(newTransaction); 28 | res.json({ note: `Transaction will be added in block ${blockIndex}.` }); 29 | }); 30 | 31 | 32 | // broadcast transaction 33 | app.post('/transaction/broadcast', function(req, res) { 34 | const newTransaction = bitcoin.createNewTransaction(req.body.amount, req.body.sender, req.body.recipient); 35 | bitcoin.addTransactionToPendingTransactions(newTransaction); 36 | 37 | const requestPromises = []; 38 | bitcoin.networkNodes.forEach(networkNodeUrl => { 39 | const requestOptions = { 40 | uri: networkNodeUrl + '/transaction', 41 | method: 'POST', 42 | body: newTransaction, 43 | json: true 44 | }; 45 | 46 | requestPromises.push(rp(requestOptions)); 47 | }); 48 | 49 | Promise.all(requestPromises) 50 | .then(data => { 51 | res.json({ note: 'Transaction created and broadcast successfully.' }); 52 | }); 53 | }); 54 | 55 | 56 | // mine a block 57 | app.get('/mine', function(req, res) { 58 | const lastBlock = bitcoin.getLastBlock(); 59 | const previousBlockHash = lastBlock['hash']; 60 | const currentBlockData = { 61 | transactions: bitcoin.pendingTransactions, 62 | index: lastBlock['index'] + 1 63 | }; 64 | const nonce = bitcoin.proofOfWork(previousBlockHash, currentBlockData); 65 | const blockHash = bitcoin.hashBlock(previousBlockHash, currentBlockData, nonce); 66 | const newBlock = bitcoin.createNewBlock(nonce, previousBlockHash, blockHash); 67 | 68 | const requestPromises = []; 69 | bitcoin.networkNodes.forEach(networkNodeUrl => { 70 | const requestOptions = { 71 | uri: networkNodeUrl + '/receive-new-block', 72 | method: 'POST', 73 | body: { newBlock: newBlock }, 74 | json: true 75 | }; 76 | 77 | requestPromises.push(rp(requestOptions)); 78 | }); 79 | 80 | Promise.all(requestPromises) 81 | .then(data => { 82 | const requestOptions = { 83 | uri: bitcoin.currentNodeUrl + '/transaction/broadcast', 84 | method: 'POST', 85 | body: { 86 | amount: 12.5, 87 | sender: "00", 88 | recipient: nodeAddress 89 | }, 90 | json: true 91 | }; 92 | 93 | return rp(requestOptions); 94 | }) 95 | .then(data => { 96 | res.json({ 97 | note: "New block mined & broadcast successfully", 98 | block: newBlock 99 | }); 100 | }); 101 | }); 102 | 103 | 104 | // receive new block 105 | app.post('/receive-new-block', function(req, res) { 106 | const newBlock = req.body.newBlock; 107 | const lastBlock = bitcoin.getLastBlock(); 108 | const correctHash = lastBlock.hash === newBlock.previousBlockHash; 109 | const correctIndex = lastBlock['index'] + 1 === newBlock['index']; 110 | 111 | if (correctHash && correctIndex) { 112 | bitcoin.chain.push(newBlock); 113 | bitcoin.pendingTransactions = []; 114 | res.json({ 115 | note: 'New block received and accepted.', 116 | newBlock: newBlock 117 | }); 118 | } else { 119 | res.json({ 120 | note: 'New block rejected.', 121 | newBlock: newBlock 122 | }); 123 | } 124 | }); 125 | 126 | 127 | // register a node and broadcast it the network 128 | app.post('/register-and-broadcast-node', function(req, res) { 129 | const newNodeUrl = req.body.newNodeUrl; 130 | if (bitcoin.networkNodes.indexOf(newNodeUrl) == -1) bitcoin.networkNodes.push(newNodeUrl); 131 | 132 | const regNodesPromises = []; 133 | bitcoin.networkNodes.forEach(networkNodeUrl => { 134 | const requestOptions = { 135 | uri: networkNodeUrl + '/register-node', 136 | method: 'POST', 137 | body: { newNodeUrl: newNodeUrl }, 138 | json: true 139 | }; 140 | 141 | regNodesPromises.push(rp(requestOptions)); 142 | }); 143 | 144 | Promise.all(regNodesPromises) 145 | .then(data => { 146 | const bulkRegisterOptions = { 147 | uri: newNodeUrl + '/register-nodes-bulk', 148 | method: 'POST', 149 | body: { allNetworkNodes: [ ...bitcoin.networkNodes, bitcoin.currentNodeUrl ] }, 150 | json: true 151 | }; 152 | 153 | return rp(bulkRegisterOptions); 154 | }) 155 | .then(data => { 156 | res.json({ note: 'New node registered with network successfully.' }); 157 | }); 158 | }); 159 | 160 | 161 | // register a node with the network 162 | app.post('/register-node', function(req, res) { 163 | const newNodeUrl = req.body.newNodeUrl; 164 | const nodeNotAlreadyPresent = bitcoin.networkNodes.indexOf(newNodeUrl) == -1; 165 | const notCurrentNode = bitcoin.currentNodeUrl !== newNodeUrl; 166 | if (nodeNotAlreadyPresent && notCurrentNode) bitcoin.networkNodes.push(newNodeUrl); 167 | res.json({ note: 'New node registered successfully.' }); 168 | }); 169 | 170 | 171 | // register multiple nodes at once 172 | app.post('/register-nodes-bulk', function(req, res) { 173 | const allNetworkNodes = req.body.allNetworkNodes; 174 | allNetworkNodes.forEach(networkNodeUrl => { 175 | const nodeNotAlreadyPresent = bitcoin.networkNodes.indexOf(networkNodeUrl) == -1; 176 | const notCurrentNode = bitcoin.currentNodeUrl !== networkNodeUrl; 177 | if (nodeNotAlreadyPresent && notCurrentNode) bitcoin.networkNodes.push(networkNodeUrl); 178 | }); 179 | 180 | res.json({ note: 'Bulk registration successful.' }); 181 | }); 182 | 183 | 184 | // consensus 185 | app.get('/consensus', function(req, res) { 186 | const requestPromises = []; 187 | bitcoin.networkNodes.forEach(networkNodeUrl => { 188 | const requestOptions = { 189 | uri: networkNodeUrl + '/blockchain', 190 | method: 'GET', 191 | json: true 192 | }; 193 | 194 | requestPromises.push(rp(requestOptions)); 195 | }); 196 | 197 | Promise.all(requestPromises) 198 | .then(blockchains => { 199 | const currentChainLength = bitcoin.chain.length; 200 | let maxChainLength = currentChainLength; 201 | let newLongestChain = null; 202 | let newPendingTransactions = null; 203 | 204 | blockchains.forEach(blockchain => { 205 | if (blockchain.chain.length > maxChainLength) { 206 | maxChainLength = blockchain.chain.length; 207 | newLongestChain = blockchain.chain; 208 | newPendingTransactions = blockchain.pendingTransactions; 209 | }; 210 | }); 211 | 212 | 213 | if (!newLongestChain || (newLongestChain && !bitcoin.chainIsValid(newLongestChain))) { 214 | res.json({ 215 | note: 'Current chain has not been replaced.', 216 | chain: bitcoin.chain 217 | }); 218 | } 219 | else { 220 | bitcoin.chain = newLongestChain; 221 | bitcoin.pendingTransactions = newPendingTransactions; 222 | res.json({ 223 | note: 'This chain has been replaced.', 224 | chain: bitcoin.chain 225 | }); 226 | } 227 | }); 228 | }); 229 | 230 | 231 | // get block by blockHash 232 | app.get('/block/:blockHash', function(req, res) { 233 | const blockHash = req.params.blockHash; 234 | const correctBlock = bitcoin.getBlock(blockHash); 235 | res.json({ 236 | block: correctBlock 237 | }); 238 | }); 239 | 240 | 241 | // get transaction by transactionId 242 | app.get('/transaction/:transactionId', function(req, res) { 243 | const transactionId = req.params.transactionId; 244 | const trasactionData = bitcoin.getTransaction(transactionId); 245 | res.json({ 246 | transaction: trasactionData.transaction, 247 | block: trasactionData.block 248 | }); 249 | }); 250 | 251 | 252 | // get address by address 253 | app.get('/address/:address', function(req, res) { 254 | const address = req.params.address; 255 | const addressData = bitcoin.getAddressData(address); 256 | res.json({ 257 | addressData: addressData 258 | }); 259 | }); 260 | 261 | 262 | // block explorer 263 | app.get('/block-explorer', function(req, res) { 264 | res.sendFile('./block-explorer/index.html', { root: __dirname }); 265 | }); 266 | 267 | 268 | 269 | 270 | 271 | app.listen(port, function() { 272 | console.log(`Listening on port ${port}...`); 273 | }); 274 | 275 | 276 | 277 | 278 | 279 | --------------------------------------------------------------------------------