Skip to content

Commit 5f2df19

Browse files
committed
avoid data race on cache multi store lazy store loading
1 parent 52cd5f3 commit 5f2df19

File tree

4 files changed

+19
-5
lines changed

4 files changed

+19
-5
lines changed

store/cachemulti/store.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"io"
66
"maps"
7+
"sync"
78

89
"cosmossdk.io/store/tracekv"
910
"cosmossdk.io/store/types"
@@ -21,7 +22,10 @@ const storeNameCtxKey = "store_name"
2122
// NOTE: a Store (and MultiStores in general) should never expose the
2223
// keys for the substores.
2324
type Store struct {
24-
stores map[types.StoreKey]types.CacheWrap
25+
// storesMut ensures concurrent callers (e.g. ExportGenesisForModules goroutines)
26+
// don't race when lazily creating substores.
27+
storesMut *sync.RWMutex
28+
stores map[types.StoreKey]types.CacheWrap
2529

2630
traceWriter io.Writer
2731
traceContext types.TraceContext
@@ -38,6 +42,7 @@ func NewFromKVStore(
3842
traceWriter io.Writer, traceContext types.TraceContext,
3943
) Store {
4044
cms := Store{
45+
storesMut: &sync.RWMutex{},
4146
stores: make(map[types.StoreKey]types.CacheWrap, len(stores)),
4247
traceWriter: traceWriter,
4348
traceContext: traceContext,
@@ -66,6 +71,7 @@ func NewFromParent(
6671
traceWriter io.Writer, traceContext types.TraceContext,
6772
) Store {
6873
return Store{
74+
storesMut: &sync.RWMutex{},
6975
stores: make(map[types.StoreKey]types.CacheWrap),
7076
traceWriter: traceWriter,
7177
traceContext: traceContext,
@@ -126,7 +132,12 @@ func (cms Store) GetStoreType() types.StoreType {
126132

127133
// Write calls Write on each underlying store.
128134
func (cms Store) Write() {
129-
for _, store := range cms.stores {
135+
cms.storesMut.RLock()
136+
stores := make(map[types.StoreKey]types.CacheWrap, len(cms.stores))
137+
maps.Copy(stores, cms.stores)
138+
cms.storesMut.RUnlock()
139+
140+
for _, store := range stores {
130141
store.Write()
131142
}
132143
}
@@ -157,6 +168,9 @@ func (cms Store) CacheMultiStoreWithVersion(_ int64) (types.CacheMultiStore, err
157168
}
158169

159170
func (cms Store) getCacheWrapper(key types.StoreKey) types.CacheWrapper {
171+
cms.storesMut.Lock()
172+
defer cms.storesMut.Unlock()
173+
160174
store, ok := cms.stores[key]
161175
if !ok && cms.parentStore != nil {
162176
// load on demand

store/cachemulti/store_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cachemulti
22

33
import (
44
"fmt"
5+
"sync"
56
"testing"
67

78
"github.com/stretchr/testify/require"
@@ -12,7 +13,7 @@ import (
1213
func TestStoreGetKVStore(t *testing.T) {
1314
require := require.New(t)
1415

15-
s := Store{stores: map[types.StoreKey]types.CacheWrap{}}
16+
s := Store{storesMut: &sync.RWMutex{}, stores: map[types.StoreKey]types.CacheWrap{}}
1617
key := types.NewKVStoreKey("abc")
1718
errMsg := fmt.Sprintf("kv store with key %v has not been registered in stores", key)
1819

tests/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ require (
239239
replace (
240240
// We always want to test against the latest version of the simapp.
241241
cosmossdk.io/simapp => ../simapp
242+
cosmossdk.io/store => ../store
242243
github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0
243244
// We always want to test against the latest version of the SDK.
244245
github.com/cosmos/cosmos-sdk => ../.

tests/go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U=
4040
cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ=
4141
cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE=
4242
cosmossdk.io/schema v1.1.0/go.mod h1:Gb7pqO+tpR+jLW5qDcNOSv0KtppYs7881kfzakguhhI=
43-
cosmossdk.io/store v1.3.0-beta.0 h1:jwJvAQkMsCY9xJHU/nz7yOo1WnNRvcI/9yLRSgZoFTk=
44-
cosmossdk.io/store v1.3.0-beta.0/go.mod h1:CMz9JQGEA8eRcZv2pK07NgEbL4NEb9wVgzWK4tNQaPg=
4543
cosmossdk.io/x/tx v0.14.0 h1:hB3O25kIcyDW/7kMTLMaO8Ripj3yqs5imceVd6c/heA=
4644
cosmossdk.io/x/tx v0.14.0/go.mod h1:Tn30rSRA1PRfdGB3Yz55W4Sn6EIutr9xtMKSHij+9PM=
4745
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=

0 commit comments

Comments
 (0)