diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c250503 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +testdb diff --git a/README.md b/README.md index 16496ee..8149ddb 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ [![NPM Package](https://img.shields.io/npm/v/dfinity-radix-tree.svg?style=flat-square)](https://www.npmjs.org/package/dfinity-radix-tree) [![Build Status](https://img.shields.io/travis/dfinity/js-dfinity-radix-tree.svg?branch=master&style=flat-square)](https://travis-ci.org/dfinity/js-dfinity-radix-tree) -[![Coverage Status](https://img.shields.io/coveralls/dfinity/js-dfinity-radix-tree.svg?style=flat-square)](https://coveralls.io/dfinity/js-dfinity-radix-tree) +[![Coverage Status](https://img.shields.io/coveralls/dfinity/js-dfinity-radix-tree.svg?style=flat-square)](https://coveralls.io/dfinity/js-dfinity-radix-tree) -[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) +[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) # Synopsis :evergreen_tree: This implements a binary merkle radix tree. The point of using a binary radix tree is that it generates smaller proof size then trees with larger radixes. -This tree is well suited for storing large dictonaries of fairly random keys. -And is optimized for storing keys of the same length. If the keys are not -random better performance can be achived by hashing them first. It builds on +This tree is well suited for storing large dictionaries of fairly random keys. +And is optimized for storing keys of the same length. If the keys are not +random better performance can be archived by hashing them first. It builds on top of [ipld-graph-builder](https://github.com/ipld/js-ipld-graph-builder) and the resulting state and proofs are generated using it. @@ -52,18 +52,18 @@ main() ## API ['./docs/'](./docs/index.md) -## Spefication +## Specification ['./docs/spec.md'](./docs/spec.md) ## Benchmarks The result of the benchmarks show that the binary radix tree produces proofs on -average %67 small then the Ethereum Trie with 100000 keys stored. +average 67% small then the Ethereum Trie with 100000 keys stored. ['./benchmarks/benchmarks.md'](./benchmark/results.md) ## License -[**(C) 2017 DFINITY STIFTUNG**](http://dfinity.network) +[**(C) 2018 DFINITY STIFTUNG**](http://dfinity.network) All code and designs are open sourced under GPL V3. diff --git a/datastore.js b/datastore.js index 93c7727..8cf51fa 100644 --- a/datastore.js +++ b/datastore.js @@ -1,5 +1,5 @@ const Buffer = require('safe-buffer').Buffer -const crypto = require('node-webcrypto-shim') +const crypto = require('crypto') const DAG = require('ipld-graph-builder/datastore.js') const HASH_LEN = 20 const cbor = require('borc') @@ -35,8 +35,8 @@ module.exports = class TreeDAG extends DAG { } static getMerkleLink (buf) { - return crypto.subtle.digest({ - name: 'SHA-256' - }, buf).then(link => Buffer.from(link.slice(0, HASH_LEN))) + const hash = crypto.createHash('sha256') + hash.update(buf) + return hash.digest().slice(0, HASH_LEN) } } diff --git a/docs/index.md b/docs/index.md index e332105..f473d94 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,31 +2,31 @@ ### Table of Contents -- [constructor][1] -- [get][2] -- [set][3] -- [delete][4] -- [done][5] -- [flush][6] -- [emptyTreeState][7] -- [ArrayConstructor][8] -- [getMerkleLink][9] +- [constructor](#constructor) +- [get](#get) +- [set](#set) +- [delete](#delete) +- [done](#done) +- [flush](#flush) +- [emptyTreeState](#emptytreestate) +- [ArrayConstructor](#arrayconstructor) +- [getMerkleLink](#getmerklelink) ## constructor -[index.js:17-25][10] +[index.js:17-25](https://github.com/dfinity/js-dfinity-radix-tree/blob/806b9f80cab0da81d7e98a62754b80167fe58296/index.js#L17-L25 "Source code on GitHub") **Parameters** - `opts` - `opts.root` {object} a merkle root to a radix tree. If none, RadixTree will create an new root. - - `opts.db` {object} a level db instance alternitly `opts.graph` can be used - - `opts.graph` {object} an instance of [ipld-graph-builder][11] alternitvly `opts.dag` can be used - - `opts.dag` {object} an instance if [ipfs.dag][12]. If there is no `opts.graph` this will be used to create a new graph instance. + - `opts.db` {object} a level db instance; alternatively, `opts.graph` can be used + - `opts.graph` {object} an instance of [ipld-graph-builder](https://github.com/ipld/js-ipld-graph-builder); alternatively, `opts.dag` can be used + - `opts.dag` {object} an instance if [ipfs.dag](https://github.com/ipfs/js-ipfs#dag). If there is no `opts.graph` this will be used to create a new graph instance. ## get -[index.js:32-36][13] +[index.js:32-36](https://github.com/dfinity/js-dfinity-radix-tree/blob/806b9f80cab0da81d7e98a62754b80167fe58296/index.js#L32-L36 "Source code on GitHub") gets a value given a key @@ -34,11 +34,11 @@ gets a value given a key - `key` **any** -Returns **[Promise][14]** +Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)** ## set -[index.js:87-90][15] +[index.js:87-90](https://github.com/dfinity/js-dfinity-radix-tree/blob/806b9f80cab0da81d7e98a62754b80167fe58296/index.js#L87-L90 "Source code on GitHub") stores a value at a given key returning the tree node that the value was saved in @@ -47,11 +47,11 @@ stores a value at a given key returning the tree node that the value was saved i - `key` **any** - `value` -Returns **[Promise][14]** +Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)** ## delete -[index.js:139-142][16] +[index.js:139-142](https://github.com/dfinity/js-dfinity-radix-tree/blob/806b9f80cab0da81d7e98a62754b80167fe58296/index.js#L139-L142 "Source code on GitHub") smContainer.js deletes a value at a given key @@ -59,92 +59,46 @@ smContainer.js deletes a value at a given key - `key` **any** -Returns **[Promise][14]** +Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)** ## done -[index.js:201-207][17] +[index.js:201-207](https://github.com/dfinity/js-dfinity-radix-tree/blob/806b9f80cab0da81d7e98a62754b80167fe58296/index.js#L201-L207 "Source code on GitHub") returns a promise that resolve when the tree is done with all of its writes -Returns **[Promise][14]** +Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)** ## flush -[index.js:223-226][18] +[index.js:223-226](https://github.com/dfinity/js-dfinity-radix-tree/blob/806b9f80cab0da81d7e98a62754b80167fe58296/index.js#L223-L226 "Source code on GitHub") -creates a merkle root for the current tree and stores the data perstantly +creates a merkle root for the current tree and stores the data persistently -Returns **[Promise][14]** +Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)** ## emptyTreeState -[index.js:252-254][19] +[index.js:252-254](https://github.com/dfinity/js-dfinity-radix-tree/blob/806b9f80cab0da81d7e98a62754b80167fe58296/index.js#L252-L254 "Source code on GitHub") returns the state of an empty tree ## ArrayConstructor -[index.js:260-262][20] +[index.js:260-262](https://github.com/dfinity/js-dfinity-radix-tree/blob/806b9f80cab0da81d7e98a62754b80167fe58296/index.js#L260-L262 "Source code on GitHub") -returns an Uint1Array constructir which is used to repersent keys +returns an Uint1Array constructor which is used to represent keys -Returns **[object][21]** +Returns **[object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** ## getMerkleLink -[index.js:269-271][22] +[index.js:269-271](https://github.com/dfinity/js-dfinity-radix-tree/blob/806b9f80cab0da81d7e98a62754b80167fe58296/index.js#L269-L271 "Source code on GitHub") returns a merkle link for some given data **Parameters** -- `data` **[Buffer][23]** the data which you would like to hash +- `data` **[Buffer](https://nodejs.org/api/buffer.html)** the data which you would like to hash -Returns **[Buffer][23]** - -[1]: #constructor - -[2]: #get - -[3]: #set - -[4]: #delete - -[5]: #done - -[6]: #flush - -[7]: #emptytreestate - -[8]: #arrayconstructor - -[9]: #getmerklelink - -[10]: https://github.com/dfinity/js-dfinity-radix-tree/blob/0ab6c08c96392d6f3a76fbaf0a826b48445e56b8/index.js#L17-L25 "Source code on GitHub" - -[11]: https://github.com/ipld/js-ipld-graph-builder - -[12]: https://github.com/ipfs/js-ipfs#dag - -[13]: https://github.com/dfinity/js-dfinity-radix-tree/blob/0ab6c08c96392d6f3a76fbaf0a826b48445e56b8/index.js#L32-L36 "Source code on GitHub" - -[14]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise - -[15]: https://github.com/dfinity/js-dfinity-radix-tree/blob/0ab6c08c96392d6f3a76fbaf0a826b48445e56b8/index.js#L87-L90 "Source code on GitHub" - -[16]: https://github.com/dfinity/js-dfinity-radix-tree/blob/0ab6c08c96392d6f3a76fbaf0a826b48445e56b8/index.js#L139-L142 "Source code on GitHub" - -[17]: https://github.com/dfinity/js-dfinity-radix-tree/blob/0ab6c08c96392d6f3a76fbaf0a826b48445e56b8/index.js#L201-L207 "Source code on GitHub" - -[18]: https://github.com/dfinity/js-dfinity-radix-tree/blob/0ab6c08c96392d6f3a76fbaf0a826b48445e56b8/index.js#L223-L226 "Source code on GitHub" - -[19]: https://github.com/dfinity/js-dfinity-radix-tree/blob/0ab6c08c96392d6f3a76fbaf0a826b48445e56b8/index.js#L252-L254 "Source code on GitHub" - -[20]: https://github.com/dfinity/js-dfinity-radix-tree/blob/0ab6c08c96392d6f3a76fbaf0a826b48445e56b8/index.js#L260-L262 "Source code on GitHub" - -[21]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object - -[22]: https://github.com/dfinity/js-dfinity-radix-tree/blob/0ab6c08c96392d6f3a76fbaf0a826b48445e56b8/index.js#L269-L271 "Source code on GitHub" - -[23]: https://nodejs.org/api/buffer.html +Returns **[Buffer](https://nodejs.org/api/buffer.html)** diff --git a/docs/spec.md b/docs/spec.md index 927f0b9..d1d9758 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -1,8 +1,8 @@ -This documnet provides the structure of the [Dfinity's Radix Tree.](https://ipfs.io/ipns/QmdJiuMWp2FxyaerfLrtdLF6Nr1EWpL7dPAxA9oKSPYYgV/wiki/Radix_tree.html) -The radix tree data structure stores the key-values; the tree is an instances of nodes that contains the value and the key is the path to the node in the tree. All values are encoded with [CBOR](http://cbor.io) +This document provides the structure of the [Dfinity Radix Tree.](https://ipfs.io/ipns/QmdJiuMWp2FxyaerfLrtdLF6Nr1EWpL7dPAxA9oKSPYYgV/wiki/Radix_tree.html) +The radix tree data structure stores the key-values; the tree is an instance of nodes that contains the value and the key is the path to the node in the tree. All values are encoded with [CBOR](http://cbor.io) ## Node -Each node has a type and contains at most four elements: +Each node has a type and contains at most four elements: "extension", "left branch", "right branch" and "value". ``` @@ -10,7 +10,7 @@ node : = TYPE | EXTENSION | LBRANCH | RBRANCH | VALUE ``` ### Type -The type field contains a byte. The first 4 bits are paded to zero while the Node is stored in the tree. These bits are reserved as insicators of type when sending the nodes to other clients which we will describe later. The last 4 bits are used to signify which elements a node contains. The bit field is defined a the following +The type field contains a byte. The first 4 bits are padded to zero while the Node is stored in the tree. These bits are reserved as indicators of type when sending the nodes to other clients which we will describe later. The last 4 bits are used to signify which elements a node contains. The bit field is defined a the following ``` Type := 0 | 0 | 0 | 0 | HasEXTENSION | HasLBRANCH | HasRBRANCH | HasVALUE @@ -18,7 +18,7 @@ Type := 0 | 0 | 0 | 0 | HasEXTENSION | HasLBRANCH | HasRBRANCH | HasVALUE For example a node that contained a left branch and a value would have a prefix byte of 00000101 or 0x07 -The full encoded node would then look something like. `0x07<20_bytes_for_lbranch>` +The full encoded node would then look something like. `0x07<20_bytes_for_lbranch>` ### Branches @@ -43,8 +43,8 @@ For optimization, we use the Extension element that encodes shared paths in the extension := Length | ExtensionValue ``` -Where the length is the number of bits that extension repesents. This varuint32 -encoded with leb128. And the extension is bit array padded with 0's to the nearst byte. +Where the length is the number of bits that extension represents. This varuint32 +encoded with leb128. And the extension is bit array padded with 0's to the nearest byte. For example if the binary keys [0, 0, 1, 1] and [0, 0, 1, 0] have a shared path of [0, 0, 1]. The extension node would therefor be diff --git a/index.js b/index.js index 6d8a907..2ca6e4d 100644 --- a/index.js +++ b/index.js @@ -10,8 +10,8 @@ module.exports = class RadixTree { /** * @param opts * @param opts.root {object} a merkle root to a radix tree. If none, RadixTree will create an new root. - * @param opts.db {object} a level db instance alternitly `opts.graph` can be used - * @param opts.graph {object} an instance of [ipld-graph-builder](https://github.com/ipld/js-ipld-graph-builder) alternitvly `opts.dag` can be used + * @param opts.db {object} a level db instance; alternatively, `opts.graph` can be used + * @param opts.graph {object} an instance of [ipld-graph-builder](https://github.com/ipld/js-ipld-graph-builder); alternatively, `opts.dag` can be used * @param opts.dag {object} an instance if [ipfs.dag](https://github.com/ipfs/js-ipfs#dag). If there is no `opts.graph` this will be used to create a new graph instance. */ constructor (opts) { @@ -48,7 +48,7 @@ module.exports = class RadixTree { const {extensionIndex, extensionLen, extension} = findMatchBits(subKey, root) index += extensionIndex - // check if we compelete travered the extension + // check if we complete traversed the extension if (extensionIndex !== extensionLen) { return {index, root, extension, extensionIndex} } @@ -58,7 +58,7 @@ module.exports = class RadixTree { if (keySegment !== undefined) { const branch = treeNode.getBranch(root) await this.graph.get(branch, keySegment, true) - // preseves the '/' + // preserves the '/' const nextRoot = branch[keySegment] if (!nextRoot) { return {root, index} @@ -217,7 +217,7 @@ module.exports = class RadixTree { } /** - * creates a merkle root for the current tree and stores the data perstantly + * creates a merkle root for the current tree and stores the data persistently * @returns {Promise} */ async flush () { @@ -254,7 +254,7 @@ module.exports = class RadixTree { } /** - * returns an Uint1Array constructir which is used to repersent keys + * returns an Uint1Array constructor which is used to represent keys * @returns {object} */ static get ArrayConstructor () { diff --git a/package-lock.json b/package-lock.json index f032ef8..70b454f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5403,7 +5403,8 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true }, "mixin-deep": { "version": "1.3.1", @@ -5430,6 +5431,7 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, "requires": { "minimist": "0.0.8" } @@ -5531,7 +5533,8 @@ "nan": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", - "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=" + "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=", + "dev": true }, "nanomatch": { "version": "1.2.9", @@ -5575,25 +5578,6 @@ "is-stream": "1.1.0" } }, - "node-webcrypto-ossl": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/node-webcrypto-ossl/-/node-webcrypto-ossl-1.0.31.tgz", - "integrity": "sha512-IrNfBY6ur0g0jtELGE0FqZ9/P9aPphDF/l/1Of//eFlwyYCjhsIKgHzyMbArixYeMRkGkHHWVpo+Ff1xc0dsRw==", - "requires": { - "mkdirp": "0.5.1", - "nan": "2.7.0", - "tslib": "1.8.0", - "webcrypto-core": "0.1.17" - } - }, - "node-webcrypto-shim": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/node-webcrypto-shim/-/node-webcrypto-shim-0.0.0.tgz", - "integrity": "sha512-/zFEyq/FQNBjA/9Z9/TKKW5KRIcvZiAZNHYb8DOwSC6Vkdp8yGBFkXHNiS1F0QLV+2ffJ24YKmG7pf/oQ2D4yA==", - "requires": { - "node-webcrypto-ossl": "1.0.31" - } - }, "noop-logger": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", @@ -9278,11 +9262,6 @@ "integrity": "sha1-qf2LA5Swro//guBjOgo2zK1bX4Y=", "dev": true }, - "tslib": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.8.0.tgz", - "integrity": "sha512-ymKWWZJST0/CkgduC2qkzjMOWr4bouhuURNXCn/inEX0L57BnRG6FhX76o7FOnsjHazCjfU2LKeSrlS2sIKQJg==" - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -9785,14 +9764,6 @@ "vinyl": "2.1.0" } }, - "webcrypto-core": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-0.1.17.tgz", - "integrity": "sha512-pyyNqOmUlsvOZVff6GUbZSzL8WDDuyFOrx8JWeUYz0nJ3rwfQbARwDMePuBV65dF7FkUS4ECGzNS6PTue98gLw==", - "requires": { - "tslib": "1.8.0" - } - }, "websocket-driver": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", diff --git a/package.json b/package.json index 170ff49..2413aa5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dfinity-radix-tree", - "version": "0.1.1", + "version": "0.1.2", "description": "This implements a binary merkle radix tree", "main": "index.js", "scripts": { @@ -29,7 +29,6 @@ "dependencies": { "borc": "^2.0.2", "ipld-graph-builder": "^1.3.7", - "node-webcrypto-shim": "0.0.0", "text-encoding": "^0.6.4", "uint1array": "^1.0.5" },