From a427411a57d092e94d50b78c2f65dc4916d42b0f Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Fri, 6 May 2022 10:27:48 +0300 Subject: [PATCH] core: fix race during native cache persist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following race: ``` 2022-05-06T06:51:33.3980029Z WARNING: DATA RACE 2022-05-06T06:51:33.3980178Z Read at 0x00c0007e02a0 by goroutine 96: 2022-05-06T06:51:33.3980338Z runtime.mapaccess2_fast32() 2022-05-06T06:51:33.3980863Z /opt/hostedtoolcache/go/1.17.9/x64/src/runtime/map_fast32.go:52 +0x0 2022-05-06T06:51:33.3981249Z github.com/nspcc-dev/neo-go/pkg/core/dao.(*Simple).getCache() 2022-05-06T06:51:33.3982707Z /home/runner/work/neo-go/neo-go/pkg/core/dao/dao.go:905 +0x64 2022-05-06T06:51:33.3983443Z github.com/nspcc-dev/neo-go/pkg/core/dao.(*Simple).GetROCache() 2022-05-06T06:51:33.3983900Z /home/runner/work/neo-go/neo-go/pkg/core/dao/dao.go:889 +0xd4 2022-05-06T06:51:33.3984231Z github.com/nspcc-dev/neo-go/pkg/core/dao.(*Simple).getCache() 2022-05-06T06:51:33.3984869Z /home/runner/work/neo-go/neo-go/pkg/core/dao/dao.go:913 +0x196 2022-05-06T06:51:33.3985254Z github.com/nspcc-dev/neo-go/pkg/core/dao.(*Simple).GetROCache() 2022-05-06T06:51:33.3985756Z /home/runner/work/neo-go/neo-go/pkg/core/dao/dao.go:889 +0xd4 2022-05-06T06:51:33.3986167Z github.com/nspcc-dev/neo-go/pkg/core/native.(*Policy).isBlockedInternal() 2022-05-06T06:51:33.3986824Z /home/runner/work/neo-go/neo-go/pkg/core/native/policy.go:258 +0x6a 2022-05-06T06:51:33.3987264Z github.com/nspcc-dev/neo-go/pkg/core/native.(*Policy).IsBlocked() 2022-05-06T06:51:33.3987743Z /home/runner/work/neo-go/neo-go/pkg/core/native/policy.go:250 +0x2f7 2022-05-06T06:51:33.3988155Z github.com/nspcc-dev/neo-go/pkg/core/native.(*NEO).getAllCandidatesCall.func1() 2022-05-06T06:51:33.3988645Z /home/runner/work/neo-go/neo-go/pkg/core/native/native_neo.go:948 +0x109 2022-05-06T06:51:33.3989053Z github.com/nspcc-dev/neo-go/pkg/core/native.(*NEO).getAllCandidatesCall.func2() 2022-05-06T06:51:33.3989550Z /home/runner/work/neo-go/neo-go/pkg/core/native/native_neo.go:959 +0x137 2022-05-06T06:51:33.3989561Z 2022-05-06T06:51:33.3989735Z Previous write at 0x00c0007e02a0 by goroutine 40: 2022-05-06T06:51:33.3989891Z runtime.mapassign_fast32() 2022-05-06T06:51:33.3990260Z /opt/hostedtoolcache/go/1.17.9/x64/src/runtime/map_fast32.go:92 +0x0 2022-05-06T06:51:33.3990640Z github.com/nspcc-dev/neo-go/pkg/core/dao.(*Simple).persistNativeCache() 2022-05-06T06:51:33.3991084Z /home/runner/work/neo-go/neo-go/pkg/core/dao/dao.go:876 +0x12d 2022-05-06T06:51:33.3991411Z github.com/nspcc-dev/neo-go/pkg/core/dao.(*Simple).Persist() 2022-05-06T06:51:33.3991852Z /home/runner/work/neo-go/neo-go/pkg/core/dao/dao.go:850 +0x1d4 2022-05-06T06:51:33.3992186Z github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).runPersist() 2022-05-06T06:51:33.3992650Z /home/runner/work/neo-go/neo-go/pkg/core/blockchain.go:1285 +0x28a 2022-05-06T06:51:33.3992971Z github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).storeBlock() 2022-05-06T06:51:33.3993845Z /home/runner/work/neo-go/neo-go/pkg/core/blockchain.go:1143 +0x1b9c 2022-05-06T06:51:33.3994241Z github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).AddBlock() 2022-05-06T06:51:33.3994707Z /home/runner/work/neo-go/neo-go/pkg/core/blockchain.go:910 +0x791 2022-05-06T06:51:33.3995053Z github.com/nspcc-dev/neo-go/pkg/neotest.(*Executor).AddNewBlock() 2022-05-06T06:51:33.3995492Z /home/runner/work/neo-go/neo-go/pkg/neotest/basic.go:334 +0xa7 2022-05-06T06:51:33.3995842Z github.com/nspcc-dev/neo-go/pkg/neotest.(*Executor).InvokeScript() 2022-05-06T06:51:33.3996288Z /home/runner/work/neo-go/neo-go/pkg/neotest/basic.go:178 +0x169 2022-05-06T06:51:33.3996725Z github.com/nspcc-dev/neo-go/pkg/core/native/native_test_test.TestNEO_GetCandidates.func2() 2022-05-06T06:51:33.3997253Z /home/runner/work/neo-go/neo-go/pkg/core/native/native_test/neo_test.go:549 +0x4cb 2022-05-06T06:51:33.3997672Z github.com/nspcc-dev/neo-go/pkg/core/native/native_test_test.TestNEO_GetCandidates() 2022-05-06T06:51:33.3998404Z /home/runner/work/neo-go/neo-go/pkg/core/native/native_test/neo_test.go:574 +0x2103 2022-05-06T06:51:33.3998751Z github.com/nspcc-dev/neo-go/pkg/neotest.(*Executor).AddNewBlock() 2022-05-06T06:51:33.3999193Z /home/runner/work/neo-go/neo-go/pkg/neotest/basic.go:334 +0xa7 2022-05-06T06:51:33.3999541Z github.com/nspcc-dev/neo-go/pkg/neotest.(*Executor).InvokeScript() 2022-05-06T06:51:33.3999988Z /home/runner/work/neo-go/neo-go/pkg/neotest/basic.go:178 +0x169 2022-05-06T06:51:33.4000305Z github.com/nspcc-dev/neo-go/pkg/neotest.AddSystemFee() 2022-05-06T06:51:33.4000733Z /home/runner/work/neo-go/neo-go/pkg/neotest/basic.go:291 +0x85 2022-05-06T06:51:33.4001062Z github.com/nspcc-dev/neo-go/pkg/neotest.(*Executor).SignTx() 2022-05-06T06:51:33.4001509Z /home/runner/work/neo-go/neo-go/pkg/neotest/basic.go:111 +0x109 2022-05-06T06:51:33.4001885Z github.com/nspcc-dev/neo-go/pkg/neotest.(*Executor).PrepareInvocation() 2022-05-06T06:51:33.4002435Z /home/runner/work/neo-go/neo-go/pkg/neotest/basic.go:191 +0x1b2 2022-05-06T06:51:33.4002808Z github.com/nspcc-dev/neo-go/pkg/neotest.(*Executor).InvokeScript() 2022-05-06T06:51:33.4003249Z /home/runner/work/neo-go/neo-go/pkg/neotest/basic.go:177 +0xed 2022-05-06T06:51:33.4003685Z github.com/nspcc-dev/neo-go/pkg/core/native/native_test_test.TestNEO_GetCandidates.func2() 2022-05-06T06:51:33.4004216Z /home/runner/work/neo-go/neo-go/pkg/core/native/native_test/neo_test.go:549 +0x4cb 2022-05-06T06:51:33.4004634Z github.com/nspcc-dev/neo-go/pkg/core/native/native_test_test.TestNEO_GetCandidates() 2022-05-06T06:51:33.4005165Z /home/runner/work/neo-go/neo-go/pkg/core/native/native_test/neo_test.go:558 +0x1bbb 2022-05-06T06:51:33.4005298Z testing.tRunner() 2022-05-06T06:51:33.4005674Z /opt/hostedtoolcache/go/1.17.9/x64/src/testing/testing.go:1259 +0x22f 2022-05-06T06:51:33.4005916Z testing.(*T).Run·dwrap·21() 2022-05-06T06:51:33.4006298Z /opt/hostedtoolcache/go/1.17.9/x64/src/testing/testing.go:1306 +0x47 ... ``` --- pkg/core/dao/dao.go | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/pkg/core/dao/dao.go b/pkg/core/dao/dao.go index 5620ad7c0..daf2e60c2 100644 --- a/pkg/core/dao/dao.go +++ b/pkg/core/dao/dao.go @@ -839,14 +839,13 @@ func (dao *Simple) getDataBuf() *io.BufBinWriter { // underlying store. It doesn't block accesses to DAO from other threads. func (dao *Simple) Persist() (int, error) { if dao.nativeCachePS != nil { - if !dao.private { - dao.nativeCacheLock.Lock() - defer dao.nativeCacheLock.Unlock() - } - if !dao.nativeCachePS.private { - dao.nativeCachePS.nativeCacheLock.Lock() - defer dao.nativeCachePS.nativeCacheLock.Unlock() - } + dao.nativeCacheLock.Lock() + dao.nativeCachePS.nativeCacheLock.Lock() + defer func() { + dao.nativeCachePS.nativeCacheLock.Unlock() + dao.nativeCacheLock.Unlock() + }() + dao.persistNativeCache() } return dao.Store.Persist() @@ -881,10 +880,8 @@ func (dao *Simple) persistNativeCache() { // GetROCache returns native contact cache. The cache CAN NOT be modified by // the caller. It's the caller's duty to keep it unmodified. func (dao *Simple) GetROCache(id int32) NativeContractCache { - if !dao.private { - dao.nativeCacheLock.RLock() - defer dao.nativeCacheLock.RUnlock() - } + dao.nativeCacheLock.RLock() + defer dao.nativeCacheLock.RUnlock() return dao.getCache(id, true) } @@ -892,10 +889,8 @@ func (dao *Simple) GetROCache(id int32) NativeContractCache { // GetRWCache returns native contact cache. The cache CAN BE safely modified // by the caller. func (dao *Simple) GetRWCache(id int32) NativeContractCache { - if !dao.private { - dao.nativeCacheLock.Lock() - defer dao.nativeCacheLock.Unlock() - } + dao.nativeCacheLock.Lock() + defer dao.nativeCacheLock.Unlock() return dao.getCache(id, false) }