native: cache GAS per vote values

`storage.Seek()` is rather expensive and we need only last updated value
of gas per block in `PostPersist()`.

Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgeniy Stratonikov 2021-07-01 10:33:04 +03:00
parent 3646270af0
commit 0591366f85

View file

@ -51,6 +51,11 @@ type NEO struct {
committee atomic.Value committee atomic.Value
// committeeHash contains script hash of the committee. // committeeHash contains script hash of the committee.
committeeHash atomic.Value committeeHash atomic.Value
// 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
// by any mutex.
gasPerVoteCache map[string]big.Int
} }
const ( const (
@ -117,6 +122,7 @@ func newNEO() *NEO {
n.committee.Store(keysWithVotes(nil)) n.committee.Store(keysWithVotes(nil))
n.committeeHash.Store(util.Uint160{}) n.committeeHash.Store(util.Uint160{})
n.registerPriceChanged.Store(true) n.registerPriceChanged.Store(true)
n.gasPerVoteCache = make(map[string]big.Int)
desc := newDescriptor("unclaimedGas", smartcontract.IntegerType, desc := newDescriptor("unclaimedGas", smartcontract.IntegerType,
manifest.NewParameter("account", smartcontract.Hash160Type), manifest.NewParameter("account", smartcontract.Hash160Type),
@ -333,10 +339,18 @@ func (n *NEO) PostPersist(ic *interop.Context) error {
tmp.Div(tmp, cs[i].Votes) tmp.Div(tmp, cs[i].Votes)
key = makeVoterKey([]byte(cs[i].Key), key) key = makeVoterKey([]byte(cs[i].Key), key)
var reward = n.getGASPerVote(ic.DAO, key[:34], ic.Block.Index+1)
tmp.Add(tmp, &reward[0]) var r *big.Int
if g, ok := n.gasPerVoteCache[cs[i].Key]; ok {
r = &g
} else {
reward := n.getGASPerVote(ic.DAO, key[:34], ic.Block.Index+1)
r = &reward[0]
}
tmp.Add(tmp, r)
binary.BigEndian.PutUint32(key[34:], ic.Block.Index+1) binary.BigEndian.PutUint32(key[34:], ic.Block.Index+1)
n.gasPerVoteCache[cs[i].Key] = *tmp
if err := ic.DAO.PutStorageItem(n.ID, key, bigint.ToBytes(tmp)); err != nil { if err := ic.DAO.PutStorageItem(n.ID, key, bigint.ToBytes(tmp)); err != nil {
return err return err
@ -562,7 +576,8 @@ func (n *NEO) dropCandidateIfZero(d dao.DAO, pub *keys.PublicKey, c *candidate)
} }
var toRemove []string var toRemove []string
d.Seek(n.ID, makeVoterKey(pub.Bytes()), func(k, v []byte) { voterKey := makeVoterKey(pub.Bytes())
d.Seek(n.ID, voterKey, func(k, v []byte) {
toRemove = append(toRemove, string(k)) toRemove = append(toRemove, string(k))
}) })
for i := range toRemove { for i := range toRemove {
@ -570,6 +585,8 @@ func (n *NEO) dropCandidateIfZero(d dao.DAO, pub *keys.PublicKey, c *candidate)
return true, err return true, err
} }
} }
delete(n.gasPerVoteCache, string(voterKey))
return true, nil return true, nil
} }