core/native: move Votes from account to native NEO state

This commit is contained in:
Roman Khimov 2020-04-26 14:00:17 +03:00
parent bc4a6a6bab
commit 2fa3bdf6a9
10 changed files with 18 additions and 72 deletions

View file

@ -404,24 +404,6 @@ func accountGetScriptHash(ic *interop.Context, v *vm.VM) error {
return nil
}
// accountGetVotes returns votes of a given account.
func accountGetVotes(ic *interop.Context, v *vm.VM) error {
accInterface := v.Estack().Pop().Value()
acc, ok := accInterface.(*state.Account)
if !ok {
return fmt.Errorf("%T is not an account state", acc)
}
if len(acc.Votes) > vm.MaxArraySize {
return errors.New("too many votes")
}
votes := make([]vm.StackItem, 0, len(acc.Votes))
for _, key := range acc.Votes {
votes = append(votes, vm.NewByteArrayItem(key.Bytes()))
}
v.Estack().PushVal(votes)
return nil
}
// accountIsStandard checks whether given account is standard.
func accountIsStandard(ic *interop.Context, v *vm.VM) error {
accbytes := v.Estack().Pop().Bytes()

View file

@ -417,17 +417,6 @@ func TestAccountGetScriptHash(t *testing.T) {
require.Equal(t, accState.ScriptHash.BytesBE(), hash)
}
func TestAccountGetVotes(t *testing.T) {
v, accState, context, chain := createVMAndAccState(t)
defer chain.Close()
v.Estack().PushVal(vm.NewInteropItem(accState))
err := accountGetVotes(context, v)
require.NoError(t, err)
votes := v.Estack().Pop().Value().([]vm.StackItem)
require.Equal(t, vm.NewByteArrayItem(accState.Votes[0].Bytes()), votes[0])
}
func TestContractGetScript(t *testing.T) {
v, contractState, context, chain := createVMAndContractState(t)
defer chain.Close()
@ -603,9 +592,6 @@ func createVMAndAccState(t *testing.T) (*vm.VM, *state.Account, *interop.Context
hash, err := util.Uint160DecodeStringBE(rawHash)
accountState := state.NewAccount(hash)
key := &keys.PublicKey{X: big.NewInt(1), Y: big.NewInt(1)}
accountState.Votes = []*keys.PublicKey{key}
require.NoError(t, err)
chain := newTestChain(t)
context := chain.newInteropContext(trigger.Application, dao.NewSimple(storage.NewMemoryStore()), nil, nil)

View file

@ -115,7 +115,6 @@ var systemInterops = []interop.Function{
var neoInterops = []interop.Function{
{Name: "Neo.Account.GetBalance", Func: accountGetBalance, Price: 1},
{Name: "Neo.Account.GetScriptHash", Func: accountGetScriptHash, Price: 1},
{Name: "Neo.Account.GetVotes", Func: accountGetVotes, Price: 1},
{Name: "Neo.Account.IsStandard", Func: accountIsStandard, Price: 100},
{Name: "Neo.Asset.Create", Func: assetCreate, Price: 0},
{Name: "Neo.Asset.GetAdmin", Func: assetGetAdmin, Price: 1},
@ -204,7 +203,6 @@ var neoInterops = []interop.Function{
// Old compatibility APIs.
{Name: "AntShares.Account.GetBalance", Func: accountGetBalance, Price: 1},
{Name: "AntShares.Account.GetScriptHash", Func: accountGetScriptHash, Price: 1},
{Name: "AntShares.Account.GetVotes", Func: accountGetVotes, Price: 1},
{Name: "AntShares.Asset.Create", Func: assetCreate, Price: 0},
{Name: "AntShares.Asset.GetAdmin", Func: assetGetAdmin, Price: 1},
{Name: "AntShares.Asset.GetAmount", Func: assetGetAmount, Price: 1},

View file

@ -34,7 +34,6 @@ func TestUnexpectedNonInterops(t *testing.T) {
funcs := []func(*interop.Context, *vm.VM) error{
accountGetBalance,
accountGetScriptHash,
accountGetVotes,
assetGetAdmin,
assetGetAmount,
assetGetAssetID,

View file

@ -166,12 +166,8 @@ func (n *NEO) increaseBalance(ic *interop.Context, h util.Uint160, si *state.Sto
if amount.Sign() == 0 {
return nil
}
oldAcc, err := ic.DAO.GetAccountState(h)
if err != nil {
return err
}
if len(oldAcc.Votes) > 0 {
if err := n.ModifyAccountVotes(oldAcc, ic.DAO, new(big.Int).Neg(&acc.Balance)); err != nil {
if len(acc.Votes) > 0 {
if err := n.ModifyAccountVotes(acc, ic.DAO, new(big.Int).Neg(&acc.Balance)); err != nil {
return err
}
siVC := ic.DAO.GetStorageItem(n.Hash, validatorsCountKey)
@ -182,7 +178,7 @@ func (n *NEO) increaseBalance(ic *interop.Context, h util.Uint160, si *state.Sto
if err != nil {
return err
}
vc[len(oldAcc.Votes)-1].Add(&vc[len(oldAcc.Votes)-1], amount)
vc[len(acc.Votes)-1].Add(&vc[len(acc.Votes)-1], amount)
siVC.Value = vc.Bytes()
if err := ic.DAO.PutStorageItem(n.Hash, validatorsCountKey, siVC); err != nil {
return err
@ -276,11 +272,7 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pubs keys.Public
if err != nil {
return err
}
oldAcc, err := ic.DAO.GetAccountState(h)
if err != nil {
return err
}
if err := n.ModifyAccountVotes(oldAcc, ic.DAO, new(big.Int).Neg(&acc.Balance)); err != nil {
if err := n.ModifyAccountVotes(acc, ic.DAO, new(big.Int).Neg(&acc.Balance)); err != nil {
return err
}
pubs = pubs.Unique()
@ -292,7 +284,7 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pubs keys.Public
}
newPubs = append(newPubs, pub)
}
if lp, lv := len(newPubs), len(oldAcc.Votes); lp != lv {
if lp, lv := len(newPubs), len(acc.Votes); lp != lv {
si := ic.DAO.GetStorageItem(n.Hash, validatorsCountKey)
if si == nil {
return errors.New("validators count uninitialized")
@ -312,15 +304,16 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pubs keys.Public
return err
}
}
oldAcc.Votes = newPubs
if err := n.ModifyAccountVotes(oldAcc, ic.DAO, &acc.Balance); err != nil {
acc.Votes = newPubs
if err := n.ModifyAccountVotes(acc, ic.DAO, &acc.Balance); err != nil {
return err
}
return ic.DAO.PutAccountState(oldAcc)
si.Value = acc.Bytes()
return ic.DAO.PutStorageItem(n.Hash, key, si)
}
// ModifyAccountVotes modifies votes of the specified account by value (can be negative).
func (n *NEO) ModifyAccountVotes(acc *state.Account, d dao.DAO, value *big.Int) error {
func (n *NEO) ModifyAccountVotes(acc *state.NEOBalanceState, d dao.DAO, value *big.Int) error {
for _, vote := range acc.Votes {
key := makeValidatorKey(vote)
si := d.GetStorageItem(n.Hash, key)

View file

@ -1,7 +1,6 @@
package state
import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/util"
)
@ -32,7 +31,6 @@ type Account struct {
Version uint8
ScriptHash util.Uint160
IsFrozen bool
Votes []*keys.PublicKey
Balances map[util.Uint256][]UnspentBalance
Unclaimed UnclaimedBalances
}
@ -43,7 +41,6 @@ func NewAccount(scriptHash util.Uint160) *Account {
Version: 0,
ScriptHash: scriptHash,
IsFrozen: false,
Votes: []*keys.PublicKey{},
Balances: make(map[util.Uint256][]UnspentBalance),
Unclaimed: UnclaimedBalances{Raw: []byte{}},
}
@ -54,7 +51,6 @@ func (s *Account) DecodeBinary(br *io.BinReader) {
s.Version = uint8(br.ReadB())
br.ReadBytes(s.ScriptHash[:])
s.IsFrozen = br.ReadBool()
br.ReadArray(&s.Votes)
s.Balances = make(map[util.Uint256][]UnspentBalance)
lenBalances := br.ReadVarUint()
@ -79,7 +75,6 @@ func (s *Account) EncodeBinary(bw *io.BinWriter) {
bw.WriteB(byte(s.Version))
bw.WriteBytes(s.ScriptHash[:])
bw.WriteBool(s.IsFrozen)
bw.WriteArray(s.Votes)
bw.WriteVarUint(uint64(len(s.Balances)))
for k, v := range s.Balances {

View file

@ -3,7 +3,6 @@ package state
import (
"testing"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/internal/random"
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
"github.com/nspcc-dev/neo-go/pkg/util"
@ -14,7 +13,6 @@ func TestDecodeEncodeAccountState(t *testing.T) {
var (
n = 10
balances = make(map[util.Uint256][]UnspentBalance)
votes = make([]*keys.PublicKey, n)
)
for i := 0; i < n; i++ {
asset := random.Uint256()
@ -25,16 +23,12 @@ func TestDecodeEncodeAccountState(t *testing.T) {
Value: util.Fixed8(int64(random.Int(1, 10000))),
})
}
k, err := keys.NewPrivateKey()
assert.Nil(t, err)
votes[i] = k.PublicKey()
}
a := &Account{
Version: 0,
ScriptHash: random.Uint160(),
IsFrozen: true,
Votes: votes,
Balances: balances,
Unclaimed: UnclaimedBalances{Raw: []byte{}},
}

View file

@ -3,6 +3,7 @@ package state
import (
"math/big"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
)
@ -16,6 +17,7 @@ type NEP5BalanceState struct {
type NEOBalanceState struct {
NEP5BalanceState
BalanceHeight uint32
Votes keys.PublicKeys
}
// NEP5BalanceStateFromBytes converts serialized NEP5BalanceState to structure.
@ -85,10 +87,12 @@ func (s *NEOBalanceState) Bytes() []byte {
func (s *NEOBalanceState) EncodeBinary(w *io.BinWriter) {
s.NEP5BalanceState.EncodeBinary(w)
w.WriteU32LE(s.BalanceHeight)
w.WriteArray(s.Votes)
}
// DecodeBinary implements io.Serializable interface.
func (s *NEOBalanceState) DecodeBinary(r *io.BinReader) {
s.NEP5BalanceState.DecodeBinary(r)
s.BalanceHeight = r.ReadU32LE()
r.ReadArray(&s.Votes)
}

View file

@ -11,7 +11,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/rpc/request"
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
@ -49,7 +48,6 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
Version: 0,
ScriptHash: scriptHash,
IsFrozen: false,
Votes: []*keys.PublicKey{},
Balances: result.Balances{
result.Balance{
Asset: core.GoverningTokenID(),

View file

@ -5,18 +5,16 @@ import (
"sort"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util"
)
// AccountState wrapper used for the representation of
// state.Account on the RPC Server.
type AccountState struct {
Version uint8 `json:"version"`
ScriptHash util.Uint160 `json:"script_hash"`
IsFrozen bool `json:"frozen"`
Votes []*keys.PublicKey `json:"votes"`
Balances []Balance `json:"balances"`
Version uint8 `json:"version"`
ScriptHash util.Uint160 `json:"script_hash"`
IsFrozen bool `json:"frozen"`
Balances []Balance `json:"balances"`
}
// Balances type for sorting balances in rpc response.
@ -48,7 +46,6 @@ func NewAccountState(a *state.Account) AccountState {
Version: a.Version,
ScriptHash: a.ScriptHash,
IsFrozen: a.IsFrozen,
Votes: a.Votes,
Balances: balances,
}
}