├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── lib ├── accounts.js ├── blockchains.js ├── blocks.js ├── miners.js ├── nodes.js ├── stores.js ├── transactions.js ├── tries.js └── utils.js ├── package.json └── test ├── accounts.js ├── blockchains.js ├── blocks.js ├── blockstores.js ├── miners.js ├── nodes.js ├── states.js ├── transactions.js ├── tries.js └── utils.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /samples 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (C) 2016-present, Angel J Lopez 3 | http://www.ajlopez.com 4 | http://ajlopez.wordpress.com 5 | http://twitter.com/ajlopez 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajlopez/SimpleBlockchain/701ba713e776c82a3d042f60654975f12d2c0cc5/README.md -------------------------------------------------------------------------------- /lib/accounts.js: -------------------------------------------------------------------------------- 1 | 2 | var utils = require('./utils'); 3 | 4 | function createAccount() { 5 | return { address: utils.address() }; 6 | } 7 | 8 | module.exports = { 9 | account: createAccount 10 | } 11 | 12 | -------------------------------------------------------------------------------- /lib/blockchains.js: -------------------------------------------------------------------------------- 1 | 2 | var stores = require('./stores'); 3 | var utils = require('./utils'); 4 | 5 | function Blockchain() { 6 | var self = this; 7 | var blocks = []; 8 | var initial = 0; 9 | var blockstore = stores.blockstore(); 10 | 11 | this.bestBlock = function () { 12 | if (!blocks.length) 13 | return null; 14 | 15 | return blocks[blocks.length - 1]; 16 | } 17 | 18 | this.add = function (block) { 19 | if (blockstore.hasBlockHash(block.hash)) 20 | return; 21 | 22 | blockstore.save(block); 23 | 24 | if (blocks.length === 0) { 25 | blocks.push(block); 26 | initial = block.number; 27 | return; 28 | } 29 | 30 | if (getUnknownAncestor(block) != null) 31 | return; 32 | 33 | tryAdd(block); 34 | } 35 | 36 | this.getBlock = function (number) { 37 | return blocks[number - initial]; 38 | } 39 | 40 | function tryAdd(block) { 41 | if (isBestBlockChild(block) || (blocks.length === 0 && block.number === 0)) 42 | blocks.push(block); 43 | else if (isBetterBestBlock(block)) 44 | tryFork(block); 45 | 46 | tryChildren(block); 47 | } 48 | 49 | function tryChildren(block) { 50 | var children = blockstore.getChildren(block.hash); 51 | 52 | for (var n in children) 53 | tryAdd(children[n]); 54 | } 55 | 56 | function isBestBlockChild(block) { 57 | var bblock = self.bestBlock(); 58 | 59 | if (bblock === null) 60 | return block.number === 0; 61 | 62 | return bblock.hash === block.parentHash && bblock.number === block.number - 1; 63 | } 64 | 65 | function isBetterBestBlock(block) { 66 | var bblock = self.bestBlock(); 67 | 68 | return bblock.number < block.number; 69 | } 70 | 71 | function tryFork(block) { 72 | var newbranch = [block]; 73 | var parentHash = block.parentHash; 74 | 75 | while (parentHash && blockstore.hasBlockHash(parentHash)) { 76 | var parent = blockstore.getByHash(parentHash); 77 | 78 | if (parent.hash === blocks[parent.number - initial].hash) 79 | return switchToFork(newbranch); 80 | 81 | newbranch.push(parent); 82 | 83 | parentHash = parent.parentHash; 84 | } 85 | } 86 | 87 | function getUnknownAncestor(block) { 88 | var parentHash = block.parentHash; 89 | 90 | while (parentHash && blockstore.hasBlockHash(parentHash)) { 91 | var parent = blockstore.getByHash(parentHash); 92 | 93 | if (blocks[parent.number - initial] && parent.hash === blocks[parent.number - initial].hash) 94 | return null; 95 | 96 | parentHash = parent.parentHash; 97 | } 98 | 99 | if (parentHash === utils.zeroHash()) 100 | return null; 101 | 102 | return parentHash; 103 | } 104 | 105 | function switchToFork(newbranch) { 106 | for (var n = newbranch.length; n-- > 0;) { 107 | var block = newbranch[n]; 108 | blocks[block.number - initial] = block; 109 | } 110 | } 111 | } 112 | 113 | function createBlockchain() { 114 | return new Blockchain(); 115 | } 116 | 117 | module.exports = { 118 | blockchain: createBlockchain 119 | } 120 | 121 | -------------------------------------------------------------------------------- /lib/blocks.js: -------------------------------------------------------------------------------- 1 | 2 | var utils = require('./utils'); 3 | var transactions = require('./transactions'); 4 | 5 | function createBlock(data, parent) { 6 | if (data && !parent) { 7 | parent = data; 8 | data = null; 9 | } 10 | 11 | data = data || {} 12 | 13 | var block = { 14 | number: parent ? parent.number + 1 : 0, 15 | hash: utils.hash(), 16 | parentHash: parent ? parent.hash : utils.zeroHash() 17 | }; 18 | 19 | for (var n in data) 20 | if (block[n] == null) 21 | block[n] = data[n]; 22 | 23 | return block; 24 | } 25 | 26 | function executeBlock(block, states) { 27 | if (!block.transactions) 28 | return states; 29 | 30 | for (var n in block.transactions) { 31 | var tx = block.transactions[n]; 32 | 33 | var newstates = transactions.execute(tx, states); 34 | 35 | if (!newstates) 36 | return null; 37 | 38 | states = newstates; 39 | } 40 | 41 | return states; 42 | } 43 | 44 | module.exports = { 45 | block: createBlock, 46 | execute: executeBlock 47 | }; 48 | 49 | -------------------------------------------------------------------------------- /lib/miners.js: -------------------------------------------------------------------------------- 1 | 2 | var blocks = require('./blocks'); 3 | var transactions = require('./transactions'); 4 | 5 | function Miner(txs) { 6 | this.mine = function (parent, states) { 7 | var ptxs = txs.list(); 8 | var btxs = []; 9 | 10 | ptxs.forEach(function (ptx) { 11 | var newstates = transactions.execute(ptx, states); 12 | 13 | if (newstates == null) 14 | return; 15 | 16 | states = newstates; 17 | btxs.push(ptx); 18 | txs.remove(ptx); 19 | }); 20 | 21 | var block = blocks.block({ transactions: btxs }, parent); 22 | 23 | return block; 24 | } 25 | } 26 | 27 | function createMiner(txs) { 28 | return new Miner(txs); 29 | } 30 | 31 | module.exports = { 32 | miner: createMiner 33 | }; -------------------------------------------------------------------------------- /lib/nodes.js: -------------------------------------------------------------------------------- 1 | 2 | var blockchains = require('./blockchains'); 3 | var transactions = require('./transactions'); 4 | var miners = require('./miners'); 5 | var tries = require('./tries'); 6 | 7 | function Node(initialStates) { 8 | var blockchain = blockchains.blockchain(); 9 | var txs = transactions.txs(); 10 | var miner; 11 | var states = initialStates || tries.states(); 12 | 13 | this.addBlock = function (block) { blockchain.add(block); } 14 | 15 | this.bestBlock = function () { return blockchain.bestBlock(); } 16 | 17 | this.addTransaction = function (tx) { txs.add(tx); } 18 | 19 | this.transactions = function () { return txs.list(); } 20 | 21 | this.states = function () { return states; } 22 | 23 | this.mine = function () { 24 | if (!miner) 25 | miner = miners.miner(txs); 26 | 27 | return miner.mine(blockchain.bestBlock(), states); 28 | } 29 | } 30 | 31 | function createNode(states) { 32 | return new Node(states); 33 | } 34 | 35 | module.exports = { 36 | node: createNode 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /lib/stores.js: -------------------------------------------------------------------------------- 1 | 2 | function BlockStore() { 3 | var byhash = {}; 4 | var byparenthash = {}; 5 | var bynumber = []; 6 | 7 | this.save = function (block) { 8 | if (block.hash) 9 | byhash[block.hash] = block; 10 | 11 | if (block.parentHash) { 12 | var byphash = byparenthash[block.parentHash]; 13 | 14 | if (!byphash) 15 | byparenthash[block.parentHash] = [block]; 16 | else 17 | byphash.push(block); 18 | } 19 | 20 | if (block.number != null) { 21 | var byn = bynumber[block.number]; 22 | 23 | if (!byn) 24 | bynumber[block.number] = [block]; 25 | else 26 | byn.push(block); 27 | } 28 | }; 29 | 30 | this.getByHash = function (hash) { 31 | return byhash[hash]; 32 | }; 33 | 34 | this.hasBlockHash = function (hash) { 35 | return byhash[hash] != null; 36 | }; 37 | 38 | this.getChildren = function (hash) { 39 | var result = byparenthash[hash]; 40 | 41 | if (result) 42 | return result; 43 | 44 | return []; 45 | } 46 | 47 | this.getByNumber = function (number) { 48 | var result = bynumber[number]; 49 | 50 | if (result) 51 | return result; 52 | 53 | return []; 54 | } 55 | } 56 | 57 | function createBlockStore() { 58 | return new BlockStore(); 59 | } 60 | 61 | module.exports = { 62 | blockstore: createBlockStore 63 | }; 64 | 65 | -------------------------------------------------------------------------------- /lib/transactions.js: -------------------------------------------------------------------------------- 1 | 2 | var utils = require('./utils'); 3 | 4 | function Transactions() { 5 | var txs = {}; 6 | 7 | this.list = function () { 8 | var list = []; 9 | 10 | for (var n in txs) 11 | list.push(txs[n]); 12 | 13 | return list; 14 | }; 15 | 16 | this.add = function (tx) { txs[tx.id] = tx; }; 17 | 18 | this.remove = function (tx) { 19 | delete txs[tx.id]; 20 | }; 21 | } 22 | 23 | function transfer(from, to, value) { 24 | return { 25 | id: utils.hash(), 26 | from: from, 27 | to: to, 28 | value: value 29 | }; 30 | } 31 | 32 | function execute(tx, states) { 33 | var fromstate = states.get(tx.from); 34 | var tostate = states.get(tx.to); 35 | 36 | fromstate.balance -= tx.value; 37 | 38 | if (fromstate.balance < 0) 39 | return null; 40 | 41 | tostate.balance += tx.value; 42 | 43 | return states.put(tx.from, fromstate).put(tx.to, tostate); 44 | } 45 | 46 | function getPending() { 47 | return []; 48 | } 49 | 50 | function createTransactions() { 51 | return new Transactions(); 52 | } 53 | 54 | module.exports = { 55 | transfer: transfer, 56 | execute: execute, 57 | pending: getPending, 58 | txs: createTransactions 59 | }; 60 | 61 | -------------------------------------------------------------------------------- /lib/tries.js: -------------------------------------------------------------------------------- 1 | 2 | function Trie(values) { 3 | if (values == null) 4 | values = []; 5 | 6 | var defvalue = null; 7 | 8 | this.default = function (value) { 9 | defvalue = value; 10 | }; 11 | 12 | this.get = function (key, offset) { 13 | var value = get(key, offset); 14 | 15 | if (value == null) 16 | if (!offset) 17 | return cloneObject(defvalue); 18 | else 19 | return defvalue; 20 | 21 | if (!offset) 22 | return cloneObject(value); 23 | 24 | return value; 25 | }; 26 | 27 | function get(key, offset) { 28 | if (offset == null) 29 | offset = 0; 30 | 31 | var ky = key[offset]; 32 | 33 | if (offset === key.length - 1) 34 | return values[ky]; 35 | else if (values[ky]) 36 | return values[ky].get(key, offset + 1); 37 | else 38 | return null; 39 | }; 40 | 41 | this.put = function (key, data, offset) { 42 | if (offset == null) 43 | offset = 0; 44 | 45 | var newvalues = cloneValues(values); 46 | 47 | var ky = key[offset]; 48 | 49 | if (offset === key.length - 1) 50 | newvalues[ky] = data; 51 | else { 52 | if (!newvalues[ky]) { 53 | newvalues[ky] = new Trie(); 54 | newvalues[ky].default(defvalue); 55 | } 56 | 57 | newvalues[ky] = newvalues[ky].put(key, data, offset + 1); 58 | } 59 | 60 | var newtrie = new Trie(newvalues); 61 | newtrie.default(defvalue); 62 | 63 | return newtrie; 64 | }; 65 | } 66 | 67 | function cloneValues(values) { 68 | var newvalues = []; 69 | 70 | for (var n in values) 71 | newvalues[n] = values[n]; 72 | 73 | return newvalues; 74 | } 75 | 76 | function cloneObject(obj) { 77 | if (obj == null) 78 | return null; 79 | 80 | if (typeof obj !== 'object') 81 | return obj; 82 | 83 | var newobj; 84 | 85 | if (Array.isArray(obj)) 86 | newobj = []; 87 | else 88 | newobj = {}; 89 | 90 | for (var n in obj) 91 | newobj[n] = cloneObject(obj[n]); 92 | 93 | return newobj; 94 | } 95 | 96 | function createTrie() { 97 | return new Trie(); 98 | } 99 | 100 | function createStates() { 101 | var trie = new Trie(); 102 | 103 | trie.default({ balance: 0 }); 104 | 105 | return trie; 106 | } 107 | 108 | module.exports = { 109 | trie: createTrie, 110 | states: createStates 111 | }; 112 | 113 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | 2 | var zerohash = ''; 3 | 4 | for (var k = 0; k < 32; k++) 5 | zerohash += '00'; 6 | 7 | function generateByte() { 8 | var value = Math.floor(Math.random() * 256).toString(16); 9 | 10 | if (value.length < 2) 11 | value = '0' + value; 12 | 13 | return value; 14 | } 15 | 16 | function generateBytes(n) { 17 | var key = ''; 18 | 19 | for (var k = 0; k < n; k++) 20 | key += generateByte(); 21 | 22 | return key; 23 | } 24 | 25 | function generateHash() { 26 | return generateBytes(32); 27 | } 28 | 29 | function generateAddress() { 30 | return generateBytes(20); 31 | } 32 | 33 | function zeroHash() { 34 | return zerohash; 35 | } 36 | 37 | function isHexadecimal(text) { 38 | for (var k = 0; k < text.length; k++) { 39 | var ch = text[k]; 40 | if (ch >= '0' && ch <='9') 41 | continue; 42 | if (ch >= 'a' && ch <= 'f') 43 | continue; 44 | 45 | return false; 46 | } 47 | 48 | return true; 49 | } 50 | 51 | function isHash(hash) { 52 | if (typeof hash !== 'string') 53 | return false; 54 | 55 | if (hash.length != 64) 56 | return false; 57 | 58 | return isHexadecimal(hash); 59 | } 60 | 61 | module.exports = { 62 | hash: generateHash, 63 | zeroHash: zeroHash, 64 | address: generateAddress, 65 | isHexadecimal: isHexadecimal, 66 | isHash: isHash 67 | } 68 | 69 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { "name": "simpleblockchain" 2 | , "description": "Simple blockchain implementation in NodeJS/JavaScript" 3 | , "keywords": [ "blockchain", "bitcoin", "ethereum" ] 4 | , "version": "0.0.1alpha" 5 | , "author": "Angel 'Java' Lopez (http://www.ajlopez.com)" 6 | , "repository": { "type": "git", "url": "git://github.com/ajlopez/SimpleBlockchain.git" } 7 | , "main": "./lib/simpleblockchain.js" 8 | , "engines": { "node": ">= 0.6.0 && < 0.13.0" } 9 | , "scripts": { 10 | "test": "simpleunit -r ./test" 11 | } 12 | , "dependencies": { 13 | } 14 | , "devDependencies": { 15 | "simpleunit": "0.0.7" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/accounts.js: -------------------------------------------------------------------------------- 1 | 2 | var accounts = require('../lib/accounts'); 3 | var utils = require('../lib/utils'); 4 | 5 | exports['create account with address'] = function (test) { 6 | var account = accounts.account(); 7 | 8 | test.ok(account); 9 | test.ok(account.address); 10 | test.equal(account.address.length, 40); 11 | test.ok(utils.isHexadecimal(account.address)); 12 | }; 13 | 14 | -------------------------------------------------------------------------------- /test/blockchains.js: -------------------------------------------------------------------------------- 1 | 2 | var blockchains = require('../lib/blockchains'); 3 | var blocks = require('../lib/blocks'); 4 | 5 | exports['create blockchain'] = function (test) { 6 | var genesis = blocks.block(); 7 | var bc = blockchains.blockchain(); 8 | 9 | bc.add(genesis); 10 | 11 | test.ok(bc); 12 | test.equal(typeof bc, 'object'); 13 | test.equal(bc.bestBlock().number, genesis.number); 14 | test.equal(bc.bestBlock().hash, genesis.hash); 15 | }; 16 | 17 | exports['create partial blockchain'] = function (test) { 18 | var genesis = blocks.block(); 19 | var block1 = blocks.block(genesis); 20 | var block2 = blocks.block(block1); 21 | 22 | var bc = blockchains.blockchain(); 23 | 24 | bc.add(block2); 25 | 26 | test.ok(bc); 27 | test.equal(typeof bc, 'object'); 28 | test.equal(bc.bestBlock().number, block2.number); 29 | test.equal(bc.bestBlock().hash, block2.hash); 30 | }; 31 | 32 | exports['add block'] = function (test) { 33 | var genesis = blocks.block(); 34 | var block = blocks.block(genesis); 35 | var bc = blockchains.blockchain(); 36 | 37 | bc.add(genesis); 38 | bc.add(block); 39 | 40 | test.equal(bc.bestBlock().number, block.number); 41 | test.equal(bc.bestBlock().hash, block.hash); 42 | }; 43 | 44 | exports['add block same height'] = function (test) { 45 | var genesis = blocks.block(); 46 | var block = blocks.block(genesis); 47 | var block2 = blocks.block(genesis); 48 | 49 | var bc = blockchains.blockchain(); 50 | 51 | bc.add(genesis); 52 | bc.add(block); 53 | bc.add(block2); 54 | 55 | test.equal(bc.bestBlock().number, block.number); 56 | test.equal(bc.bestBlock().hash, block.hash); 57 | }; 58 | 59 | exports['add block with next height'] = function (test) { 60 | var genesis = blocks.block(); 61 | var block = blocks.block(genesis); 62 | var block2 = blocks.block(block); 63 | 64 | var bc = blockchains.blockchain(); 65 | 66 | bc.add(genesis); 67 | bc.add(block); 68 | bc.add(block2); 69 | 70 | test.equal(bc.bestBlock().number, block2.number); 71 | test.equal(bc.bestBlock().hash, block2.hash); 72 | }; 73 | 74 | exports['add two blocks in wrong order'] = function (test) { 75 | var genesis = blocks.block(); 76 | var block = blocks.block(genesis); 77 | var block2 = blocks.block(block); 78 | 79 | var bc = blockchains.blockchain(); 80 | 81 | bc.add(genesis); 82 | bc.add(block2); 83 | bc.add(block); 84 | 85 | test.equal(bc.bestBlock().number, block2.number); 86 | test.equal(bc.bestBlock().hash, block2.hash); 87 | }; 88 | 89 | exports['add block next height but with another parent block'] = function (test) { 90 | var genesis = blocks.block(); 91 | var block = blocks.block(genesis); 92 | var block2 = blocks.block(genesis); 93 | var block3 = blocks.block(block2); 94 | 95 | var bc = blockchains.blockchain(); 96 | 97 | bc.add(genesis); 98 | bc.add(block); 99 | bc.add(block3); 100 | 101 | test.equal(bc.bestBlock().number, block.number); 102 | test.equal(bc.bestBlock().hash, block.hash); 103 | }; 104 | 105 | exports['switch to a better blockchain'] = function (test) { 106 | var genesis = blocks.block(); 107 | var block = blocks.block(genesis); 108 | var block2 = blocks.block(genesis); 109 | var block3 = blocks.block(block2); 110 | 111 | var bc = blockchains.blockchain(); 112 | 113 | bc.add(genesis); 114 | bc.add(block); 115 | bc.add(block2); 116 | 117 | test.equal(bc.bestBlock().number, block.number); 118 | test.equal(bc.bestBlock().hash, block.hash); 119 | 120 | bc.add(block3); 121 | 122 | test.equal(bc.bestBlock().number, block3.number); 123 | test.equal(bc.bestBlock().hash, block3.hash); 124 | }; 125 | 126 | exports['switch to a better blockchain with gap'] = function (test) { 127 | var genesis = blocks.block(); 128 | var block = blocks.block(genesis); 129 | var block2 = blocks.block(genesis); 130 | var block3 = blocks.block(block2); 131 | var block4 = blocks.block(block3); 132 | 133 | var bc = blockchains.blockchain(); 134 | 135 | bc.add(genesis); 136 | bc.add(block); 137 | bc.add(block2); 138 | 139 | test.equal(bc.bestBlock().number, block.number); 140 | test.equal(bc.bestBlock().hash, block.hash); 141 | 142 | bc.add(block4); 143 | bc.add(block3); 144 | 145 | test.equal(bc.bestBlock().number, block4.number); 146 | test.equal(bc.bestBlock().hash, block4.hash); 147 | }; 148 | 149 | exports['get blocks in blockchain by number'] = function (test) { 150 | var genesis = blocks.block(); 151 | var block = blocks.block(genesis); 152 | var block2 = blocks.block(block); 153 | var block3 = blocks.block(block2); 154 | var block4 = blocks.block(block3); 155 | 156 | var bc = blockchains.blockchain(); 157 | 158 | bc.add(genesis); 159 | bc.add(block); 160 | bc.add(block2); 161 | bc.add(block3); 162 | bc.add(block4); 163 | 164 | var result = bc.getBlock(0); 165 | 166 | test.ok(result); 167 | test.equal(result.number, genesis.number); 168 | test.equal(result.hash, genesis.hash); 169 | 170 | var result = bc.getBlock(1); 171 | 172 | test.ok(result); 173 | test.equal(result.number, block.number); 174 | test.equal(result.hash, block.hash); 175 | 176 | var result = bc.getBlock(2); 177 | 178 | test.ok(result); 179 | test.equal(result.number, block2.number); 180 | test.equal(result.hash, block2.hash); 181 | 182 | var result = bc.getBlock(3); 183 | 184 | test.ok(result); 185 | test.equal(result.number, block3.number); 186 | test.equal(result.hash, block3.hash); 187 | 188 | var result = bc.getBlock(4); 189 | 190 | test.ok(result); 191 | test.equal(result.number, block4.number); 192 | test.equal(result.hash, block4.hash); 193 | 194 | var result = bc.getBlock(5); 195 | 196 | test.ok(!result); 197 | test.equal(result, null); 198 | }; 199 | 200 | exports['get blocks in partial blockchain by number'] = function (test) { 201 | var genesis = blocks.block(); 202 | var block = blocks.block(genesis); 203 | var block2 = blocks.block(block); 204 | var block3 = blocks.block(block2); 205 | var block4 = blocks.block(block3); 206 | 207 | var bc = blockchains.blockchain(); 208 | 209 | bc.add(block2); 210 | bc.add(block3); 211 | bc.add(block4); 212 | 213 | var result = bc.getBlock(0); 214 | 215 | test.ok(!result); 216 | test.equal(result, null); 217 | 218 | var result = bc.getBlock(1); 219 | 220 | test.ok(!result); 221 | test.equal(result, null); 222 | 223 | var result = bc.getBlock(2); 224 | 225 | test.ok(result); 226 | test.equal(result.number, block2.number); 227 | test.equal(result.hash, block2.hash); 228 | 229 | var result = bc.getBlock(3); 230 | 231 | test.ok(result); 232 | test.equal(result.number, block3.number); 233 | test.equal(result.hash, block3.hash); 234 | 235 | var result = bc.getBlock(4); 236 | 237 | test.ok(result); 238 | test.equal(result.number, block4.number); 239 | test.equal(result.hash, block4.hash); 240 | 241 | var result = bc.getBlock(5); 242 | 243 | test.ok(!result); 244 | test.equal(result, null); 245 | }; 246 | -------------------------------------------------------------------------------- /test/blocks.js: -------------------------------------------------------------------------------- 1 | 2 | var blocks = require('../lib/blocks'); 3 | var utils = require('../lib/utils'); 4 | var transactions = require('../lib/transactions'); 5 | var tries = require('../lib/tries'); 6 | 7 | exports['create genesis block'] = function (test) { 8 | var block = blocks.block(); 9 | 10 | test.ok(block); 11 | test.equal(typeof block, 'object'); 12 | test.equal(block.number, 0); 13 | test.ok(utils.isHash(block.hash)); 14 | test.ok(utils.isHash(block.parentHash)); 15 | test.equal(block.parentHash, '0000000000000000000000000000000000000000000000000000000000000000'); 16 | } 17 | 18 | exports['create child block'] = function (test) { 19 | var genesis = blocks.block(); 20 | var block = blocks.block(genesis); 21 | 22 | test.ok(block); 23 | test.equal(typeof block, 'object'); 24 | test.equal(block.number, 1); 25 | test.ok(utils.isHash(block.hash)); 26 | test.ok(utils.isHash(block.parentHash)); 27 | test.equal(block.parentHash, genesis.hash); 28 | } 29 | 30 | exports['create child block with initial data'] = function (test) { 31 | var genesis = blocks.block(); 32 | var block = blocks.block({ extra: 'hello' }, genesis); 33 | 34 | test.ok(block); 35 | test.equal(typeof block, 'object'); 36 | test.equal(block.number, 1); 37 | test.ok(utils.isHash(block.hash)); 38 | test.ok(utils.isHash(block.parentHash)); 39 | test.equal(block.parentHash, genesis.hash); 40 | test.equal(block.extra, 'hello'); 41 | } 42 | 43 | 44 | exports['execute block with transfer'] = function (test) { 45 | var from = utils.hash(); 46 | var to = utils.hash(); 47 | var value = 1000; 48 | 49 | var states = tries.states().put(from, { balance: 3000 }); 50 | 51 | var tx = transactions.transfer(from, to, value); 52 | 53 | test.ok(tx); 54 | test.equal(tx.from, from); 55 | test.equal(tx.to, to); 56 | test.equal(tx.value, value); 57 | 58 | var genesis = blocks.block(); 59 | var block = blocks.block({ transactions: [tx] }, genesis); 60 | 61 | var newstates = blocks.execute(block, states); 62 | 63 | test.ok(newstates); 64 | 65 | var oldfromstate = states.get(tx.from); 66 | 67 | test.ok(oldfromstate); 68 | test.equal(oldfromstate.balance, 3000); 69 | 70 | var oldtostate = states.get(tx.to); 71 | 72 | test.ok(oldtostate); 73 | test.equal(oldtostate.balance, 0); 74 | 75 | var newtostate = newstates.get(tx.to); 76 | 77 | test.ok(newtostate); 78 | test.equal(newtostate.balance, 1000); 79 | 80 | var newfromstate = newstates.get(tx.from); 81 | 82 | test.ok(newfromstate); 83 | test.equal(newfromstate.balance, 2000); 84 | } 85 | 86 | exports['execute block with transfer without funds'] = function (test) { 87 | var from = utils.hash(); 88 | var to = utils.hash(); 89 | var value = 1000; 90 | 91 | var states = tries.states(); 92 | 93 | var tx = transactions.transfer(from, to, value); 94 | 95 | test.ok(tx); 96 | test.equal(tx.from, from); 97 | test.equal(tx.to, to); 98 | test.equal(tx.value, value); 99 | 100 | var genesis = blocks.block(); 101 | var block = blocks.block({ transactions: [tx] }, genesis); 102 | 103 | var newstates = blocks.execute(block, states); 104 | 105 | test.equal(newstates, null); 106 | 107 | var oldfromstate = states.get(tx.from); 108 | 109 | test.ok(oldfromstate); 110 | test.equal(oldfromstate.balance, 0); 111 | 112 | var oldtostate = states.get(tx.to); 113 | 114 | test.ok(oldtostate); 115 | test.equal(oldtostate.balance, 0); 116 | } 117 | 118 | -------------------------------------------------------------------------------- /test/blockstores.js: -------------------------------------------------------------------------------- 1 | 2 | var stores = require('../lib/stores'); 3 | var utils = require('../lib/utils'); 4 | 5 | exports['create store'] = function (test) { 6 | var store = stores.blockstore(); 7 | 8 | test.ok(store); 9 | test.equal(typeof store, 'object'); 10 | }; 11 | 12 | exports['retrieve unknown block by hash'] = function (test) { 13 | var store = stores.blockstore(); 14 | 15 | var block = store.getByHash(utils.hash()); 16 | 17 | test.equal(block, null); 18 | }; 19 | 20 | exports['retrieve no children'] = function (test) { 21 | var store = stores.blockstore(); 22 | 23 | var result = store.getChildren(utils.hash()); 24 | 25 | test.ok(result); 26 | test.ok(Array.isArray(result)); 27 | test.equal(result.length, 0); 28 | }; 29 | 30 | exports['save block and retrieve it by hash'] = function (test) { 31 | var store = stores.blockstore(); 32 | var hash = utils.hash(); 33 | var block = { hash: hash }; 34 | 35 | store.save(block); 36 | 37 | var result = store.getByHash(hash); 38 | 39 | test.ok(result); 40 | test.equal(result.hash, hash); 41 | }; 42 | 43 | exports['get children'] = function (test) { 44 | var store = stores.blockstore(); 45 | var hash = utils.hash(); 46 | var parentHash = utils.hash(); 47 | var block = { hash: hash, parentHash: parentHash }; 48 | 49 | store.save(block); 50 | 51 | var result = store.getChildren(parentHash); 52 | 53 | test.ok(result); 54 | test.ok(Array.isArray(result)); 55 | test.equal(result.length, 1); 56 | test.equal(result[0].hash, hash); 57 | test.equal(result[0].parentHash, parentHash); 58 | }; 59 | 60 | exports['save block and retrieve it by number'] = function (test) { 61 | var store = stores.blockstore(); 62 | var hash = utils.hash(); 63 | var parentHash = utils.hash(); 64 | var block = { hash: hash, number: 1, parentHash: parentHash }; 65 | 66 | store.save(block); 67 | 68 | var result = store.getByNumber(1); 69 | 70 | test.ok(result); 71 | test.ok(Array.isArray(result)); 72 | test.equal(result.length, 1); 73 | test.equal(result[0].number, 1); 74 | test.equal(result[0].hash, hash); 75 | test.equal(result[0].parentHash, parentHash); 76 | }; 77 | 78 | -------------------------------------------------------------------------------- /test/miners.js: -------------------------------------------------------------------------------- 1 | 2 | var miners = require('../lib/miners'); 3 | var blocks = require('../lib/blocks'); 4 | var tries = require('../lib/tries'); 5 | var transactions = require('../lib/transactions'); 6 | var utils = require('../lib/utils'); 7 | 8 | exports['mine empty block'] = function (test) { 9 | var txs = transactions.txs(); 10 | var miner = miners.miner(txs); 11 | 12 | var states = tries.states(); 13 | var genesis = blocks.block(); 14 | 15 | var result = miner.mine(genesis, states); 16 | 17 | test.ok(result); 18 | test.ok(result.hash); 19 | test.ok(result.transactions); 20 | test.ok(Array.isArray(result.transactions)); 21 | test.equal(result.transactions.length, 0); 22 | test.ok(result.parentHash); 23 | test.equal(result.parentHash, genesis.hash); 24 | }; 25 | 26 | exports['mine block with transaction'] = function (test) { 27 | var from = utils.hash(); 28 | var to = utils.hash(); 29 | var value = 1000; 30 | 31 | var states = tries.states().put(from, { balance: 3000 }); 32 | var tx = transactions.transfer(from, to, value); 33 | 34 | var txs = transactions.txs(); 35 | txs.add(tx); 36 | 37 | var miner = miners.miner(txs); 38 | 39 | var genesis = blocks.block(); 40 | 41 | var result = miner.mine(genesis, states); 42 | 43 | test.ok(result); 44 | test.ok(result.hash); 45 | test.ok(result.transactions); 46 | test.ok(Array.isArray(result.transactions)); 47 | test.equal(result.transactions.length, 1); 48 | 49 | test.equal(result.transactions[0].from, from); 50 | test.equal(result.transactions[0].to, to); 51 | test.equal(result.transactions[0].value, 1000); 52 | 53 | test.ok(result.parentHash); 54 | test.equal(result.parentHash, genesis.hash); 55 | 56 | var pendingtxs = txs.list(); 57 | 58 | test.ok(pendingtxs); 59 | test.ok(Array.isArray(pendingtxs)); 60 | test.equal(pendingtxs.length, 0); 61 | }; 62 | 63 | exports['mine block rejecting transaction without funds'] = function (test) { 64 | var from = utils.hash(); 65 | var to = utils.hash(); 66 | var value = 1000; 67 | 68 | var states = tries.states(); 69 | var tx = transactions.transfer(from, to, value); 70 | 71 | var txs = transactions.txs(); 72 | txs.add(tx); 73 | 74 | var miner = miners.miner(txs); 75 | 76 | var genesis = blocks.block(); 77 | 78 | var result = miner.mine(genesis, states); 79 | 80 | test.ok(result); 81 | test.ok(result.hash); 82 | test.ok(result.transactions); 83 | test.ok(Array.isArray(result.transactions)); 84 | test.equal(result.transactions.length, 0); 85 | 86 | test.ok(result.parentHash); 87 | test.equal(result.parentHash, genesis.hash); 88 | 89 | var pendingtxs = txs.list(); 90 | 91 | test.ok(pendingtxs); 92 | test.ok(Array.isArray(pendingtxs)); 93 | test.equal(pendingtxs.length, 1); 94 | }; 95 | 96 | -------------------------------------------------------------------------------- /test/nodes.js: -------------------------------------------------------------------------------- 1 | 2 | var nodes = require('../lib/nodes'); 3 | var blocks = require('../lib/blocks'); 4 | var transactions = require('../lib/transactions'); 5 | var utils = require('../lib/utils'); 6 | var tries = require('../lib/tries'); 7 | 8 | exports['create node'] = function (test) { 9 | var node = nodes.node(); 10 | 11 | test.ok(node); 12 | test.equal(typeof node, 'object'); 13 | }; 14 | 15 | exports['nodes with states'] = function (test) { 16 | var node = nodes.node(); 17 | 18 | var result = node.states(); 19 | 20 | test.ok(result); 21 | test.equal(typeof result, 'object'); 22 | } 23 | 24 | exports['add genesis block'] = function (test) { 25 | var genesis = blocks.block(); 26 | var node = nodes.node(); 27 | 28 | node.addBlock(genesis); 29 | 30 | var best = node.bestBlock(); 31 | 32 | test.ok(best); 33 | test.equal(best.number, genesis.number); 34 | test.equal(best.hash, genesis.hash); 35 | }; 36 | 37 | exports['add transfer'] = function (test) { 38 | var from = utils.hash(); 39 | var to = utils.hash(); 40 | var value = 1000; 41 | 42 | var tx = transactions.transfer(from, to, value); 43 | 44 | var node = nodes.node(); 45 | 46 | node.addTransaction(tx); 47 | 48 | var txs = node.transactions(); 49 | 50 | test.ok(txs); 51 | test.ok(Array.isArray(txs)); 52 | test.equal(txs.length, 1); 53 | 54 | var ntx = txs[0]; 55 | 56 | test.equal(ntx.id, tx.id); 57 | test.equal(ntx.to, tx.to); 58 | test.equal(ntx.value, tx.value); 59 | test.equal(ntx.from, tx.from); 60 | }; 61 | 62 | exports['mine with no transfers'] = function (test) { 63 | var genesis = blocks.block(); 64 | var node = nodes.node(); 65 | 66 | node.addBlock(genesis); 67 | 68 | var result = node.mine(); 69 | 70 | test.ok(result); 71 | test.ok(result.hash); 72 | test.ok(result.transactions); 73 | test.ok(Array.isArray(result.transactions)); 74 | test.equal(result.transactions.length, 0); 75 | test.ok(result.parentHash); 76 | test.equal(result.parentHash, genesis.hash); 77 | }; 78 | 79 | exports['mine with one transfer'] = function (test) { 80 | var from = utils.hash(); 81 | var to = utils.hash(); 82 | var value = 0; 83 | 84 | var tx = transactions.transfer(from, to, value); 85 | 86 | var genesis = blocks.block(); 87 | var node = nodes.node(); 88 | 89 | node.addBlock(genesis); 90 | node.addTransaction(tx); 91 | 92 | var result = node.mine(); 93 | 94 | test.ok(result); 95 | test.ok(result.hash); 96 | test.ok(result.transactions); 97 | test.ok(Array.isArray(result.transactions)); 98 | test.equal(result.transactions.length, 1); 99 | test.ok(result.parentHash); 100 | test.equal(result.parentHash, genesis.hash); 101 | }; 102 | 103 | 104 | exports['mine with two transfers'] = function (test) { 105 | var from = utils.hash(); 106 | var to = utils.hash(); 107 | 108 | var tx1 = transactions.transfer(from, to, 100); 109 | var tx2 = transactions.transfer(to, from, 50); 110 | 111 | var states = tries.states().put(from, { balance: 3000 }); 112 | 113 | var genesis = blocks.block(); 114 | var node = nodes.node(states); 115 | 116 | node.addBlock(genesis); 117 | node.addTransaction(tx1); 118 | node.addTransaction(tx2); 119 | 120 | var result = node.mine(); 121 | 122 | test.ok(result); 123 | test.ok(result.hash); 124 | test.ok(result.transactions); 125 | test.ok(Array.isArray(result.transactions)); 126 | test.equal(result.transactions.length, 2); 127 | test.ok(result.parentHash); 128 | test.equal(result.parentHash, genesis.hash); 129 | }; 130 | 131 | -------------------------------------------------------------------------------- /test/states.js: -------------------------------------------------------------------------------- 1 | 2 | var tries = require('../lib/tries'); 3 | 4 | exports['create states with default value'] = function (test) { 5 | var states = tries.states(); 6 | 7 | test.ok(states); 8 | test.equal(typeof states, 'object'); 9 | 10 | var result = states.get('1234'); 11 | 12 | test.ok(result); 13 | test.equal(typeof result, 'object'); 14 | test.equal(result.balance, 0); 15 | }; 16 | 17 | exports['change balance'] = function (test) { 18 | var states = tries.states(); 19 | 20 | test.ok(states); 21 | test.equal(typeof states, 'object'); 22 | 23 | var newstates = states.put('1234', { balance: 1000 }); 24 | 25 | test.ok(newstates); 26 | 27 | var result = states.get('1234'); 28 | 29 | test.ok(result); 30 | test.equal(typeof result, 'object'); 31 | test.equal(result.balance, 0); 32 | 33 | var result = newstates.get('1234'); 34 | 35 | test.ok(result); 36 | test.equal(typeof result, 'object'); 37 | test.equal(result.balance, 1000); 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /test/transactions.js: -------------------------------------------------------------------------------- 1 | 2 | var transactions = require('../lib/transactions'); 3 | var utils = require('../lib/utils'); 4 | var tries = require('../lib/tries'); 5 | 6 | exports['create transfer'] = function (test) { 7 | var from = utils.hash(); 8 | var to = utils.hash(); 9 | var value = 1000; 10 | 11 | var tx = transactions.transfer(from, to, value); 12 | 13 | test.ok(tx); 14 | test.equal(tx.from, from); 15 | test.equal(tx.to, to); 16 | test.equal(tx.value, value); 17 | } 18 | 19 | exports['create transfer with id'] = function (test) { 20 | var from = utils.hash(); 21 | var to = utils.hash(); 22 | var value = 1000; 23 | 24 | var tx = transactions.transfer(from, to, value); 25 | 26 | test.ok(tx); 27 | test.ok(tx.id); 28 | test.ok(utils.isHexadecimal(tx.id)); 29 | } 30 | 31 | exports['no pending transaction'] = function (test) { 32 | var pending = transactions.pending(); 33 | 34 | test.ok(pending); 35 | test.ok(Array.isArray(pending)); 36 | test.equal(pending.length, 0); 37 | } 38 | 39 | exports['empty transaction list'] = function (test) { 40 | var txs = transactions.txs(); 41 | 42 | test.ok(txs); 43 | 44 | var result = txs.list(); 45 | 46 | test.ok(result); 47 | test.ok(Array.isArray(result)); 48 | test.equal(result.length, 0); 49 | } 50 | 51 | exports['add transaction to transaction list'] = function (test) { 52 | var from = utils.hash(); 53 | var to = utils.hash(); 54 | var value = 1000; 55 | 56 | var tx = transactions.transfer(from, to, value); 57 | 58 | var txs = transactions.txs(); 59 | 60 | txs.add(tx); 61 | 62 | var result = txs.list(); 63 | 64 | test.ok(result); 65 | test.ok(Array.isArray(result)); 66 | test.equal(result.length, 1); 67 | test.equal(result[0].id, tx.id); 68 | test.equal(result[0].from, tx.from); 69 | test.equal(result[0].to, tx.to); 70 | test.equal(result[0].value, tx.value); 71 | } 72 | 73 | exports['add two transactions to transaction list'] = function (test) { 74 | var from = utils.hash(); 75 | var to = utils.hash(); 76 | var value = 1000; 77 | 78 | var tx1 = transactions.transfer(from, to, value); 79 | var tx2 = transactions.transfer(from, to, value); 80 | 81 | var txs = transactions.txs(); 82 | 83 | txs.add(tx1); 84 | txs.add(tx2); 85 | 86 | var result = txs.list(); 87 | 88 | test.ok(result); 89 | test.ok(Array.isArray(result)); 90 | test.equal(result.length, 2); 91 | test.equal(result[0].id, tx1.id); 92 | test.equal(result[1].id, tx2.id); 93 | } 94 | 95 | exports['remove transaction from transaction list'] = function (test) { 96 | var from = utils.hash(); 97 | var to = utils.hash(); 98 | var value = 1000; 99 | 100 | var tx = transactions.transfer(from, to, value); 101 | 102 | var txs = transactions.txs(); 103 | 104 | txs.add(tx); 105 | txs.remove(tx); 106 | 107 | var result = txs.list(); 108 | 109 | test.ok(result); 110 | test.ok(Array.isArray(result)); 111 | test.equal(result.length, 0); 112 | } 113 | 114 | exports['execute transfer'] = function (test) { 115 | var from = utils.hash(); 116 | var to = utils.hash(); 117 | var value = 1000; 118 | 119 | var states = tries.states().put(from, { balance: 3000 }); 120 | 121 | var tx = transactions.transfer(from, to, value); 122 | 123 | test.ok(tx); 124 | test.equal(tx.from, from); 125 | test.equal(tx.to, to); 126 | test.equal(tx.value, value); 127 | 128 | var newstates = transactions.execute(tx, states); 129 | 130 | test.ok(newstates); 131 | 132 | var oldfromstate = states.get(tx.from); 133 | 134 | test.ok(oldfromstate); 135 | test.equal(oldfromstate.balance, 3000); 136 | 137 | var oldtostate = states.get(tx.to); 138 | 139 | test.ok(oldtostate); 140 | test.equal(oldtostate.balance, 0); 141 | 142 | var newtostate = newstates.get(tx.to); 143 | 144 | test.ok(newtostate); 145 | test.equal(newtostate.balance, 1000); 146 | 147 | var newfromstate = newstates.get(tx.from); 148 | 149 | test.ok(newfromstate); 150 | test.equal(newfromstate.balance, 2000); 151 | } 152 | 153 | exports['execute transfer without funds'] = function (test) { 154 | var from = utils.hash(); 155 | var to = utils.hash(); 156 | var value = 1000; 157 | 158 | var states = tries.states(); 159 | 160 | var tx = transactions.transfer(from, to, value); 161 | 162 | test.ok(tx); 163 | test.equal(tx.from, from); 164 | test.equal(tx.to, to); 165 | test.equal(tx.value, value); 166 | 167 | var newstates = transactions.execute(tx, states); 168 | 169 | test.equal(newstates, null); 170 | 171 | var oldfromstate = states.get(tx.from); 172 | 173 | test.ok(oldfromstate); 174 | test.equal(oldfromstate.balance, 0); 175 | 176 | var oldtostate = states.get(tx.to); 177 | 178 | test.ok(oldtostate); 179 | test.equal(oldtostate.balance, 0); 180 | } 181 | 182 | -------------------------------------------------------------------------------- /test/tries.js: -------------------------------------------------------------------------------- 1 | 2 | var tries = require('../lib/tries'); 3 | var utils = require('../lib/utils'); 4 | 5 | exports['get trie as object'] = function (test) { 6 | var trie = tries.trie(); 7 | 8 | test.ok(trie); 9 | test.equal(typeof trie, 'object'); 10 | }; 11 | 12 | exports['get no data from empty trie'] = function (test) { 13 | var trie = tries.trie(); 14 | 15 | var result = trie.get('0123'); 16 | 17 | test.equal(result, null); 18 | }; 19 | 20 | exports['get default data from empty trie'] = function (test) { 21 | var trie = tries.trie(); 22 | 23 | trie.default(42); 24 | 25 | var result = trie.get('0123'); 26 | 27 | test.equal(result, 42); 28 | }; 29 | 30 | exports['get default data from non empty trie'] = function (test) { 31 | var trie = tries.trie(); 32 | 33 | trie.default(42); 34 | 35 | trie = trie.put('0000', 'foo'); 36 | 37 | var result = trie.get('0123'); 38 | 39 | test.equal(result, 42); 40 | }; 41 | 42 | exports['get default data as immutable object from empty trie'] = function (test) { 43 | var trie = tries.trie(); 44 | 45 | trie.default({ name: "Adam", age: 900 }); 46 | 47 | var result = trie.get('0123'); 48 | 49 | test.deepEqual(result, { name: "Adam", age: 900 }); 50 | 51 | result.name = "Eve"; 52 | result.age = 800; 53 | 54 | var result = trie.get('0123'); 55 | 56 | test.deepEqual(result, { name: "Adam", age: 900 }); 57 | }; 58 | 59 | exports['put data and create another trie'] = function (test) { 60 | var trie = tries.trie(); 61 | 62 | var result = trie.put('0123', 42); 63 | 64 | test.ok(result); 65 | test.ok(result !== trie); 66 | }; 67 | 68 | exports['put array and get cloned array'] = function (test) { 69 | var trie = tries.trie(); 70 | 71 | trie = trie.put('0123', [1, 2, 3]); 72 | 73 | var result = trie.get('0123'); 74 | 75 | test.ok(result); 76 | test.ok(Array.isArray(result)); 77 | test.deepEqual(result, [1, 2, 3]); 78 | 79 | result[0] = 42; 80 | 81 | var result = trie.get('0123'); 82 | 83 | test.ok(result); 84 | test.ok(Array.isArray(result)); 85 | test.deepEqual(result, [1, 2, 3]); 86 | }; 87 | 88 | exports['put data and get data'] = function (test) { 89 | var trie = tries.trie(); 90 | 91 | var result = trie.put('abcd', 42).get('abcd'); 92 | 93 | test.ok(result); 94 | test.equal(result, 42); 95 | }; 96 | 97 | exports['put two data and get two data'] = function (test) { 98 | var trie = tries.trie(); 99 | var hash1 = utils.hash(); 100 | var hash2 = utils.hash(); 101 | 102 | var newtrie = trie.put(hash1, 42).put(hash2, 'foo'); 103 | 104 | var result = newtrie.get(hash1); 105 | 106 | test.ok(result); 107 | test.equal(result, 42); 108 | 109 | var result = newtrie.get(hash2); 110 | 111 | test.ok(result); 112 | test.equal(result, 'foo'); 113 | }; 114 | 115 | exports['put two new data and retrieve them'] = function (test) { 116 | var trie = tries.trie(); 117 | 118 | var result = trie.put('0123', 42) 119 | .put('3210', 1); 120 | 121 | test.ok(result); 122 | test.equal(result.get('0123'), 42); 123 | test.equal(result.get('3210'), 1); 124 | test.equal(trie.get('0123'), null); 125 | test.equal(trie.get('3210'), null); 126 | }; 127 | 128 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | 2 | var utils = require('../lib/utils'); 3 | 4 | exports['generate hash'] = function (test) { 5 | var hash = utils.hash(); 6 | 7 | test.ok(hash); 8 | test.equal(typeof hash, 'string'); 9 | test.equal(hash.length, 64); 10 | test.ok(utils.isHexadecimal(hash)); 11 | test 12 | }; 13 | 14 | exports['generate address'] = function (test) { 15 | var hash = utils.address(); 16 | 17 | test.ok(hash); 18 | test.equal(typeof hash, 'string'); 19 | test.equal(hash.length, 40); 20 | test.ok(utils.isHexadecimal(hash)); 21 | test 22 | }; 23 | 24 | --------------------------------------------------------------------------------