Skip to content
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
merged 58 commits into from
Jun 21, 2024

Conversation

acolytec3
Copy link
Contributor

@acolytec3 acolytec3 commented May 15, 2024

Foundations for a full verkle trie implementation:

  1. Completely reworks the structure of the VerkleTrie class to remove unnecessary code that was borrowed from trie as well as go-verkle
  2. Simplifies the public surface of the InternalNode and LeafNode classes to make them easier to work with (e.g. commitments are updated internally when you update a value/child in the node)
  3. Updates the structure of the children array within InternalNode so that each element of children stores both the commitment for that child node as well as the path to that node (which is either a partial stem - if the child node is an Internal Node, or a full stem if the child node is a Leaf Node)
  4. Update findPath to use the new structure of the internal nodes described above so that walking the trie is merely a matter of retrieving the child node at each level of the path key provided as an input to findPath
  5. Removes depth as a property on the VerkleNode class (since no obvious use case)

Copy link
Contributor

@gabrocheleau gabrocheleau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had a little bit of time and quickly glanced through, nice work! left some comments on some of your questions/todos

electra.yaml Outdated
- el_type: ethereumjs
el_image: ethereumjs:local
cl_type: grandine
cl_image: ethpandaops/grandine:feature-electra
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't seem like that should belong to this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't. Accidentally included and will remove.

// 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) {
// TODO: Understand the intent of what cowChild is suppoded to do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cow stands for "copy-on-write". As far as I recall cowChild is used as a record to mark the children that have been modified, in order to stack the commitment updates at the end since that is way more efficient.


// TODO - Why is the leaf node set at depth + 2 instead of + 1)?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this is because the leaf is inserted in the position of the suffix level commitment. So we have:

depth n : internal node:
depth n+1: the extension level commitment
depth n+2: the suffix level commitment

See this picture for how that corresponds to the structure:
image

newBranch.children[nextByteInExistingKey] = child
child.depth += 1

const nextByteInInsertedKey = stem[this.depth + 1]
if (nextByteInInsertedKey === nextByteInExistingKey) {
return newBranch.insertStem(stem, values, resolver)
return newBranch.insertStem(stem, values, resolver, verkleCrypto)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return newBranch.insertStem(stem, values, resolver, verkleCrypto)
return newBranch.insertStem(stem, values, resolver)

@acolytec3 acolytec3 marked this pull request as ready for review June 19, 2024 18:59
Copy link

codecov bot commented Jun 19, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 87.69%. Comparing base (d24ca11) to head (0b4904c).
Report is 31 commits behind head on master.

Current head 0b4904c differs from pull request most recent head b47fa49

Please upload reports for the commit b47fa49 to get more accurate results.

Additional details and impacted files

Impacted file tree graph

Flag Coverage Δ
blockchain ?
common 94.38% <ø> (+0.09%) ⬆️
statemanager ?
tx 85.93% <ø> (?)
util 80.12% <100.00%> (-1.31%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

@acolytec3 acolytec3 mentioned this pull request Jun 20, 2024
16 tasks
@acolytec3
Copy link
Contributor Author

This is ready for final review.

static fromRawNode(rawNode: Uint8Array[], depth: number): InternalNode {
static fromRawNode(
rawNode: Uint8Array[],
depth: number,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove depth from this API?

static async create(
stem: Uint8Array,
values: Uint8Array[],
depth: number,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove depth here too?

}

static fromRawNode(rawNode: Uint8Array[], depth: number): LeafNode {
static fromRawNode(rawNode: Uint8Array[], depth: number, verkleCrypto: VerkleCrypto): LeafNode {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove depth here?

}
async findPath(key: Uint8Array): Promise<Path> {
this.DEBUG && this.debug(`Path (${key.length}): [${bytesToHex(key)}]`, ['FIND_PATH'])
// TODO: Decide if we should allow keys longer than 31 bytes (since a verkle stem can never be longer than that)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this Todo? We've already discussed this right?

// Calculate the index of the last matching byte in the key
const matchingKeyLength = matchingBytesLength(key, child.path)
const foundNode = equalsBytes(key, child.path)
if (foundNode || child.path.length >= key.length || decodedNode instanceof LeafNode) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the last condition necessary? If I'm thinking about this correctly, whenever the child path length is longer than the key, the found node would necessarily be a leaf node?

@holgerd77 holgerd77 changed the title Build out verkle trie processing Verkle Implementation: Build out Trie Processing Jun 21, 2024
Copy link
Member

@holgerd77 holgerd77 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't really dive deep into the code base this morning, so just some quick broader comment on how we want to integrate the crypto package.

But pretty cool to see this evolving so strongly, looking forward to go deeper! 🤩

@@ -2,24 +2,22 @@ import { RLP } from '@ethereumjs/rlp'

import { type VerkleNodeInterface, type VerkleNodeOptions, type VerkleNodeType } from './types.js'

import type { VerkleCrypto } from 'verkle-cryptography-wasm'
Copy link
Member

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 in Util, just opened a related issue here ethereumjs/verkle-cryptography-wasm#54

I 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.

Copy link
Member

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.

Co-authored-by: Gabriel Rocheleau <contact@rockwaterweb.com>
Comment on lines 218 to 223
async put(_key: Uint8Array, _value: Uint8Array): Promise<void> {
throw new Error('not implemented')
// verifyKeyLength(key)
// const stem = key.slice(0, 31)
// this.DEBUG && this.debug(`Key: ${bytesToHex(key)}`, ['PUT'])
// this.DEBUG && this.debug(`Value: ${bytesToHex(value)}`, ['PUT'])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big fan of having a lot of commented out code merge into the master branch. Could we take note of this code peripherally and just re-add it in the follow-up PR? Not a major deal as this is an experimental package though

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, have stashed it locally

gabrocheleau
gabrocheleau previously approved these changes Jun 21, 2024
@acolytec3 acolytec3 merged commit 05552af into master Jun 21, 2024
33 of 34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants