Created
November 27, 2017 08:19
-
-
Save tylerdiaz/8a44e7acc6273de6197e9ebf8c5e4ba7 to your computer and use it in GitHub Desktop.
blockchain
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 RushaClass = require('Rusha'); | |
const rusha = new RushaClass(); | |
const CONFIG = { difficulty: 3 } | |
// from: https://bitcoin.org/bitcoin.pdf | |
// and: https://www.igvita.com/2014/05/05/minimum-viable-block-chain/ | |
// I do sha1 instead of sha256 here for performance | |
class Block { | |
constructor({ prevHash = 0, timestamp = null, nonce = 0, body = "", hash = "", height = 0 }) { | |
this.prevHash = prevHash | |
this.nonce = nonce | |
this.body = body | |
this.hash = hash | |
this.height = height | |
this.timestamp = (timestamp || new Date().getTime()) | |
} | |
static fromString(blockString){ | |
return new Block(JSON.parse(blockString)) | |
} | |
difficulty() { | |
return this.hash.search(/[1-9a-zA-Z]/) // serch for none 0 | |
} | |
get data() { | |
return { | |
prevHash: this.prevHash, | |
nonce: this.nonce, | |
height: this.height, | |
timestamp: this.timestamp, | |
body: this.body | |
} | |
} | |
generateHash() { | |
this.hash = rusha.digestFromString(this.toString()) | |
return this.hash | |
} | |
mine() { | |
let attempts = 0; | |
while(!this.isValid()){ | |
this.nonce = rusha.digestFromString(Math.random().toString()) | |
this.generateHash(); | |
attempts++ | |
} | |
// console.log(`Mined "${this.body}" block after ${attempts} tries`) | |
return { attempts } | |
} | |
isValid() { | |
return this.difficulty() >= CONFIG.difficulty | |
} | |
toString() { | |
return JSON.stringify({ ...this.data, hash: this.hash }) | |
} | |
} | |
class Blockchain { | |
constructor(blocks) { | |
this.blocks = blocks | |
} | |
static fromString(blockchain_dump) { | |
return blockchain_dump.split("\n") | |
.map(b => { return Block.fromString(b) }) | |
} | |
length() { | |
return this.blocks.length | |
} | |
toString() { | |
return this.blocks.map(b => { return b.toString() }) | |
.join("\n") | |
} | |
// review the entire blockchain and ensure it's valid | |
mine() { | |
for (var i = 0; i < this.blocks.length; i++) { | |
if (i == 0) continue // genesis | |
let currentBlock = this.blocks[i] | |
let prevBlock = this.blocks[i - 1] | |
if (currentBlock.prevHash != prevBlock.hash) { | |
console.log(`correcting block sequence to ${prevBlock.body}->${currentBlock.body}`) | |
currentBlock.prevHash = prevBlock.hash | |
} | |
currentBlock.mine() | |
} | |
} | |
// this function might invalidate the blockchain | |
append(block) { | |
let tailBlock = this.blocks[this.blocks.length - 1] | |
block.prevHash = tailBlock.hash | |
block.height = this.blocks.length | |
if (! block.isValid()) block.mine() | |
this.blocks.push(block) | |
return this | |
} | |
} | |
let genesisBlock = new Block({ | |
prevHash: "0", | |
nonce: "919ddb02165d3c490133e479d1955b08ad3ab0cb", | |
hash: "000cc64a0037f5a29d4f18736d201c7cd38c696c", | |
height: 0, | |
timestamp: 1, | |
body: "The Genesis block" | |
}) | |
let blockchain = new Blockchain([ genesisBlock ]) | |
blockchain.append(new Block({ body: "An extension block" })) | |
blockchain.append(new Block({ body: "maybe an action in here?" })) | |
blockchain.append(new Block({ body: "then a reaction in here" })) | |
blockchain.append(new Block({ body: "one last block" })) | |
blockchain.mine() | |
console.log( | |
`Blockchain started`, | |
blockchain | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment