From 8ec8511d9d2ad108426064ea9f73081ac0758212 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Tue, 19 Apr 2022 12:26:46 +0300 Subject: [PATCH] core: remove mutexes and atomic values from native cache Native cache is always wrapped into independant layers, so concurrent RW access is no-op. --- pkg/core/native/designate.go | 62 +++++--------- pkg/core/native/management.go | 14 ---- pkg/core/native/native_neo.go | 154 +++++++++++++++------------------- pkg/core/native/notary.go | 16 +--- pkg/core/native/oracle.go | 27 +++--- pkg/core/native/policy.go | 24 ------ 6 files changed, 101 insertions(+), 196 deletions(-) diff --git a/pkg/core/native/designate.go b/pkg/core/native/designate.go index 93411c46f..33cda42c2 100644 --- a/pkg/core/native/designate.go +++ b/pkg/core/native/designate.go @@ -48,11 +48,11 @@ type roleData struct { } type DesignationCache struct { - rolesChangedFlag atomic.Value - oracles atomic.Value - stateVals atomic.Value - neofsAlphabet atomic.Value - notaries atomic.Value + rolesChangedFlag bool + oracles roleData + stateVals roleData + neofsAlphabet roleData + notaries roleData } const ( @@ -101,24 +101,7 @@ func (c *DesignationCache) Persist(ps storage.NativeContractCache) (storage.Nati } func copyDesignationCache(src, dst *DesignationCache) { - dst.rolesChangedFlag.Store(src.rolesChangedFlag.Load()) - for _, r := range []noderoles.Role{noderoles.StateValidator, noderoles.Oracle, noderoles.NeoFSAlphabet, noderoles.P2PNotary} { - data := getCachedRoleData(src, r) - if data != nil { - var v = &roleData{} - *v = *data - switch r { - case noderoles.StateValidator: - dst.stateVals.Store(v) - case noderoles.Oracle: - dst.oracles.Store(v) - case noderoles.NeoFSAlphabet: - dst.neofsAlphabet.Store(v) - case noderoles.P2PNotary: - dst.notaries.Store(v) - } - } - } + *dst = *src } func (s *Designate) isValidRole(r noderoles.Role) bool { @@ -153,7 +136,7 @@ func newDesignate(p2pSigExtensionsEnabled bool) *Designate { // Initialize initializes Oracle contract. func (s *Designate) Initialize(ic *interop.Context) error { cache := &DesignationCache{} - cache.rolesChangedFlag.Store(true) + cache.rolesChangedFlag = true ic.DAO.Store.SetCache(s.ID, cache) return nil } @@ -185,7 +168,7 @@ func (s *Designate) PostPersist(ic *interop.Context) error { } } - cache.rolesChangedFlag.Store(false) + cache.rolesChangedFlag = false return nil } @@ -215,8 +198,7 @@ func (s *Designate) getDesignatedByRole(ic *interop.Context, args []stackitem.It } func rolesChanged(cache *DesignationCache) bool { - rc := cache.rolesChangedFlag.Load() - return rc == nil || rc.(bool) + return cache.rolesChangedFlag } func (s *Designate) hashFromNodes(r noderoles.Role, nodes keys.PublicKeys) util.Uint160 { @@ -233,16 +215,14 @@ func (s *Designate) hashFromNodes(r noderoles.Role, nodes keys.PublicKeys) util. return hash.Hash160(script) } -func (s *Designate) updateCachedRoleData(v *atomic.Value, d *dao.Simple, r noderoles.Role) error { +func (s *Designate) updateCachedRoleData(v *roleData, d *dao.Simple, r noderoles.Role) error { nodeKeys, height, err := s.GetDesignatedByRole(d, r, math.MaxUint32) if err != nil { return err } - v.Store(&roleData{ - nodes: nodeKeys, - addr: s.hashFromNodes(r, nodeKeys), - height: height, - }) + v.nodes = nodeKeys + v.addr = s.hashFromNodes(r, nodeKeys) + v.height = height switch r { case noderoles.Oracle: if orc, _ := s.OracleService.Load().(services.Oracle); orc != nil { @@ -261,19 +241,15 @@ func (s *Designate) updateCachedRoleData(v *atomic.Value, d *dao.Simple, r noder } func getCachedRoleData(cache *DesignationCache, r noderoles.Role) *roleData { - var val interface{} switch r { case noderoles.Oracle: - val = cache.oracles.Load() + return &cache.oracles case noderoles.StateValidator: - val = cache.stateVals.Load() + return &cache.stateVals case noderoles.NeoFSAlphabet: - val = cache.neofsAlphabet.Load() + return &cache.neofsAlphabet case noderoles.P2PNotary: - val = cache.notaries.Load() - } - if val != nil { - return val.(*roleData) + return &cache.notaries } return nil } @@ -381,7 +357,7 @@ func (s *Designate) DesignateAsRole(ic *interop.Context, r noderoles.Role, pubs } sort.Sort(pubs) nl := NodeList(pubs) - ic.DAO.Store.GetRWCache(s.ID).(*DesignationCache).rolesChangedFlag.Store(true) + ic.DAO.Store.GetRWCache(s.ID).(*DesignationCache).rolesChangedFlag = true err := putConvertibleToDAO(s.ID, ic.DAO, key, &nl) if err != nil { return err @@ -413,6 +389,6 @@ func (s *Designate) getRole(item stackitem.Item) (noderoles.Role, bool) { // InitializeCache invalidates native Designate cache. func (s *Designate) InitializeCache(d *dao.Simple) { cache := &DesignationCache{} - cache.rolesChangedFlag.Store(true) + cache.rolesChangedFlag = true d.Store.SetCache(s.ID, cache) } diff --git a/pkg/core/native/management.go b/pkg/core/native/management.go index 765bb7ed4..00286955b 100644 --- a/pkg/core/native/management.go +++ b/pkg/core/native/management.go @@ -6,7 +6,6 @@ import ( "fmt" "math" "math/big" - "sync" "unicode/utf8" "github.com/nspcc-dev/neo-go/pkg/core/dao" @@ -33,7 +32,6 @@ type Management struct { } type ManagementCache struct { - mtx sync.RWMutex contracts map[util.Uint160]*state.Contract // nep11 is a map of NEP11-compliant contracts which is updated with every PostPersist. nep11 map[util.Uint160]struct{} @@ -188,9 +186,7 @@ func (m *Management) getContract(ic *interop.Context, args []stackitem.Item) sta // GetContract returns contract with given hash from given DAO. func (m *Management) GetContract(d *dao.Simple, hash util.Uint160) (*state.Contract, error) { cache := d.Store.GetROCache(m.ID).(*ManagementCache) - cache.mtx.RLock() cs, ok := cache.contracts[hash] - cache.mtx.RUnlock() if !ok { return nil, storage.ErrKeyNotFound } else if cs != nil { @@ -304,10 +300,8 @@ func (m *Management) deployWithData(ic *interop.Context, args []stackitem.Item) func (m *Management) markUpdated(d *dao.Simple, h util.Uint160) { cache := d.Store.GetRWCache(m.ID).(*ManagementCache) - cache.mtx.Lock() // Just set it to nil, to refresh cache in `PostPersist`. cache.contracts[h] = nil - cache.mtx.Unlock() } // Deploy creates contract's hash/ID and saves new contract into the given DAO. @@ -520,9 +514,7 @@ func (m *Management) OnPersist(ic *interop.Context) error { if cache == nil { cache = ic.DAO.Store.GetRWCache(m.ID).(*ManagementCache) } - cache.mtx.Lock() updateContractCache(cache, cs) - cache.mtx.Unlock() } return nil @@ -558,8 +550,6 @@ func (m *Management) InitializeCache(d *dao.Simple) error { // PostPersist implements Contract interface. func (m *Management) PostPersist(ic *interop.Context) error { cache := ic.DAO.Store.GetRWCache(m.ID).(*ManagementCache) - cache.mtx.Lock() - defer cache.mtx.Unlock() for h, cs := range cache.contracts { if cs != nil { continue @@ -582,12 +572,10 @@ func (m *Management) PostPersist(ic *interop.Context) error { // is returned. func (m *Management) GetNEP11Contracts(d *dao.Simple) []util.Uint160 { cache := d.Store.GetROCache(m.ID).(*ManagementCache) - cache.mtx.RLock() result := make([]util.Uint160, 0, len(cache.nep11)) for h := range cache.nep11 { result = append(result, h) } - cache.mtx.RUnlock() return result } @@ -596,12 +584,10 @@ func (m *Management) GetNEP11Contracts(d *dao.Simple) []util.Uint160 { // is returned. func (m *Management) GetNEP17Contracts(d *dao.Simple) []util.Uint160 { cache := d.Store.GetROCache(m.ID).(*ManagementCache) - cache.mtx.RLock() result := make([]util.Uint160, 0, len(cache.nep17)) for h := range cache.nep17 { result = append(result, h) } - cache.mtx.RUnlock() return result } diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index bf2574121..85ec58fed 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -8,7 +8,6 @@ import ( "math/big" "sort" "strings" - "sync/atomic" "github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/core/dao" @@ -44,22 +43,22 @@ type NEO struct { type NeoCache struct { // gasPerBlock represents current value of generated gas per block. // It is append-only and doesn't need to be copied when used. - gasPerBlock atomic.Value - gasPerBlockChanged atomic.Value + gasPerBlock gasRecord + gasPerBlockChanged bool - registerPrice atomic.Value - registerPriceChanged atomic.Value + registerPrice int64 + registerPriceChanged bool - votesChanged atomic.Value - nextValidators atomic.Value - validators atomic.Value + votesChanged bool + nextValidators keys.PublicKeys + validators keys.PublicKeys // committee contains cached committee members and their votes. // It is updated once in a while depending on committee size // (every 28 blocks for mainnet). It's value // is always equal to value stored by `prefixCommittee`. - committee atomic.Value + committee keysWithVotes // committeeHash contains script hash of the committee. - committeeHash atomic.Value + committeeHash util.Uint160 // gasPerVoteCache contains last updated value of GAS per vote reward for candidates. // It is set in state-modifying methods only and read in `PostPersist` thus is not protected @@ -134,27 +133,21 @@ func (c *NeoCache) Persist(ps storage.NativeContractCache) (storage.NativeContra } func copyNeoCache(src, dst *NeoCache) { - dst.votesChanged.Store(src.votesChanged.Load()) - dst.nextValidators.Store(src.nextValidators.Load().(keys.PublicKeys).Copy()) - dst.validators.Store(src.validators.Load().(keys.PublicKeys).Copy()) - committeeSrc := src.committee.Load().(keysWithVotes) - committeeDst := make(keysWithVotes, len(committeeSrc)) - copy(committeeDst, committeeSrc) - dst.committee.Store(committeeDst) - dst.committeeHash.Store(src.committeeHash.Load()) - regPriceChanged := src.registerPriceChanged.Load().(bool) - dst.registerPriceChanged.Store(regPriceChanged) - if !regPriceChanged { - dst.registerPrice.Store(src.registerPrice.Load()) - } - gasPerBlockChanged := src.gasPerBlockChanged.Load().(bool) - dst.gasPerBlockChanged.Store(gasPerBlockChanged) - if !gasPerBlockChanged { - recordsSrc := src.gasPerBlock.Load().(gasRecord) - recordsDst := make(gasRecord, len(recordsSrc)) - copy(recordsDst, recordsSrc) - dst.gasPerBlock.Store(recordsDst) - } + dst.votesChanged = src.votesChanged + dst.nextValidators = src.nextValidators.Copy() + dst.validators = src.validators.Copy() + + dst.committee = make(keysWithVotes, len(src.committee)) + copy(dst.committee, src.committee) + dst.committeeHash = src.committeeHash + + dst.registerPriceChanged = src.registerPriceChanged + dst.registerPrice = src.registerPrice + + dst.gasPerBlockChanged = src.gasPerBlockChanged + dst.gasPerBlock = make(gasRecord, len(src.gasPerBlock)) + copy(dst.gasPerBlock, src.gasPerBlock) + dst.gasPerVoteCache = make(map[string]big.Int) for k, v := range src.gasPerVoteCache { dst.gasPerVoteCache[k] = v @@ -262,14 +255,10 @@ func (n *NEO) Initialize(ic *interop.Context) error { } cache := &NeoCache{ - gasPerVoteCache: make(map[string]big.Int), + gasPerVoteCache: make(map[string]big.Int), + votesChanged: true, + registerPriceChanged: true, } - cache.votesChanged.Store(true) - cache.nextValidators.Store(keys.PublicKeys(nil)) - cache.validators.Store(keys.PublicKeys(nil)) - cache.committee.Store(keysWithVotes(nil)) - cache.committeeHash.Store(util.Uint160{}) - cache.registerPriceChanged.Store(true) // We need cache to be present in DAO before the subsequent call to `mint`. ic.DAO.Store.SetCache(n.ID, cache) @@ -294,13 +283,13 @@ func (n *NEO) Initialize(ic *interop.Context) error { n.putGASRecord(ic.DAO, index, value) gr := &gasRecord{{Index: index, GASPerBlock: *value}} - cache.gasPerBlock.Store(*gr) - cache.gasPerBlockChanged.Store(false) + cache.gasPerBlock = *gr + cache.gasPerBlockChanged = false ic.DAO.PutStorageItem(n.ID, []byte{prefixVotersCount}, state.StorageItem{}) setIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}, DefaultRegisterPrice) - cache.registerPrice.Store(int64(DefaultRegisterPrice)) - cache.registerPriceChanged.Store(false) + cache.registerPrice = int64(DefaultRegisterPrice) + cache.registerPriceChanged = false return nil } @@ -310,16 +299,11 @@ func (n *NEO) Initialize(ic *interop.Context) error { // called only when deploying native contracts. func (n *NEO) InitializeCache(bc interop.Ledger, d *dao.Simple) error { cache := &NeoCache{ - gasPerVoteCache: make(map[string]big.Int), + gasPerVoteCache: make(map[string]big.Int), + votesChanged: true, + registerPriceChanged: true, } - cache.votesChanged.Store(true) - cache.nextValidators.Store(keys.PublicKeys(nil)) - cache.validators.Store(keys.PublicKeys(nil)) - cache.committee.Store(keysWithVotes(nil)) - cache.committeeHash.Store(util.Uint160{}) - cache.registerPriceChanged.Store(true) - var committee = keysWithVotes{} si := d.GetStorageItem(n.ID, prefixCommittee) if err := committee.DecodeBytes(si); err != nil { @@ -329,8 +313,8 @@ func (n *NEO) InitializeCache(bc interop.Ledger, d *dao.Simple) error { return fmt.Errorf("failed to update cache: %w", err) } - cache.gasPerBlock.Store(n.getSortedGASRecordFromDAO(d)) - cache.gasPerBlockChanged.Store(false) + cache.gasPerBlock = n.getSortedGASRecordFromDAO(d) + cache.gasPerBlockChanged = false d.Store.SetCache(n.ID, cache) return nil @@ -345,28 +329,26 @@ func (n *NEO) initConfigCache(cfg config.ProtocolConfiguration) error { } func (n *NEO) updateCache(cache *NeoCache, cvs keysWithVotes, bc interop.Ledger) error { - cache.committee.Store(cvs) + cache.committee = cvs var committee = getCommitteeMembers(cache) script, err := smartcontract.CreateMajorityMultiSigRedeemScript(committee.Copy()) if err != nil { return err } - cache.committeeHash.Store(hash.Hash160(script)) + cache.committeeHash = hash.Hash160(script) // TODO: use block height from interop context for proper historical calls handling. nextVals := committee[:n.cfg.GetNumOfCNs(bc.BlockHeight()+1)].Copy() sort.Sort(nextVals) - cache.nextValidators.Store(nextVals) + cache.nextValidators = nextVals return nil } func (n *NEO) updateCommittee(cache *NeoCache, ic *interop.Context) error { - votesChanged := cache.votesChanged.Load().(bool) - if !votesChanged { + if !cache.votesChanged { // We need to put in storage anyway, as it affects dumps - committee := cache.committee.Load().(keysWithVotes) - ic.DAO.PutStorageItem(n.ID, prefixCommittee, committee.Bytes()) + ic.DAO.PutStorageItem(n.ID, prefixCommittee, cache.committee.Bytes()) return nil } @@ -377,7 +359,7 @@ func (n *NEO) updateCommittee(cache *NeoCache, ic *interop.Context) error { if err := n.updateCache(cache, cvs, ic.Chain); err != nil { return err } - cache.votesChanged.Store(false) + cache.votesChanged = false ic.DAO.PutStorageItem(n.ID, prefixCommittee, cvs.Bytes()) return nil } @@ -386,11 +368,11 @@ func (n *NEO) updateCommittee(cache *NeoCache, ic *interop.Context) error { func (n *NEO) OnPersist(ic *interop.Context) error { if n.cfg.ShouldUpdateCommitteeAt(ic.Block.Index) { cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache) - oldKeys := cache.nextValidators.Load().(keys.PublicKeys) - oldCom := cache.committee.Load().(keysWithVotes) + oldKeys := cache.nextValidators + oldCom := cache.committee if n.cfg.GetNumOfCNs(ic.Block.Index) != len(oldKeys) || n.cfg.GetCommitteeSize(ic.Block.Index) != len(oldCom) { - cache.votesChanged.Store(true) + cache.votesChanged = true } if err := n.updateCommittee(cache, ic); err != nil { return err @@ -417,7 +399,7 @@ func (n *NEO) PostPersist(ic *interop.Context) error { voterReward.Div(voterReward, big.NewInt(int64(committeeSize+validatorsCount))) voterReward.Div(voterReward, big100) - var cs = cache.committee.Load().(keysWithVotes) + var cs = cache.committee var key = make([]byte, 38) for i := range cs { if cs[i].Votes.Sign() > 0 { @@ -448,15 +430,15 @@ func (n *NEO) PostPersist(ic *interop.Context) error { } } } - if cache.gasPerBlockChanged.Load().(bool) { - cache.gasPerBlock.Store(n.getSortedGASRecordFromDAO(ic.DAO)) - cache.gasPerBlockChanged.Store(false) + if cache.gasPerBlockChanged { + cache.gasPerBlock = n.getSortedGASRecordFromDAO(ic.DAO) + cache.gasPerBlockChanged = false } - if cache.registerPriceChanged.Load().(bool) { + if cache.registerPriceChanged { p := getIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}) - cache.registerPrice.Store(p) - cache.registerPriceChanged.Store(false) + cache.registerPrice = p + cache.registerPriceChanged = false } return nil } @@ -581,10 +563,10 @@ func (n *NEO) getSortedGASRecordFromDAO(d *dao.Simple) gasRecord { func (n *NEO) GetGASPerBlock(d *dao.Simple, index uint32) *big.Int { cache := d.Store.GetROCache(n.ID).(*NeoCache) var gr gasRecord - if cache.gasPerBlockChanged.Load().(bool) { + if cache.gasPerBlockChanged { gr = n.getSortedGASRecordFromDAO(d) } else { - gr = cache.gasPerBlock.Load().(gasRecord) + gr = cache.gasPerBlock } for i := len(gr) - 1; i >= 0; i-- { if gr[i].Index <= index { @@ -598,7 +580,7 @@ func (n *NEO) GetGASPerBlock(d *dao.Simple, index uint32) *big.Int { // GetCommitteeAddress returns address of the committee. func (n *NEO) GetCommitteeAddress(d *dao.Simple) util.Uint160 { cache := d.Store.GetROCache(n.ID).(*NeoCache) - return cache.committeeHash.Load().(util.Uint160) + return cache.committeeHash } func (n *NEO) checkCommittee(ic *interop.Context) bool { @@ -627,7 +609,7 @@ func (n *NEO) SetGASPerBlock(ic *interop.Context, index uint32, gas *big.Int) er return errors.New("invalid committee signature") } cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache) - cache.gasPerBlockChanged.Store(true) + cache.gasPerBlockChanged = true n.putGASRecord(ic.DAO, index, gas) return nil } @@ -638,8 +620,8 @@ func (n *NEO) getRegisterPrice(ic *interop.Context, _ []stackitem.Item) stackite func (n *NEO) getRegisterPriceInternal(d *dao.Simple) int64 { cache := d.Store.GetROCache(n.ID).(*NeoCache) - if !cache.registerPriceChanged.Load().(bool) { - return cache.registerPrice.Load().(int64) + if !cache.registerPriceChanged { + return cache.registerPrice } return getIntWithKey(n.ID, d, []byte{prefixRegisterPrice}) } @@ -655,7 +637,7 @@ func (n *NEO) setRegisterPrice(ic *interop.Context, args []stackitem.Item) stack setIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}, price.Int64()) cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache) - cache.registerPriceChanged.Store(true) + cache.registerPriceChanged = true return stackitem.Null{} } @@ -726,8 +708,8 @@ func (n *NEO) CalculateNEOHolderReward(d *dao.Simple, value *big.Int, start, end } var gr gasRecord cache := d.Store.GetROCache(n.ID).(*NeoCache) - if !cache.gasPerBlockChanged.Load().(bool) { - gr = cache.gasPerBlock.Load().(gasRecord) + if !cache.gasPerBlockChanged { + gr = cache.gasPerBlock } else { gr = n.getSortedGASRecordFromDAO(d) } @@ -801,7 +783,7 @@ func (n *NEO) UnregisterCandidateInternal(ic *interop.Context, pub *keys.PublicK return nil } cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache) - cache.validators.Store(keys.PublicKeys(nil)) + cache.validators = nil c := new(candidate).FromBytes(si) c.Registered = false ok, err := n.dropCandidateIfZero(ic.DAO, cache, pub, c) @@ -881,7 +863,7 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pub *keys.Public // typ specifies if this modify is occurring during transfer or vote (with old or new validator). func (n *NEO) ModifyAccountVotes(acc *state.NEOBalance, d *dao.Simple, value *big.Int, isNewVote bool) error { cache := d.Store.GetRWCache(n.ID).(*NeoCache) - cache.votesChanged.Store(true) + cache.votesChanged = true if acc.VoteTo != nil { key := makeValidatorKey(acc.VoteTo) si := d.GetStorageItem(n.ID, key) @@ -896,7 +878,7 @@ func (n *NEO) ModifyAccountVotes(acc *state.NEOBalance, d *dao.Simple, value *bi return err } } - cache.validators.Store(keys.PublicKeys(nil)) + cache.validators = nil return putConvertibleToDAO(n.ID, d, key, cd) } return nil @@ -992,7 +974,7 @@ func (n *NEO) getAccountState(ic *interop.Context, args []stackitem.Item) stacki func (n *NEO) ComputeNextBlockValidators(bc interop.Ledger, d *dao.Simple) (keys.PublicKeys, error) { numOfCNs := n.cfg.GetNumOfCNs(bc.BlockHeight() + 1) cache := d.Store.GetRWCache(n.ID).(*NeoCache) - if vals := cache.validators.Load().(keys.PublicKeys); vals != nil && numOfCNs == len(vals) { + if vals := cache.validators; vals != nil && numOfCNs == len(vals) { return vals.Copy(), nil } result, _, err := n.computeCommitteeMembers(bc, d) @@ -1001,7 +983,7 @@ func (n *NEO) ComputeNextBlockValidators(bc interop.Ledger, d *dao.Simple) (keys } result = result[:numOfCNs] sort.Sort(result) - cache.validators.Store(result) + cache.validators = result return result, nil } @@ -1031,7 +1013,7 @@ func (n *NEO) GetCommitteeMembers(d *dao.Simple) keys.PublicKeys { } func getCommitteeMembers(cache *NeoCache) keys.PublicKeys { - var cvs = cache.committee.Load().(keysWithVotes) + var cvs = cache.committee var committee = make(keys.PublicKeys, len(cvs)) var err error for i := range committee { @@ -1107,7 +1089,7 @@ func (n *NEO) getNextBlockValidators(ic *interop.Context, _ []stackitem.Item) st // GetNextBlockValidatorsInternal returns next block validators. func (n *NEO) GetNextBlockValidatorsInternal(d *dao.Simple) keys.PublicKeys { cache := d.Store.GetROCache(n.ID).(*NeoCache) - return cache.nextValidators.Load().(keys.PublicKeys).Copy() + return cache.nextValidators.Copy() } // BalanceOf returns native NEO token balance for the acc. diff --git a/pkg/core/native/notary.go b/pkg/core/native/notary.go index 817a5e73a..325cedce6 100644 --- a/pkg/core/native/notary.go +++ b/pkg/core/native/notary.go @@ -5,7 +5,6 @@ import ( "fmt" "math" "math/big" - "sync" "github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/interop" @@ -35,7 +34,6 @@ type Notary struct { } type NotaryCache struct { - lock sync.RWMutex // isValid defies whether cached values were changed during the current // consensus iteration. If false, these values will be updated after // blockchain DAO persisting. If true, we can safely use cached values. @@ -84,9 +82,7 @@ func (c *NotaryCache) Persist(ps storage.NativeContractCache) (storage.NativeCon } func copyNotaryCache(src, dst *NotaryCache) { - dst.isValid = src.isValid - dst.maxNotValidBeforeDelta = src.maxNotValidBeforeDelta - dst.notaryServiceFeePerKey = src.notaryServiceFeePerKey + *dst = *src } // newNotary returns Notary native contract. @@ -224,8 +220,6 @@ func (n *Notary) OnPersist(ic *interop.Context) error { // PostPersist implements Contract interface. func (n *Notary) PostPersist(ic *interop.Context) error { cache := ic.DAO.Store.GetRWCache(n.ID).(*NotaryCache) - cache.lock.Lock() - defer cache.lock.Unlock() if cache.isValid { return nil } @@ -440,8 +434,6 @@ func (n *Notary) getMaxNotValidBeforeDelta(ic *interop.Context, _ []stackitem.It // GetMaxNotValidBeforeDelta is an internal representation of Notary getMaxNotValidBeforeDelta method. func (n *Notary) GetMaxNotValidBeforeDelta(dao *dao.Simple) uint32 { cache := dao.Store.GetROCache(n.ID).(*NotaryCache) - cache.lock.RLock() - defer cache.lock.RUnlock() if cache.isValid { return cache.maxNotValidBeforeDelta } @@ -460,8 +452,6 @@ func (n *Notary) setMaxNotValidBeforeDelta(ic *interop.Context, args []stackitem panic("invalid committee signature") } cache := ic.DAO.Store.GetRWCache(n.ID).(*NotaryCache) - cache.lock.Lock() - defer cache.lock.Unlock() setIntWithKey(n.ID, ic.DAO, maxNotValidBeforeDeltaKey, int64(value)) cache.isValid = false return stackitem.Null{} @@ -475,8 +465,6 @@ func (n *Notary) getNotaryServiceFeePerKey(ic *interop.Context, _ []stackitem.It // GetNotaryServiceFeePerKey is an internal representation of Notary getNotaryServiceFeePerKey method. func (n *Notary) GetNotaryServiceFeePerKey(dao *dao.Simple) int64 { cache := dao.Store.GetROCache(n.ID).(*NotaryCache) - cache.lock.RLock() - defer cache.lock.RUnlock() if cache.isValid { return cache.notaryServiceFeePerKey } @@ -493,8 +481,6 @@ func (n *Notary) setNotaryServiceFeePerKey(ic *interop.Context, args []stackitem panic("invalid committee signature") } cache := ic.DAO.Store.GetRWCache(n.ID).(*NotaryCache) - cache.lock.Lock() - defer cache.lock.Unlock() setIntWithKey(n.ID, ic.DAO, notaryServiceFeeKey, int64(value)) cache.isValid = false return stackitem.Null{} diff --git a/pkg/core/native/oracle.go b/pkg/core/native/oracle.go index 893b5cebf..f1914cd65 100644 --- a/pkg/core/native/oracle.go +++ b/pkg/core/native/oracle.go @@ -47,8 +47,8 @@ type Oracle struct { } type OracleCache struct { - requestPrice atomic.Value - requestPriceChanged atomic.Value + requestPrice int64 + requestPriceChanged bool } const ( @@ -110,8 +110,7 @@ func (c *OracleCache) Persist(ps storage.NativeContractCache) (storage.NativeCon } func copyOracleCache(src, dst *OracleCache) { - dst.requestPrice.Store(src.requestPrice.Load()) - dst.requestPriceChanged.Store(src.requestPriceChanged.Load()) + *dst = *src } func newOracle() *Oracle { @@ -174,9 +173,9 @@ func (o *Oracle) OnPersist(ic *interop.Context) error { func (o *Oracle) PostPersist(ic *interop.Context) error { p := o.getPriceInternal(ic.DAO) cache := ic.DAO.Store.GetRWCache(o.ID).(*OracleCache) - if cache.requestPriceChanged.Load().(bool) { - cache.requestPrice.Store(p) - cache.requestPriceChanged.Store(false) + if cache.requestPriceChanged { + cache.requestPrice = p + cache.requestPriceChanged = false } var nodes keys.PublicKeys @@ -253,16 +252,16 @@ func (o *Oracle) Initialize(ic *interop.Context) error { setIntWithKey(o.ID, ic.DAO, prefixRequestPrice, DefaultOracleRequestPrice) cache := &OracleCache{} - cache.requestPrice.Store(int64(DefaultOracleRequestPrice)) - cache.requestPriceChanged.Store(false) + cache.requestPrice = int64(DefaultOracleRequestPrice) + cache.requestPriceChanged = false ic.DAO.Store.SetCache(o.ID, cache) return nil } func (o *Oracle) InitializeCache(d *dao.Simple) { cache := &OracleCache{} - cache.requestPrice.Store(getIntWithKey(o.ID, d, prefixRequestPrice)) - cache.requestPriceChanged.Store(false) + cache.requestPrice = getIntWithKey(o.ID, d, prefixRequestPrice) + cache.requestPriceChanged = false d.Store.SetCache(o.ID, cache) } @@ -481,8 +480,8 @@ func (o *Oracle) getPrice(ic *interop.Context, _ []stackitem.Item) stackitem.Ite func (o *Oracle) getPriceInternal(d *dao.Simple) int64 { cache := d.Store.GetROCache(o.ID).(*OracleCache) - if !cache.requestPriceChanged.Load().(bool) { - return cache.requestPrice.Load().(int64) + if !cache.requestPriceChanged { + return cache.requestPrice } return getIntWithKey(o.ID, d, prefixRequestPrice) } @@ -497,7 +496,7 @@ func (o *Oracle) setPrice(ic *interop.Context, args []stackitem.Item) stackitem. } setIntWithKey(o.ID, ic.DAO, prefixRequestPrice, price.Int64()) cache := ic.DAO.Store.GetRWCache(o.ID).(*OracleCache) - cache.requestPriceChanged.Store(true) + cache.requestPriceChanged = true return stackitem.Null{} } diff --git a/pkg/core/native/policy.go b/pkg/core/native/policy.go index d4446e8b5..78b64d652 100644 --- a/pkg/core/native/policy.go +++ b/pkg/core/native/policy.go @@ -5,7 +5,6 @@ import ( "fmt" "math/big" "sort" - "sync" "github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/interop" @@ -57,7 +56,6 @@ type Policy struct { } type PolicyCache struct { - lock sync.RWMutex // isValid defies whether cached values were changed during the current // consensus iteration. If false, these values will be updated after // blockchain DAO persisting. If true, we can safely use cached values. @@ -215,8 +213,6 @@ func (p *Policy) OnPersist(ic *interop.Context) error { // PostPersist implements Contract interface. func (p *Policy) PostPersist(ic *interop.Context) error { cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache) - cache.lock.Lock() - defer cache.lock.Unlock() if cache.isValid { return nil } @@ -233,8 +229,6 @@ func (p *Policy) getFeePerByte(ic *interop.Context, _ []stackitem.Item) stackite // GetFeePerByteInternal returns required transaction's fee per byte. func (p *Policy) GetFeePerByteInternal(dao *dao.Simple) int64 { cache := dao.Store.GetROCache(p.ID).(*PolicyCache) - cache.lock.RLock() - defer cache.lock.RUnlock() if cache.isValid { return cache.feePerByte } @@ -244,8 +238,6 @@ func (p *Policy) GetFeePerByteInternal(dao *dao.Simple) int64 { // GetMaxVerificationGas returns maximum gas allowed to be burned during verificaion. func (p *Policy) GetMaxVerificationGas(dao *dao.Simple) int64 { cache := dao.Store.GetROCache(p.ID).(*PolicyCache) - cache.lock.RLock() - defer cache.lock.RUnlock() if cache.isValid { return cache.maxVerificationGas } @@ -259,8 +251,6 @@ func (p *Policy) getExecFeeFactor(ic *interop.Context, _ []stackitem.Item) stack // GetExecFeeFactorInternal returns current execution fee factor. func (p *Policy) GetExecFeeFactorInternal(d *dao.Simple) int64 { cache := d.Store.GetROCache(p.ID).(*PolicyCache) - cache.lock.RLock() - defer cache.lock.RUnlock() if cache.isValid { return int64(cache.execFeeFactor) } @@ -276,8 +266,6 @@ func (p *Policy) setExecFeeFactor(ic *interop.Context, args []stackitem.Item) st panic("invalid committee signature") } cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache) - cache.lock.Lock() - defer cache.lock.Unlock() setIntWithKey(p.ID, ic.DAO, execFeeFactorKey, int64(value)) cache.isValid = false return stackitem.Null{} @@ -292,8 +280,6 @@ func (p *Policy) isBlocked(ic *interop.Context, args []stackitem.Item) stackitem // IsBlockedInternal checks whether provided account is blocked. func (p *Policy) IsBlockedInternal(dao *dao.Simple, hash util.Uint160) bool { cache := dao.Store.GetROCache(p.ID).(*PolicyCache) - cache.lock.RLock() - defer cache.lock.RUnlock() if cache.isValid { length := len(cache.blockedAccounts) i := sort.Search(length, func(i int) bool { @@ -315,8 +301,6 @@ func (p *Policy) getStoragePrice(ic *interop.Context, _ []stackitem.Item) stacki // GetStoragePriceInternal returns current execution fee factor. func (p *Policy) GetStoragePriceInternal(d *dao.Simple) int64 { cache := d.Store.GetROCache(p.ID).(*PolicyCache) - cache.lock.RLock() - defer cache.lock.RUnlock() if cache.isValid { return int64(cache.storagePrice) } @@ -332,8 +316,6 @@ func (p *Policy) setStoragePrice(ic *interop.Context, args []stackitem.Item) sta panic("invalid committee signature") } cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache) - cache.lock.Lock() - defer cache.lock.Unlock() setIntWithKey(p.ID, ic.DAO, storagePriceKey, int64(value)) cache.isValid = false return stackitem.Null{} @@ -349,8 +331,6 @@ func (p *Policy) setFeePerByte(ic *interop.Context, args []stackitem.Item) stack panic("invalid committee signature") } cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache) - cache.lock.Lock() - defer cache.lock.Unlock() setIntWithKey(p.ID, ic.DAO, feePerByteKey, value) cache.isValid = false return stackitem.Null{} @@ -373,8 +353,6 @@ func (p *Policy) blockAccount(ic *interop.Context, args []stackitem.Item) stacki } key := append([]byte{blockedAccountPrefix}, hash.BytesBE()...) cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache) - cache.lock.Lock() - defer cache.lock.Unlock() ic.DAO.PutStorageItem(p.ID, key, state.StorageItem{}) cache.isValid = false return stackitem.NewBool(true) @@ -392,8 +370,6 @@ func (p *Policy) unblockAccount(ic *interop.Context, args []stackitem.Item) stac } key := append([]byte{blockedAccountPrefix}, hash.BytesBE()...) cache := ic.DAO.Store.GetRWCache(p.ID).(*PolicyCache) - cache.lock.Lock() - defer cache.lock.Unlock() ic.DAO.DeleteStorageItem(p.ID, key) cache.isValid = false return stackitem.NewBool(true)