Merge branch 'PreetamSing-task/binary-search-leaf'

This commit is contained in:
Miguel Mota 2022-11-10 05:32:51 -08:00
commit ab6543a74e
No known key found for this signature in database
GPG Key ID: 67EC1161588A00F9
3 changed files with 152 additions and 26 deletions

View File

@ -26,9 +26,103 @@ export class Base {
*const index = tree.bufferIndexOf(haystack, needle)
*```
*/
protected _bufferIndexOf (array: Buffer[], element: Buffer):number {
protected _bufferIndexOf (
array: Buffer[],
element: Buffer,
isSorted: boolean = false
): number {
if (isSorted) {
return this.binarySearch(array, element, Buffer.compare)
}
const eqChecker = (buffer1, buffer2) => buffer1.equals(buffer2)
return this.linearSearch(array, element, eqChecker)
}
/**
* binarySearch
* @desc Returns the first index of which given item is found in array using binary search.
* @param {Buffer[]} array - Array of items.
* @param {Buffer} element - Item to find.
* @param {Function} compareFunction
* @return {Number} - Index number
*
* @example
* ```js
*const index = MerkleTree.binarySearch(array, element, Buffer.compare)
*```
*/
static binarySearch (
array: Buffer[],
element: Buffer,
compareFunction: (a: unknown, b: unknown) => number
): number {
let start = 0
let end = array.length - 1
// Iterate while start not meets end
while (start <= end) {
// Find the mid index
const mid = Math.floor((start + end) / 2)
// Check if the mid value is greater than, equal to, or less than search element.
const ordering = compareFunction(array[mid], element)
// If element is present at mid, start iterating for searching first appearance.
if (ordering === 0) {
// Linear reverse iteration until the first matching item index is found.
for (let i = mid - 1; i >= 0; i--) {
if (compareFunction(array[i], element) === 0) continue
return i + 1
}
return 0
} /* Else look in left or right half accordingly */ else if (ordering < 0) {
start = mid + 1
} else {
end = mid - 1
}
}
return -1
}
/**
* binarySearch
* @desc Returns the first index of which given item is found in array using binary search.
* @param {Buffer[]} array - Array of items.
* @param {Buffer} element - Item to find.
* @param {Function} compareFunction
* @return {Number} - Index number
*
* @example
* ```js
*const index = tree.binarySearch(array, element, Buffer.compare)
*```
*/
binarySearch (
array: Buffer[],
element: Buffer,
compareFunction: (a: unknown, b: unknown) => number
): number {
return Base.binarySearch(array, element, compareFunction)
}
/**
* linearSearch
* @desc Returns the first index of which given item is found in array using linear search.
* @param {Buffer[]} array - Array of items.
* @param {Buffer} element - Item to find.
* @param {Function} eqChecker
* @return {Number} - Index number
*
* @example
* ```js
*const index = MerkleTree.linearSearch(array, element, (a, b) => a === b)
*```
*/
static linearSearch (array: Buffer[], element: Buffer, eqChecker: (a: unknown, b: unknown) => boolean):number {
for (let i = 0; i < array.length; i++) {
if (element.equals(array[i])) {
if (eqChecker(array[i], element)) {
return i
}
}
@ -36,6 +130,23 @@ export class Base {
return -1
}
/**
* linearSearch
* @desc Returns the first index of which given item is found in array using linear search.
* @param {Buffer[]} array - Array of items.
* @param {Buffer} element - Item to find.
* @param {Function} eqChecker
* @return {Number} - Index number
*
* @example
* ```js
*const index = tree.linearSearch(array, element, (a, b) => a === b)
*```
*/
linearSearch (array: Buffer[], element: Buffer, eqChecker: (a: unknown, b: unknown) => boolean):number {
return Base.linearSearch(array, element, eqChecker)
}
/**
* bufferify
* @desc Returns a buffer type for the given value.
@ -82,7 +193,7 @@ export class Base {
*```
*/
static isHexString (v: string): boolean {
return (typeof v === 'string' && /^(0x)?[0-9A-Fa-f]*$/.test(v))
return typeof v === 'string' && /^(0x)?[0-9A-Fa-f]*$/.test(v)
}
/**
@ -124,7 +235,9 @@ export class Base {
*```
*/
static bufferToHex (value: Buffer, withPrefix: boolean = true): string {
return `${withPrefix ? '0x' : ''}${(value || Buffer.alloc(0)).toString('hex')}`
return `${withPrefix ? '0x' : ''}${(value || Buffer.alloc(0)).toString(
'hex'
)}`
}
/**
@ -173,7 +286,12 @@ export class Base {
}
// crypto-js support
return Buffer.from(f(CryptoJS.enc.Hex.parse(value.toString('hex'))).toString(CryptoJS.enc.Hex), 'hex')
return Buffer.from(
f(CryptoJS.enc.Hex.parse(value.toString('hex'))).toString(
CryptoJS.enc.Hex
),
'hex'
)
}
}

View File

@ -256,7 +256,7 @@ export class MerkleTree extends Base {
}
}
return this.leaves.filter(leaf => this._bufferIndexOf(values, leaf) !== -1)
return this.leaves.filter(leaf => this._bufferIndexOf(values, leaf, this.sortLeaves) !== -1)
}
return this.leaves
@ -518,13 +518,7 @@ export class MerkleTree extends Base {
const proof = []
if (!Number.isInteger(index)) {
index = -1
for (let i = 0; i < this.leaves.length; i++) {
if (Buffer.compare(leaf, this.leaves[i]) === 0) {
index = i
}
}
index = this._bufferIndexOf(this.leaves, leaf, this.sortLeaves)
}
if (index <= -1) {
@ -870,7 +864,7 @@ export class MerkleTree extends Base {
els = els.sort(Buffer.compare)
}
let ids = els.map((el) => this._bufferIndexOf(this.leaves, el)).sort((a, b) => a === b ? 0 : a > b ? 1 : -1)
let ids = els.map((el) => this._bufferIndexOf(this.leaves, el, this.sortLeaves)).sort((a, b) => a === b ? 0 : a > b ? 1 : -1)
if (!ids.every((idx) => idx !== -1)) {
throw new Error('Element does not exist in Merkle tree')
}
@ -993,7 +987,7 @@ export class MerkleTree extends Base {
if (leaves.every(Number.isInteger)) {
ids = [...leaves].sort((a, b) => a === b ? 0 : a > b ? 1 : -1) // Indices where passed
} else {
ids = leaves.map((el) => this._bufferIndexOf(this.leaves, el)).sort((a, b) => a === b ? 0 : a > b ? 1 : -1)
ids = leaves.map((el) => this._bufferIndexOf(this.leaves, el, this.sortLeaves)).sort((a, b) => a === b ? 0 : a > b ? 1 : -1)
}
if (!ids.every((idx: number) => idx !== -1)) {

View File

@ -20,3 +20,17 @@ test('bufferifyFn', t => {
t.deepEqual(fn('0x123'), Buffer.from('123', 'hex'))
t.deepEqual(fn('XYZ'), Buffer.from('XYZ'))
})
test('binarySearch', t => {
t.plan(3)
const base = new Base()
const compareFunction = (a, b) => {
if (a === b) return 0
else if (a < b) return -1
else return 1
}
t.equal(base.binarySearch([2, 2, 3, 3, 3, 4, 4, 4, 4], 3, compareFunction), 2)
t.equal(base.binarySearch([3, 3, 3, 3, 3, 4, 4, 4, 4], 3, compareFunction), 0)
t.equal(base.binarySearch([2, 2, 3, 3, 3, 4, 4, 4, 4], 1, compareFunction), -1)
})