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)
|
||||
* [getLeaves](_src_merkletree_.merkletree.md#getleaves)
|
||||
* [getMultiProof](_src_merkletree_.merkletree.md#getmultiproof)
|
||||
* [getOptions](_src_merkletree_.merkletree.md#getoptions)
|
||||
* [getPositionalHexProof](_src_merkletree_.merkletree.md#getpositionalhexproof)
|
||||
* [getProof](_src_merkletree_.merkletree.md#getproof)
|
||||
* [getProofFlags](_src_merkletree_.merkletree.md#getproofflags)
|
||||
|
@ -71,9 +72,11 @@ Class reprensenting a Merkle Tree
|
|||
* [linearSearch](_src_merkletree_.merkletree.md#static-linearsearch)
|
||||
* [marshalLeaves](_src_merkletree_.merkletree.md#static-marshalleaves)
|
||||
* [marshalProof](_src_merkletree_.merkletree.md#static-marshalproof)
|
||||
* [marshalTree](_src_merkletree_.merkletree.md#static-marshaltree)
|
||||
* [print](_src_merkletree_.merkletree.md#static-print)
|
||||
* [unmarshalLeaves](_src_merkletree_.merkletree.md#static-unmarshalleaves)
|
||||
* [unmarshalProof](_src_merkletree_.merkletree.md#static-unmarshalproof)
|
||||
* [unmarshalTree](_src_merkletree_.merkletree.md#static-unmarshaltree)
|
||||
* [verify](_src_merkletree_.merkletree.md#static-verify)
|
||||
|
||||
## 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**(`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
|
||||
|
||||
▸ **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
|
||||
|
||||
▸ **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)
|
||||
}
|
||||
|
||||
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[]) {
|
||||
if (this.hashLeaves) {
|
||||
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
|
||||
* @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')
|
||||
})
|
||||
|
||||
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 => {
|
||||
t.plan(1)
|
||||
|
||||
|
|
Loading…
Reference in New Issue