/ blockchain.test.js
blockchain.test.js
1 const Blockchain = require("./blockchain"); 2 const Block = require("./block"); 3 const cryptoHash = require("./crypto-hash"); 4 5 describe("Blockchain", () => { 6 let blockchain, newChain, originalChain; 7 8 beforeEach(() => { 9 blockchain = new Blockchain(); 10 newChain = new Blockchain(); 11 12 originalChain = blockchain.chain; 13 }); 14 15 it("contains a `chain` Array instance", () => { 16 expect(blockchain.chain instanceof Array).toBe(true); 17 }); 18 19 it("starts with the genesis block", () => { 20 expect(blockchain.chain[0]).toEqual(Block.genesis()); 21 }); 22 23 it("adds a new block to the chain", () => { 24 const newData = "new data"; 25 blockchain.addBlock({ data: newData }); 26 27 expect(blockchain.chain[blockchain.chain.length - 1].data).toEqual(newData); 28 }); 29 30 describe("isValidChain()", () => { 31 describe("when the chain does not start with the genesis block", () => { 32 it("returns false", () => { 33 blockchain.chain[0] = { data: "fake-genesis" }; 34 expect(Blockchain.isValidChain(blockchain.chain)).toBe(false); 35 }); 36 37 describe("when the chain starts with the genesis block and has multiple blocks", () => { 38 beforeEach(() => { 39 blockchain.addBlock({ data: "test" }); 40 blockchain.addBlock({ data: "test1" }); 41 blockchain.addBlock({ data: "test2" }); 42 }); 43 44 describe("and a lasthash reference has change", () => { 45 it("returns false", () => { 46 blockchain.chain[2].lastHash = "broken-lastHash"; 47 48 expect(Blockchain.isValidChain(blockchain.chain)).toBe(false); 49 }); 50 describe("and the chain contains a block with an invalid field", () => { 51 it("returns false", () => { 52 blockchain.chain[2].data = "evil-data"; 53 54 expect(Blockchain.isValidChain(blockchain.chain)).toBe(false); 55 }); 56 }); 57 58 describe("and the chain contains a block with jumped difficulty", () => { 59 it("returns false", () => { 60 const lastBlock = blockchain.chain[blockchain.chain.length - 1]; 61 62 const lastHash = lastBlock.hash; 63 const timestamp = Date.now(); 64 const nonce = 0; 65 const data = []; 66 67 const difficulty = lastBlock.difficulty - 3; 68 69 const hash = cryptoHash( 70 timestamp, 71 lastHash, 72 difficulty, 73 nonce, 74 data 75 ); 76 77 const badBlock = new Block({ 78 timestamp, 79 lastHash, 80 hash, 81 nonce, 82 difficulty, 83 data, 84 }); 85 86 blockchain.chain.push(badBlock); 87 expect(Blockchain.isValidChain(blockchain.chain)).toBe(false); 88 }); 89 }); 90 91 describe("and the chain does not contain any invalid blocks", () => { 92 it("returns true", () => { 93 console.log(blockchain.chain); 94 expect(Blockchain.isValidChain(blockchain.chain)).toBe(true); 95 }); 96 }); 97 }); 98 }); 99 }); 100 }); 101 102 describe("replaceChain()", () => { 103 let errorMock, logMock; 104 beforeEach(() => { 105 errorMock = jest.fn(); 106 logMock = jest.fn(); 107 108 global.console.error = errorMock; 109 global.console.log = logMock; 110 }); 111 112 describe("when the new chain is not longer", () => { 113 beforeEach(() => { 114 newChain.chain[0] = { new: "chain" }; 115 116 blockchain.replaceChain(newChain.chain); 117 }); 118 119 it("does not replace the chain", () => { 120 expect(blockchain.chain).toEqual(originalChain); 121 }); 122 123 it("logs an error", () => { 124 expect(errorMock).toHaveBeenCalled(); 125 }); 126 }); 127 128 describe("when the new chain is longer", () => { 129 beforeEach(() => { 130 newChain.addBlock({ data: "test" }); 131 newChain.addBlock({ data: "test1" }); 132 newChain.addBlock({ data: "test2" }); 133 }); 134 describe("and the chain is invalid", () => { 135 beforeEach(() => { 136 newChain.chain[2].hash = "fake-hash"; 137 138 blockchain.replaceChain(newChain.chain); 139 }); 140 it("does not replace the chain", () => { 141 expect(blockchain.chain).toEqual(originalChain); 142 }); 143 144 it("logs an error", () => { 145 expect(errorMock).toHaveBeenCalled(); 146 }); 147 }); 148 149 describe("and the chain is valid", () => { 150 beforeEach(() => { 151 blockchain.replaceChain(newChain.chain); 152 }); 153 154 it("replaces the chain", () => { 155 expect(blockchain.chain).toEqual(newChain.chain); 156 }); 157 158 it("logs about the chain replacement", () => { 159 expect(logMock).toHaveBeenCalled(); 160 }); 161 }); 162 }); 163 }); 164 });