Commit 6bc933a81719dede128577c8261ed8f5b64e808d
fix encoding bugs
wanderer committed on 3/22/2018, 11:24:19 PMParent: fac7ea03e4bddd4c95ce4337479feba208d63c48
Files changed
datastore.js | changed |
index.js | changed |
package-lock.json | changed |
package.json | changed |
tests/index.js | changed |
treeNode.js | changed |
datastore.js | ||
---|---|---|
@@ -5,17 +5,37 @@ | ||
5 | 5 | |
6 | 6 | const HASH_LEN = 20 |
7 | 7 | const LINK_TAG = 42 |
8 | 8 | |
9 | +function insertTags (val) { | |
10 | + if (Array.isArray(val)) { | |
11 | + val = val.map(v => { | |
12 | + if (v && v.hasOwnProperty('/')) { | |
13 | + return new cbor.Tagged(LINK_TAG, v['/']) | |
14 | + } else { | |
15 | + return insertTags(v) | |
16 | + } | |
17 | + }) | |
18 | + } | |
19 | + return val | |
20 | +} | |
21 | + | |
9 | 22 | module.exports = class TreeDAG extends DAG { |
10 | - async put (val) { | |
11 | - if (val[1]) { | |
12 | - val[1] = new cbor.Tagged(LINK_TAG, val[1]['/']) | |
23 | + constructor (dag, decoder = new cbor.Decoder({ | |
24 | + tags: { | |
25 | + 42: val => { | |
26 | + return { | |
27 | + '/': val | |
28 | + } | |
29 | + } | |
13 | 30 | } |
14 | - if (val[2]) { | |
15 | - val[2] = new cbor.Tagged(LINK_TAG, val[2]['/']) | |
16 | - } | |
31 | + })) { | |
32 | + super(dag) | |
33 | + this.decoder = decoder | |
34 | + } | |
17 | 35 | |
36 | + async put (val) { | |
37 | + val = insertTags(val) | |
18 | 38 | const encoded = cbor.encode(val) |
19 | 39 | const key = await TreeDAG.getMerkleLink(encoded) |
20 | 40 | |
21 | 41 | return new Promise((resolve, reject) => { |
@@ -31,15 +51,9 @@ | ||
31 | 51 | if (err) { |
32 | 52 | reject(err) |
33 | 53 | } else { |
34 | 54 | val = Buffer.from(val, 'hex') |
35 | - const decoded = cbor.decode(val) | |
36 | - if (decoded[1]) { | |
37 | - decoded[1]['/'] = decoded[1].value | |
38 | - } | |
39 | - if (decoded[2]) { | |
40 | - decoded[2]['/'] = decoded[2].value | |
41 | - } | |
55 | + const decoded = this.decoder.decodeFirst(val) | |
42 | 56 | resolve(decoded) |
43 | 57 | } |
44 | 58 | }) |
45 | 59 | }) |
index.js | ||
---|---|---|
@@ -12,15 +12,16 @@ | ||
12 | 12 | * @param opts.root {object} a merkle root to a radix tree. If none, RadixTree will create an new root. |
13 | 13 | * @param opts.db {object} a level db instance; alternatively, `opts.graph` can be used |
14 | 14 | * @param opts.graph {object} an instance of [ipld-graph-builder](https://github.com/ipld/js-ipld-graph-builder); alternatively, `opts.dag` can be used |
15 | 15 | * @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. |
16 | + * @param opts.decoder {object} a cbor decoder | |
16 | 17 | */ |
17 | 18 | constructor (opts) { |
18 | 19 | this.root = opts.root || { |
19 | 20 | '/': RadixTree.emptyTreeState |
20 | 21 | } |
21 | 22 | |
22 | - this.dag = opts.dag || new DataStore(opts.db) | |
23 | + this.dag = opts.dag || new DataStore(opts.db, opts.decoder) | |
23 | 24 | this.graph = opts.graph || new Graph(this.dag) |
24 | 25 | this._setting = Promise.resolve() |
25 | 26 | } |
26 | 27 | |
@@ -44,9 +45,8 @@ | ||
44 | 45 | // load the root |
45 | 46 | const exNode = await this.graph.get(root, treeNode.EXTENSION, true) |
46 | 47 | if (exNode) { |
47 | 48 | let subKey = key.subarray(index) |
48 | - | |
49 | 49 | const {extensionIndex, extensionLen, extension} = findMatchBits(subKey, root) |
50 | 50 | index += extensionIndex |
51 | 51 | // check if we complete traversed the extension |
52 | 52 | if (extensionIndex !== extensionLen) { |
package-lock.json | ||
---|---|---|
The diff is too large to show. Use a local git client to view these changes. Old file size: 357982 bytes New file size: 358067 bytes |
package.json | ||
---|---|---|
@@ -26,9 +26,9 @@ | ||
26 | 26 | "standard": "^11.0.1", |
27 | 27 | "tape": "^4.6.3" |
28 | 28 | }, |
29 | 29 | "dependencies": { |
30 | - "borc": "^2.0.2", | |
30 | + "borc": "git+ssh://git@github.com:dignifiedquire/borc.git#fix/nested-array", | |
31 | 31 | "ipld-graph-builder": "^1.3.8", |
32 | 32 | "text-encoding": "^0.6.4", |
33 | 33 | "uint1array": "^1.0.5" |
34 | 34 | }, |
tests/index.js | ||
---|---|---|
@@ -13,8 +13,25 @@ | ||
13 | 13 | t.deepEquals(stateRoot2, stateRoot) |
14 | 14 | t.end() |
15 | 15 | }) |
16 | 16 | |
17 | +tape('should generate the same stateRoot', async t => { | |
18 | + let tree1 = new RadixTree({ | |
19 | + db | |
20 | + }) | |
21 | + | |
22 | + let tree2 = new RadixTree({ | |
23 | + db | |
24 | + }) | |
25 | + await tree1.flush() | |
26 | + tree1.set('test', Buffer.from('cat')) | |
27 | + tree2.set('test', Buffer.from('cat')) | |
28 | + const stateRoot = await tree1.flush() | |
29 | + const stateRoot2 = await tree2.flush() | |
30 | + t.deepEquals(stateRoot2, stateRoot) | |
31 | + t.end() | |
32 | +}) | |
33 | + | |
17 | 34 | tape('set and get', async t => { |
18 | 35 | const r = await RadixTree.getMerkleLink(Buffer.from([0])) |
19 | 36 | |
20 | 37 | t.equal(r.toString('hex'), '6e340b9cffb37a989ca544e6bb780a2c78901d3f', 'should hash') |
treeNode.js | ||
---|---|---|
@@ -1,5 +1,6 @@ | ||
1 | 1 | const Uint1Array = require('uint1array') |
2 | +const EMPTY_STATE_ROOT = Buffer.from('4cf812be9be2c6008325050f43d06676a08612c7', 'hex') | |
2 | 3 | |
3 | 4 | function toTypedArray (array) { |
4 | 5 | return new Uint1Array(new Uint8Array(array).buffer) |
5 | 6 | } |
@@ -49,7 +50,10 @@ | ||
49 | 50 | node['/'][VALUE] = val |
50 | 51 | } |
51 | 52 | |
52 | 53 | exports.isEmpty = function (node) { |
53 | - const branch = exports.getBranch(node) | |
54 | - return !node['/'][EXTENSION] && !branch[0] && !branch[1] && node['/'][VALUE] === undefined | |
54 | + if (Buffer.isBuffer(node['/'])) { | |
55 | + return !Buffer.compare(node['/'], EMPTY_STATE_ROOT) | |
56 | + } else { | |
57 | + return node['/'].every(el => !el) | |
58 | + } | |
55 | 59 | } |
Built with git-ssb-web