Open TimDaub opened 1 year ago
Update, I now forked the WalkController to pass in a level variable. Not sure how useful you deem this to the main library: https://github.com/attestate/kiwistand/commit/ecdad2b2d52d7e0200e0371322fd76d63f056e0b, but I could send a PR for that
Hi there, we are in the process of preparing (breaking) releases for the monorepo atm which is time consuming, so I don't think we'll have the ressources to judge on this extensive proposal short-term (sorry for that).
are you expecting breaking changes on the trie library interface? I‘m using it quite a bit, also internal structures and it‘d be quite bad if it was broken. Can I get in touch with the maintainer in case?
btw: no worries, I forked the walkcontroller so it‘s all good
are you expecting breaking changes on the trie library interface? I‘m using it quite a bit, also internal structures and it‘d be quite bad if it was broken. Can I get in touch with the maintainer in case?
btw: no worries, I forked the walkcontroller so it‘s all good
We do not have a specific maintainer for our trie library (actually: for all our libraries). Yes, these releases will change the API for all our libraries to some extend, if you are interested in a change summary see https://github.com/ethereumjs/ethereumjs-monorepo/pull/2832.
Yes, this will need some upgrade work if you plan to upgrade. But that's the way of libraries I guess, we want to evolve them, but also do not make it too hard for users to upgrade? Sorry, not possible to solve this target conflict. 😋
You should be able to stay on the current version for some time if you do not want to have the work right now, especially the trie library is not change-intense in terms of EIP or API changes/additions.
@TimDaub --
The "optimizations" you mentioned kind of obscure my ability to conceive of the Ethereum Trie in "Levels" like an ordinary merkle tree.
The "Patricia" structure is condensed prior to the Trie hashing, which is how we end up with ExtensionNodes, and why some LeafNodes have more "nibbles" than others.
I find some contradictions if I try to think about "Level 10" of such a structure, since some nodes will hold longer sections (more nibbles) of the key path.
Is Level 10:
Either way, 10 levels down one path will look very different than 10 levels down another path.
But we could also make it based on nibbles. Tbh, I was surprised that there isn‘t a good way to descend as part of the library itself.
To use the ethereumjs/trie library for set reconciliation, we go breadth-first, level by level, take those nodes as an array and then send them to remote node for comparing their hashes; we implement a function descend as follows
https://github.com/attestate/kiwistand/blob/e2c8562fc202a7b5450a1d28e9774b52ca512409/src/store.mjs#L162-L220
For that, we keep track of a decrementing value we call level until it reaches zero, in a naive attempt to figure out how far in the trie we can traverse into. Note that the key length of a node itself cannot be used as a substitute for this, as a PMT in Ethereum features several optimizations e.g. ExtensionNodes, which I don't know how to e.g. handle in terms of their key length.
While recently coming across this while investigating a synchronization bug, I noticed that the level variable won't decrement often enough if the trie has a big branching factor, as this unit test shows.
So I've been playing around a bit today and I'm noticing that it is pretty difficult to figure out a nice way to keep track of the tries current level within onFound. E.g. allChildren, walkTrie and onFound don't permit additional data to be passed in, but then how is one supposed to e.g. keep track how often allChildren has been called already. I've actually played several options through also with gpt4 today and none of them really seemed elegant to me, for why I now opened this issue to shed some light on the problem. I think ideally, I could just get all nodes of a level from the walkController in the native implementation.
However, I do feel like using JS's https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy Proxy could actually help keeping track and achieving what I want. We could make onFound accept the level variable, which is then internally used to keep track of the initial level. Furthermore, every node's allChildren could be manipulated with the Proxy pattern where ... but no essentially not because the implementation of allChildren is too complex to proxy any behavior in multiple parts of the module
So conceptually, the only way I can think of keeping track of the level externally would be through a pretty weird javascript object that keeps track of all paths I'm traversing down and maintaining a level variable (as opposed to passing this through in the invocation scope), or implementing a sort-of walkController myself.
In fact, I have actually attempted to build my own breadth first trie traversal but only with non-successful results (slight modification from the above mentioned (and buggy) function descend):
This is mainly because it then would really complicate my self-implemented hashing function with an alternative representation of some of the trie nodes
Besides, I've found out in this process that nodeRef does not always returns a Buffer, which represents the hash of a node, but sometimes it also returns the above special case for handling trie nodes in this internal representation.
So a couple more thoughts here to conclude this: