-
Notifications
You must be signed in to change notification settings - Fork 773
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Verkle Implementation: Build out Trie Processing #3430
Merged
+685
−624
Merged
Changes from all commits
Commits
Show all changes
58 commits
Select commit
Hold shift + click to select a range
0b03444
add verkle crypto to trie
acolytec3 f468ce2
Merge remote-tracking branch 'origin/master' into verkle-trie-build-out
acolytec3 c1ce5eb
More spam
acolytec3 a317698
Merge remote-tracking branch 'origin/master' into verkle-trie-build-out
acolytec3 1670155
Update leafNode.create [no ci]
acolytec3 55d644f
Merge remote-tracking branch 'origin/master' into verkle-trie-build-o…
acolytec3 974d1ae
small removal [no ci]
acolytec3 570f8c4
Merge remote-tracking branch 'origin/master' into verkle-trie-build-o…
acolytec3 430d801
Update trie.get to check existence first
acolytec3 fa34dde
Update `put` when inserting a new leaf node [no ci]
acolytec3 b2806cf
more halfway stuff [no ci]
acolytec3 f9e019e
Remove unnecessary commit [no ci]
acolytec3 74676b0
update verkle crypto dep [no ci]
acolytec3 a267be1
Add helper to create leaf values as 16 bytes
acolytec3 e3ab994
Changes to support c1 and c2 [no ci]
acolytec3 6e7e91e
update new leaf node commitment correctly [no ci]
acolytec3 4a716a7
Merge remote-tracking branch 'origin/master' into verkle-trie-build-o…
acolytec3 a2ed90e
Changes needed to make `put` work [no ci]
acolytec3 1902ebc
Begin fixing internal node implementation [no ci]
acolytec3 541240c
move verkleCrypto to verkleNode constructor opts
acolytec3 76da96c
address feedback
acolytec3 52d50a8
WIP [no ci]
acolytec3 86dd9e9
Finish naive findpath implementation
acolytec3 189b112
Update internal node layout
acolytec3 60219ae
WIP [no ci]
acolytec3 bbd0e96
Partial implementation of put [no ci]
acolytec3 2301d2c
update verkle crypto [no ci]
acolytec3 dcdd778
Update this.root [no ci]
acolytec3 cf33476
Clean up db opt typing [no ci]
acolytec3 b9285e2
API clean/comments [no ci]
acolytec3 1dcc64d
fix logic bug for nonexistent path [no ci]
acolytec3 f42ac23
Describe logic for updating tree along path [no ci]
acolytec3 e4e257a
Update `put` to use `saveStack` [no ci]
acolytec3 1b1706d
WIP [no ci]
acolytec3 96f99aa
revise leafNode.create API [no ci]
acolytec3 e4bcb66
more updates to put/get [no ci]
acolytec3 27144c0
More wip [no ci]
acolytec3 7f4ead6
Fix bug in internalNode deserialization [no ci]
acolytec3 abc442d
Add more comments [no ci]
acolytec3 eeb2ec8
remove duplicative function [no ci]
acolytec3 e7e81bf
more wip [no ci]
acolytec3 991f4d2
Add code to produce a 2 layer tree [no ci]
acolytec3 58e5298
wip [no ci]
acolytec3 06350d0
Add some initial debug logs [no ci]
acolytec3 df22e18
More progress [no ci]
acolytec3 69267f7
more half-working fixes [no ci]
acolytec3 911c5b1
Merge remote-tracking branch 'origin/master' into verkle-trie-build-out
acolytec3 a38cc80
Fix typing issues and remove walk controller
acolytec3 ce343ae
Remove walk controller export [no ci]
acolytec3 9c7b214
Add new test to demonstrate putting values in the trie [no ci]
acolytec3 ae09bdb
Add comment
acolytec3 05bfebd
Remove obsolete references
acolytec3 0b4904c
lint
acolytec3 cd65a9a
Remove references to depth and unused API components
acolytec3 1ca879e
Merge branch 'master' into verkle-trie-build-out
acolytec3 3ab0700
Update packages/verkle/src/node/internalNode.ts
acolytec3 720ab09
Address feedback
acolytec3 b47fa49
fix tests
acolytec3 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,119 +1,89 @@ | ||
import { equalsBytes } from '@ethereumjs/util' | ||
|
||
import { POINT_IDENTITY } from '../util/crypto.js' | ||
import { type VerkleCrypto } from '@ethereumjs/util' | ||
|
||
import { BaseVerkleNode } from './baseVerkleNode.js' | ||
import { LeafNode } from './leafNode.js' | ||
import { NODE_WIDTH, VerkleNodeType } from './types.js' | ||
|
||
import type { VerkleNode, VerkleNodeOptions } from './types.js' | ||
import type { ChildNode, VerkleNodeOptions } from './types.js' | ||
|
||
export class InternalNode extends BaseVerkleNode<VerkleNodeType.Internal> { | ||
// Array of references to children nodes | ||
public children: Array<VerkleNode | null> | ||
public copyOnWrite: Record<string, Uint8Array> | ||
// Array of tuples of uncompressed commitments (i.e. 64 byte Uint8Arrays) to child nodes along with the path to that child (i.e. the partial stem) | ||
public children: Array<ChildNode> | ||
public type = VerkleNodeType.Internal | ||
|
||
/* TODO: options.children is not actually used here */ | ||
constructor(options: VerkleNodeOptions[VerkleNodeType.Internal]) { | ||
super(options) | ||
this.children = options.children ?? new Array(NODE_WIDTH).fill(null) | ||
this.copyOnWrite = options.copyOnWrite ?? {} | ||
} | ||
|
||
commit(): Uint8Array { | ||
throw new Error('Not implemented') | ||
} | ||
|
||
cowChild(_: number): void { | ||
// Not implemented yet | ||
this.children = | ||
options.children ?? | ||
new Array(256).fill({ | ||
commitment: options.verkleCrypto.zeroCommitment, | ||
path: new Uint8Array(), | ||
}) | ||
} | ||
|
||
setChild(index: number, child: VerkleNode) { | ||
this.children[index] = child | ||
// Updates the commitment value for a child node at the corresponding index | ||
setChild(childIndex: number, child: ChildNode) { | ||
// Get previous child commitment at `index` | ||
const oldChildReference = this.children[childIndex] | ||
// Updates the commitment to the child node at `index` | ||
this.children[childIndex] = { ...child } | ||
// Updates the overall node commitment based on the update to this child | ||
gabrocheleau marked this conversation as resolved.
Show resolved
Hide resolved
|
||
this.commitment = this.verkleCrypto.updateCommitment( | ||
this.commitment, | ||
childIndex, | ||
// The hashed child commitments are used when updating the internal node commitment | ||
this.verkleCrypto.hashCommitment(oldChildReference.commitment), | ||
this.verkleCrypto.hashCommitment(child.commitment) | ||
) | ||
} | ||
|
||
static fromRawNode(rawNode: Uint8Array[], depth: number): InternalNode { | ||
static fromRawNode(rawNode: Uint8Array[], verkleCrypto: VerkleCrypto): InternalNode { | ||
const nodeType = rawNode[0][0] | ||
if (nodeType !== VerkleNodeType.Internal) { | ||
throw new Error('Invalid node type') | ||
} | ||
|
||
// The length of the rawNode should be the # of children, + 2 for the node type and the commitment | ||
if (rawNode.length !== NODE_WIDTH + 2) { | ||
// The length of the rawNode should be the # of children * 2 (for commitments and paths) + 2 for the node type and the commitment | ||
if (rawNode.length !== NODE_WIDTH * 2 + 2) { | ||
throw new Error('Invalid node length') | ||
} | ||
|
||
// TODO: Generate Point from rawNode value | ||
const commitment = rawNode[rawNode.length - 1] | ||
const childrenCommitments = rawNode.slice(1, NODE_WIDTH + 1) | ||
const childrenPaths = rawNode.slice(NODE_WIDTH + 1, NODE_WIDTH * 2 + 1) | ||
|
||
return new InternalNode({ commitment, depth }) | ||
const children = childrenCommitments.map((commitment, idx) => { | ||
return { commitment, path: childrenPaths[idx] } | ||
}) | ||
return new InternalNode({ commitment, verkleCrypto, children }) | ||
} | ||
|
||
static create(depth: number): InternalNode { | ||
/** | ||
* Generates a new Internal node with default commitment | ||
*/ | ||
static create(verkleCrypto: VerkleCrypto): InternalNode { | ||
const node = new InternalNode({ | ||
commitment: POINT_IDENTITY, | ||
depth, | ||
commitment: verkleCrypto.zeroCommitment, | ||
verkleCrypto, | ||
}) | ||
|
||
return node | ||
} | ||
|
||
getChildren(index: number): VerkleNode | null { | ||
return this.children?.[index] ?? null | ||
} | ||
|
||
insert(key: Uint8Array, value: Uint8Array, resolver: () => void): void { | ||
const values = new Array<Uint8Array>(NODE_WIDTH) | ||
values[key[31]] = value | ||
this.insertStem(key.slice(0, 31), values, resolver) | ||
} | ||
|
||
insertStem(stem: Uint8Array, values: Uint8Array[], resolver: () => void): void { | ||
// Index of the child pointed by the next byte in the key | ||
const childIndex = stem[this.depth] | ||
|
||
const child = this.children[childIndex] | ||
|
||
if (child instanceof LeafNode) { | ||
this.cowChild(childIndex) | ||
if (equalsBytes(child.stem, stem)) { | ||
return child.insertMultiple(stem, values) | ||
} | ||
|
||
// A new branch node has to be inserted. Depending | ||
// on the next byte in both keys, a recursion into | ||
// the moved leaf node can occur. | ||
const nextByteInExistingKey = child.stem[this.depth + 1] | ||
const newBranch = InternalNode.create(this.depth + 1) | ||
newBranch.cowChild(nextByteInExistingKey) | ||
this.children[childIndex] = newBranch | ||
newBranch.children[nextByteInExistingKey] = child | ||
child.depth += 1 | ||
|
||
const nextByteInInsertedKey = stem[this.depth + 1] | ||
if (nextByteInInsertedKey === nextByteInExistingKey) { | ||
return newBranch.insertStem(stem, values, resolver) | ||
} | ||
|
||
// Next word differs, so this was the last level. | ||
// Insert it directly into its final slot. | ||
const leafNode = LeafNode.create(stem, values) | ||
|
||
leafNode.setDepth(this.depth + 2) | ||
newBranch.cowChild(nextByteInInsertedKey) | ||
newBranch.children[nextByteInInsertedKey] = leafNode | ||
} else if (child instanceof InternalNode) { | ||
this.cowChild(childIndex) | ||
return child.insertStem(stem, values, resolver) | ||
} else { | ||
throw new Error('Invalid node type') | ||
} | ||
/** | ||
* | ||
* @param index The index in the children array to retrieve the child node commitment from | ||
* @returns the uncompressed 64byte commitment for the child node at the `index` position in the children array | ||
*/ | ||
getChildren(index: number): ChildNode | null { | ||
return this.children[index] | ||
} | ||
|
||
// TODO: go-verkle also adds the bitlist to the raw format. | ||
raw(): Uint8Array[] { | ||
throw new Error('not implemented yet') | ||
// return [new Uint8Array([VerkleNodeType.Internal]), ...this.children, this.commitment] | ||
return [ | ||
new Uint8Array([VerkleNodeType.Internal]), | ||
...this.children.map((child) => child.commitment), | ||
...this.children.map((child) => child.path), | ||
this.commitment, | ||
] | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should now use the import from
verkle
inUtil
, just opened a related issue here ethereumjs/verkle-cryptography-wasm#54I would go as far and argue that we should also remove the
verkle-cryptography-wasm
dependency from this package as well and dependency inject, and so to have this wider strategic goal over the head that this should be replaceable and also here optimally a JS implementation being used.We then also automatically continue to evolve a generic interface around this and keep thinking about what's needed and what not (I e.g. still like the idea that we take the more hashing related parts out directly and move over to the pedersen/poseidon hash usage from Pauls libraries https://github.com/paulmillr/scure-starknet (if applicable) and with this slowly shrink down the surface of what we need to compile over into the WASM stuff.
Feels to me that there is still too much in.
Practical note: if depency injection feels a bit impractical for now for testing and the like we could also decide to do at a later stage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, but the main argument for direct dependency injection (so, this would mean: having a mandatory
crypto
constructor argument) is actually that we avoid having the same bundle problems again once/if we have Verkle added somewhere as a dependency.