diff --git a/README.md b/README.md index 9bca076..60ad07b 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ - [Diagrams](#diagrams) - [Install](#install) +- [Getting started](#Getting-started) - [Documentation](#documentation) - [Test](#test) - [FAQ](#faq) @@ -43,6 +44,48 @@ Diagram of Bitcoin Merkle Tree npm install merkletreejs ``` +## Getting started + +Construct tree, generate proof, and verify proof: + +```bash +const MerkleTree = require('merkletreejs') +const SHA256 = require('crypto-js/sha256') + +const leaves = ['a', 'b', 'c'].map(x => SHA256(x)) +const tree = new MerkleTree(leaves, SHA256) +const root = tree.getRoot().toString('hex') +const leaf = SHA256('a') +const proof = tree.getProof(leaf) +console.log(tree.verify(proof, leaf, root)) // true + + +const badLeaves = ['a', 'x', 'c'].map(x => SHA256(x)) +const badTree = new MerkleTree(badLeaves, SHA256) +const badLeaf = SHA256('x') +const badProof = tree.getProof(badLeaf) +console.log(tree.verify(badProof, leaf, root)) // false +``` + +Print tree to console: + +```js +const leaves = ['a', 'b', 'c'].map(x => sha3(x)) +const tree = new MerkleTree(leaves, sha256) +MerkleTree.print(tree) +``` + +Output + +```bash +└─ 311d2e46f49b15fff8b746b74ad57f2cc9e0d9939fda94387141a2d3fdf187ae + ├─ 176f0f307632fdd5831875eb709e2f68d770b102262998b214ddeb3f04164ae1 + │ ├─ 3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb + │ └─ b5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510 + └─ 0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2 + └─ 0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2 +``` + ## Documentation ## Classes diff --git a/index.js b/index.js index c680d0d..7da35bc 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ const reverse = require('buffer-reverse') const CryptoJS = require('crypto-js') +const treeify = require('treeify') /** * Class reprensenting a Merkle Tree @@ -220,6 +221,7 @@ class MerkleTree { */ verify(proof, targetNode, root) { let hash = bufferify(targetNode) + root = bufferify(root) if (!Array.isArray(proof) || !proof.length || @@ -256,6 +258,38 @@ class MerkleTree { static bufferify(x) { return bufferify(x) } + + static print(tree, opts) { + opts = opts || {} + const log = opts instanceof Object && opts.log !== false + const layers = tree.getLayers().map(x => x.map(x => x.toString('hex'))) + const objs = [] + for (let i = 0; i < layers.length; i++) { + const arr = [] + for (let j = 0; j < layers[i].length; j++) { + const obj = { [layers[i][j]]: {} } + if (objs.length) { + const a = objs.shift() + const akey = Object.keys(a)[0] + obj[layers[i][j]][akey] = a[akey] + if (objs.length) { + const b = objs.shift() + const bkey = Object.keys(b)[0] + obj[layers[i][j]][bkey] = b[bkey] + } + } + + arr.push(obj) + } + + objs.push(...arr) + } + + const str = treeify.asTree(objs[0], true) + if (log) console.log(str) + + return str + } } function bufferify(x) { diff --git a/package-lock.json b/package-lock.json index d52c9b6..0a16e16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { - "acorn": "3.3.0" + "acorn": "^3.0.4" } }, "align-text": { @@ -25,9 +25,9 @@ "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" } }, "amdefine": { @@ -42,7 +42,7 @@ "integrity": "sha1-HBg5S2r5t2/5pjUJ+kl2af0s5T4=", "dev": true, "requires": { - "array-back": "1.0.4" + "array-back": "^1.0.3" }, "dependencies": { "array-back": { @@ -51,7 +51,7 @@ "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", "dev": true, "requires": { - "typical": "2.6.1" + "typical": "^2.6.0" } } } @@ -62,7 +62,7 @@ "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", "dev": true, "requires": { - "typical": "2.6.1" + "typical": "^2.6.1" } }, "async": { @@ -89,7 +89,7 @@ "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.0.1" } }, "bluebird": { @@ -110,7 +110,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -126,12 +126,12 @@ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { - "buffer-xor": "1.0.3", - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "buffer-reverse": { @@ -151,9 +151,9 @@ "integrity": "sha512-4TgWfe9SF+bUy5cCql8gWHqKNrviufNwSYxLjf2utB0pY4+bdcuFwMmY1hDB+67Gz/L1vmhFNhePAjJTFBtV+Q==", "dev": true, "requires": { - "array-back": "2.0.0", - "fs-then-native": "2.0.0", - "mkdirp2": "1.0.4" + "array-back": "^2.0.0", + "fs-then-native": "^2.0.0", + "mkdirp2": "^1.0.3" } }, "camelcase": { @@ -169,7 +169,7 @@ "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=", "dev": true, "requires": { - "underscore-contrib": "0.3.0" + "underscore-contrib": "~0.3.0" } }, "center-align": { @@ -179,8 +179,8 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" } }, "cipher-base": { @@ -189,8 +189,8 @@ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dev": true, "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "cliui": { @@ -200,8 +200,8 @@ "dev": true, "optional": true, "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", + "center-align": "^0.1.1", + "right-align": "^0.1.1", "wordwrap": "0.0.2" }, "dependencies": { @@ -220,8 +220,8 @@ "integrity": "sha512-0y0rBgoX8IzIjBAUnO73SEtSb4Mhk3IoceWJq5zZSxb9mWORhWH8xLYo4EDSOE1jRBk1LhmfjqWFFt10h/+MEA==", "dev": true, "requires": { - "stream-connect": "1.0.2", - "stream-via": "1.0.4" + "stream-connect": "^1.0.2", + "stream-via": "^1.0.4" } }, "command-line-args": { @@ -230,9 +230,9 @@ "integrity": "sha512-aUdPvQRAyBvQd2n7jXcsMDz68ckBJELXNzBybCHOibUWEg0mWTnaYCSRU8h9R+aNRSvDihJtssSRCiDRpLaezA==", "dev": true, "requires": { - "array-back": "2.0.0", - "find-replace": "1.0.3", - "typical": "2.6.1" + "array-back": "^2.0.0", + "find-replace": "^1.0.3", + "typical": "^2.6.1" } }, "command-line-tool": { @@ -241,11 +241,11 @@ "integrity": "sha1-yoB5KuIGnPfKpWLAy8LNEYERIqA=", "dev": true, "requires": { - "ansi-escape-sequences": "3.0.0", - "array-back": "1.0.4", - "command-line-args": "4.0.7", - "command-line-usage": "4.1.0", - "typical": "2.6.1" + "ansi-escape-sequences": "^3.0.0", + "array-back": "^1.0.4", + "command-line-args": "^4.0.1", + "command-line-usage": "^4.0.0", + "typical": "^2.6.0" }, "dependencies": { "array-back": { @@ -254,7 +254,7 @@ "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", "dev": true, "requires": { - "typical": "2.6.1" + "typical": "^2.6.0" } } } @@ -265,10 +265,10 @@ "integrity": "sha512-MxS8Ad995KpdAC0Jopo/ovGIroV/m0KHwzKfXxKag6FHOkGsH8/lv5yjgablcRxCJJC0oJeUMuO/gmaq+Wq46g==", "dev": true, "requires": { - "ansi-escape-sequences": "4.0.0", - "array-back": "2.0.0", - "table-layout": "0.4.4", - "typical": "2.6.1" + "ansi-escape-sequences": "^4.0.0", + "array-back": "^2.0.0", + "table-layout": "^0.4.2", + "typical": "^2.6.1" }, "dependencies": { "ansi-escape-sequences": { @@ -277,7 +277,7 @@ "integrity": "sha512-v+0wW9Wezwsyb0uF4aBVCjmSqit3Ru7PZFziGF0o2KwTvN2zWfTi3BRLq9EkJFdg3eBbyERXGTntVpBxH1J68Q==", "dev": true, "requires": { - "array-back": "2.0.0" + "array-back": "^2.0.0" } } } @@ -300,7 +300,7 @@ "integrity": "sha1-ZnZjWQUFooO/JqSE1oSJ10xUhdo=", "dev": true, "requires": { - "walk-back": "2.0.1" + "walk-back": "^2.0.1" }, "dependencies": { "walk-back": { @@ -317,11 +317,11 @@ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { - "cipher-base": "1.0.4", - "inherits": "2.0.3", - "md5.js": "1.3.4", - "ripemd160": "2.0.2", - "sha.js": "2.4.11" + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" } }, "create-hmac": { @@ -330,12 +330,12 @@ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "inherits": "2.0.3", - "ripemd160": "2.0.2", - "safe-buffer": "5.1.2", - "sha.js": "2.4.11" + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, "crypto": { @@ -380,18 +380,18 @@ "integrity": "sha512-79w644JdsB2TthYpVl2bDurX7i9Abaegg2E7X46Ajc135aASTMXxrHzJ9mOa5X5nbmnXwlBYiF68K+1baX+BzQ==", "dev": true, "requires": { - "array-back": "2.0.0", - "cache-point": "0.4.1", - "common-sequence": "1.0.2", - "file-set": "2.0.0", - "handlebars": "4.0.11", - "marked": "0.3.19", - "object-get": "2.1.0", - "reduce-flatten": "1.0.1", - "reduce-unique": "1.0.0", - "reduce-without": "1.0.1", - "test-value": "3.0.0", - "walk-back": "3.0.0" + "array-back": "^2.0.0", + "cache-point": "^0.4.1", + "common-sequence": "^1.0.2", + "file-set": "^2.0.0", + "handlebars": "^4.0.11", + "marked": "^0.3.16", + "object-get": "^2.1.0", + "reduce-flatten": "^1.0.1", + "reduce-unique": "^1.0.0", + "reduce-without": "^1.0.1", + "test-value": "^3.0.0", + "walk-back": "^3.0.0" }, "dependencies": { "test-value": { @@ -400,8 +400,8 @@ "integrity": "sha512-sVACdAWcZkSU9x7AOmJo5TqE+GyNJknHaHsMrR6ZnhjVlVN9Yx6FjHrsKZ3BjIpPCT68zYesPWkakrNupwfOTQ==", "dev": true, "requires": { - "array-back": "2.0.0", - "typical": "2.6.1" + "array-back": "^2.0.0", + "typical": "^2.6.1" } } } @@ -412,9 +412,9 @@ "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", "dev": true, "requires": { - "browserify-aes": "1.2.0", - "create-hash": "1.2.0", - "create-hmac": "1.1.7" + "browserify-aes": "^1.0.6", + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4" } }, "elliptic": { @@ -423,13 +423,13 @@ "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", "dev": true, "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0", - "hash.js": "1.1.4", - "hmac-drbg": "1.0.1", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" } }, "escape-string-regexp": { @@ -444,8 +444,8 @@ "integrity": "sha1-/V3ux2qXpRIKnNOnyxF3oJI7EdI=", "dev": true, "requires": { - "acorn": "3.3.0", - "acorn-jsx": "3.0.1" + "acorn": "^3.3.0", + "acorn-jsx": "^3.0.0" } }, "ethereumjs-util": { @@ -454,13 +454,13 @@ "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", "dev": true, "requires": { - "bn.js": "4.11.8", - "create-hash": "1.2.0", - "ethjs-util": "0.1.6", - "keccak": "1.4.0", - "rlp": "2.1.0", - "safe-buffer": "5.1.2", - "secp256k1": "3.5.0" + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "^0.1.3", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" } }, "ethjs-util": { @@ -479,8 +479,8 @@ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "requires": { - "md5.js": "1.3.4", - "safe-buffer": "5.1.2" + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" } }, "file-set": { @@ -489,8 +489,8 @@ "integrity": "sha512-cCWXfw+nrYoIoUVmEF7Xsw91lGWuObtSnTEZ7AmdvZou1A/6Xx237HfxdQyC/ayKRvQSMbNOBwg62OjN5JxbXw==", "dev": true, "requires": { - "array-back": "2.0.0", - "glob": "7.1.2" + "array-back": "^2.0.0", + "glob": "^7.1.2" } }, "find-replace": { @@ -499,8 +499,8 @@ "integrity": "sha1-uI5zZNLZyVlVnziMZmcNYTBEH6A=", "dev": true, "requires": { - "array-back": "1.0.4", - "test-value": "2.1.0" + "array-back": "^1.0.4", + "test-value": "^2.1.0" }, "dependencies": { "array-back": { @@ -509,7 +509,7 @@ "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", "dev": true, "requires": { - "typical": "2.6.1" + "typical": "^2.6.0" } } } @@ -532,12 +532,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "graceful-fs": { @@ -553,10 +553,10 @@ "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { - "async": "1.5.2", - "optimist": "0.6.1", - "source-map": "0.4.4", - "uglify-js": "2.8.29" + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" } }, "hash-base": { @@ -565,8 +565,8 @@ "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "dev": true, "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "hash.js": { @@ -575,8 +575,8 @@ "integrity": "sha512-A6RlQvvZEtFS5fLU43IDu0QUmBy+fDO9VMdTXvufKwIkt/rFfvICAViCax5fbDO4zdNzaC3/27ZhKUok5bAJyw==", "dev": true, "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" } }, "hmac-drbg": { @@ -585,9 +585,9 @@ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "dev": true, "requires": { - "hash.js": "1.1.4", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, "inflight": { @@ -596,8 +596,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -629,18 +629,18 @@ "integrity": "sha1-qAcRlSi0AJzLyrSbdSL2P+xs0L0=", "dev": true, "requires": { - "bluebird": "3.4.7", - "catharsis": "0.8.9", - "escape-string-regexp": "1.0.5", - "espree": "3.1.7", - "js2xmlparser": "1.0.0", - "klaw": "1.3.1", - "marked": "0.3.19", - "mkdirp": "0.5.1", - "requizzle": "0.2.1", - "strip-json-comments": "2.0.1", + "bluebird": "~3.4.6", + "catharsis": "~0.8.8", + "escape-string-regexp": "~1.0.5", + "espree": "~3.1.7", + "js2xmlparser": "~1.0.0", + "klaw": "~1.3.0", + "marked": "~0.3.6", + "mkdirp": "~0.5.1", + "requizzle": "~0.2.1", + "strip-json-comments": "~2.0.1", "taffydb": "2.6.2", - "underscore": "1.8.3" + "underscore": "~1.8.3" } }, "jsdoc-api": { @@ -649,15 +649,15 @@ "integrity": "sha1-DVJwAjX4Zb1Ki61evB77Vi/IrSo=", "dev": true, "requires": { - "array-back": "1.0.4", - "cache-point": "0.4.1", - "collect-all": "1.0.3", - "file-set": "1.1.1", - "fs-then-native": "2.0.0", - "jsdoc-75lb": "3.6.0", - "object-to-spawn-args": "1.1.1", - "temp-path": "1.0.0", - "walk-back": "2.0.1" + "array-back": "^1.0.4", + "cache-point": "~0.4.0", + "collect-all": "^1.0.2", + "file-set": "^1.1.1", + "fs-then-native": "^2.0.0", + "jsdoc-75lb": "^3.6.0", + "object-to-spawn-args": "^1.1.0", + "temp-path": "^1.0.0", + "walk-back": "^2.0.1" }, "dependencies": { "array-back": { @@ -666,7 +666,7 @@ "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", "dev": true, "requires": { - "typical": "2.6.1" + "typical": "^2.6.0" } }, "file-set": { @@ -675,8 +675,8 @@ "integrity": "sha1-0+xwwIDsjxjyBLod4QZ4DJBWkms=", "dev": true, "requires": { - "array-back": "1.0.4", - "glob": "7.1.2" + "array-back": "^1.0.3", + "glob": "^7.1.0" } }, "walk-back": { @@ -693,12 +693,12 @@ "integrity": "sha512-btZLp4wYl90vcAfgk4hoGQbO17iBVrhh3LJRMKZNtZgniO3F8H2CjxXld0owBIB1XxN+j3bAcWZnZKMnSj3iMA==", "dev": true, "requires": { - "array-back": "2.0.0", - "lodash.omit": "4.5.0", - "lodash.pick": "4.4.0", - "reduce-extract": "1.0.0", - "sort-array": "2.0.0", - "test-value": "3.0.0" + "array-back": "^2.0.0", + "lodash.omit": "^4.5.0", + "lodash.pick": "^4.4.0", + "reduce-extract": "^1.0.0", + "sort-array": "^2.0.0", + "test-value": "^3.0.0" }, "dependencies": { "test-value": { @@ -707,8 +707,8 @@ "integrity": "sha512-sVACdAWcZkSU9x7AOmJo5TqE+GyNJknHaHsMrR6ZnhjVlVN9Yx6FjHrsKZ3BjIpPCT68zYesPWkakrNupwfOTQ==", "dev": true, "requires": { - "array-back": "2.0.0", - "typical": "2.6.1" + "array-back": "^2.0.0", + "typical": "^2.6.1" } } } @@ -719,13 +719,13 @@ "integrity": "sha512-NDD+dpLiF9SYJXFcYPutKi/K8pRtIHHmVyQJzUArYQCoVhNISKeIVK5Pe78mi7K5s16/Nk7EviN2xxlJJ+S5Bw==", "dev": true, "requires": { - "array-back": "2.0.0", - "command-line-tool": "0.7.0", - "config-master": "3.1.0", - "dmd": "3.0.12", - "jsdoc-api": "3.0.0", - "jsdoc-parse": "3.0.1", - "walk-back": "3.0.0" + "array-back": "^2.0.0", + "command-line-tool": "^0.7.0", + "config-master": "^3.1.0", + "dmd": "^3.0.9", + "jsdoc-api": "^3.0.0", + "jsdoc-parse": "^3.0.1", + "walk-back": "^3.0.0" } }, "keccak": { @@ -734,10 +734,10 @@ "integrity": "sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw==", "dev": true, "requires": { - "bindings": "1.3.0", - "inherits": "2.0.3", - "nan": "2.10.0", - "safe-buffer": "5.1.2" + "bindings": "^1.2.1", + "inherits": "^2.0.3", + "nan": "^2.2.1", + "safe-buffer": "^5.1.0" } }, "kind-of": { @@ -746,7 +746,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" }, "dependencies": { "is-buffer": { @@ -763,7 +763,7 @@ "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", "dev": true, "requires": { - "graceful-fs": "4.1.11" + "graceful-fs": "^4.1.9" } }, "lazy-cache": { @@ -815,8 +815,8 @@ "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", "dev": true, "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.3" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "minimalistic-assert": { @@ -837,7 +837,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -899,7 +899,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "optimist": { @@ -908,8 +908,8 @@ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { - "minimist": "0.0.10", - "wordwrap": "0.0.3" + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" } }, "path-is-absolute": { @@ -924,7 +924,7 @@ "integrity": "sha1-Z/I4W+2mUGG19fQxJmLosIDKFSU=", "dev": true, "requires": { - "test-value": "1.1.0" + "test-value": "^1.0.1" }, "dependencies": { "array-back": { @@ -933,7 +933,7 @@ "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", "dev": true, "requires": { - "typical": "2.6.1" + "typical": "^2.6.0" } }, "test-value": { @@ -942,8 +942,8 @@ "integrity": "sha1-oJE29y7AQ9J8iTcHwrFZv6196T8=", "dev": true, "requires": { - "array-back": "1.0.4", - "typical": "2.6.1" + "array-back": "^1.0.2", + "typical": "^2.4.2" } } } @@ -966,7 +966,7 @@ "integrity": "sha1-aK0OrRGFXJo31OglbBW7+Hly/Iw=", "dev": true, "requires": { - "test-value": "2.1.0" + "test-value": "^2.0.0" } }, "repeat-string": { @@ -981,7 +981,7 @@ "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=", "dev": true, "requires": { - "underscore": "1.6.0" + "underscore": "~1.6.0" }, "dependencies": { "underscore": { @@ -998,7 +998,7 @@ "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", "dev": true, "requires": { - "through": "2.3.8" + "through": "~2.3.4" } }, "right-align": { @@ -1008,7 +1008,7 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4" + "align-text": "^0.1.1" } }, "ripemd160": { @@ -1017,8 +1017,8 @@ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "dev": true, "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.3" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "rlp": { @@ -1027,7 +1027,7 @@ "integrity": "sha512-93U7IKH5j7nmXFVg19MeNBGzQW5uXW1pmCuKY8veeKIhYTE32C2d0mOegfiIAfXcHOKJjjPlJisn8iHDF5AezA==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.1.1" } }, "safe-buffer": { @@ -1042,14 +1042,14 @@ "integrity": "sha512-e5QIJl8W7Y4tT6LHffVcZAxJjvpgE5Owawv6/XCYPQljE9aP2NFFddQ8OYMKhdLshNu88FfL3qCN3/xYkXGRsA==", "dev": true, "requires": { - "bindings": "1.3.0", - "bip66": "1.1.5", - "bn.js": "4.11.8", - "create-hash": "1.2.0", - "drbg.js": "1.0.1", - "elliptic": "6.4.0", - "nan": "2.10.0", - "safe-buffer": "5.1.2" + "bindings": "^1.2.1", + "bip66": "^1.1.3", + "bn.js": "^4.11.3", + "create-hash": "^1.1.2", + "drbg.js": "^1.0.1", + "elliptic": "^6.2.3", + "nan": "^2.2.1", + "safe-buffer": "^5.1.0" } }, "sha.js": { @@ -1058,8 +1058,8 @@ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "sigmund": { @@ -1074,9 +1074,9 @@ "integrity": "sha1-OKnG2if9fRR7QuYFVPKBGHtN9HI=", "dev": true, "requires": { - "array-back": "1.0.4", - "object-get": "2.1.0", - "typical": "2.6.1" + "array-back": "^1.0.4", + "object-get": "^2.1.0", + "typical": "^2.6.0" }, "dependencies": { "array-back": { @@ -1085,7 +1085,7 @@ "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", "dev": true, "requires": { - "typical": "2.6.1" + "typical": "^2.6.0" } } } @@ -1096,7 +1096,7 @@ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } }, "stream-connect": { @@ -1105,7 +1105,7 @@ "integrity": "sha1-GLyB8u2zW4tdmoAJIAqYUxRCipc=", "dev": true, "requires": { - "array-back": "1.0.4" + "array-back": "^1.0.2" }, "dependencies": { "array-back": { @@ -1114,7 +1114,7 @@ "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", "dev": true, "requires": { - "typical": "2.6.1" + "typical": "^2.6.0" } } } @@ -1146,11 +1146,11 @@ "integrity": "sha512-uNaR3SRMJwfdp9OUr36eyEi6LLsbcTqTO/hfTsNviKsNeyMBPICJCC7QXRF3+07bAP6FRwA8rczJPBqXDc0CkQ==", "dev": true, "requires": { - "array-back": "2.0.0", - "deep-extend": "0.6.0", - "lodash.padend": "4.6.1", - "typical": "2.6.1", - "wordwrapjs": "3.0.0" + "array-back": "^2.0.0", + "deep-extend": "~0.6.0", + "lodash.padend": "^4.6.1", + "typical": "^2.6.1", + "wordwrapjs": "^3.0.0" } }, "taffydb": { @@ -1165,13 +1165,13 @@ "integrity": "sha1-SJPdU+KApfWMDOswwsDrs7zVHh8=", "dev": true, "requires": { - "deep-equal": "0.2.2", - "defined": "0.0.0", - "glob": "3.2.11", - "inherits": "2.0.3", - "object-inspect": "0.4.0", - "resumer": "0.0.0", - "through": "2.3.8" + "deep-equal": "~0.2.0", + "defined": "~0.0.0", + "glob": "~3.2.9", + "inherits": "~2.0.1", + "object-inspect": "~0.4.0", + "resumer": "~0.0.0", + "through": "~2.3.4" }, "dependencies": { "glob": { @@ -1180,8 +1180,8 @@ "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", "dev": true, "requires": { - "inherits": "2.0.3", - "minimatch": "0.3.0" + "inherits": "2", + "minimatch": "0.3" } }, "minimatch": { @@ -1190,8 +1190,8 @@ "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", "dev": true, "requires": { - "lru-cache": "2.7.3", - "sigmund": "1.0.1" + "lru-cache": "2", + "sigmund": "~1.0.0" } } } @@ -1208,8 +1208,8 @@ "integrity": "sha1-Edpv9nDzRxpztiXKTz/c97t0gpE=", "dev": true, "requires": { - "array-back": "1.0.4", - "typical": "2.6.1" + "array-back": "^1.0.3", + "typical": "^2.6.0" }, "dependencies": { "array-back": { @@ -1218,7 +1218,7 @@ "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", "dev": true, "requires": { - "typical": "2.6.1" + "typical": "^2.6.0" } } } @@ -1229,6 +1229,11 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, + "treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==" + }, "typical": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz", @@ -1242,9 +1247,9 @@ "dev": true, "optional": true, "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" }, "dependencies": { "source-map": { @@ -1311,8 +1316,8 @@ "integrity": "sha512-mO8XtqyPvykVCsrwj5MlOVWvSnCdT+C+QVbm6blradR7JExAhbkZ7hZ9A+9NUtwzSqrlUo9a67ws0EiILrvRpw==", "dev": true, "requires": { - "reduce-flatten": "1.0.1", - "typical": "2.6.1" + "reduce-flatten": "^1.0.1", + "typical": "^2.6.1" } }, "wrappy": { @@ -1328,9 +1333,9 @@ "dev": true, "optional": true, "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", "window-size": "0.1.0" } } diff --git a/package.json b/package.json index 41a8f63..8121199 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "dependencies": { "buffer-reverse": "^1.0.1", "crypto-js": "^3.1.9-1", - "is-buffer": "^2.0.3" + "is-buffer": "^2.0.3", + "treeify": "^1.1.0" } } diff --git a/test/index.js b/test/index.js index db7cb06..5e79525 100644 --- a/test/index.js +++ b/test/index.js @@ -309,3 +309,20 @@ test('crypto-js bufferify', t => { t.deepEqual(leaves.map(MerkleTree.bufferify), leaves.map(bufferifyCryptoJS)) }) + +test('print', t => { + t.plan(1) + + const leaves = ['a', 'b', 'c'].map(x => sha3(x)) + const tree = new MerkleTree(leaves, sha256) + const str = MerkleTree.print(tree, {log: false}) + + t.equal(str, +`└─ 311d2e46f49b15fff8b746b74ad57f2cc9e0d9939fda94387141a2d3fdf187ae + ├─ 176f0f307632fdd5831875eb709e2f68d770b102262998b214ddeb3f04164ae1 + │ ├─ 3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb + │ └─ b5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510 + └─ 0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2 + └─ 0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2 +`) +})