-
Notifications
You must be signed in to change notification settings - Fork 14
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
Convert rvgo's memory implementation to radix trie #83
base: master
Are you sure you want to change the base?
Conversation
rvgo/fast/radix.go
Outdated
// InvalidateNode invalidates the hash cache along the path to the specified address. | ||
InvalidateNode(addr uint64) | ||
// GenerateProof generates the Merkle proof for the given address. | ||
GenerateProof(addr uint64) [][32]byte |
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.
from @protolambda :
You could add a slice as argument, to append the result to, and then return the updated slice header. Then you can allocate a slice with the capacity of the expected proof size once, and write to that in each proof level, to prevent allocations.
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.
I modified the function so that GenerateProof takes a slice as argument, and each radix node fills in the proof slice at the correct index. The proof slice is only allocated once in the initial generateProof call (make([][32]byte, 60)
) to reduce the allocations: c5a040b
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #83 +/- ##
==========================================
+ Coverage 72.30% 73.17% +0.86%
==========================================
Files 16 17 +1
Lines 2723 2923 +200
==========================================
+ Hits 1969 2139 +170
- Misses 670 689 +19
- Partials 84 95 +11 ☔ View full report in Codecov by Sentry. |
rvgo/fast/memory_test.go
Outdated
largeDataset = 1_000_000 | ||
) | ||
|
||
func BenchmarkMemoryOperations(b *testing.B) { |
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.
Adding a new file for benchmarking would be good. Also, why these methods are implemented as test? Do they validate something?
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.
I moved the benchmarking to a new file: memory_benchmarking_test.go
.
I'm not sure if I understand why you mean by implemented as test
. If you're talking about testing.B
, it's because the benchmarking capabilities are offered under testing package. Also, there is no validation in the benchmarking test, we only measure the function calls themselves.
rvgo/fast/memory_test.go
Outdated
data := make([]byte, 1) | ||
b.ResetTimer() | ||
for i := 0; i < b.N; i++ { | ||
addr := mathrand.Uint64() % 1000000 // Confined to a smaller range |
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.
We can use mathrand.Intn
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.
Nice, thanks!
rvgo/fast/radix.go
Outdated
if p, ok := m.pages[pageIndex]; ok { | ||
return p.GenerateProof(addr) // Generate proof from the page. | ||
} else { | ||
return zeroHashRange(0, 8) // Return zero hashes if the page does not exist. |
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.
May I ask why is zeroHashRange(0, 8)
?
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.
It's because the number of proof for a page is 8, where 0 is the leaf page data and 7 is the page's merkle root. I've also added this as a comment.
rvgo/fast/radix.go
Outdated
} | ||
} | ||
|
||
if depth > 16 { |
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.
what about the range between 8 < depth <= 16
?
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.
Sorry, the correct code should be depth > 9
.
depth 0~7: the intermediate merkle hashes.
depth 8: the leaf nodes pointing to the children nodes
depth 9~: invalid gindex.
rvgo/fast/radix.go
Outdated
// Build the radix trie path to the new page, creating nodes as necessary. | ||
radixLevel1 := m.radix | ||
if (*radixLevel1).Children[branchPaths[0]] == nil { | ||
node := &SmallRadixNode[L3]{Depth: 4} |
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.
Why are we starting at L3, not L2 or L1?
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.
The L1 is the radix root, and it's type is SmallRadixNode[L2]
. This [L2]
points to the children node's type.
When we allocate the children of a L1, the L2's children type is SmallRadixNode[L3]
, where the [L3]
is the L2's children type.
So, it seems like we're skipping L2, but the SmallRadixNode[L3]
itself is the alias of L2.
rvgo/fast/radix.go
Outdated
|
||
radixLevel2 := (*radixLevel1).Children[branchPaths[0]] | ||
if (*radixLevel2).Children[branchPaths[1]] == nil { | ||
node := &SmallRadixNode[L4]{Depth: 8} |
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.
These Depth value can be evaluated using branchFactors: [10]uint64{4, 4, 4, 4, 4, 4, 4, 8, 8, 8},
rvgo/fast/memory_test.go
Outdated
require.Equal(t, r1, r2, "expecting manual page combination to match subtree merkle func") | ||
}) | ||
|
||
//t.Run("random few pages", func(t *testing.T) { |
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.
Why are this test commented out?
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.
I forgot to uncomment & fix the test after I've changed the implementation. I uncommented it and fixed the code :)
c5a040b
to
f263b31
Compare
Description
Detailed design doc is at: https://www.notion.so/op-tip/Asterisc-Memory-Optimization-Design-Doc-Draft-b64a61f0c844403d99b59b120cc3222b?pvs=4