Skip to content

Commit

Permalink
native: fix nspcc-dev#2844 optimize vote reward data
Browse files Browse the repository at this point in the history
  • Loading branch information
ZhangTao1596 committed Jan 31, 2023
1 parent b56dff2 commit 93a9e55
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 59 deletions.
2 changes: 1 addition & 1 deletion cli/wallet/wallet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ func TestWalletClaimGas(t *testing.T) {

balanceBefore := e.Chain.GetUtilityTokenBalance(h)
claimHeight := e.Chain.BlockHeight() + 1
cl, err := e.Chain.CalculateClaimable(h, claimHeight)
cl, err := e.Chain.CalculateClaimable(h)
require.NoError(t, err)
require.True(t, cl.Sign() > 0)

Expand Down
3 changes: 1 addition & 2 deletions pkg/core/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,13 +206,12 @@ func benchmarkGasPerVote(t *testing.B, ps storage.Store, nRewardRecords int, rew

// Advance chain one more time to avoid same start/end rewarding bounds.
e.GenerateNewBlocks(t, rewardDistance)
end := bc.BlockHeight()

t.ResetTimer()
t.ReportAllocs()
t.StartTimer()
for i := 0; i < t.N; i++ {
_, err := bc.CalculateClaimable(to, end)
_, err := bc.CalculateClaimable(to)
require.NoError(t, err)
}
t.StopTimer()
Expand Down
5 changes: 3 additions & 2 deletions pkg/core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2239,8 +2239,9 @@ unsubloop:

// CalculateClaimable calculates the amount of GAS generated by owning specified
// amount of NEO between specified blocks.
func (bc *Blockchain) CalculateClaimable(acc util.Uint160, endHeight uint32) (*big.Int, error) {
return bc.contracts.NEO.CalculateBonus(bc.dao, acc, endHeight)
func (bc *Blockchain) CalculateClaimable(acc util.Uint160) (*big.Int, error) {
ic := bc.newInteropContext(trigger.Application, bc.dao, nil, nil)
return bc.contracts.NEO.CalculateBonus(ic, acc)
}

// FeePerByte returns transaction network fee per byte.
Expand Down
2 changes: 1 addition & 1 deletion pkg/core/blockchain_neotest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ func TestBlockchain_GetClaimable(t *testing.T) {
e.GenerateNewBlocks(t, 10)

t.Run("first generation period", func(t *testing.T) {
amount, err := bc.CalculateClaimable(acc.ScriptHash(), 1)
amount, err := bc.CalculateClaimable(acc.ScriptHash())
require.NoError(t, err)
require.EqualValues(t, big.NewInt(5*native.GASFactor/10), amount)
})
Expand Down
80 changes: 31 additions & 49 deletions pkg/core/native/native_neo.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ func (n *NEO) PostPersist(ic *interop.Context) error {
var (
cs = cache.committee
isCacheRW bool
key = make([]byte, 38)
key = make([]byte, 34)
)
for i := range cs {
if cs[i].Votes.Sign() > 0 {
Expand All @@ -428,12 +428,11 @@ func (n *NEO) PostPersist(ic *interop.Context) error {
if g, ok := cache.gasPerVoteCache[cs[i].Key]; ok {
r = &g
} else {
reward := n.getGASPerVote(ic.DAO, key[:34], []uint32{ic.Block.Index + 1})
r = &reward[0]
reward := n.getLatestGASPerVote(ic.DAO, key)
r = &reward
}
tmp.Add(tmp, r)

binary.BigEndian.PutUint32(key[34:], ic.Block.Index+1)
if !isCacheRW {
cache = ic.DAO.GetRWCache(n.ID).(*NeoCache)
isCacheRW = true
Expand All @@ -447,33 +446,12 @@ func (n *NEO) PostPersist(ic *interop.Context) error {
return nil
}

func (n *NEO) getGASPerVote(d *dao.Simple, key []byte, indexes []uint32) []big.Int {
sort.Slice(indexes, func(i, j int) bool {
return indexes[i] < indexes[j]
})
start := make([]byte, 4)
binary.BigEndian.PutUint32(start, indexes[len(indexes)-1])

need := len(indexes)
var reward = make([]big.Int, need)
collected := 0
d.Seek(n.ID, storage.SeekRange{
Prefix: key,
Start: start,
Backwards: true,
}, func(k, v []byte) bool {
if len(k) == 4 {
num := binary.BigEndian.Uint32(k)
for i, ind := range indexes {
if reward[i].Sign() == 0 && num <= ind {
reward[i] = *bigint.FromBytes(v)
collected++
}
}
}
return collected < need
})
return reward
func (n *NEO) getLatestGASPerVote(d *dao.Simple, key []byte) big.Int {
item := d.GetStorageItem(n.ID, key)
if item == nil {
return *big.NewInt(0)
}
return *bigint.FromBytes(item)
}

func (n *NEO) increaseBalance(ic *interop.Context, h util.Uint160, si *state.StorageItem, amount *big.Int, checkBal *big.Int) (func(), error) {
Expand Down Expand Up @@ -527,19 +505,22 @@ func (n *NEO) distributeGas(ic *interop.Context, acc *state.NEOBalance) (*big.In
if ic.Block == nil || ic.Block.Index == 0 || ic.Block.Index == acc.BalanceHeight {
return nil, nil
}
gen, err := n.calculateBonus(ic.DAO, acc.VoteTo, &acc.Balance, acc.BalanceHeight, ic.Block.Index)
gen, err := n.calculateBonus(ic, acc)
if err != nil {
return nil, err
}
acc.BalanceHeight = ic.Block.Index
if acc.VoteTo != nil {
latestGasPerVote := n.getLatestGASPerVote(ic.DAO, makeVoterKey(acc.VoteTo.Bytes()))
acc.LastGasPerVote = latestGasPerVote
}

return gen, nil
}

func (n *NEO) unclaimedGas(ic *interop.Context, args []stackitem.Item) stackitem.Item {
u := toUint160(args[0])
end := uint32(toBigInt(args[1]).Int64())
gen, err := n.CalculateBonus(ic.DAO, u, end)
gen, err := n.CalculateBonus(ic, u)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -647,10 +628,7 @@ func (n *NEO) dropCandidateIfZero(d *dao.Simple, cache *NeoCache, pub *keys.Publ
d.DeleteStorageItem(n.ID, makeValidatorKey(pub))

voterKey := makeVoterKey(pub.Bytes())
d.Seek(n.ID, storage.SeekRange{Prefix: voterKey}, func(k, v []byte) bool {
d.DeleteStorageItem(n.ID, append(voterKey, k...)) // d.Seek cuts prefix, thus need to append it again.
return true
})
d.DeleteStorageItem(n.ID, voterKey)
delete(cache.gasPerVoteCache, string(voterKey))

return true
Expand All @@ -661,7 +639,7 @@ func makeVoterKey(pub []byte, prealloc ...[]byte) []byte {
if len(prealloc) != 0 {
key = prealloc[0]
} else {
key = make([]byte, 34, 38)
key = make([]byte, 34)
}
key[0] = prefixVoterRewardPerCommittee
copy(key[1:], pub)
Expand All @@ -670,29 +648,30 @@ func makeVoterKey(pub []byte, prealloc ...[]byte) []byte {

// CalculateBonus calculates amount of gas generated for holding value NEO from start to end block
// and having voted for active committee member.
func (n *NEO) CalculateBonus(d *dao.Simple, acc util.Uint160, end uint32) (*big.Int, error) {
func (n *NEO) CalculateBonus(ic *interop.Context, acc util.Uint160) (*big.Int, error) {
key := makeAccountKey(acc)
si := d.GetStorageItem(n.ID, key)
si := ic.DAO.GetStorageItem(n.ID, key)
if si == nil {
return nil, storage.ErrKeyNotFound
}
st, err := state.NEOBalanceFromBytes(si)
if err != nil {
return nil, err
}
return n.calculateBonus(d, st.VoteTo, &st.Balance, st.BalanceHeight, end)
return n.calculateBonus(ic, st)
}

func (n *NEO) calculateBonus(d *dao.Simple, vote *keys.PublicKey, value *big.Int, start, end uint32) (*big.Int, error) {
r, err := n.CalculateNEOHolderReward(d, value, start, end)
if err != nil || vote == nil {
func (n *NEO) calculateBonus(ic *interop.Context, acc *state.NEOBalance) (*big.Int, error) {
end := ic.BlockHeight() + 1
r, err := n.CalculateNEOHolderReward(ic.DAO, &acc.Balance, acc.BalanceHeight, end)
if err != nil || acc.VoteTo == nil {
return r, err
}

var key = makeVoterKey(vote.Bytes())
var reward = n.getGASPerVote(d, key, []uint32{start, end})
var tmp = (&reward[1]).Sub(&reward[1], &reward[0])
tmp.Mul(tmp, value)
var key = makeVoterKey(acc.VoteTo.Bytes())
var reward = n.getLatestGASPerVote(ic.DAO, key)
var tmp = (&reward).Sub(&reward, &acc.LastGasPerVote)
tmp.Mul(tmp, &acc.Balance)
tmp.Div(tmp, bigVoterRewardFactor)
tmp.Add(tmp, r)
return tmp, nil
Expand Down Expand Up @@ -869,6 +848,9 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pub *keys.Public
if err := n.ModifyAccountVotes(acc, ic.DAO, new(big.Int).Neg(&acc.Balance), false); err != nil {
return err
}
if pub != nil && pub != acc.VoteTo {
acc.LastGasPerVote = n.getLatestGASPerVote(ic.DAO, makeVoterKey(pub.Bytes()))
}
oldVote := acc.VoteTo
acc.VoteTo = pub
if err := n.ModifyAccountVotes(acc, ic.DAO, &acc.Balance, true); err != nil {
Expand Down
11 changes: 9 additions & 2 deletions pkg/core/state/native_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ type NEP17Balance struct {
// NEOBalance represents the balance state of a NEO-token.
type NEOBalance struct {
NEP17Balance
BalanceHeight uint32
VoteTo *keys.PublicKey
BalanceHeight uint32
VoteTo *keys.PublicKey
LastGasPerVote big.Int
}

// NEP17BalanceFromBytes converts the serialized NEP17Balance to a structure.
Expand Down Expand Up @@ -125,6 +126,7 @@ func (s *NEOBalance) ToStackItem() (stackitem.Item, error) {
stackitem.NewBigInteger(&s.Balance),
stackitem.NewBigInteger(big.NewInt(int64(s.BalanceHeight))),
voteItem,
stackitem.NewBigInteger(&s.LastGasPerVote),
}), nil
}

Expand Down Expand Up @@ -157,5 +159,10 @@ func (s *NEOBalance) FromStackItem(item stackitem.Item) error {
return fmt.Errorf("invalid public key bytes: %w", err)
}
s.VoteTo = pub
lastGasPerVote, err := structItem[3].TryInteger()
if err != nil {
return fmt.Errorf("invalid last vote reward per neo stackitem: %w", err)
}
s.LastGasPerVote = *lastGasPerVote
return nil
}
4 changes: 2 additions & 2 deletions pkg/services/rpcsrv/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ type (
Ledger interface {
AddBlock(block *block.Block) error
BlockHeight() uint32
CalculateClaimable(h util.Uint160, endHeight uint32) (*big.Int, error)
CalculateClaimable(h util.Uint160) (*big.Int, error)
CurrentBlockHash() util.Uint256
FeePerByte() int64
ForEachNEP11Transfer(acc util.Uint160, newestTimestamp uint64, f func(*state.NEP11Transfer) (bool, error)) error
Expand Down Expand Up @@ -1785,7 +1785,7 @@ func (s *Server) getUnclaimedGas(ps params.Params) (interface{}, *neorpc.Error)
Address: u,
}, nil
}
gas, err := s.chain.CalculateClaimable(u, s.chain.BlockHeight()+1) // +1 as in C#, for the next block.
gas, err := s.chain.CalculateClaimable(u) // +1 as in C#, for the next block.
if err != nil {
return nil, neorpc.NewRPCError("Can't calculate claimable", err.Error())
}
Expand Down

0 comments on commit 93a9e55

Please sign in to comment.