Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
wemeetagain committed Mar 18, 2024
1 parent d534e6c commit dd59a2b
Show file tree
Hide file tree
Showing 20 changed files with 2,100 additions and 1,123 deletions.
1 change: 1 addition & 0 deletions packages/hash-object/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ ethereum_hashing = "0.6.0"
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { version = "2.12.2", default-features = false, features = ["napi4"] }
napi-derive = "2.12.2"
once_cell = "1.19.0"

[build-dependencies]
napi-build = "2.0.1"
Expand Down
64 changes: 61 additions & 3 deletions packages/hash-object/__test__/index.spec.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,65 @@
import test from 'ava'

import { sum } from '../index.js'
import { getNode, getNodesAtDepth, setNode, setNodesAtDepth, subtreeFillToContents, subtreeFillToDepth, subtreeFillToLength, zeroNode, } from '../index.js'

test('sum from native', (t) => {
t.is(sum(1, 2), 3)
test('basics', (t) => {
const z0 = zeroNode(0)
const z1 = zeroNode(1)
const z2 = zeroNode(2)
const z3 = zeroNode(3)
t.deepEqual(z1.left.root, z0.root)
t.deepEqual(z2.left.left.root, z0.root)

const t0 = subtreeFillToDepth(z0, 2)
t.deepEqual(t0.root, z2.root)

const t1 = subtreeFillToLength(z1, 2, 3)
t.deepEqual(t1.left.root, z2.root)

const t2 = subtreeFillToContents([z1, z1], 2)
t.deepEqual(t2.left.root, z2.root)
t.deepEqual(t2.right.root, z1.root)

const t3 = subtreeFillToContents([z0, z1, z2, z3], 2)
t.deepEqual(getNode(t3, "100").root, z0.root)
t.deepEqual(getNode(t3, "101").root, z1.root)
t.deepEqual(getNode(t3, "110").root, z2.root)
t.deepEqual(getNode(t3, "111").root, z3.root)

const t4 = setNode(t3, "111", z0)
t.deepEqual(getNode(t4, "100").root, z0.root)
t.deepEqual(getNode(t4, "101").root, z1.root)
t.deepEqual(getNode(t4, "110").root, z2.root)
t.deepEqual(getNode(t4, "111").root, z0.root)

const n0 = [getNode(t3, "101"), getNode(t3, "110")]
t.deepEqual(n0[0].root, z1.root)
t.deepEqual(n0[1].root, z2.root)

console.log("t3")
for (let i = 0; i < 8; i++) {
const gindex = i.toString(2);
console.log(gindex, Buffer.from(getNode(t3, gindex).root).toString('hex'))
}
const n1 = getNodesAtDepth(t3, 2, 0, 2)
t.deepEqual(n1[0].root, z0.root)
t.deepEqual(n1[1].root, z1.root)

const n2 = getNodesAtDepth(t3, 2, 1, 2)
t.deepEqual(n2[0].root, z1.root)
t.deepEqual(n2[1].root, z2.root)

const n3 = getNodesAtDepth(t3, 2, 1, 3)
t.deepEqual(n3[0].root, z1.root)
t.deepEqual(n3[1].root, z2.root)
t.deepEqual(n3[2].root, z3.root)

const t5 = setNodesAtDepth(t3, 2, [0, 1], [z2, z3])
console.log("t5")
for (let i = 0; i < 8; i++) {
const gindex = i.toString(2);
console.log(gindex, Buffer.from(getNode(t5, gindex).root).toString('hex'))
}
t.deepEqual(getNode(t5, "100").root, z2.root)
t.deepEqual(getNode(t5, "101").root, z3.root)
})
71 changes: 57 additions & 14 deletions packages/hash-object/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,52 @@

/* auto-generated by NAPI-RS */

export function hash(left: HashObject, right: HashObject): HashObject
export function hash64(left: HashObject, right: HashObject): HashObject
export function hashtreeOne(left: HashObject, right: HashObject): HashObject
export function hashtree(objects: HashObject[]): HashObject[]
export function hashtreeUint8Array(input: Uint8Array): Uint8Array
export function initHashObjectCache(n: number): void
export class HashObject {
constructor(h0: number, h1: number, h2: number, h3: number, h4: number, h5: number, h6: number, h7: number)
static zero(): HashObject
static fromUint8Array(bytes: Uint8Array): HashObject
export function getNode(root: Node, gindex: string): Node
export function setNode(root: Node, gindex: string, value: Node): Node
export function setNodeWithFn(root: Node, gindex: string, getNewNode: (arg0: Node) => Node): Node
export function getNodeAtDepth(root: Node, depth: number, index: number): Node
/**
* Fast read-only iteration
* In-order traversal of nodes at `depth`
* starting from the `start_index`-indexed node
* iterating through `count` nodes
*
* **Strategy**
* 1. Navigate down to parent depth storing a stack of parents
* 2. At target level push current node
* 3. Go up to the first level that navigated left
* 4. Repeat (1) for next index
*/
export function getNodesAtDepth(root: Node, depth: number, startIndex: number, count: number): Array<Node>
/**
* Set multiple nodes in batch, editing and traversing nodes strictly once.
* - gindexes MUST be sorted in ascending order beforehand.
* - All gindexes must be at the exact same depth.
* - Depth must be > 0, if 0 just replace the root node.
*
* Strategy: for each gindex in `gindexes` navigate to the depth of its parent,
* and create a new parent. Then calculate the closest common depth with the next
* gindex and navigate upwards creating or caching nodes as necessary. Loop and repeat.
*/
export function setNodesAtDepth(root: Node, depth: number, indices: Array<number>, nodes: Array<Node>): Node
/**
* Return the `Node` at a specified height from the merkle tree made of "zero data"
* ```
* ...
* /
* x <- height 2
* / \
* x x <- height 1
* / \ / \
* 0x0 0x0 0x0 0x0 <- height 0
* ```
*/
export function zeroNode(height: number): Node
export function subtreeFillToDepth(bottom: Node, depth: number): Node
export function subtreeFillToLength(bottom: Node, depth: number, length: number): Node
export function subtreeFillToContents(nodes: Array<Node>, depth: number): Node
export type JsNode = Node
export class Node {
get h0(): number
get h1(): number
get h2(): number
Expand All @@ -29,8 +65,15 @@ export class HashObject {
set h5(value: number)
set h6(value: number)
set h7(value: number)
applyHash(other: HashObject): void
applyUint8Array(bytes: Uint8Array): void
toUint8Array(): Uint8Array
asBytes(): number[]
get left(): Node
get right(): Node
get root(): Uint8Array
get rootHashObject(): this
isLeaf(): boolean
constructor()
static newLeafNode(h0: number, h1: number, h2: number, h3: number, h4: number, h5: number, h6: number, h7: number): JsNode
static fromRoot(bytes: Uint8Array): JsNode
static fromZero(): JsNode
static fromUint32(value: number): JsNode
static newBranchNode(left: Node, right: Node): JsNode
}
20 changes: 12 additions & 8 deletions packages/hash-object/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,12 +295,16 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}

const { HashObject, hash, hash64, hashtreeOne, hashtree, hashtreeUint8Array, initHashObjectCache } = nativeBinding
const { Node, getNode, setNode, setNodeWithFn, getNodeAtDepth, getNodesAtDepth, setNodesAtDepth, zeroNode, subtreeFillToDepth, subtreeFillToLength, subtreeFillToContents } = nativeBinding

module.exports.HashObject = HashObject
module.exports.hash = hash
module.exports.hash64 = hash64
module.exports.hashtreeOne = hashtreeOne
module.exports.hashtree = hashtree
module.exports.hashtreeUint8Array = hashtreeUint8Array
module.exports.initHashObjectCache = initHashObjectCache
module.exports.Node = Node
module.exports.getNode = getNode
module.exports.setNode = setNode
module.exports.setNodeWithFn = setNodeWithFn
module.exports.getNodeAtDepth = getNodeAtDepth
module.exports.getNodesAtDepth = getNodesAtDepth
module.exports.setNodesAtDepth = setNodesAtDepth
module.exports.zeroNode = zeroNode
module.exports.subtreeFillToDepth = subtreeFillToDepth
module.exports.subtreeFillToLength = subtreeFillToLength
module.exports.subtreeFillToContents = subtreeFillToContents
Loading

0 comments on commit dd59a2b

Please sign in to comment.