From b14b047c78563769bc5fe82ed59d14a35084322e Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Mon, 3 Aug 2020 16:24:22 +0300 Subject: [PATCH] native: add tests for delegated voting --- pkg/core/native/native_neo.go | 7 +-- pkg/core/native/native_nep5.go | 5 +- pkg/core/native_neo_test.go | 95 ++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 pkg/core/native_neo_test.go diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index 41e257fb2..99579165f 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -143,7 +143,7 @@ func (n *NEO) Initialize(ic *interop.Context) error { } for i := range vs { - if err := n.registerCandidateInternal(ic, vs[i]); err != nil { + if err := n.RegisterCandidateInternal(ic, vs[i]); err != nil { return err } } @@ -218,11 +218,12 @@ func (n *NEO) unclaimedGas(ic *interop.Context, args []stackitem.Item) stackitem } func (n *NEO) registerCandidate(ic *interop.Context, args []stackitem.Item) stackitem.Item { - err := n.registerCandidateInternal(ic, toPublicKey(args[0])) + err := n.RegisterCandidateInternal(ic, toPublicKey(args[0])) return stackitem.NewBool(err == nil) } -func (n *NEO) registerCandidateInternal(ic *interop.Context, pub *keys.PublicKey) error { +// RegisterCandidateInternal registers pub as a new candidate. +func (n *NEO) RegisterCandidateInternal(ic *interop.Context, pub *keys.PublicKey) error { key := makeValidatorKey(pub) si := ic.DAO.GetStorageItem(n.ContractID, key) if si == nil { diff --git a/pkg/core/native/native_nep5.go b/pkg/core/native/native_nep5.go index ec971278c..938395fbe 100644 --- a/pkg/core/native/native_nep5.go +++ b/pkg/core/native/native_nep5.go @@ -125,7 +125,7 @@ func (c *nep5TokenNative) Transfer(ic *interop.Context, args []stackitem.Item) s from := toUint160(args[0]) to := toUint160(args[1]) amount := toBigInt(args[2]) - err := c.transfer(ic, from, to, amount) + err := c.TransferInternal(ic, from, to, amount) return stackitem.NewBool(err == nil) } @@ -171,7 +171,8 @@ func (c *nep5TokenNative) updateAccBalance(ic *interop.Context, acc util.Uint160 return err } -func (c *nep5TokenNative) transfer(ic *interop.Context, from, to util.Uint160, amount *big.Int) error { +// TransferInternal transfers NEO between accounts. +func (c *nep5TokenNative) TransferInternal(ic *interop.Context, from, to util.Uint160, amount *big.Int) error { if amount.Sign() == -1 { return errors.New("negative amount") } diff --git a/pkg/core/native_neo_test.go b/pkg/core/native_neo_test.go new file mode 100644 index 000000000..72da75bb9 --- /dev/null +++ b/pkg/core/native_neo_test.go @@ -0,0 +1,95 @@ +package core + +import ( + "math/big" + "testing" + + "github.com/nspcc-dev/neo-go/pkg/config/netmode" + "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/internal/testchain" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" + "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/stretchr/testify/require" +) + +// testScriptGetter is an auxilliary struct to pass CheckWitness checks. +type testScriptGetter struct { + h util.Uint160 +} + +func (t testScriptGetter) GetCallingScriptHash() util.Uint160 { return t.h } +func (t testScriptGetter) GetEntryScriptHash() util.Uint160 { return t.h } +func (t testScriptGetter) GetCurrentScriptHash() util.Uint160 { return t.h } + +func setSigner(tx *transaction.Transaction, h util.Uint160) { + tx.Signers = []transaction.Signer{{ + Account: h, + Scopes: transaction.Global, + }} +} + +func TestNEO_Vote(t *testing.T) { + bc := newTestChain(t) + defer bc.Close() + + neo := bc.contracts.NEO + tx := transaction.New(netmode.UnitTestNet, []byte{}, 0) + ic := bc.newInteropContext(trigger.System, bc.dao, nil, tx) + + pubs, err := neo.GetValidatorsInternal(bc, ic.DAO) + require.NoError(t, err) + require.Equal(t, bc.GetStandByValidators(), pubs) + + sz := testchain.Size() + + candidates := make(keys.PublicKeys, sz) + for i := 0; i < sz; i++ { + priv, err := keys.NewPrivateKey() + require.NoError(t, err) + candidates[i] = priv.PublicKey() + if i > 0 { + require.NoError(t, neo.RegisterCandidateInternal(ic, candidates[i])) + } + } + + for i := 0; i < sz; i++ { + to := testchain.PrivateKeyByID(i).GetScriptHash() + ic.ScriptGetter = testScriptGetter{testchain.MultisigScriptHash()} + require.NoError(t, neo.TransferInternal(ic, testchain.MultisigScriptHash(), to, big.NewInt(int64(sz-i)*10000000))) + } + + for i := 1; i < sz; i++ { + h := testchain.PrivateKeyByID(i).GetScriptHash() + setSigner(tx, h) + ic.ScriptGetter = testScriptGetter{h} + require.NoError(t, neo.VoteInternal(ic, h, candidates[i])) + } + + // First 3 validators must be the ones we have voted for. + pubs, err = neo.GetValidatorsInternal(bc, ic.DAO) + require.NoError(t, err) + for i := 1; i < sz; i++ { + require.Equal(t, pubs[i-1], candidates[i]) + } + + var ok bool + for _, p := range bc.GetStandByValidators() { + if pubs[sz-1].Equal(p) { + ok = true + break + } + } + require.True(t, ok, "last validator must be stand by") + + // Register and give some value to the last validator. + require.NoError(t, neo.RegisterCandidateInternal(ic, candidates[0])) + h := testchain.PrivateKeyByID(0).GetScriptHash() + setSigner(tx, h) + ic.ScriptGetter = testScriptGetter{h} + require.NoError(t, neo.VoteInternal(ic, h, candidates[0])) + + pubs, err = neo.GetValidatorsInternal(bc, ic.DAO) + require.NoError(t, err) + require.Equal(t, candidates, pubs) +}