diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index 7a72111833..9978e0b97a 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -750,18 +750,21 @@ 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(ic *interop.Context, acc util.Uint160, end uint32) (*big.Int, error) { - if ic.Block == nil || end != ic.Block.Index { - return nil, errors.New("can't calculate bonus of height unequal (BlockHeight + 1)") - } key := makeAccountKey(acc) si := ic.DAO.GetStorageItem(n.ID, key) if si == nil { - return nil, storage.ErrKeyNotFound + return big.NewInt(0), nil } st, err := state.NEOBalanceFromBytes(si) if err != nil { return nil, err } + if st.Balance.Sign() == 0 { + return big.NewInt(0), nil + } + if ic.Block == nil || end != ic.Block.Index { + return nil, errors.New("can't calculate bonus of height unequal (BlockHeight + 1)") + } return n.calculateBonus(ic.DAO, st, end) } diff --git a/pkg/core/native/native_test/neo_test.go b/pkg/core/native/native_test/neo_test.go index e25e0b91fb..f0ef78ed70 100644 --- a/pkg/core/native/native_test/neo_test.go +++ b/pkg/core/native/native_test/neo_test.go @@ -776,6 +776,35 @@ func TestNEO_CalculateBonus(t *testing.T) { }) } +func TestNEO_UnclaimedGas(t *testing.T) { + neoValidatorsInvoker := newNeoValidatorsClient(t) + e := neoValidatorsInvoker.Executor + + acc := neoValidatorsInvoker.WithSigners(e.NewAccount(t)) + accH := acc.Signers[0].ScriptHash() + + t.Run("non-existing account", func(t *testing.T) { + // non-existing account, should return zero unclaimed GAS. + acc.Invoke(t, 0, "unclaimedGas", util.Uint160{}, 1) + }) + + t.Run("non-zero balance", func(t *testing.T) { + amount := 100 + defaultGASPerBlock := 5 + neoHolderRewardRatio := 10 + rewardDistance := 10 + neoValidatorsInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), accH, amount, nil) + + for range rewardDistance - 1 { + e.AddNewBlock(t) + } + expectedGas := int64(amount * neoHolderRewardRatio / 100 * defaultGASPerBlock * rewardDistance) + acc.Invoke(t, expectedGas, "unclaimedGas", accH, e.Chain.BlockHeight()+1) + + acc.InvokeFail(t, "can't calculate bonus of height unequal (BlockHeight + 1)", "unclaimedGas", accH, e.Chain.BlockHeight()) + }) +} + func TestNEO_GetCandidates(t *testing.T) { neoCommitteeInvoker := newNeoCommitteeClient(t, 100_0000_0000) neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)