Skip to content

Instantly share code, notes, and snippets.

@fielding
Last active December 28, 2018 21:19
Show Gist options
  • Select an option

  • Save fielding/77614bec52ec67104a2d326f59476f8e to your computer and use it in GitHub Desktop.

Select an option

Save fielding/77614bec52ec67104a2d326f59476f8e to your computer and use it in GitHub Desktop.
primitive blockchain implementation in javascript
const sha256 = require("crypto-js/sha256");
function Block(data, parent) {
if ( parent) {
this.index = parent.index + 1;
this.parentHash = parent.hash;
} else {
this.index = 0;
this.parentHash = null;
}
this.data = data;
this.timestamp = Date.now();
this.hash = Block.calculateHash(this);
}
// static methods that are not called on instances of Block
// considering switching this over to node's crypto library
Block.calculateHash = block =>
sha256(block.index + block.parentHash + block.timestamp + JSON.stringify(block.data)).toString();
Block.validate= (block, parent) =>
parent.index + 1 === block.index &&
parent.hash === block.parentHash &&
Block.calculateHash(block) === block.hash;
module.exports = Block;
const Block = require('./Block.js');
function Blockchain(chain) {
if (chain) {
if (!Blockchain.validateChain(chain)) {
throw new Error('Invalid chain.');
}
this.chain = chain;
} else {
this.chain = [new Block('genesis block')];
}
}
Blockchain.prototype.getData = function () {
return this.chain.map(block => block.data);
};
Blockchain.prototype.getChain = function () {
return this.chain;
};
Blockchain.prototype.getGenesisBlock = function () {
return this.chain[0];
};
Blockchain.prototype.getLatestBlock = function () {
return this.chain[this.chain.length - 1];
};
Blockchain.prototype.add = function (data) {
const parent = this.getLatestBlock();
const block = new Block(data, parent);
this.chain.push(block);
return block;
};
Blockchain.prototype.update = function (chain) {
const isValid = Blockchain.validateChain(chain, this.getGenesisBlock());
const isChainLonger = chain.length > this.chain.length;
if (isValid && isChainLonger) {
this.chain = chain;
return true;
}
return false;
};
Blockchain.prototype.toJSON = function () {
return JSON.stringify(this.chain);
};
// static method that is not called on instances of Block
Blockchain.validateChain = function (chain, genesis) {
const isGenesisInvalid =
genesis && Block.calculateHash(genesis) !== chain[0].hash;
if (!Array.isArray(chain) || chain.length === 0 || isGenesisInvalid) {
return false;
}
return chain.reduce(
(valid, block) =>
(block.index !== 0 && Block.validate(block, chain[block.index - 1])) ||
valid,
true
);
};
module.exports = Blockchain;
const Blockchain = require('./Blockchain.js');
const b = new Blockchain();
b.add({
from: 'fielding',
to: 'jeffrey',
amount: 15,
});
b.add({
from: 'jeffrey',
to: 'chad',
amount: 10,
});
b.add({
from: 'chad',
to: 'fielding',
amount: 5,
});
console.log('full chain: \r\n', b.getChain(), '\r\n\r\n');
console.log('data only: \r\n', b.getData(), '\r\n\r\n');
console.log('genesis block: \r\n', b.getGenesisBlock(), '\r\n\r\n');
console.log('latest block: \r\n', b.getLatestBlock(), '\r\n\r\n');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment