Skip to content

Commit 6b2be87

Browse files
antouhouCofresi
authored andcommitted
Feature/merkle utils (#102)
* Add util and test for the merkle tree * Add test clarification * Bump package version
1 parent 767a492 commit 6b2be87

File tree

3 files changed

+100
-1
lines changed

3 files changed

+100
-1
lines changed

lib/util/merkletree.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* eslint-disable */
2+
var doubleSha256 = require('../crypto/hash').sha256sha256;
3+
4+
/**
5+
* Builds a merkle tree of all passed hashes
6+
* @link https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees
7+
* @param {Buffer[]} hashes
8+
* @returns {Buffer[]} - An array with each level of the tree after the other.
9+
*/
10+
function getMerkleTree(hashes) {
11+
// Copy all buffers in the tree to avoid unexpected behaviour
12+
var tree = hashes.map(Buffer.from);
13+
14+
var j = 0;
15+
for (var size = hashes.length; size > 1; size = Math.floor((size + 1) / 2)) {
16+
for (var i = 0; i < size; i += 2) {
17+
var i2 = Math.min(i + 1, size - 1);
18+
var buf = Buffer.concat([tree[j + i], tree[j + i2]]);
19+
tree.push(Buffer.from(doubleSha256(buf), 'hex'));
20+
}
21+
j += size;
22+
}
23+
24+
return tree;
25+
}
26+
27+
/**
28+
* Copies root of the passed tree to a new Buffer and returns it
29+
* @param {Buffer[]} merkleTree
30+
* @returns {Buffer|undefined} - A buffer of the merkle root hash
31+
*/
32+
function getMerkleRoot(merkleTree) {
33+
if (merkleTree.length === 0) {
34+
return undefined;
35+
}
36+
// Copy root buffer
37+
return Buffer.from(merkleTree[merkleTree.length - 1]);
38+
}
39+
40+
module.exports = {
41+
getMerkleTree: getMerkleTree,
42+
getMerkleRoot: getMerkleRoot
43+
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@dashevo/dashcore-lib",
3-
"version": "0.16.2",
3+
"version": "0.16.3",
44
"description": "A pure and powerful JavaScript Dash library.",
55
"author": "Dash Core Group, Inc. <dev@dash.org>",
66
"main": "index.js",

test/util/merkletree.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/* eslint-disable */
2+
var expect = require('chai').expect;
3+
var merkleTreeUtil = require('../../lib/util/merkletree');
4+
var getMerkleTree = merkleTreeUtil.getMerkleTree;
5+
var getMerkleRoot = merkleTreeUtil.getMerkleRoot;
6+
7+
var hashes = [
8+
Buffer.from('6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b', 'hex'),
9+
Buffer.from('bf7e815688420059a4a77c66ad8d154487a25f3fcee73e36514f66fbc26ae91a', 'hex'),
10+
Buffer.from('18083d9866ba7fde28e819520ff4a4e9a7c871fe7929d997c84aebe7ae8b9385', 'hex')
11+
];
12+
13+
var expectedTree = [
14+
Buffer.from('6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b', 'hex'),
15+
Buffer.from('bf7e815688420059a4a77c66ad8d154487a25f3fcee73e36514f66fbc26ae91a', 'hex'),
16+
Buffer.from('18083d9866ba7fde28e819520ff4a4e9a7c871fe7929d997c84aebe7ae8b9385', 'hex'),
17+
Buffer.from('509051b275340cb2c5bf784764c4ca4505a2d96178e8166523145ce496dd1c24', 'hex'),
18+
Buffer.from('30b07f4b48fac0ff36f1ba88198267392d4b684db4eb8dff313722c86fab17e4', 'hex'),
19+
Buffer.from('f7be256fbaef5f3f5eb1d0807852a396314c11a964848b57e6a38b8e82c8777b', 'hex')
20+
];
21+
22+
describe('merkleTree', function () {
23+
describe('getMerkleTree', function () {
24+
it('should build a proper merkle tree', function () {
25+
var tree = getMerkleTree(hashes);
26+
27+
expect(tree).to.be.an('array');
28+
// Three leaves, two nodes and a root, 6 in total
29+
expect(tree.length).to.be.equal(6);
30+
tree.forEach(function (node, index) {
31+
expect(node).to.be.instanceOf(Buffer);
32+
// sha256 is 32 bytes
33+
expect(node.length).to.be.equal(32);
34+
expect(node).to.be.deep.equal(expectedTree[index]);
35+
});
36+
});
37+
});
38+
describe('getMerkleRoot', function () {
39+
it('should return a copy of merkle root from merkle tree', function () {
40+
var tree = getMerkleTree(hashes);
41+
var root = getMerkleRoot(tree);
42+
43+
// Last element of the tree is root
44+
expect(root).to.be.deep.equal(expectedTree[5]);
45+
46+
// Test that resulted buffer is decoupled from the tree
47+
root.reverse();
48+
expect(root).to.be.not.deep.equal(expectedTree[5]);
49+
});
50+
it('should return undefined if tree is empty', function () {
51+
var root = getMerkleRoot([]);
52+
53+
expect(root).to.be.undefined;
54+
});
55+
});
56+
});

0 commit comments

Comments
 (0)