forked from 15Dkatz/cryptochain
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit f7b29f1
Showing
10 changed files
with
5,689 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*node_modules* | ||
*dist* | ||
*.cache* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
const { GENESIS_DATA } = require('./config'); | ||
const cryptoHash = require('./crypto-hash'); | ||
|
||
class Block { | ||
constructor({ timestamp, lastHash, hash, data }) { | ||
this.timestamp = timestamp; | ||
this.lastHash = lastHash; | ||
this.hash = hash; | ||
this.data = data; | ||
} | ||
|
||
static genesis() { | ||
return new this(GENESIS_DATA); | ||
} | ||
|
||
static mineBlock({ lastBlock, data }) { | ||
const timestamp = Date.now(); | ||
const lastHash = lastBlock.hash; | ||
|
||
return new this({ | ||
timestamp, | ||
lastHash, | ||
data, | ||
hash: cryptoHash(timestamp, lastHash, data) | ||
}); | ||
} | ||
} | ||
|
||
module.exports = Block; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
const Block = require('./block'); | ||
const { GENESIS_DATA } = require('./config'); | ||
const cryptoHash = require('./crypto-hash'); | ||
|
||
describe('Block', () => { | ||
const timestamp = 'a-date'; | ||
const lastHash = 'foo-hash'; | ||
const hash = 'bar-hash'; | ||
const data = ['blockchain', 'data']; | ||
const block = new Block({ timestamp, lastHash, hash, data }); | ||
|
||
it('has a timestamp, lastHash, hash, and data property', () => { | ||
expect(block.timestamp).toEqual(timestamp); | ||
expect(block.lastHash).toEqual(lastHash); | ||
expect(block.hash).toEqual(hash); | ||
expect(block.data).toEqual(data); | ||
}); | ||
|
||
describe('genesis()', () => { | ||
const genesisBlock = Block.genesis(); | ||
|
||
it('returns a Block instance', () => { | ||
expect(genesisBlock instanceof Block).toBe(true); | ||
}); | ||
|
||
it('returns the genesis data', () => { | ||
expect(genesisBlock).toEqual(GENESIS_DATA); | ||
}); | ||
}); | ||
|
||
describe('mineBlock()', () => { | ||
const lastBlock = Block.genesis(); | ||
const data = 'mined data'; | ||
const minedBlock = Block.mineBlock({ lastBlock, data }); | ||
|
||
it('returns a Block instance', () => { | ||
expect(minedBlock instanceof Block).toBe(true); | ||
}); | ||
|
||
it('sets the `lastHash` to be the `hash` of the lastBlock', () => { | ||
expect(minedBlock.lastHash).toEqual(lastBlock.hash); | ||
}); | ||
|
||
it('sets the `data`', () => { | ||
expect(minedBlock.data).toEqual(data); | ||
}); | ||
|
||
it('sets a `timestamp`', () => { | ||
expect(minedBlock.timestamp).not.toEqual(undefined); | ||
}); | ||
|
||
it('creates a SHA-256 `hash` based on the proper inputs', () => { | ||
expect(minedBlock.hash) | ||
.toEqual(cryptoHash(minedBlock.timestamp, lastBlock.hash, data)); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
const Block = require('./block'); | ||
|
||
class Blockchain { | ||
constructor() { | ||
this.chain = [Block.genesis()]; | ||
} | ||
|
||
addBlock({ data }) { | ||
const newBlock = Block.mineBlock({ | ||
lastBlock: this.chain[this.chain.length-1], | ||
data | ||
}); | ||
|
||
this.chain.push(newBlock); | ||
} | ||
} | ||
|
||
module.exports = Blockchain; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
const Blockchain = require('./blockchain'); | ||
const Block = require('./block'); | ||
|
||
describe('Blockchain', () => { | ||
let blockchain; | ||
|
||
beforeEach(() => { | ||
blockchain = new Blockchain(); | ||
}); | ||
|
||
it('contains a `chain` Array instance', () => { | ||
expect(blockchain.chain instanceof Array).toBe(true); | ||
}); | ||
|
||
it('starts with the genesis block', () => { | ||
expect(blockchain.chain[0]).toEqual(Block.genesis()); | ||
}); | ||
|
||
it('adds a new block to the chain', () => { | ||
const newData = 'foo bar'; | ||
blockchain.addBlock({ data: newData }); | ||
|
||
expect(blockchain.chain[blockchain.chain.length-1].data).toEqual(newData); | ||
}); | ||
|
||
describe('isValidChain()', () => { | ||
describe('when the chain does not start with the genesis block', () => { | ||
it('returns false', () => { | ||
blockchain.chain[0] = { data: 'fake-genesis' }; | ||
|
||
expect(Blockchain.isValidChain(blockchain.chain)).toBe(false); | ||
}); | ||
}); | ||
|
||
describe('when the chain starts with the genesis block and has multiple blocks', () => { | ||
beforeEach(() => { | ||
blockchain.addBlock({ data: 'Bears' }); | ||
blockchain.addBlock({ data: 'Beets' }); | ||
blockchain.addBlock({ data: 'Battlestar Galactica' }); | ||
}); | ||
|
||
describe('and a lastHash reference has changed', () => { | ||
it('returns false', () => { | ||
blockchain.chain[2].lastHash = 'broken-lastHash'; | ||
|
||
expect(Blockchain.isValidChain(blockchain.chain)).toBe(false); | ||
}); | ||
}); | ||
|
||
describe('and the chain contains a block with an invalid field', () => { | ||
it('returns false', () => { | ||
blockchain.chain[2].data = 'some-bad-and-evil-data'; | ||
|
||
expect(Blockchain.isValidChain(blockchain.chain)).toBe(false); | ||
}); | ||
}); | ||
|
||
describe('and the chain does not contain any invalid blocks', () => { | ||
it('returns true', () => { | ||
expect(Blockchain.isValidChain(blockchain.chain)).toBe(true); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
const GENESIS_DATA = { | ||
timestamp: 1, | ||
lastHash: '-----', | ||
hash: 'hash-one', | ||
data: [] | ||
}; | ||
|
||
module.exports = { GENESIS_DATA }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const crypto = require('crypto'); | ||
|
||
const cryptoHash = (...inputs) => { | ||
const hash = crypto.createHash('sha256'); | ||
|
||
hash.update(inputs.sort().join(' ')); | ||
|
||
return hash.digest('hex'); | ||
}; | ||
|
||
module.exports = cryptoHash; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
const cryptoHash = require('./crypto-hash'); | ||
|
||
describe('cryptoHash()', () => { | ||
it('generates a SHA-256 hashed output', () => { | ||
expect(cryptoHash('foo')) | ||
.toEqual('2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae'); | ||
}); | ||
|
||
it('produces the same hash with the same input arguments in any order', () => { | ||
expect(cryptoHash('one', 'two', 'three')) | ||
.toEqual(cryptoHash('three', 'one', 'two')); | ||
}); | ||
}); |
Oops, something went wrong.