Skip to content

Commit ec09eae

Browse files
authored
fix: app-hash mismatch if upgrade migration commit is interrupted (backport #13530) (#13627)
1 parent afdf06a commit ec09eae

File tree

3 files changed

+83
-1
lines changed

3 files changed

+83
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
4444
## Bug Fixes
4545

4646
* (x/auth/tx) [#12474](https://github.com/cosmos/cosmos-sdk/pull/12474) Remove condition in GetTxsEvent that disallowed multiple equal signs, which would break event queries with base64 strings (i.e. query by signature).
47+
* (store) [#13530](https://github.com/cosmos/cosmos-sdk/pull/13530) Fix app-hash mismatch if upgrade migration commit is interrupted.
4748

4849
## [v0.46.3](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.46.3) - 2022-10-20
4950

store/rootmulti/store.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1013,8 +1013,16 @@ func commitStores(version int64, storeMap map[types.StoreKey]types.CommitKVStore
10131013
storeInfos := make([]types.StoreInfo, 0, len(storeMap))
10141014

10151015
for key, store := range storeMap {
1016-
commitID := store.Commit()
1016+
last := store.LastCommitID()
10171017

1018+
// If a commit event execution is interrupted, a new iavl store's version will be larger than the rootmulti's metadata, when the block is replayed, we should avoid committing that iavl store again.
1019+
var commitID types.CommitID
1020+
if last.Version >= version {
1021+
last.Version = version
1022+
commitID = last
1023+
} else {
1024+
commitID = store.Commit()
1025+
}
10181026
if store.GetStoreType() == types.StoreTypeTransient {
10191027
continue
10201028
}

store/rootmulti/store_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -961,3 +961,76 @@ func TestStateListeners(t *testing.T) {
961961
cacheMulti.Write()
962962
require.Equal(t, 1, len(listener.stateCache))
963963
}
964+
965+
type commitKVStoreStub struct {
966+
types.CommitKVStore
967+
Committed int
968+
}
969+
970+
func (stub *commitKVStoreStub) Commit() types.CommitID {
971+
commitID := stub.CommitKVStore.Commit()
972+
stub.Committed += 1
973+
return commitID
974+
}
975+
976+
func prepareStoreMap() map[types.StoreKey]types.CommitKVStore {
977+
var db dbm.DB = dbm.NewMemDB()
978+
store := NewStore(db, log.NewNopLogger())
979+
store.MountStoreWithDB(types.NewKVStoreKey("iavl1"), types.StoreTypeIAVL, nil)
980+
store.MountStoreWithDB(types.NewKVStoreKey("iavl2"), types.StoreTypeIAVL, nil)
981+
store.MountStoreWithDB(types.NewTransientStoreKey("trans1"), types.StoreTypeTransient, nil)
982+
store.LoadLatestVersion()
983+
return map[types.StoreKey]types.CommitKVStore{
984+
testStoreKey1: &commitKVStoreStub{
985+
CommitKVStore: store.GetStoreByName("iavl1").(types.CommitKVStore),
986+
},
987+
testStoreKey2: &commitKVStoreStub{
988+
CommitKVStore: store.GetStoreByName("iavl2").(types.CommitKVStore),
989+
},
990+
testStoreKey3: &commitKVStoreStub{
991+
CommitKVStore: store.GetStoreByName("trans1").(types.CommitKVStore),
992+
},
993+
}
994+
}
995+
996+
func TestCommitStores(t *testing.T) {
997+
testCases := []struct {
998+
name string
999+
committed int
1000+
exptectCommit int
1001+
}{
1002+
{
1003+
"when upgrade not get interrupted",
1004+
0,
1005+
1,
1006+
},
1007+
{
1008+
"when upgrade get interrupted once",
1009+
1,
1010+
0,
1011+
},
1012+
{
1013+
"when upgrade get interrupted twice",
1014+
2,
1015+
0,
1016+
},
1017+
}
1018+
for _, tc := range testCases {
1019+
t.Run(tc.name, func(t *testing.T) {
1020+
storeMap := prepareStoreMap()
1021+
store := storeMap[testStoreKey1].(*commitKVStoreStub)
1022+
for i := tc.committed; i > 0; i-- {
1023+
store.Commit()
1024+
}
1025+
store.Committed = 0
1026+
var version int64 = 1
1027+
removalMap := map[types.StoreKey]bool{}
1028+
res := commitStores(version, storeMap, removalMap)
1029+
for _, s := range res.StoreInfos {
1030+
require.Equal(t, version, s.CommitId.Version)
1031+
}
1032+
require.Equal(t, version, res.Version)
1033+
require.Equal(t, tc.exptectCommit, store.Committed)
1034+
})
1035+
}
1036+
}

0 commit comments

Comments
 (0)