-
Notifications
You must be signed in to change notification settings - Fork 717
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
Trie: add partialPath parameter to trie.findPath() #3305
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files
Flags with carried forward coverage won't be shown. Click here to find out more. |
Hey there, Some ideas and thoughts, definitely not something to absolutely follow if you have got some different picture in mind: 1. Applied scenarioMaybe it really does make sense to take this "Build up tx trie from scratch through a batch() operation" as a concrete first application scenario with a cache. At least this would have the two benefits that a) the cache would not grow that big that one would need to worry about cache management, so like deleting cache entries again from a certain point (at least I would guess so, so with roughly up to 1000 txs (aka, keys to add to the trie) for a whole block, that should not let memory completely explode). Second benefit b) would be that we would already have this benchmark I had done in the issue as a solid comparison tool to see if this works from a performance PoV (so benchmark would be to re-run a certain block and measure tx trie generation time with and without cache and see how things go 🙂). This would I guess mean to:
So going this route, also applying the idea from 2. with the new parameter and only doing this in Again, nevertheless just an option to start here, only citing some pros and cons. 2. Cache StructureOne big question I had was about the cache structure. How (and how deep) would we save path keys so that things (paths) are optimally retrievable but we are also not producing a lot of redundancy and cache bloat. So going back to the example I had on the issue, how would one assure for I think I now have at least one solution which I would think has some elegancy, also a drawback. So in a first round we could set just a maximum how deep paths should be stored (let's say 4 nibbles here, so When storing the path for 8 -> Last node in the stored path (so: for 8) When then a matching path in the cache for "8202fd" -> No match If there is a match, the cache structure would then ensure by design that one could read the full path by reading the respective last nodes from "8202f", "8202", "820",... and then putting things together. Does this make sense? Then we would have a very flexible structure where the full possible path is leveraged (eventually capped by a maximum). The downside of this structure is (I guess) that selective cache deletes are not possible (so: to delete But I guess at least for this unbounded scenario (tx trie, batch()) this might nevertheless be a well-fitting structure, since - after the batch() operation - the cache can (or: should, I guess) - be deleted anyhow. Since the whole thing from above is structurally so super simple, it might even make sense to take this variant now but to expand on this later on with a different cache structure for a different use case. My (very long 😂) two cents. 🙂 |
(have done additional edits to the previous post, please read on the website) |
Yes, what you are saying makes sense. |
Updated this via UI |
Yes, I think we can do that. 🙂 Will merge! 👍 |
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.
LGTM
addresses optimizations described in #3293
In many cases,
trie.findPath
may be called on a key when part of the path is already known. A function with multiple lookups will traverse the entire trie for each individual lookup. In many cases, this can be optimized through a caching of paths already traversed, which could be fed to the nextfindPath
call. We could skip several lookups on each call this way, streamlining processes with multiple lookups, and making some of the more complex state trie operations much more efficient.This solution adds an optional parameter called partialPath to
trie.findPath()
partialPath.stack
is a list ofTrieNodes
, identical to a slice of the target node's path.If a
partialPath
is provided,findPath
will consume the correct nibbles from the nodes in thepartialProof
, and build the return stack starting with the provided nodes:findPath
will then begin the trie walk from the last node in the partial path, instead of the trie root which is the default starting place:From there,
findPath
proceeds normally, and returns an identical result.--
To proove that the process worked, I temporarily added logging to
findPath
which counted the number of lookups occuring during each call. This example shows how the number of lookups decreases whenfindPath
is provided a partialPath of different lengths.