core: fix CalculateClaimable for NEP5 NEO

It's not stored as Fixed8, so calculations need to be adjusted for that.
This commit is contained in:
Roman Khimov 2020-06-04 23:16:43 +03:00
parent 39dfebccc4
commit 3d18f09def
7 changed files with 28 additions and 18 deletions

View file

@ -1224,8 +1224,10 @@ func (bc *Blockchain) UnsubscribeFromExecutions(ch chan<- *state.AppExecResult)
} }
// CalculateClaimable calculates the amount of GAS generated by owning specified // CalculateClaimable calculates the amount of GAS generated by owning specified
// amount of NEO between specified blocks. // amount of NEO between specified blocks. The amount of NEO being passed is in
func (bc *Blockchain) CalculateClaimable(value util.Fixed8, startHeight, endHeight uint32) util.Fixed8 { // its natural non-divisible form (1 NEO as 1, 2 NEO as 2, no multiplication by
// 10⁸ is neeeded as for Fixed8).
func (bc *Blockchain) CalculateClaimable(value int64, startHeight, endHeight uint32) util.Fixed8 {
var amount util.Fixed8 var amount util.Fixed8
di := uint32(bc.decrementInterval) di := uint32(bc.decrementInterval)
@ -1251,8 +1253,7 @@ func (bc *Blockchain) CalculateClaimable(value util.Fixed8, startHeight, endHeig
amount += util.Fixed8(iend-istart) * util.Fixed8(bc.generationAmount[ustart]) amount += util.Fixed8(iend-istart) * util.Fixed8(bc.generationAmount[ustart])
} }
ratio := value / 100000000 return amount * util.Fixed8(value)
return amount * ratio
} }
// References maps transaction's inputs into a slice of InOuts, effectively // References maps transaction's inputs into a slice of InOuts, effectively
@ -1457,7 +1458,7 @@ func (bc *Blockchain) calculateBonus(claims []transaction.Input) (util.Fixed8, e
func (bc *Blockchain) calculateBonusInternal(scs []*spentCoin) (util.Fixed8, error) { func (bc *Blockchain) calculateBonusInternal(scs []*spentCoin) (util.Fixed8, error) {
var claimed util.Fixed8 var claimed util.Fixed8
for _, sc := range scs { for _, sc := range scs {
claimed += bc.CalculateClaimable(sc.Output.Amount, sc.StartHeight, sc.EndHeight) claimed += bc.CalculateClaimable(sc.Output.Amount.IntegralValue(), sc.StartHeight, sc.EndHeight)
} }
return claimed, nil return claimed, nil

View file

@ -194,22 +194,22 @@ func TestGetClaimable(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
t.Run("first generation period", func(t *testing.T) { t.Run("first generation period", func(t *testing.T) {
amount := bc.CalculateClaimable(util.Fixed8FromInt64(1), 0, 2) amount := bc.CalculateClaimable(1, 0, 2)
require.EqualValues(t, 8, amount) require.EqualValues(t, 8, amount)
}) })
t.Run("a number of full periods", func(t *testing.T) { t.Run("a number of full periods", func(t *testing.T) {
amount := bc.CalculateClaimable(util.Fixed8FromInt64(1), 0, 6) amount := bc.CalculateClaimable(1, 0, 6)
require.EqualValues(t, 4+4+3+3+2+2, amount) require.EqualValues(t, 4+4+3+3+2+2, amount)
}) })
t.Run("start from the 2-nd block", func(t *testing.T) { t.Run("start from the 2-nd block", func(t *testing.T) {
amount := bc.CalculateClaimable(util.Fixed8FromInt64(1), 1, 7) amount := bc.CalculateClaimable(1, 1, 7)
require.EqualValues(t, 4+3+3+2+2+1, amount) require.EqualValues(t, 4+3+3+2+2+1, amount)
}) })
t.Run("end height after generation has ended", func(t *testing.T) { t.Run("end height after generation has ended", func(t *testing.T) {
amount := bc.CalculateClaimable(util.Fixed8FromInt64(1), 1, 10) amount := bc.CalculateClaimable(1, 1, 10)
require.EqualValues(t, 4+3+3+2+2+1+1, amount) require.EqualValues(t, 4+3+3+2+2+1+1, amount)
}) })
} }

View file

@ -19,7 +19,7 @@ type Blockchainer interface {
AddHeaders(...*block.Header) error AddHeaders(...*block.Header) error
AddBlock(*block.Block) error AddBlock(*block.Block) error
BlockHeight() uint32 BlockHeight() uint32
CalculateClaimable(value util.Fixed8, startHeight, endHeight uint32) util.Fixed8 CalculateClaimable(value int64, startHeight, endHeight uint32) util.Fixed8
Close() Close()
HeaderHeight() uint32 HeaderHeight() uint32
GetBlock(hash util.Uint256) (*block.Block, error) GetBlock(hash util.Uint256) (*block.Block, error)

View file

@ -188,7 +188,7 @@ func (n *NEO) distributeGas(ic *interop.Context, h util.Uint160, acc *state.NEOB
if ic.Block == nil || ic.Block.Index == 0 { if ic.Block == nil || ic.Block.Index == 0 {
return nil return nil
} }
gen := ic.Chain.CalculateClaimable(util.Fixed8(acc.Balance.Int64()), acc.BalanceHeight, ic.Block.Index) gen := ic.Chain.CalculateClaimable(acc.Balance.Int64(), acc.BalanceHeight, ic.Block.Index)
acc.BalanceHeight = ic.Block.Index acc.BalanceHeight = ic.Block.Index
n.GAS.mint(ic, h, big.NewInt(int64(gen))) n.GAS.mint(ic, h, big.NewInt(int64(gen)))
return nil return nil
@ -203,7 +203,7 @@ func (n *NEO) unclaimedGas(ic *interop.Context, args []vm.StackItem) vm.StackIte
} }
tr := bs.Trackers[n.Hash] tr := bs.Trackers[n.Hash]
gen := ic.Chain.CalculateClaimable(util.Fixed8(tr.Balance), tr.LastUpdatedBlock, end) gen := ic.Chain.CalculateClaimable(tr.Balance, tr.LastUpdatedBlock, end)
return vm.NewBigIntegerItem(big.NewInt(int64(gen))) return vm.NewBigIntegerItem(big.NewInt(int64(gen)))
} }

View file

@ -31,7 +31,7 @@ func (chain testChain) ApplyPolicyToTxSet([]mempool.TxWithFee) []mempool.TxWithF
func (chain testChain) GetConfig() config.ProtocolConfiguration { func (chain testChain) GetConfig() config.ProtocolConfiguration {
panic("TODO") panic("TODO")
} }
func (chain testChain) CalculateClaimable(util.Fixed8, uint32, uint32) util.Fixed8 { func (chain testChain) CalculateClaimable(int64, uint32, uint32) util.Fixed8 {
panic("TODO") panic("TODO")
} }

View file

@ -821,8 +821,8 @@ func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Erro
if neo == 0 { if neo == 0 {
return "0", nil return "0", nil
} }
gas := s.chain.CalculateClaimable(neo, neoHeight, s.chain.BlockHeight()+1) // +1 as in C#, for the next block. gas := s.chain.CalculateClaimable(int64(neo), neoHeight, s.chain.BlockHeight()+1) // +1 as in C#, for the next block.
return strconv.FormatInt(int64(gas), 10), nil // It's not represented as Fixed8 in C#. return strconv.FormatInt(int64(gas), 10), nil // It's not represented as Fixed8 in C#.
} }
// getValidators returns the current NEO consensus nodes information and voting status. // getValidators returns the current NEO consensus nodes information and voting status.

View file

@ -151,8 +151,8 @@ var rpcTestCases = map[string][]rpcTestCase{
}, },
{ {
Asset: e.chain.UtilityTokenHash(), Asset: e.chain.UtilityTokenHash(),
Amount: "1000", Amount: "1023.99976000",
LastUpdated: 1, LastUpdated: 4,
}}, }},
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(), Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
} }
@ -229,6 +229,15 @@ var rpcTestCases = map[string][]rpcTestCase{
NotifyIndex: 0, NotifyIndex: 0,
TxHash: txReceiveRublesHash, TxHash: txReceiveRublesHash,
}, },
{
Timestamp: blockSendNEO.Timestamp,
Asset: e.chain.UtilityTokenHash(),
Address: "", // Minted GAS.
Amount: "23.99976000",
Index: 4,
NotifyIndex: 0,
TxHash: txSendNEOHash,
},
{ {
Timestamp: blockReceiveGAS.Timestamp, Timestamp: blockReceiveGAS.Timestamp,
Asset: e.chain.UtilityTokenHash(), Asset: e.chain.UtilityTokenHash(),
@ -528,7 +537,7 @@ var rpcTestCases = map[string][]rpcTestCase{
s, ok := resp.(*string) s, ok := resp.(*string)
require.True(t, ok) require.True(t, ok)
// Incorrect, to be fixed later. // Incorrect, to be fixed later.
assert.Equal(t, "0", *s) assert.Equal(t, "48000", *s)
}, },
}, },
}, },