core: provide account in calculate claimable
`getunclaimedgas` RPC should return all GAS available to claim.
This commit is contained in:
parent
860c146260
commit
54992ad4f3
8 changed files with 76 additions and 38 deletions
|
@ -172,21 +172,48 @@ func TestClaimGas(t *testing.T) {
|
|||
e := newExecutor(t, true)
|
||||
defer e.Close(t)
|
||||
|
||||
start := e.Chain.BlockHeight()
|
||||
balanceBefore := e.Chain.GetUtilityTokenBalance(validatorHash)
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "wallet", "claim",
|
||||
const walletPath = "testdata/testwallet.json"
|
||||
w, err := wallet.NewWalletFromFile(walletPath)
|
||||
require.NoError(t, err)
|
||||
defer w.Close()
|
||||
|
||||
args := []string{
|
||||
"neo-go", "wallet", "nep5", "multitransfer",
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
"--address", validatorAddr)
|
||||
tx, end := e.checkTxPersisted(t)
|
||||
b, _ := e.Chain.GetGoverningTokenBalance(validatorHash)
|
||||
cl := e.Chain.CalculateClaimable(b, start, end)
|
||||
require.True(t, cl.Sign() > 0)
|
||||
cl.Sub(cl, big.NewInt(tx.NetworkFee+tx.SystemFee))
|
||||
"--from", validatorAddr,
|
||||
"neo:" + w.Accounts[0].Address + ":1000",
|
||||
"gas:" + w.Accounts[0].Address + ":1000", // for tx send
|
||||
}
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, args...)
|
||||
e.checkTxPersisted(t)
|
||||
|
||||
balanceAfter := e.Chain.GetUtilityTokenBalance(validatorHash)
|
||||
require.Equal(t, 0, balanceAfter.Cmp(balanceBefore.Add(balanceBefore, cl)))
|
||||
h, err := address.StringToUint160(w.Accounts[0].Address)
|
||||
require.NoError(t, err)
|
||||
|
||||
balanceBefore := e.Chain.GetUtilityTokenBalance(h)
|
||||
claimHeight := e.Chain.BlockHeight() + 1
|
||||
cl, err := e.Chain.CalculateClaimable(h, claimHeight)
|
||||
require.NoError(t, err)
|
||||
require.True(t, cl.Sign() > 0)
|
||||
|
||||
e.In.WriteString("testpass\r")
|
||||
e.Run(t, "neo-go", "wallet", "claim",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", walletPath,
|
||||
"--address", w.Accounts[0].Address)
|
||||
tx, height := e.checkTxPersisted(t)
|
||||
balanceBefore.Sub(balanceBefore, big.NewInt(tx.NetworkFee+tx.SystemFee))
|
||||
balanceBefore.Add(balanceBefore, cl)
|
||||
|
||||
balanceAfter := e.Chain.GetUtilityTokenBalance(h)
|
||||
// height can be bigger than claimHeight especially when tests are executed with -race.
|
||||
if height == claimHeight {
|
||||
require.Equal(t, 0, balanceAfter.Cmp(balanceBefore))
|
||||
} else {
|
||||
require.Equal(t, 1, balanceAfter.Cmp(balanceBefore))
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportDeployed(t *testing.T) {
|
||||
|
|
|
@ -1156,10 +1156,8 @@ func (bc *Blockchain) UnsubscribeFromExecutions(ch chan<- *state.AppExecResult)
|
|||
|
||||
// CalculateClaimable calculates the amount of GAS generated by owning specified
|
||||
// amount of NEO between specified blocks.
|
||||
func (bc *Blockchain) CalculateClaimable(value *big.Int, startHeight, endHeight uint32) *big.Int {
|
||||
ic := bc.newInteropContext(trigger.Application, bc.dao, nil, nil)
|
||||
res, _ := bc.contracts.NEO.CalculateNEOHolderReward(ic, value, startHeight, endHeight)
|
||||
return res
|
||||
func (bc *Blockchain) CalculateClaimable(acc util.Uint160, endHeight uint32) (*big.Int, error) {
|
||||
return bc.contracts.NEO.CalculateBonus(bc.dao, acc, endHeight)
|
||||
}
|
||||
|
||||
// FeePerByte returns transaction network fee per byte.
|
||||
|
|
|
@ -854,8 +854,9 @@ func TestGetClaimable(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
t.Run("first generation period", func(t *testing.T) {
|
||||
amount := bc.CalculateClaimable(big.NewInt(1), 0, 2)
|
||||
require.EqualValues(t, big.NewInt(1), amount)
|
||||
amount, err := bc.CalculateClaimable(neoOwner, 1)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, big.NewInt(5*native.GASFactor/10), amount)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ type Blockchainer interface {
|
|||
AddHeaders(...*block.Header) error
|
||||
AddBlock(*block.Block) error
|
||||
AddStateRoot(r *state.MPTRoot) error
|
||||
CalculateClaimable(value *big.Int, startHeight, endHeight uint32) *big.Int
|
||||
CalculateClaimable(h util.Uint160, endHeight uint32) (*big.Int, error)
|
||||
Close()
|
||||
HeaderHeight() uint32
|
||||
GetBlock(hash util.Uint256) (*block.Block, error)
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
|
||||
|
@ -397,7 +398,7 @@ func (n *NEO) distributeGas(ic *interop.Context, h util.Uint160, acc *state.NEOB
|
|||
if ic.Block == nil || ic.Block.Index == 0 {
|
||||
return nil
|
||||
}
|
||||
gen, err := n.CalculateBonus(ic, acc.VoteTo, &acc.Balance, acc.BalanceHeight, ic.Block.Index)
|
||||
gen, err := n.calculateBonus(ic.DAO, acc.VoteTo, &acc.Balance, acc.BalanceHeight, ic.Block.Index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -409,13 +410,7 @@ func (n *NEO) distributeGas(ic *interop.Context, h util.Uint160, acc *state.NEOB
|
|||
func (n *NEO) unclaimedGas(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
u := toUint160(args[0])
|
||||
end := uint32(toBigInt(args[1]).Int64())
|
||||
key := makeAccountKey(u)
|
||||
si := ic.DAO.GetStorageItem(n.ContractID, key)
|
||||
st, err := state.NEOBalanceStateFromBytes(si.Value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
gen, err := n.CalculateBonus(ic, st.VoteTo, &st.Balance, st.BalanceHeight, end)
|
||||
gen, err := n.CalculateBonus(ic.DAO, u, end)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -534,14 +529,27 @@ 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, vote *keys.PublicKey, value *big.Int, start, end uint32) (*big.Int, error) {
|
||||
r, err := n.CalculateNEOHolderReward(ic, value, start, end)
|
||||
func (n *NEO) CalculateBonus(d dao.DAO, acc util.Uint160, end uint32) (*big.Int, error) {
|
||||
key := makeAccountKey(acc)
|
||||
si := d.GetStorageItem(n.ContractID, key)
|
||||
if si == nil {
|
||||
return nil, storage.ErrKeyNotFound
|
||||
}
|
||||
st, err := state.NEOBalanceStateFromBytes(si.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return n.calculateBonus(d, st.VoteTo, &st.Balance, st.BalanceHeight, end)
|
||||
}
|
||||
|
||||
func (n *NEO) calculateBonus(d dao.DAO, 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 {
|
||||
return r, err
|
||||
}
|
||||
|
||||
var key = makeVoterKey(vote.Bytes())
|
||||
var reward = n.getGASPerVote(ic.DAO, key, start, end)
|
||||
var reward = n.getGASPerVote(d, key, start, end)
|
||||
var tmp = new(big.Int).Sub(&reward[1], &reward[0])
|
||||
tmp.Mul(tmp, value)
|
||||
tmp.Div(tmp, big.NewInt(voterRewardFactor))
|
||||
|
@ -550,7 +558,7 @@ func (n *NEO) CalculateBonus(ic *interop.Context, vote *keys.PublicKey, value *b
|
|||
}
|
||||
|
||||
// CalculateNEOHolderReward return GAS reward for holding `value` of NEO from start to end block.
|
||||
func (n *NEO) CalculateNEOHolderReward(ic *interop.Context, value *big.Int, start, end uint32) (*big.Int, error) {
|
||||
func (n *NEO) CalculateNEOHolderReward(d dao.DAO, value *big.Int, start, end uint32) (*big.Int, error) {
|
||||
if value.Sign() == 0 || start >= end {
|
||||
return big.NewInt(0), nil
|
||||
} else if value.Sign() < 0 {
|
||||
|
@ -563,7 +571,7 @@ func (n *NEO) CalculateNEOHolderReward(ic *interop.Context, value *big.Int, star
|
|||
if !n.gasPerBlockChanged.Load().(bool) {
|
||||
gr = n.gasPerBlock.Load().(gasRecord)
|
||||
} else {
|
||||
gr, err = n.getSortedGASRecordFromDAO(ic.DAO)
|
||||
gr, err = n.getSortedGASRecordFromDAO(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -162,7 +162,8 @@ func TestNEO_Vote(t *testing.T) {
|
|||
newGAS := bc.GetUtilityTokenBalance(accs[i].Contract.ScriptHash())
|
||||
newGAS.Sub(newGAS, gasBalance[i])
|
||||
|
||||
gasForHold := bc.CalculateClaimable(neoBalance[i], transferBlock, bc.BlockHeight())
|
||||
gasForHold, err := bc.contracts.NEO.CalculateNEOHolderReward(bc.dao, neoBalance[i], transferBlock, bc.BlockHeight())
|
||||
require.NoError(t, err)
|
||||
newGAS.Sub(newGAS, gasForHold)
|
||||
require.True(t, newGAS.Sign() > 0)
|
||||
gasBalance[i] = newGAS
|
||||
|
@ -258,11 +259,11 @@ func TestNEO_CalculateBonus(t *testing.T) {
|
|||
ic.SpawnVM()
|
||||
ic.VM.LoadScript([]byte{byte(opcode.RET)})
|
||||
t.Run("Invalid", func(t *testing.T) {
|
||||
_, err := neo.CalculateNEOHolderReward(ic, new(big.Int).SetInt64(-1), 0, 1)
|
||||
_, err := neo.CalculateNEOHolderReward(ic.DAO, new(big.Int).SetInt64(-1), 0, 1)
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("Zero", func(t *testing.T) {
|
||||
res, err := neo.CalculateNEOHolderReward(ic, big.NewInt(0), 0, 100)
|
||||
res, err := neo.CalculateNEOHolderReward(ic.DAO, big.NewInt(0), 0, 100)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 0, res.Int64())
|
||||
})
|
||||
|
@ -272,7 +273,7 @@ func TestNEO_CalculateBonus(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.True(t, ok)
|
||||
|
||||
res, err := neo.CalculateNEOHolderReward(ic, big.NewInt(100), 5, 15)
|
||||
res, err := neo.CalculateNEOHolderReward(ic.DAO, big.NewInt(100), 5, 15)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, (100*5*5/10)+(100*5*1/10), res.Int64())
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ func (chain testChain) ApplyPolicyToTxSet([]*transaction.Transaction) []*transac
|
|||
func (chain testChain) GetConfig() config.ProtocolConfiguration {
|
||||
panic("TODO")
|
||||
}
|
||||
func (chain testChain) CalculateClaimable(*big.Int, uint32, uint32) *big.Int {
|
||||
func (chain testChain) CalculateClaimable(util.Uint160, uint32) (*big.Int, error) {
|
||||
panic("TODO")
|
||||
}
|
||||
|
||||
|
|
|
@ -951,13 +951,16 @@ func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Erro
|
|||
return nil, response.ErrInvalidParams
|
||||
}
|
||||
|
||||
neo, neoHeight := s.chain.GetGoverningTokenBalance(u)
|
||||
neo, _ := s.chain.GetGoverningTokenBalance(u)
|
||||
if neo.Sign() == 0 {
|
||||
return result.UnclaimedGas{
|
||||
Address: u,
|
||||
}, nil
|
||||
}
|
||||
gas := s.chain.CalculateClaimable(neo, neoHeight, s.chain.BlockHeight()+1) // +1 as in C#, for the next block.
|
||||
gas, err := s.chain.CalculateClaimable(u, s.chain.BlockHeight()+1) // +1 as in C#, for the next block.
|
||||
if err != nil {
|
||||
return nil, response.NewInternalServerError("can't calculate claimable", err)
|
||||
}
|
||||
return result.UnclaimedGas{
|
||||
Address: u,
|
||||
Unclaimed: *gas,
|
||||
|
|
Loading…
Reference in a new issue