From 685889d195e4362eea6d226ea155255d3d77f39c Mon Sep 17 00:00:00 2001 From: Volker Mische Date: Fri, 12 Jan 2018 17:02:25 +0000 Subject: [PATCH] feat: Add tree() method --- src/resolver.js | 93 +++++++++++++++++++++++++++---------------- test/resolver.spec.js | 27 +++++++++++++ 2 files changed, 85 insertions(+), 35 deletions(-) diff --git a/src/resolver.js b/src/resolver.js index a4b245b..2605d1a 100644 --- a/src/resolver.js +++ b/src/resolver.js @@ -24,38 +24,19 @@ const resolve = (binaryBlob, path, callback) => { const pathArray = path.split('/') // `/` is the first element pathArray.shift() - - // The values that can directly be resolved - let value - // Links to other blocks - let link - switch (pathArray[0]) { - case 'version': - value = dagNode.version - break - case 'timestamp': - value = dagNode.timestamp - break - case 'difficulty': - value = dagNode.bits - break - case 'nonce': - value = dagNode.nonce - break - case 'parent': - link = dagNode.prevHash - break - case 'tx': - link = dagNode.merkleRoot - break - default: - return callback(new Error('No such path'), null) + const value = resolveField(dagNode, pathArray[0]) + if (value === null) { + return callback(new Error('No such path'), null) } let remainderPath = pathArray.slice(1).join('/') - // Bitcoin has only top-level fields, every deeper nesting needs to - // be a link - if (value !== undefined) { + // It is a link, hence it may have a remainder + if (value['/'] !== undefined) { + return callback(null, { + value: value, + remainderPath: remainderPath + }) + } else { if (remainderPath.length > 0) { return callback(new Error('No such path'), null) } else { @@ -64,16 +45,58 @@ const resolve = (binaryBlob, path, callback) => { remainderPath: '' }) } + } + }) +} + +const tree = (binaryBlob, options, callback) => { + if (typeof options === 'function') { + callback = options + options = undefined + } + options = options || {} + + util.deserialize(binaryBlob, (err, dagNode) => { + if (err) { + return callback(err) + } + + const paths = ['/version', '/timestamp', '/difficulty', '/nonce', + '/parent', '/tx'] + + if (options.value === true) { + const pathValues = {} + for (let path of paths) { + pathValues[path] = resolveField(dagNode, path.substr(1)) + } + return callback(null, pathValues) } else { - // It's a link - return callback(null, { - value: {'/': util.hashToCid(link)}, - remainderPath: remainderPath - }) + return callback(null, paths) } }) } +// Return top-level fields. Returns `null` if field doesn't exist +const resolveField = (dagNode, field) => { + switch (field) { + case 'version': + return dagNode.version + case 'timestamp': + return dagNode.timestamp + case 'difficulty': + return dagNode.bits + case 'nonce': + return dagNode.nonce + case 'parent': + return {'/': util.hashToCid(dagNode.prevHash)} + case 'tx': + return {'/': util.hashToCid(dagNode.merkleRoot)} + default: + return null + } +} + module.exports = { - resolve: resolve + resolve: resolve, + tree: tree } diff --git a/test/resolver.spec.js b/test/resolver.spec.js index a522654..9b54ce9 100644 --- a/test/resolver.spec.js +++ b/test/resolver.spec.js @@ -90,6 +90,33 @@ describe('IPLD format resolver API resolve()', () => { }) }) +describe('IPLD format resolver API tree()', () => { + it('should return only paths by default', (done) => { + IpldBitcoin.resolver.tree(fixtureBlock, (err, value) => { + expect(err).to.not.exist() + expect(value).to.deep.equal(['/version', '/timestamp', '/difficulty', + '/nonce', '/parent', '/tx']) + done() + }) + }) + + it('should be able to return paths and values', (done) => { + IpldBitcoin.resolver.tree(fixtureBlock, {value: true}, (err, value) => { + expect(err).to.not.exist() + expect(value).to.deep.equal({ + '/version': 2, + '/timestamp': 1386981279, + '/difficulty': 419740270, + '/nonce': 3159344128, + '/parent': { + '/': new CID('z4HFzdHLxSgJvCMJrsDtV7MgqiGALZdbbxgcTLVUUXQGBkGYjLb')}, + '/tx': { + '/': new CID('z4HFzdHD15kVvtmVzeD7z9sisZ7acSC88wXS3KJGwGrnr2DwcVQ')}}) + done() + }) + }) +}) + const verifyPath = (block, path, expected, done) => { IpldBitcoin.resolver.resolve(block, path, (err, value) => { expect(err).to.not.exist()