initial typescript edit

This commit is contained in:
Sergei SMART 2022-02-22 18:45:31 +10:00
parent e3c54ea818
commit 4501cae4d6
9 changed files with 5116 additions and 5572 deletions

@ -1,26 +1,57 @@
{ {
"env": {
"node": true,
"browser": true,
"es6": true,
"mocha": true
},
"extends": "eslint:recommended",
"globals": { "globals": {
"Atomics": "readonly", "Atomics": "readonly",
"SharedArrayBuffer": "readonly" "SharedArrayBuffer": "readonly"
}, },
"parser": "babel-eslint", "parser": "@typescript-eslint/parser",
"parserOptions": { "plugins": [
"ecmaVersion": 2018 "@typescript-eslint"
}, ],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"ignorePatterns": [
"test/*.spec.ts",
"lib"
],
"rules": { "rules": {
"indent": ["error", 2], "@typescript-eslint/no-unused-vars": "error",
"linebreak-style": ["error", "unix"], "@typescript-eslint/consistent-type-definitions": [
"quotes": ["error", "single"], "error",
"semi": ["error", "never"], "type"
"object-curly-spacing": ["error", "always"], ],
"comma-dangle": ["error", "always-multiline"], "indent": [
"error",
2
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"never"
],
"object-curly-spacing": [
"error",
"always"
],
"comma-dangle": [
"error",
"always-multiline"
],
"require-await": "error" "require-await": "error"
},
"env": {
"browser": true,
"es2021": true,
"node": true,
"mocha": true
} }
} }

4
.gitignore vendored

@ -1 +1,5 @@
node_modules node_modules
build
lib
yarn-error.log
.idea

5454
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -3,9 +3,11 @@
"version": "0.6.1", "version": "0.6.1",
"description": "Fixed depth merkle tree implementation with sequential inserts", "description": "Fixed depth merkle tree implementation with sequential inserts",
"repository": "https://github.com/tornadocash/fixed-merkle-tree.git", "repository": "https://github.com/tornadocash/fixed-merkle-tree.git",
"main": "src/merkleTree.js", "main": "lib/index.js",
"types": "lib/index.d.ts",
"scripts": { "scripts": {
"test": "mocha", "test": "ts-mocha 'test/*.spec.ts'",
"build": "tsc",
"lint": "eslint ." "lint": "eslint ."
}, },
"keywords": [ "keywords": [
@ -19,13 +21,18 @@
"src/*" "src/*"
], ],
"dependencies": { "dependencies": {
"snarkjs": "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5",
"circomlib": "git+https://github.com/tornadocash/circomlib.git#5beb6aee94923052faeecea40135d45b6ce6172c" "circomlib": "git+https://github.com/tornadocash/circomlib.git#5beb6aee94923052faeecea40135d45b6ce6172c"
}, },
"devDependencies": { "devDependencies": {
"babel-eslint": "^10.1.0", "@types/expect": "^24.3.0",
"@types/mocha": "^9.1.0",
"@typescript-eslint/eslint-plugin": "^5.12.0",
"@typescript-eslint/parser": "^5.12.0",
"chai": "^4.2.0", "chai": "^4.2.0",
"eslint": "^7.5.0", "eslint": "^8.9.0",
"mocha": "^8.1.0" "eslint-config-prettier": "^8.3.0",
"mocha": "^9.2.1",
"ts-mocha": "^9.0.2",
"typescript": "^4.5.5"
} }
} }

@ -1,34 +1,28 @@
import { mimcsponge } from 'circomlib'
// keccak256("tornado") % BN254_FIELD_SIZE // keccak256("tornado") % BN254_FIELD_SIZE
const DEFAULT_ZERO = '21663839004416932945382355908790599225266501822907911457504978515578255421292' const DEFAULT_ZERO = '21663839004416932945382355908790599225266501822907911457504978515578255421292'
const defaultHash = require('./mimc')
// todo ensure consistent types in tree and inserted elements? const defaultHash = (left: Element, right: Element): string => mimcsponge.multiHash([BigInt(left), BigInt(right)]).toString()
// todo make sha3 default hasher (and update tests) to get rid of mimc/snarkjs/circomlib dependency
/** export default class MerkleTree {
* @callback hashFunction levels: number
* @param left Left leaf capacity: number
* @param right Right leaf private _hash: HashFunction
*/ private zeroElement: Element
/** private _zeros: Element[]
* Merkle tree private _layers: Array<Element[]>
*/
class MerkleTree { constructor(levels: number, elements: Element[] = [], {
/** hashFunction = defaultHash,
* Constructor zeroElement = DEFAULT_ZERO,
* @param {number} levels Number of levels in the tree }: MerkleTreeOptions = {}) {
* @param {Array} [elements] Initial elements
* @param {Object} options
* @param {hashFunction} [options.hashFunction] Function used to hash 2 leaves
* @param [options.zeroElement] Value for non-existent leaves
*/
constructor(levels, elements = [], { hashFunction, zeroElement = DEFAULT_ZERO } = {}) {
this.levels = levels this.levels = levels
this.capacity = 2 ** levels this.capacity = 2 ** levels
if (elements.length > this.capacity) { if (elements.length > this.capacity) {
throw new Error('Tree is full') throw new Error('Tree is full')
} }
this._hash = hashFunction || defaultHash this._hash = hashFunction
this.zeroElement = zeroElement this.zeroElement = zeroElement
this._zeros = [] this._zeros = []
this._zeros[0] = zeroElement this._zeros[0] = zeroElement
@ -56,17 +50,16 @@ class MerkleTree {
/** /**
* Get tree root * Get tree root
* @returns {*}
*/ */
root() { root(): string {
return this._layers[this.levels].length > 0 ? this._layers[this.levels][0] : this._zeros[this.levels] return `${this._layers[this.levels].length > 0 ? this._layers[this.levels][0] : this._zeros[this.levels]}`
} }
/** /**
* Insert new element into the tree * Insert new element into the tree
* @param element Element to insert * @param element Element to insert
*/ */
insert(element) { insert(element: Element) {
if (this._layers[0].length >= this.capacity) { if (this._layers[0].length >= this.capacity) {
throw new Error('Tree is full') throw new Error('Tree is full')
} }
@ -77,7 +70,7 @@ class MerkleTree {
* Insert multiple elements into the tree. * Insert multiple elements into the tree.
* @param {Array} elements Elements to insert * @param {Array} elements Elements to insert
*/ */
bulkInsert(elements) { bulkInsert(elements: Element[]) {
if (!elements.length) { if (!elements.length) {
return return
} }
@ -109,7 +102,7 @@ class MerkleTree {
* @param {number} index Index of element to change * @param {number} index Index of element to change
* @param element Updated element value * @param element Updated element value
*/ */
update(index, element) { update(index: number, element: Element) {
if (isNaN(Number(index)) || index < 0 || index > this._layers[0].length || index >= this.capacity) { if (isNaN(Number(index)) || index < 0 || index > this._layers[0].length || index >= this.capacity) {
throw new Error('Insert index out of bounds: ' + index) throw new Error('Insert index out of bounds: ' + index)
} }
@ -130,17 +123,18 @@ class MerkleTree {
* @param {number} index Leaf index to generate path for * @param {number} index Leaf index to generate path for
* @returns {{pathElements: Object[], pathIndex: number[]}} An object containing adjacent elements and left-right index * @returns {{pathElements: Object[], pathIndex: number[]}} An object containing adjacent elements and left-right index
*/ */
path(index) { path(index: Element) {
if (isNaN(Number(index)) || index < 0 || index >= this._layers[0].length) { if (isNaN(Number(index)) || index < 0 || index >= this._layers[0].length) {
throw new Error('Index out of bounds: ' + index) throw new Error('Index out of bounds: ' + index)
} }
const pathElements = [] let elIndex = +index
const pathIndices = [] const pathElements: Element[] = []
const pathIndices: number[] = []
for (let level = 0; level < this.levels; level++) { for (let level = 0; level < this.levels; level++) {
pathIndices[level] = index % 2 pathIndices[level] = elIndex % 2
pathElements[level] = pathElements[level] =
(index ^ 1) < this._layers[level].length ? this._layers[level][index ^ 1] : this._zeros[level] (elIndex ^ 1) < this._layers[level].length ? this._layers[level][elIndex ^ 1] : this._zeros[level]
index >>= 1 elIndex >>= 1
} }
return { return {
pathElements, pathElements,
@ -154,17 +148,16 @@ class MerkleTree {
* @param comparator A function that checks leaf value equality * @param comparator A function that checks leaf value equality
* @returns {number} Index if element is found, otherwise -1 * @returns {number} Index if element is found, otherwise -1
*/ */
indexOf(element, comparator) { indexOf(element: Element, comparator?: <T, R> (arg0: T, arg1: T) => R): number {
if (comparator) { if (comparator) {
return this._layers[0].findIndex((el) => comparator(element, el)) return this._layers[0].findIndex((el) => comparator<Element, number>(element, el))
} else { } else {
return this._layers[0].indexOf(element) return this._layers[0].indexOf(element)
} }
} }
/** /**
* Returns a copy of non-zero tree elements * Returns a copy of non-zero tree elements.
* @returns {Object[]}
*/ */
elements() { elements() {
return this._layers[0].slice() return this._layers[0].slice()
@ -172,7 +165,6 @@ class MerkleTree {
/** /**
* Returns a copy of n-th zero elements array * Returns a copy of n-th zero elements array
* @returns {Object[]}
*/ */
zeros() { zeros() {
return this._zeros.slice() return this._zeros.slice()
@ -183,7 +175,7 @@ class MerkleTree {
* Deserializing it back will not require to recompute any hashes * Deserializing it back will not require to recompute any hashes
* Elements are not converted to a plain type, this is responsibility of the caller * Elements are not converted to a plain type, this is responsibility of the caller
*/ */
serialize() { serialize(): SerializedTreeState {
return { return {
levels: this.levels, levels: this.levels,
_zeros: this._zeros, _zeros: this._zeros,
@ -195,18 +187,27 @@ class MerkleTree {
* Deserialize data into a MerkleTree instance * Deserialize data into a MerkleTree instance
* Make sure to provide the same hashFunction as was used in the source tree, * Make sure to provide the same hashFunction as was used in the source tree,
* otherwise the tree state will be invalid * otherwise the tree state will be invalid
*
* @param data
* @param hashFunction
* @returns {MerkleTree}
*/ */
static deserialize(data, hashFunction) { static deserialize(data: SerializedTreeState, hashFunction?: HashFunction): MerkleTree {
const instance = Object.assign(Object.create(this.prototype), data) return new MerkleTree(data.levels, data._layers[0], { hashFunction, zeroElement: data._zeros[0] })
instance._hash = hashFunction || defaultHash
instance.capacity = 2 ** instance.levels
instance.zeroElement = instance._zeros[0]
return instance
} }
} }
module.exports = MerkleTree export type HashFunction = {
(left: string | number, right: string | number): string
}
export type MerkleTreeOptions = {
hashFunction?: HashFunction
zeroElement?: Element
}
export type Element = string | number
export type SerializedTreeState = {
levels: number,
_zeros: Array<Element>,
_layers: Array<Element[]>
}
export type Mimcsponge = {
multiHash: (arr: BigInt[], key?: Element, numOutputs?) => string
}

@ -1,3 +0,0 @@
const { mimcsponge } = require('circomlib')
const { bigInt } = require('snarkjs')
module.exports = (left, right) => mimcsponge.multiHash([bigInt(left), bigInt(right)]).toString()

@ -1,26 +1,28 @@
const MerkleTree = require('../src/merkleTree') import MerkleTree from '../src'
require('chai').should() import { assert, should } from 'chai'
describe('MerkleTree', () => { describe('MerkleTree', () => {
describe('#constructor', () => { describe('#constructor', () => {
it('should have correct zero root', () => { it('should have correct zero root', () => {
const tree = new MerkleTree(10) const tree = new MerkleTree(10, [])
return tree.root().should.equal('14030416097908897320437553787826300082392928432242046897689557706485311282736') return should().equal(tree.root(), '14030416097908897320437553787826300082392928432242046897689557706485311282736')
}) })
it('should have correct 1 element root', () => { it('should have correct 1 element root', () => {
const tree = new MerkleTree(10, [1]) const tree = new MerkleTree(10, [1])
tree.root().should.equal('8423266420989796135179818298985240707844287090553672312129988553683991994663') should().equal(tree.root(), '8423266420989796135179818298985240707844287090553672312129988553683991994663')
}) })
it('should have correct even elements root', () => { it('should have correct even elements root', () => {
const tree = new MerkleTree(10, [1, 2]) const tree = new MerkleTree(10, [1, 2])
tree.root().should.equal('6632020347849276860492323008882350357301732786233864934344775324188835172576') should().equal(tree.root(), '6632020347849276860492323008882350357301732786233864934344775324188835172576')
}) })
it('should have correct odd elements root', () => { it('should have correct odd elements root', () => {
const tree = new MerkleTree(10, [1, 2, 3]) const tree = new MerkleTree(10, [1, 2, 3])
tree.root().should.equal('13605252518346649016266481317890801910232739395710162921320863289825142055129') should().equal(tree.root(), '13605252518346649016266481317890801910232739395710162921320863289825142055129')
}) })
it('should be able to create a full tree', () => { it('should be able to create a full tree', () => {
@ -29,7 +31,7 @@ describe('MerkleTree', () => {
it('should fail to create tree with too many elements', () => { it('should fail to create tree with too many elements', () => {
const call = () => new MerkleTree(2, [1, 2, 3, 4, 5]) const call = () => new MerkleTree(2, [1, 2, 3, 4, 5])
call.should.throw('Tree is full') should().throw(call, 'Tree is full')
}) })
}) })
@ -37,19 +39,19 @@ describe('MerkleTree', () => {
it('should insert into empty tree', () => { it('should insert into empty tree', () => {
const tree = new MerkleTree(10) const tree = new MerkleTree(10)
tree.insert(42) tree.insert(42)
tree.root().should.equal('5305397050004975530787056746976521882221645950652996479084366175595194436378') should().equal(tree.root(), '5305397050004975530787056746976521882221645950652996479084366175595194436378')
}) })
it('should insert into odd tree', () => { it('should insert into odd tree', () => {
const tree = new MerkleTree(10, [1]) const tree = new MerkleTree(10, [1])
tree.insert(42) tree.insert(42)
tree.root().should.equal('4732716818150428188641303198013632061441036732749853605989871103991103096471') should().equal(tree.root(), '4732716818150428188641303198013632061441036732749853605989871103991103096471')
}) })
it('should insert into even tree', () => { it('should insert into even tree', () => {
const tree = new MerkleTree(10, [1, 2]) const tree = new MerkleTree(10, [1, 2])
tree.insert(42) tree.insert(42)
tree.root().should.equal('6204016789747878948181936326719724987136198810274146408545977300318734508764') should().equal(tree.root(), '6204016789747878948181936326719724987136198810274146408545977300318734508764')
}) })
it('should insert last element', () => { it('should insert last element', () => {
@ -60,7 +62,7 @@ describe('MerkleTree', () => {
it('should fail to insert when tree is full', () => { it('should fail to insert when tree is full', () => {
const tree = new MerkleTree(2, [1, 2, 3, 4]) const tree = new MerkleTree(2, [1, 2, 3, 4])
const call = () => tree.insert(5) const call = () => tree.insert(5)
call.should.throw('Tree is full') should().throw(call, 'Tree is full')
}) })
}) })
@ -68,7 +70,7 @@ describe('MerkleTree', () => {
it('should work', () => { it('should work', () => {
const tree = new MerkleTree(10, [1, 2, 3]) const tree = new MerkleTree(10, [1, 2, 3])
tree.bulkInsert([4, 5, 6]) tree.bulkInsert([4, 5, 6])
tree.root().should.equal('10132905325673518287563057607527946096399700874345297651940963130460267058606') should().equal(tree.root(), '10132905325673518287563057607527946096399700874345297651940963130460267058606')
}) })
it('should give the same result as sequental inserts', () => { it('should give the same result as sequental inserts', () => {
@ -92,7 +94,7 @@ describe('MerkleTree', () => {
for (const item of inserted) { for (const item of inserted) {
tree2.insert(item) tree2.insert(item)
} }
tree1.root().should.equal(tree2.root()) should().equal(tree1.root(), tree2.root())
} }
} }
}).timeout(10000) }).timeout(10000)
@ -105,7 +107,7 @@ describe('MerkleTree', () => {
it('should fail to insert too many elements', () => { it('should fail to insert too many elements', () => {
const tree = new MerkleTree(2, [1, 2]) const tree = new MerkleTree(2, [1, 2])
const call = () => tree.bulkInsert([3, 4, 5]) const call = () => tree.bulkInsert([3, 4, 5])
call.should.throw('Tree is full') should().throw(call, 'Tree is full')
}) })
}) })
@ -113,56 +115,57 @@ describe('MerkleTree', () => {
it('should update first element', () => { it('should update first element', () => {
const tree = new MerkleTree(10, [1, 2, 3, 4, 5]) const tree = new MerkleTree(10, [1, 2, 3, 4, 5])
tree.update(0, 42) tree.update(0, 42)
tree.root().should.equal('153077538697962715163231177553585573790587443799974092612333826693999310199') should().equal(tree.root(), '153077538697962715163231177553585573790587443799974092612333826693999310199')
}) })
it('should update last element', () => { it('should update last element', () => {
const tree = new MerkleTree(10, [1, 2, 3, 4, 5]) const tree = new MerkleTree(10, [1, 2, 3, 4, 5])
tree.update(4, 42) tree.update(4, 42)
tree.root().should.equal('1955192134603843666100093417117434845771298375724087600313714421260719033775') should().equal(tree.root(), '1955192134603843666100093417117434845771298375724087600313714421260719033775')
}) })
it('should update odd element', () => { it('should update odd element', () => {
const tree = new MerkleTree(10, [1, 2, 3, 4, 5]) const tree = new MerkleTree(10, [1, 2, 3, 4, 5])
tree.update(1, 42) tree.update(1, 42)
tree.root().should.equal('6642888742811380760154112624880866754768235565211186414088321870395007150538') should().equal(tree.root(), '6642888742811380760154112624880866754768235565211186414088321870395007150538')
}) })
it('should update even element', () => { it('should update even element', () => {
const tree = new MerkleTree(10, [1, 2, 3, 4, 5]) const tree = new MerkleTree(10, [1, 2, 3, 4, 5])
tree.update(2, 42) tree.update(2, 42)
tree.root().should.equal('11739358667442647096377238675718917508981868161724701476635082606510350785683') should().equal(tree.root(), '11739358667442647096377238675718917508981868161724701476635082606510350785683')
}) })
it('should update extra element', () => { it('should update extra element', () => {
const tree = new MerkleTree(10, [1, 2, 3, 4]) const tree = new MerkleTree(10, [1, 2, 3, 4])
tree.update(4, 5) tree.update(4, 5)
tree.root().should.equal('6341751103515285836339987888606244815365572869367801108789753151704260302930') should().equal(tree.root(), '6341751103515285836339987888606244815365572869367801108789753151704260302930')
}) })
it('should fail to update incorrect index', () => { it('should fail to update incorrect index', () => {
const tree = new MerkleTree(10, [1, 2, 3, 4, 5]); const tree = new MerkleTree(10, [1, 2, 3, 4, 5])
(() => tree.update(-1, 42)).should.throw('Insert index out of bounds: -1'); should().throw((() => tree.update(-1, 42)), 'Insert index out of bounds: -1')
(() => tree.update(6, 42)).should.throw('Insert index out of bounds: 6'); should().throw((() => tree.update(6, 42)), 'Insert index out of bounds: 6')
(() => tree.update('qwe', 42)).should.throw('Insert index out of bounds: qwe') // @ts-ignore
should().throw((() => tree.update('qwe', 42)), 'Insert index out of bounds: qwe')
}) })
it('should fail to update over capacity', () => { it('should fail to update over capacity', () => {
const tree = new MerkleTree(2, [1, 2, 3, 4]) const tree = new MerkleTree(2, [1, 2, 3, 4])
const call = () => tree.update(4, 42) const call = () => tree.update(4, 42)
call.should.throw('Insert index out of bounds: 4') should().throw(call, 'Insert index out of bounds: 4')
}) })
}) })
describe('#indexOf', () => { describe('#indexOf', () => {
it('should find index', () => { it('should find index', () => {
const tree = new MerkleTree(10, [1, 2, 3, 4, 5]) const tree = new MerkleTree(10, [1, 2, 3, 4, 5])
tree.indexOf(3).should.equal(2) should().equal(tree.indexOf(3), 2)
}) })
it('should return -1 for non existent element', () => { it('should return -1 for non existent element', () => {
const tree = new MerkleTree(10, [1, 2, 3, 4, 5]) const tree = new MerkleTree(10, [1, 2, 3, 4, 5])
tree.indexOf(42).should.equal(-1) should().equal(tree.indexOf(42), -1)
}) })
}) })
@ -170,8 +173,8 @@ describe('MerkleTree', () => {
it('should work for even index', () => { it('should work for even index', () => {
const tree = new MerkleTree(10, [1, 2, 3, 4, 5]) const tree = new MerkleTree(10, [1, 2, 3, 4, 5])
const path = tree.path(2) const path = tree.path(2)
path.pathIndices.should.be.deep.equal([0, 1, 0, 0, 0, 0, 0, 0, 0, 0]) assert.deepEqual(path.pathIndices, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0])
path.pathElements.should.be.deep.equal([ assert.deepEqual(path.pathElements, [
4, 4,
'19814528709687996974327303300007262407299502847885145507292406548098437687919', '19814528709687996974327303300007262407299502847885145507292406548098437687919',
'21305827034995891902714687670641862055126514524916463201449278400604999416145', '21305827034995891902714687670641862055126514524916463201449278400604999416145',
@ -188,8 +191,8 @@ describe('MerkleTree', () => {
it('should work for odd index', () => { it('should work for odd index', () => {
const tree = new MerkleTree(10, [1, 2, 3, 4, 5]) const tree = new MerkleTree(10, [1, 2, 3, 4, 5])
const path = tree.path(3) const path = tree.path(3)
path.pathIndices.should.be.deep.equal([1, 1, 0, 0, 0, 0, 0, 0, 0, 0]) assert.deepEqual(path.pathIndices, [1, 1, 0, 0, 0, 0, 0, 0, 0, 0])
path.pathElements.should.be.deep.equal([ assert.deepEqual(path.pathElements, [
3, 3,
'19814528709687996974327303300007262407299502847885145507292406548098437687919', '19814528709687996974327303300007262407299502847885145507292406548098437687919',
'21305827034995891902714687670641862055126514524916463201449278400604999416145', '21305827034995891902714687670641862055126514524916463201449278400604999416145',
@ -204,17 +207,17 @@ describe('MerkleTree', () => {
}) })
it('should fail on incorrect index', () => { it('should fail on incorrect index', () => {
const tree = new MerkleTree(10, [1, 2, 3, 4]); const tree = new MerkleTree(10, [1, 2, 3, 4])
(() => tree.path(-1)).should.throw('Index out of bounds: -1'); should().throw((() => tree.path(-1)), 'Index out of bounds: -1')
(() => tree.path(5)).should.throw('Index out of bounds: 5'); should().throw((() => tree.path(5)), 'Index out of bounds: 5')
(() => tree.path('qwe')).should.throw('Index out of bounds: qwe') should().throw((() => tree.path('qwe')), 'Index out of bounds: qwe')
}) })
it('should work for correct string index', () => { it('should work for correct string index', () => {
const tree = new MerkleTree(10, [1, 2, 3, 4, 5]) const tree = new MerkleTree(10, [1, 2, 3, 4, 5])
const path = tree.path('2') const path = tree.path('2')
path.pathIndices.should.be.deep.equal([0, 1, 0, 0, 0, 0, 0, 0, 0, 0]) assert.deepEqual(path.pathIndices, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0])
path.pathElements.should.be.deep.equal([ assert.deepEqual(path.pathElements, [
4, 4,
'19814528709687996974327303300007262407299502847885145507292406548098437687919', '19814528709687996974327303300007262407299502847885145507292406548098437687919',
'21305827034995891902714687670641862055126514524916463201449278400604999416145', '21305827034995891902714687670641862055126514524916463201449278400604999416145',
@ -231,16 +234,15 @@ describe('MerkleTree', () => {
describe('#serialize', () => { describe('#serialize', () => {
it('should work', () => { it('should work', () => {
const src = new MerkleTree(10, [1, 2, 3]) const src = new MerkleTree(10, [1, 2, 3, 4, 5, 6, 7, 8, 9])
const data = src.serialize() const data = src.serialize()
const dst = MerkleTree.deserialize(data) const dst = MerkleTree.deserialize(data)
should().equal(src.root(), dst.root())
src.root().should.equal(dst.root())
src.insert(10) src.insert(10)
dst.insert(10) dst.insert(10)
src.root().should.equal(dst.root()) should().equal(src.root(), dst.root())
}) })
}) })
}) })

26
tsconfig.json Normal file

@ -0,0 +1,26 @@
{
"compilerOptions": {
"lib": [
"es2019"
],
"target": "es2018",
"module": "CommonJS",
"moduleResolution": "Node",
"outDir": "./lib",
"rootDir": "src",
"esModuleInterop": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": false,
"allowSyntheticDefaultImports": true,
"declaration": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"types",
"**/*.spec.ts"
]
}

4930
yarn.lock Normal file

File diff suppressed because it is too large Load Diff