Skip to content

Instantly share code, notes, and snippets.

@neoeno
Last active November 6, 2024 23:10
Show Gist options
  • Save neoeno/00be262e827a1f0d7dab6bf841225d95 to your computer and use it in GitHub Desktop.
Save neoeno/00be262e827a1f0d7dab6bf841225d95 to your computer and use it in GitHub Desktop.
Blockchain (I think?? maybe there needs to be more to be real but it's something)
const hashMaker = require("hash.js");
const hashString = string =>
hashMaker
.sha256()
.update(string)
.digest("hex");
const findBlockWithHashPrefix = (signedGenerator, prefix) => {
let nonce = 0;
while (true) {
nonce++;
const signed = signedGenerator(nonce);
const hash = hashString(signed);
if (hash.slice(0, prefix.length) == prefix) {
return { signed, hash };
}
}
};
const makeSigned = (chain, payload) => nonce => {
return JSON.stringify({
lastBlockHash: chain[chain.length - 1].hash,
payload,
nonce
});
};
const addBlock = (chain, payload) => {
const signedGenerator = makeSigned(chain, payload);
return [...chain, findBlockWithHashPrefix(signedGenerator, "0")];
};
const verifyChain = chain => {
return chain.every((block, idx) => {
return (
verifyBlockHashMatchesContent(block) &&
verifyBlockContainsPreviousHash(block, chain[idx - 1])
);
});
};
const verifyBlockHashMatchesContent = block => {
return hashString(block.signed) === block.hash;
};
const verifyBlockContainsPreviousHash = (block, prevBlock) => {
// If prevBlock is undefined, we're the genesis block and we can do what we like
if (prevBlock === undefined) {
return true;
}
return JSON.parse(block.signed).lastBlockHash === prevBlock.hash;
};
module.exports = {
addBlock,
verifyChain
};
const hashMaker = require("hash.js");
const Chain = require("./chain");
const GENESIS_BLOCK = {
hash: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
signed: ""
};
describe("addBlock", () => {
test("adds a block", () => {
const chain = Chain.addBlock([GENESIS_BLOCK], "hi!");
expect(chain).toEqual([
GENESIS_BLOCK,
{
hash:
"0574f789c3b7f5cbd10470f2fdec7d9c590d51e8663d69f96dcf0a775b263449",
signed:
'{"lastBlockHash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","payload":"hi!","nonce":2}'
}
]);
});
});
describe("verifyChain", () => {
test("verifies a correct chain", () => {
const correctChain = Chain.addBlock([GENESIS_BLOCK], "hi!");
expect(Chain.verifyChain(correctChain)).toBe(true);
});
test("invalidates an incorrectly hashed chain", () => {
const correctChain = [
GENESIS_BLOCK,
{
hash: "badhash",
signed:
'{"lastBlockHash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","payload":"hi!","nonce":2}'
}
];
expect(Chain.verifyChain(correctChain)).toBe(false);
});
test("invalidates an incorrectly chained chain", () => {
const correctChain = [
GENESIS_BLOCK,
{
hash:
"0574f789c3b7f5cbd10470f2fdec7d9c590d51e8663d69f96dcf0a775b263449",
signed: '{"lastBlockHash":"badhash","payload":"hi!","nonce":2}'
}
];
expect(Chain.verifyChain(correctChain)).toBe(false);
});
});
{
"name": "bchain",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"hash.js": "^1.1.3",
"jest": "^22.0.3"
},
"scripts": {
"test": "jest"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment