Add XOR Hashes to future versions + Fix RawIterate #85
Conversation
| go func(mod string) { | ||
| defer close(dataCh) | ||
|
|
||
| _, err := db.RawIterate(mod, func(key, value []byte, ver int64) bool { | ||
| // Only feed data whose version is in [beginBlock..endBlock] | ||
| if ver >= beginBlock && ver <= endBlock { | ||
| dataCh <- types.RawSnapshotNode{ | ||
| StoreKey: mod, | ||
| Key: key, | ||
| Value: value, | ||
| Version: ver, | ||
| } | ||
| } | ||
| // false => keep iterating | ||
| return false | ||
| }) | ||
| if err != nil { | ||
| // In your environment, you might want to handle errors differently: | ||
| panic(fmt.Errorf("error scanning module %s: %w", mod, err)) | ||
| } | ||
| }(moduleName) |
Check notice
Code scanning / CodeQL
Spawning a Go routine Note
| } | ||
| // Push all the data to its corresponding channel based on version | ||
| for data := range x.DataCh { | ||
| index := data.Version / x.NumBlocksPerWorker |
There was a problem hiding this comment.
may panic when index exceeds size of allChannels?
There was a problem hiding this comment.
Fyi @blindchaser this was taken from the sei-chain implementation. I'm going to leave it as is for now. Can optimize this after but I wanted to keep it as the original implementation: https://github.com/sei-protocol/sei-chain/blob/main/tools/hash_verification/hasher/xor_hasher.go
| } | ||
|
|
||
| // HashSingle computes the hash of a single data element. | ||
| func (x XorHashCalculator) HashSingle(data []byte) []byte { |
There was a problem hiding this comment.
should we use pointer receiver func (x *XorHashCalculator) to match var _ HashCalculator = (*XorHashCalculator)(nil)? also it saves space
There was a problem hiding this comment.
Fyi @blindchaser this was taken from the sei-chain implementation. I'm going to leave it as is for now. Can optimize this after but I wanted to keep it as the original implementation: https://github.com/sei-protocol/sei-chain/blob/main/tools/hash_verification/hasher/xor_hasher.go
| "acc", | ||
| "bank", | ||
| "capability", | ||
| "distribution", |
There was a problem hiding this comment.
do we need to include dex for historical purposes? since the module used to exist, doing a backfill for the XOR hash should include that, right?
There was a problem hiding this comment.
Good point, I’ll add it in
There was a problem hiding this comment.
Fyi I'm not going to add this in @udpatil , even for the separate tool we used for backfilling historical hashes while the node is offline https://github.com/sei-protocol/sei-chain/blob/main/tools/hash_verification/pebbledb/scanner.go doesn't include it, we only really need to verify inconsistencies in the existing modules
| return false | ||
| }) | ||
| if err != nil { | ||
| panic(fmt.Errorf("error scanning module %s: %w", mod, err)) |
There was a problem hiding this comment.
@Kbhat1 if we include dex for historical data, do we need to handle this more gracefully to be able to also process ranges that no longer have the dex store? I don't recall what happens to the underlying module store, whether it will load and have no keys to rawIterate or whether it will just fail?
There was a problem hiding this comment.
I'll confirm this in a test, I think we should be okay it shouldn't throw an error but will confirm. Good call out
There was a problem hiding this comment.
dex shouldn't matter since util.Modules will exclude dex anyway, so we won't compute hash for dex module
|
@udpatil @blindchaser could you both take a look again? Made some fixes, addressed comments, passing and verified on node hashes being written. Let me know if any questions. |
| return false | ||
| }) | ||
| if err != nil { | ||
| panic(fmt.Errorf("error scanning module %s: %w", mod, err)) |
There was a problem hiding this comment.
dex shouldn't matter since util.Modules will exclude dex anyway, so we won't compute hash for dex module
|
@yzang2019 could you take a look again when possible? All comments addressed, will merge soon |
|
|
||
| if db.config.HashRange > 0 { | ||
| go func(ver int64) { | ||
| if err := db.computeMissingRanges(ver); err != nil { |
There was a problem hiding this comment.
Is it possible to only run this when previous one finishes?
There was a problem hiding this comment.
Fyi mutex added to ensure this
|
@yzang2019 lmk if you can take a look again |
| go func(ver int64) { | ||
| // Try to acquire lock, return immediately if already locked | ||
| if !db.hashComputationMu.TryLock() { | ||
| return | ||
| } | ||
| defer db.hashComputationMu.Unlock() | ||
|
|
||
| if err := db.computeMissingRanges(ver); err != nil { | ||
| fmt.Printf("maybeComputeMissingRanges error: %v\n", err) | ||
| } | ||
| }(version) |
Check notice
Code scanning / CodeQL
Spawning a Go routine Note
| go func(index int, data chan types.RawSnapshotNode) { | ||
| defer wg.Done() | ||
| var hashResult []byte | ||
| for item := range data { | ||
| entryHash := x.HashSingle(Serialize(item)) | ||
| if hashResult == nil { | ||
| hashResult = entryHash | ||
| } else { | ||
| hashResult = x.HashTwo(hashResult, entryHash) | ||
| } | ||
| } | ||
| allHashes[index] = hashResult | ||
| }(i, subsetChan) |
Check notice
Code scanning / CodeQL
Spawning a Go routine Note
Describe your changes and provide context
HashRangeblocks, kick off goroutine that will go back to the last time a hash was saved, compute hashes for all the key/vals inHashRangechunks, save it to pebbles/k:)Testing performed to validate your change