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

feat(store): add working hash #15712

Merged
merged 19 commits into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions store/iavl/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,16 @@ func (st *Store) Commit() types.CommitID {
}
}

// WorkingHash returns the hash of the current working tree.
func (st *Store) WorkingHash() []byte {
hash, err := st.tree.WorkingHash()
if err != nil {
panic(fmt.Errorf("failed to retrieve working hash: %w", err))
}

return hash
}

// LastCommitID implements Committer.
func (st *Store) LastCommitID() types.CommitID {
hash, err := st.tree.Hash()
Expand Down
5 changes: 5 additions & 0 deletions store/iavl/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type (
DeleteVersions(versions ...int64) error
Version() int64
Hash() ([]byte, error)
WorkingHash() ([]byte, error)
VersionExists(version int64) bool
GetVersioned(key []byte, version int64) ([]byte, error)
GetImmutable(version int64) (*iavl.ImmutableTree, error)
Expand Down Expand Up @@ -101,3 +102,7 @@ func (it *immutableTree) LoadVersionForOverwriting(targetVersion int64) (int64,
func (it *immutableTree) LazyLoadVersionForOverwriting(targetVersion int64) (int64, error) {
panic("cannot call 'LazyLoadVersionForOverwriting' on an immutable IAVL tree")
}

func (it *immutableTree) WorkingHash() ([]byte, error) {
panic("cannot call 'WorkingHash' on an immutable IAVL tree")
}
2 changes: 2 additions & 0 deletions store/mem/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,5 @@ func (s *Store) GetPruning() pruningtypes.PruningOptions {
}

func (s Store) LastCommitID() (id types.CommitID) { return }

func (s Store) WorkingHash() (hash []byte) { return }
9 changes: 9 additions & 0 deletions store/rootmulti/dbadapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import (

var commithash = []byte("FAKE_HASH")

var (
_ types.KVStore = (*commitDBStoreAdapter)(nil)
_ types.Committer = (*commitDBStoreAdapter)(nil)
)

//----------------------------------------
// commitDBStoreWrapper should only be used for simulation/debugging,
// as it doesn't compute any commit hash, and it cannot load older state.
Expand All @@ -32,6 +37,10 @@ func (cdsa commitDBStoreAdapter) LastCommitID() types.CommitID {
}
}

func (cdsa commitDBStoreAdapter) WorkingHash() []byte {
return commithash
}

func (cdsa commitDBStoreAdapter) SetPruning(_ pruningtypes.PruningOptions) {}

// GetPruning is a no-op as pruning options cannot be directly set on this store.
Expand Down
30 changes: 30 additions & 0 deletions store/rootmulti/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,36 @@ func (rs *Store) Commit() types.CommitID {
}
}

// WorkingHash returns the current hash of the store.
// it will be used to get the current app hash before commit.
func (rs *Store) WorkingHash() []byte {
storeInfos := make([]types.StoreInfo, 0, len(rs.stores))
storeKeys := keysFromStoreKeyMap(rs.stores)

for _, key := range storeKeys {
store := rs.stores[key]

if store.GetStoreType() != types.StoreTypeIAVL {
continue
}

if !rs.removalMap[key] {
si := types.StoreInfo{}
si.Name = key.Name()
si.CommitId = types.CommitID{
Hash: store.WorkingHash(),
}
cool-develope marked this conversation as resolved.
Show resolved Hide resolved
storeInfos = append(storeInfos, si)
}
}

sort.SliceStable(storeInfos, func(i, j int) bool {
return strings.Compare(storeInfos[i].Name, storeInfos[j].Name) < 0
cool-develope marked this conversation as resolved.
Show resolved Hide resolved
})

return types.CommitInfo{StoreInfos: storeInfos}.Hash()
}

// CacheWrap implements CacheWrapper/Store/CommitStore.
func (rs *Store) CacheWrap() types.CacheWrap {
return rs.CacheMultiStore().(types.CacheWrap)
Expand Down
10 changes: 10 additions & 0 deletions store/rootmulti/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,16 @@ func TestHashStableWithEmptyCommit(t *testing.T) {
store1 := ms.GetStoreByName("store1").(types.KVStore)
store1.Set(k, v)

workingHash := ms.WorkingHash()
cID := ms.Commit()
require.Equal(t, int64(1), cID.Version)
hash := cID.Hash
require.Equal(t, workingHash, hash)

// make an empty commit, it should update version, but not affect hash
workingHash = ms.WorkingHash()
cID = ms.Commit()
require.Equal(t, workingHash, cID.Hash)
require.Equal(t, int64(2), cID.Version)
require.Equal(t, hash, cID.Hash)
}
Expand All @@ -148,7 +152,9 @@ func TestMultistoreCommitLoad(t *testing.T) {
// Make a few commits and check them.
nCommits := int64(3)
for i := int64(0); i < nCommits; i++ {
workingHash := store.WorkingHash()
commitID = store.Commit()
require.Equal(t, workingHash, commitID.Hash)
expectedCommitID := getExpectedCommitID(store, i+1)
checkStore(t, store, expectedCommitID, commitID)
}
Expand All @@ -161,7 +167,9 @@ func TestMultistoreCommitLoad(t *testing.T) {
checkStore(t, store, commitID, commitID)

// Commit and check version.
workingHash := store.WorkingHash()
commitID = store.Commit()
require.Equal(t, workingHash, commitID.Hash)
expectedCommitID := getExpectedCommitID(store, nCommits+1)
checkStore(t, store, expectedCommitID, commitID)

Expand Down Expand Up @@ -200,7 +208,9 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) {
require.Nil(t, s4)

// do one commit
workingHash := store.WorkingHash()
commitID := store.Commit()
require.Equal(t, workingHash, commitID.Hash)
expectedCommitID := getExpectedCommitID(store, 1)
checkStore(t, store, expectedCommitID, commitID)

Expand Down
4 changes: 4 additions & 0 deletions store/transient/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ func (ts *Store) LastCommitID() (id types.CommitID) {
return
}

func (ts *Store) WorkingHash() (hash []byte) {
cool-develope marked this conversation as resolved.
Show resolved Hide resolved
return
}
cool-develope marked this conversation as resolved.
Show resolved Hide resolved

// Implements Store.
func (ts *Store) GetStoreType() types.StoreType {
return types.StoreTypeTransient
Expand Down
3 changes: 3 additions & 0 deletions store/types/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ type Committer interface {
Commit() CommitID
LastCommitID() CommitID

// WorkingHash returns the hash of the KVStore's state before commit.
WorkingHash() []byte
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved

SetPruning(pruningtypes.PruningOptions)
GetPruning() pruningtypes.PruningOptions
}
Expand Down