Skip to content

Instantly share code, notes, and snippets.

@neoeno
Last active November 6, 2024 23:10
Show Gist options
  • Select an option

  • Save neoeno/00be262e827a1f0d7dab6bf841225d95 to your computer and use it in GitHub Desktop.

Select an option

Save neoeno/00be262e827a1f0d7dab6bf841225d95 to your computer and use it in GitHub Desktop.

Revisions

  1. neoeno revised this gist Dec 24, 2017. No changes.
  2. neoeno created this gist Dec 24, 2017.
    58 changes: 58 additions & 0 deletions chain.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,58 @@
    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
    };
    53 changes: 53 additions & 0 deletions chain.test.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,53 @@
    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);
    });
    });
    13 changes: 13 additions & 0 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    {
    "name": "bchain",
    "version": "1.0.0",
    "main": "index.js",
    "license": "MIT",
    "dependencies": {
    "hash.js": "^1.1.3",
    "jest": "^22.0.3"
    },
    "scripts": {
    "test": "jest"
    }
    }