fix: state listener could observe discarded writes (#13459)
* fix: state listener could observe uncommitted writes Closes: #13457 don't pass listeners to nested cached store, only the most inner layer's cache writes should be observed. * Update CHANGELOG.md * add unit test * rename Co-authored-by: Marko <marbar3778@yahoo.com>
This commit is contained in:
parent
90bd3161a1
commit
bb54c597de
@ -166,6 +166,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
* (x/gov) [#13051](https://github.com/cosmos/cosmos-sdk/pull/13051) In SubmitPropsal, when a legacy msg fails it's handler call, wrap the error as ErrInvalidProposalContent (instead of ErrNoProposalHandlerExists).
|
||||
* (x/gov) [#13045](https://github.com/cosmos/cosmos-sdk/pull/13045) Fix gov migrations for v3(0.46).
|
||||
* (snapshot) [#13400](https://github.com/cosmos/cosmos-sdk/pull/13400) Fix snapshot checksum issue in golang 1.19.
|
||||
* (store) [#13459](https://github.com/cosmos/cosmos-sdk/pull/13459) Don't let state listener observe the uncommitted writes.
|
||||
|
||||
### Deprecated
|
||||
|
||||
|
||||
@ -45,6 +45,9 @@ func NewFromKVStore(
|
||||
keys map[string]types.StoreKey, traceWriter io.Writer, traceContext types.TraceContext,
|
||||
listeners map[types.StoreKey][]types.WriteListener,
|
||||
) Store {
|
||||
if listeners == nil {
|
||||
listeners = make(map[types.StoreKey][]types.WriteListener)
|
||||
}
|
||||
cms := Store{
|
||||
db: cachekv.NewStore(store),
|
||||
stores: make(map[types.StoreKey]types.CacheWrap, len(stores)),
|
||||
@ -86,7 +89,8 @@ func newCacheMultiStoreFromCMS(cms Store) Store {
|
||||
stores[k] = v
|
||||
}
|
||||
|
||||
return NewFromKVStore(cms.db, stores, nil, cms.traceWriter, cms.traceContext, cms.listeners)
|
||||
// don't pass listeners to nested cache store.
|
||||
return NewFromKVStore(cms.db, stores, nil, cms.traceWriter, cms.traceContext, nil)
|
||||
}
|
||||
|
||||
// SetTracer sets the tracer for the MultiStore that the underlying
|
||||
|
||||
@ -912,3 +912,52 @@ func hashStores(stores map[types.StoreKey]types.CommitKVStore) []byte {
|
||||
}
|
||||
return sdkmaps.HashFromMap(m)
|
||||
}
|
||||
|
||||
type MockListener struct {
|
||||
stateCache []types.StoreKVPair
|
||||
}
|
||||
|
||||
func (tl *MockListener) OnWrite(storeKey types.StoreKey, key []byte, value []byte, delete bool) error {
|
||||
tl.stateCache = append(tl.stateCache, types.StoreKVPair{
|
||||
StoreKey: storeKey.Name(),
|
||||
Key: key,
|
||||
Value: value,
|
||||
Delete: delete,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestStateListeners(t *testing.T) {
|
||||
var db dbm.DB = dbm.NewMemDB()
|
||||
ms := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing))
|
||||
|
||||
listener := &MockListener{}
|
||||
ms.AddListeners(testStoreKey1, []types.WriteListener{listener})
|
||||
|
||||
require.NoError(t, ms.LoadLatestVersion())
|
||||
cacheMulti := ms.CacheMultiStore()
|
||||
|
||||
store1 := cacheMulti.GetKVStore(testStoreKey1)
|
||||
store1.Set([]byte{1}, []byte{1})
|
||||
require.Empty(t, listener.stateCache)
|
||||
|
||||
// writes are observed when cache store commit.
|
||||
cacheMulti.Write()
|
||||
require.Equal(t, 1, len(listener.stateCache))
|
||||
|
||||
// test nested cache store
|
||||
listener.stateCache = []types.StoreKVPair{}
|
||||
nested := cacheMulti.CacheMultiStore()
|
||||
|
||||
store1 = nested.GetKVStore(testStoreKey1)
|
||||
store1.Set([]byte{1}, []byte{1})
|
||||
require.Empty(t, listener.stateCache)
|
||||
|
||||
// writes are not observed when nested cache store commit
|
||||
nested.Write()
|
||||
require.Empty(t, listener.stateCache)
|
||||
|
||||
// writes are observed when inner cache store commit
|
||||
cacheMulti.Write()
|
||||
require.Equal(t, 1, len(listener.stateCache))
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user