Add marshal tree method
This commit is contained in:
parent
68566c5ae9
commit
5c169b13d4
|
@ -48,6 +48,7 @@ Class reprensenting a Merkle Tree
|
||||||
* [getLeafIndex](_src_merkletree_.merkletree.md#getleafindex)
|
* [getLeafIndex](_src_merkletree_.merkletree.md#getleafindex)
|
||||||
* [getLeaves](_src_merkletree_.merkletree.md#getleaves)
|
* [getLeaves](_src_merkletree_.merkletree.md#getleaves)
|
||||||
* [getMultiProof](_src_merkletree_.merkletree.md#getmultiproof)
|
* [getMultiProof](_src_merkletree_.merkletree.md#getmultiproof)
|
||||||
|
* [getOptions](_src_merkletree_.merkletree.md#getoptions)
|
||||||
* [getPositionalHexProof](_src_merkletree_.merkletree.md#getpositionalhexproof)
|
* [getPositionalHexProof](_src_merkletree_.merkletree.md#getpositionalhexproof)
|
||||||
* [getProof](_src_merkletree_.merkletree.md#getproof)
|
* [getProof](_src_merkletree_.merkletree.md#getproof)
|
||||||
* [getProofFlags](_src_merkletree_.merkletree.md#getproofflags)
|
* [getProofFlags](_src_merkletree_.merkletree.md#getproofflags)
|
||||||
|
@ -71,9 +72,11 @@ Class reprensenting a Merkle Tree
|
||||||
* [linearSearch](_src_merkletree_.merkletree.md#static-linearsearch)
|
* [linearSearch](_src_merkletree_.merkletree.md#static-linearsearch)
|
||||||
* [marshalLeaves](_src_merkletree_.merkletree.md#static-marshalleaves)
|
* [marshalLeaves](_src_merkletree_.merkletree.md#static-marshalleaves)
|
||||||
* [marshalProof](_src_merkletree_.merkletree.md#static-marshalproof)
|
* [marshalProof](_src_merkletree_.merkletree.md#static-marshalproof)
|
||||||
|
* [marshalTree](_src_merkletree_.merkletree.md#static-marshaltree)
|
||||||
* [print](_src_merkletree_.merkletree.md#static-print)
|
* [print](_src_merkletree_.merkletree.md#static-print)
|
||||||
* [unmarshalLeaves](_src_merkletree_.merkletree.md#static-unmarshalleaves)
|
* [unmarshalLeaves](_src_merkletree_.merkletree.md#static-unmarshalleaves)
|
||||||
* [unmarshalProof](_src_merkletree_.merkletree.md#static-unmarshalproof)
|
* [unmarshalProof](_src_merkletree_.merkletree.md#static-unmarshalproof)
|
||||||
|
* [unmarshalTree](_src_merkletree_.merkletree.md#static-unmarshaltree)
|
||||||
* [verify](_src_merkletree_.merkletree.md#static-verify)
|
* [verify](_src_merkletree_.merkletree.md#static-verify)
|
||||||
|
|
||||||
## Constructors
|
## Constructors
|
||||||
|
@ -736,6 +739,30 @@ Name | Type | Description |
|
||||||
|
|
||||||
___
|
___
|
||||||
|
|
||||||
|
### getOptions
|
||||||
|
|
||||||
|
▸ **getOptions**(): *object*
|
||||||
|
|
||||||
|
**Returns:** *object*
|
||||||
|
|
||||||
|
* **complete**: *boolean* = this.complete
|
||||||
|
|
||||||
|
* **duplicateOdd**: *boolean* = this.duplicateOdd
|
||||||
|
|
||||||
|
* **fillDefaultHash**: *string* = this.fillDefaultHash?.toString() ?? null
|
||||||
|
|
||||||
|
* **hashLeaves**: *boolean* = this.hashLeaves
|
||||||
|
|
||||||
|
* **isBitcoinTree**: *boolean* = this.isBitcoinTree
|
||||||
|
|
||||||
|
* **sort**: *boolean* = this.sort
|
||||||
|
|
||||||
|
* **sortLeaves**: *boolean* = this.sortLeaves
|
||||||
|
|
||||||
|
* **sortPairs**: *boolean* = this.sortPairs
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
### getPositionalHexProof
|
### getPositionalHexProof
|
||||||
|
|
||||||
▸ **getPositionalHexProof**(`leaf`: Buffer | string, `index?`: number): *(string | number)[][]*
|
▸ **getPositionalHexProof**(`leaf`: Buffer | string, `index?`: number): *(string | number)[][]*
|
||||||
|
@ -1352,6 +1379,20 @@ Name | Type | Description |
|
||||||
|
|
||||||
___
|
___
|
||||||
|
|
||||||
|
### `Static` marshalTree
|
||||||
|
|
||||||
|
▸ **marshalTree**(`tree`: [MerkleTree](_src_merkletree_.merkletree.md)): *string*
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
Name | Type |
|
||||||
|
------ | ------ |
|
||||||
|
`tree` | [MerkleTree](_src_merkletree_.merkletree.md) |
|
||||||
|
|
||||||
|
**Returns:** *string*
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
### `Static` print
|
### `Static` print
|
||||||
|
|
||||||
▸ **print**(`tree`: any): *void*
|
▸ **print**(`tree`: any): *void*
|
||||||
|
@ -1427,6 +1468,22 @@ Name | Type |
|
||||||
|
|
||||||
___
|
___
|
||||||
|
|
||||||
|
### `Static` unmarshalTree
|
||||||
|
|
||||||
|
▸ **unmarshalTree**(`jsonStr`: string | object, `hashFn`: any, `options`: [Options](../interfaces/_src_merkletree_.options.md)): *[MerkleTree](_src_merkletree_.merkletree.md)*
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
Name | Type | Default |
|
||||||
|
------ | ------ | ------ |
|
||||||
|
`jsonStr` | string | object | - |
|
||||||
|
`hashFn` | any | SHA256 |
|
||||||
|
`options` | [Options](../interfaces/_src_merkletree_.options.md) | {} |
|
||||||
|
|
||||||
|
**Returns:** *[MerkleTree](_src_merkletree_.merkletree.md)*
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
### `Static` verify
|
### `Static` verify
|
||||||
|
|
||||||
▸ **verify**(`proof`: any[], `targetNode`: Buffer | string, `root`: Buffer | string, `hashFn`: any, `options`: [Options](../interfaces/_src_merkletree_.options.md)): *boolean*
|
▸ **verify**(`proof`: any[], `targetNode`: Buffer | string, `root`: Buffer | string, `hashFn`: any, `options`: [Options](../interfaces/_src_merkletree_.options.md)): *boolean*
|
||||||
|
|
|
@ -112,6 +112,19 @@ export class MerkleTree extends Base {
|
||||||
this.processLeaves(leaves)
|
this.processLeaves(leaves)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getOptions() {
|
||||||
|
return {
|
||||||
|
complete: this.complete,
|
||||||
|
isBitcoinTree: this.isBitcoinTree,
|
||||||
|
hashLeaves: this.hashLeaves,
|
||||||
|
sortLeaves: this.sortLeaves,
|
||||||
|
sortPairs: this.sortPairs,
|
||||||
|
sort: this.sort,
|
||||||
|
fillDefaultHash: this.fillDefaultHash?.toString() ?? null,
|
||||||
|
duplicateOdd: this.duplicateOdd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private processLeaves (leaves: TLeaf[]) {
|
private processLeaves (leaves: TLeaf[]) {
|
||||||
if (this.hashLeaves) {
|
if (this.hashLeaves) {
|
||||||
leaves = leaves.map(this.hashFn)
|
leaves = leaves.map(this.hashFn)
|
||||||
|
@ -740,6 +753,39 @@ export class MerkleTree extends Base {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static marshalTree (tree: MerkleTree):string {
|
||||||
|
const root = tree.getHexRoot()
|
||||||
|
const leaves = tree.leaves.map(leaf => MerkleTree.bufferToHex(leaf))
|
||||||
|
const layers = tree.getHexLayers()
|
||||||
|
const options = tree.getOptions()
|
||||||
|
|
||||||
|
return JSON.stringify({
|
||||||
|
options,
|
||||||
|
root,
|
||||||
|
layers,
|
||||||
|
leaves,
|
||||||
|
}, null, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
static unmarshalTree (jsonStr: string | object, hashFn = SHA256, options: Options = {}):MerkleTree {
|
||||||
|
let parsed :any = null
|
||||||
|
if (typeof jsonStr === 'string') {
|
||||||
|
parsed = JSON.parse(jsonStr)
|
||||||
|
} else if (jsonStr instanceof Object) {
|
||||||
|
parsed = jsonStr
|
||||||
|
} else {
|
||||||
|
throw new Error('Expected type of string or object')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsed) {
|
||||||
|
throw new Error('could not parse json')
|
||||||
|
}
|
||||||
|
|
||||||
|
options = Object.assign({}, parsed.options || {}, options)
|
||||||
|
|
||||||
|
return new MerkleTree(parsed.leaves, hashFn, options)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getProofIndices
|
* getProofIndices
|
||||||
* @desc Returns the proof indices for given tree indices.
|
* @desc Returns the proof indices for given tree indices.
|
||||||
|
|
|
@ -1046,6 +1046,112 @@ test('unmarshal proof', t => {
|
||||||
t.equal(proof[1].data.toString('hex'), '43e061172b1177f25d0f156b2d2ed11728006fade8e167ff3d1b9dbc979a3358')
|
t.equal(proof[1].data.toString('hex'), '43e061172b1177f25d0f156b2d2ed11728006fade8e167ff3d1b9dbc979a3358')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('marshal tree', t => {
|
||||||
|
t.plan(7)
|
||||||
|
|
||||||
|
const leaves = ['a', 'b', 'c'].map(keccak256)
|
||||||
|
const tree = new MerkleTree(leaves, keccak256, { sort: true })
|
||||||
|
const jsonTree = MerkleTree.marshalTree(tree)
|
||||||
|
t.equal(typeof jsonTree, 'string')
|
||||||
|
|
||||||
|
const parsed = JSON.parse(jsonTree)
|
||||||
|
t.deepEqual(parsed.options, {
|
||||||
|
complete: false,
|
||||||
|
isBitcoinTree: false,
|
||||||
|
hashLeaves: false,
|
||||||
|
sortLeaves: true,
|
||||||
|
sortPairs: true,
|
||||||
|
sort: true,
|
||||||
|
fillDefaultHash: null,
|
||||||
|
duplicateOdd: false
|
||||||
|
})
|
||||||
|
t.equal(parsed.root, '0xc3b537cc8a2c6dcb3657718e1f3505ff751ff8c2eba2a70460df2cbee2b1413a')
|
||||||
|
t.equal(parsed.leaves.length, 3)
|
||||||
|
t.deepEqual(parsed.leaves, [
|
||||||
|
'0x0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2',
|
||||||
|
'0x3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb',
|
||||||
|
'0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510'
|
||||||
|
])
|
||||||
|
t.equal(parsed.layers.length, 3)
|
||||||
|
t.deepEqual(parsed.layers, [
|
||||||
|
[
|
||||||
|
'0x0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2',
|
||||||
|
'0x3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb',
|
||||||
|
'0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'0x7dea550f679f3caab547cbbc5ee1a4c978c8c039b572ba00af1baa6481b88360',
|
||||||
|
'0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'0xc3b537cc8a2c6dcb3657718e1f3505ff751ff8c2eba2a70460df2cbee2b1413a'
|
||||||
|
]
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('unmarshal tree', t => {
|
||||||
|
t.plan(4)
|
||||||
|
|
||||||
|
const json = `{
|
||||||
|
"options": {
|
||||||
|
"complete": false,
|
||||||
|
"isBitcoinTree": false,
|
||||||
|
"hashLeaves": false,
|
||||||
|
"sortLeaves": true,
|
||||||
|
"sortPairs": true,
|
||||||
|
"sort": true,
|
||||||
|
"fillDefaultHash": null,
|
||||||
|
"duplicateOdd": false
|
||||||
|
},
|
||||||
|
"root": "0xc3b537cc8a2c6dcb3657718e1f3505ff751ff8c2eba2a70460df2cbee2b1413a",
|
||||||
|
"layers": [
|
||||||
|
[
|
||||||
|
"0x0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2",
|
||||||
|
"0x3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb",
|
||||||
|
"0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"0x7dea550f679f3caab547cbbc5ee1a4c978c8c039b572ba00af1baa6481b88360",
|
||||||
|
"0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"0xc3b537cc8a2c6dcb3657718e1f3505ff751ff8c2eba2a70460df2cbee2b1413a"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"leaves": [
|
||||||
|
"0x0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2",
|
||||||
|
"0x3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb",
|
||||||
|
"0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510"
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
|
||||||
|
const parsed = JSON.parse(json)
|
||||||
|
const tree = MerkleTree.unmarshalTree(json, keccak256)
|
||||||
|
|
||||||
|
t.equal(tree.getHexRoot(), parsed.root)
|
||||||
|
t.deepEqual(tree.getOptions(), parsed.options)
|
||||||
|
t.deepEqual(tree.getHexLeaves(), parsed.leaves)
|
||||||
|
t.deepEqual(tree.getHexLayers(), parsed.layers)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('getOptions', t => {
|
||||||
|
t.plan(1)
|
||||||
|
|
||||||
|
const leaves = ['a', 'b', 'c', 'd', 'e', 'f'].map(sha256)
|
||||||
|
const tree = new MerkleTree(leaves, sha256, { sortPairs: true, sortLeaves: true })
|
||||||
|
|
||||||
|
t.deepEqual(tree.getOptions(), {
|
||||||
|
complete: false,
|
||||||
|
isBitcoinTree: false,
|
||||||
|
hashLeaves: false,
|
||||||
|
sortLeaves: true,
|
||||||
|
sortPairs: true,
|
||||||
|
sort: false,
|
||||||
|
fillDefaultHash: null,
|
||||||
|
duplicateOdd: false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test('fillDefaultHashes', t => {
|
test('fillDefaultHashes', t => {
|
||||||
t.plan(1)
|
t.plan(1)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue