core: remove mutexes and atomic values from native cache
Native cache is always wrapped into independant layers, so concurrent RW access is no-op.
This commit is contained in:
parent
7b632c8ee8
commit
8ec8511d9d
6 changed files with 101 additions and 196 deletions
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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{}
|
||||
|
|
|
@ -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{}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue