Implements:
- Basic in-memory blockchain
- Basic Proof of work
- Methods to serialize/deserialize complete chain
Again none of this is supposed to be production ready.
const crypto = require('crypto'); | |
let blockchain = []; | |
class BlockchainError extends Error { | |
constructor(message) { | |
super(message); | |
Error.captureStackTrace(this, this.constructor); | |
} | |
} | |
function sha256(value) { | |
return crypto.createHash('sha256', '').update(`${value}`).digest("hex") | |
} | |
function hash(parent_hash, timestamp, data) { | |
return sha256(`${parent_hash}-${timestamp}-${JSON.stringify(data)}`); | |
} | |
function append({parent_hash, timestamp, data}) { | |
if (!(parent_hash && timestamp && data)) { | |
throw new Error('Invalid block'); | |
} | |
if (blockchain.length) { | |
const lastBlock = blockchain[blockchain.length - 1]; | |
if (lastBlock.hash !== parent_hash) { | |
throw new BlockchainError(`Can not append child for ${parent_hash} after ${lastBlock.parent_hash}`) | |
} | |
} | |
blockchain.push({ | |
parent_hash, | |
timestamp, | |
data, | |
hash: hash(parent_hash, timestamp, data) | |
}); | |
return true; | |
} | |
function proven(str) { | |
return str.startsWith("51873"); | |
} | |
function proofOfWork(previous) { | |
let next = previous + 1; | |
let hash = sha256(next); | |
while (!proven(hash)) { | |
hash = sha256(++next); | |
} | |
return next; | |
} | |
function mine(payload) { | |
while (true) { | |
try { | |
const lastBlock = blockchain[blockchain.length - 1]; | |
const proof = proofOfWork(lastBlock.data.proof); | |
const newBlock = { | |
parent_hash: lastBlock.hash, | |
timestamp: new Date().getTime(), | |
data: { | |
proof, | |
payload, | |
proof_digest: sha256(proof) | |
} | |
}; | |
appended = append(newBlock); | |
return newBlock; | |
} catch (e) { | |
if (e instanceof BlockchainError) { | |
continue; | |
} | |
throw e; | |
} | |
} | |
} | |
function boot() { | |
if (blockchain.length === 0) { | |
append({ | |
parent_hash: "~", | |
timestamp: new Date().getTime(), | |
data: { | |
proof: 0, | |
payload: [] | |
} | |
}); | |
} | |
} | |
function serialize() { | |
return JSON.stringify(blockchain); | |
} | |
function deserialize(val) { | |
blockchain = JSON.parse(val); | |
} | |
function size() { | |
return blockchain.length; | |
} | |
module.exports = { | |
mine, | |
boot, | |
serialize, | |
deserialize, | |
size | |
}; |
const blockchain = require('./blockchain'); | |
blockchain.boot(); | |
while (true) { | |
console.log( | |
blockchain.mine([]) | |
); | |
} |