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)
|
e := newExecutor(t, true)
|
||||||
defer e.Close(t)
|
defer e.Close(t)
|
||||||
|
|
||||||
start := e.Chain.BlockHeight()
|
const walletPath = "testdata/testwallet.json"
|
||||||
balanceBefore := e.Chain.GetUtilityTokenBalance(validatorHash)
|
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,
|
||||||
|
"--from", validatorAddr,
|
||||||
|
"neo:" + w.Accounts[0].Address + ":1000",
|
||||||
|
"gas:" + w.Accounts[0].Address + ":1000", // for tx send
|
||||||
|
}
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, args...)
|
||||||
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
|
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",
|
e.Run(t, "neo-go", "wallet", "claim",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", validatorWallet,
|
"--wallet", walletPath,
|
||||||
"--address", validatorAddr)
|
"--address", w.Accounts[0].Address)
|
||||||
tx, end := e.checkTxPersisted(t)
|
tx, height := e.checkTxPersisted(t)
|
||||||
b, _ := e.Chain.GetGoverningTokenBalance(validatorHash)
|
balanceBefore.Sub(balanceBefore, big.NewInt(tx.NetworkFee+tx.SystemFee))
|
||||||
cl := e.Chain.CalculateClaimable(b, start, end)
|
balanceBefore.Add(balanceBefore, cl)
|
||||||
require.True(t, cl.Sign() > 0)
|
|
||||||
cl.Sub(cl, big.NewInt(tx.NetworkFee+tx.SystemFee))
|
|
||||||
|
|
||||||
balanceAfter := e.Chain.GetUtilityTokenBalance(validatorHash)
|
balanceAfter := e.Chain.GetUtilityTokenBalance(h)
|
||||||
require.Equal(t, 0, balanceAfter.Cmp(balanceBefore.Add(balanceBefore, cl)))
|
// 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) {
|
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
|
// CalculateClaimable calculates the amount of GAS generated by owning specified
|
||||||
// amount of NEO between specified blocks.
|
// amount of NEO between specified blocks.
|
||||||
func (bc *Blockchain) CalculateClaimable(value *big.Int, startHeight, endHeight uint32) *big.Int {
|
func (bc *Blockchain) CalculateClaimable(acc util.Uint160, endHeight uint32) (*big.Int, error) {
|
||||||
ic := bc.newInteropContext(trigger.Application, bc.dao, nil, nil)
|
return bc.contracts.NEO.CalculateBonus(bc.dao, acc, endHeight)
|
||||||
res, _ := bc.contracts.NEO.CalculateNEOHolderReward(ic, value, startHeight, endHeight)
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FeePerByte returns transaction network fee per byte.
|
// FeePerByte returns transaction network fee per byte.
|
||||||
|
|
|
@ -854,8 +854,9 @@ 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(big.NewInt(1), 0, 2)
|
amount, err := bc.CalculateClaimable(neoOwner, 1)
|
||||||
require.EqualValues(t, big.NewInt(1), amount)
|
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
|
AddHeaders(...*block.Header) error
|
||||||
AddBlock(*block.Block) error
|
AddBlock(*block.Block) error
|
||||||
AddStateRoot(r *state.MPTRoot) 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()
|
Close()
|
||||||
HeaderHeight() uint32
|
HeaderHeight() uint32
|
||||||
GetBlock(hash util.Uint256) (*block.Block, error)
|
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"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
|
"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/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/hash"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
|
"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 {
|
if ic.Block == nil || ic.Block.Index == 0 {
|
||||||
return nil
|
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 {
|
if err != nil {
|
||||||
return err
|
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 {
|
func (n *NEO) unclaimedGas(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||||
u := toUint160(args[0])
|
u := toUint160(args[0])
|
||||||
end := uint32(toBigInt(args[1]).Int64())
|
end := uint32(toBigInt(args[1]).Int64())
|
||||||
key := makeAccountKey(u)
|
gen, err := n.CalculateBonus(ic.DAO, u, end)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
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
|
// CalculateBonus calculates amount of gas generated for holding value NEO from start to end block
|
||||||
// and having voted for active committee member.
|
// 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) {
|
func (n *NEO) CalculateBonus(d dao.DAO, acc util.Uint160, end uint32) (*big.Int, error) {
|
||||||
r, err := n.CalculateNEOHolderReward(ic, value, start, end)
|
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 {
|
if err != nil || vote == nil {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var key = makeVoterKey(vote.Bytes())
|
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])
|
var tmp = new(big.Int).Sub(&reward[1], &reward[0])
|
||||||
tmp.Mul(tmp, value)
|
tmp.Mul(tmp, value)
|
||||||
tmp.Div(tmp, big.NewInt(voterRewardFactor))
|
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.
|
// 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 {
|
if value.Sign() == 0 || start >= end {
|
||||||
return big.NewInt(0), nil
|
return big.NewInt(0), nil
|
||||||
} else if value.Sign() < 0 {
|
} 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) {
|
if !n.gasPerBlockChanged.Load().(bool) {
|
||||||
gr = n.gasPerBlock.Load().(gasRecord)
|
gr = n.gasPerBlock.Load().(gasRecord)
|
||||||
} else {
|
} else {
|
||||||
gr, err = n.getSortedGASRecordFromDAO(ic.DAO)
|
gr, err = n.getSortedGASRecordFromDAO(d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,7 +162,8 @@ func TestNEO_Vote(t *testing.T) {
|
||||||
newGAS := bc.GetUtilityTokenBalance(accs[i].Contract.ScriptHash())
|
newGAS := bc.GetUtilityTokenBalance(accs[i].Contract.ScriptHash())
|
||||||
newGAS.Sub(newGAS, gasBalance[i])
|
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)
|
newGAS.Sub(newGAS, gasForHold)
|
||||||
require.True(t, newGAS.Sign() > 0)
|
require.True(t, newGAS.Sign() > 0)
|
||||||
gasBalance[i] = newGAS
|
gasBalance[i] = newGAS
|
||||||
|
@ -258,11 +259,11 @@ func TestNEO_CalculateBonus(t *testing.T) {
|
||||||
ic.SpawnVM()
|
ic.SpawnVM()
|
||||||
ic.VM.LoadScript([]byte{byte(opcode.RET)})
|
ic.VM.LoadScript([]byte{byte(opcode.RET)})
|
||||||
t.Run("Invalid", func(t *testing.T) {
|
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)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
t.Run("Zero", func(t *testing.T) {
|
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.NoError(t, err)
|
||||||
require.EqualValues(t, 0, res.Int64())
|
require.EqualValues(t, 0, res.Int64())
|
||||||
})
|
})
|
||||||
|
@ -272,7 +273,7 @@ func TestNEO_CalculateBonus(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, ok)
|
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.NoError(t, err)
|
||||||
require.EqualValues(t, (100*5*5/10)+(100*5*1/10), res.Int64())
|
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 {
|
func (chain testChain) GetConfig() config.ProtocolConfiguration {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
func (chain testChain) CalculateClaimable(*big.Int, uint32, uint32) *big.Int {
|
func (chain testChain) CalculateClaimable(util.Uint160, uint32) (*big.Int, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -951,13 +951,16 @@ func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Erro
|
||||||
return nil, response.ErrInvalidParams
|
return nil, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
|
|
||||||
neo, neoHeight := s.chain.GetGoverningTokenBalance(u)
|
neo, _ := s.chain.GetGoverningTokenBalance(u)
|
||||||
if neo.Sign() == 0 {
|
if neo.Sign() == 0 {
|
||||||
return result.UnclaimedGas{
|
return result.UnclaimedGas{
|
||||||
Address: u,
|
Address: u,
|
||||||
}, nil
|
}, 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{
|
return result.UnclaimedGas{
|
||||||
Address: u,
|
Address: u,
|
||||||
Unclaimed: *gas,
|
Unclaimed: *gas,
|
||||||
|
|
Loading…
Reference in a new issue