Created
December 28, 2017 14:47
-
-
Save michielmulders/aee06173042c1472419a7123c8c3a915 to your computer and use it in GitHub Desktop.
Build Your Own Blockchain with JavaScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const SHA256 = require('crypto-js/sha256'); | |
class Block { | |
constructor(index, timestamp, data, previousHash = '') { | |
this.index = index; | |
this.previousHash = previousHash; | |
this.timestamp = timestamp; | |
this.data = data; | |
this.hash = this.calculateHash(); | |
this.nonce = 0; | |
} | |
calculateHash() { | |
return SHA256(this.index + this.previousHash + this.timestamp + JSON.stringify(this.data) + this.nonce).toString(); | |
} | |
mineBlock(difficulty) { | |
while (this.hash.substring(0, difficulty) !== Array(difficulty + 1).join('0')) { | |
this.nonce++; | |
this.hash = this.calculateHash(); | |
} | |
console.log('BLOCK MINED: ' + this.hash); | |
} | |
} | |
class Blockchain{ | |
constructor() { | |
this.chain = [this.createGenesisBlock()]; | |
this.difficulty = 1; | |
} | |
createGenesisBlock() { | |
return new Block(0, '01/01/2018', 'Genesis block', '0'); | |
} | |
getLatestBlock() { | |
return this.chain[this.chain.length - 1]; | |
} | |
getBlockByIndex(index) { | |
if (index >= this.chain.length) { | |
return 'Error: Index out of range! Could not find block.' | |
} | |
return this.chain[index]; | |
} | |
addBlock(newBlock) { | |
newBlock.previousHash = this.getLatestBlock().hash; | |
newBlock.mineBlock(this.difficulty); | |
this.chain.push(newBlock); | |
} | |
isChainValid() { | |
for (let i = 1; i < this.chain.length; i++){ | |
const currentBlock = this.chain[i]; | |
const previousBlock = this.chain[i - 1]; | |
if (currentBlock.hash !== currentBlock.calculateHash()) { | |
return false; | |
} | |
if (currentBlock.previousHash !== previousBlock.hash) { | |
return false; | |
} | |
} | |
return true; | |
} | |
} | |
let carChain = new Blockchain(); | |
console.log('Mining block 1...'); | |
carChain.addBlock(new Block(1, '01/01/2018', { owner: 'Ben', license: '1-45A-UD9' })); | |
console.log('Retrieve block 1: ', JSON.stringify(carChain.getBlockByIndex(1), null, 4)) | |
console.log('\n\nMining block 2...'); | |
carChain.addBlock(new Block(2, '01/01/2018', { owner: 'Alice', license: '3-6EY-KL0' })); | |
console.log('\nTry to change blockchain data: give myself a new car which actually belongs to Ben.') | |
carChain.chain[1].data = { owner: 'Michiel', license: '1-45A-UD9' }; | |
console.log('Regenerating hash for changed block and adding it back...\n') | |
carChain.chain[1].hash = carChain.chain[1].calculateHash(); | |
console.log('Blockchain valid? ' + carChain.isChainValid()); | |
console.log('Print My Blockchain\n'); | |
console.log(JSON.stringify(carChain, null, 4)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "build-your-own-blockchain", | |
"main": "main.js", | |
"scripts": { | |
"start": "node main.js" | |
}, | |
"author": "Michiel Mulders", | |
"dependencies": { | |
"crypto-js": "^3.1.9-1" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @mrharel , thanks!
We don't need to have zeros. For example ethereum uses '0x' as prefix and uses a much harder algorithm.
You can hard code whatever you want to use as a prefix.
Mining allows us to have public validation of the chain.
Side note: I'm more a fan of systems that use a Tangle / DAG / Hashgraph where mining is 'eliminated'.
The transaction proposer has to mine some other transactions first before his transaction will be verified.
Interesting read!