neoneo-go/pkg/rpcclient/neo/neo_test.go
Roman Khimov f011b3c3dd rpcclient: introduce NEO wrapper
Notice that int64 types are used for gas per block or registration price
because the price has to fit into the system fee limitation and gas per block
value can't be more than 10 GAS. We use int64 for votes as well in other types
since NEO is limited to 100M.
2022-08-17 22:03:09 +03:00

568 lines
13 KiB
Go

package neo
import (
"errors"
"math/big"
"testing"
"github.com/google/uuid"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"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/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require"
)
type testAct struct {
err error
ser error
res *result.Invoke
rre *result.Invoke
rer error
tx *transaction.Transaction
txh util.Uint256
vub uint32
inv *result.Invoke
}
func (t *testAct) Call(contract util.Uint160, operation string, params ...interface{}) (*result.Invoke, error) {
return t.res, t.err
}
func (t *testAct) MakeRun(script []byte) (*transaction.Transaction, error) {
return t.tx, t.err
}
func (t *testAct) MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error) {
return t.tx, t.err
}
func (t *testAct) SendRun(script []byte) (util.Uint256, uint32, error) {
return t.txh, t.vub, t.err
}
func (t *testAct) MakeCall(contract util.Uint160, method string, params ...interface{}) (*transaction.Transaction, error) {
return t.tx, t.err
}
func (t *testAct) MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...interface{}) (*transaction.Transaction, error) {
return t.tx, t.err
}
func (t *testAct) SendCall(contract util.Uint160, method string, params ...interface{}) (util.Uint256, uint32, error) {
return t.txh, t.vub, t.err
}
func (t *testAct) Run(script []byte) (*result.Invoke, error) {
return t.rre, t.rer
}
func (t *testAct) MakeUnsignedUncheckedRun(script []byte, sysFee int64, attrs []transaction.Attribute) (*transaction.Transaction, error) {
return t.tx, t.err
}
func (t *testAct) Sign(tx *transaction.Transaction) error {
return t.ser
}
func (t *testAct) SignAndSend(tx *transaction.Transaction) (util.Uint256, uint32, error) {
return t.txh, t.vub, t.err
}
func (t *testAct) CallAndExpandIterator(contract util.Uint160, method string, maxItems int, params ...interface{}) (*result.Invoke, error) {
return t.inv, t.err
}
func (t *testAct) TerminateSession(sessionID uuid.UUID) error {
return t.err
}
func (t *testAct) TraverseIterator(sessionID uuid.UUID, iterator *result.Iterator, num int) ([]stackitem.Item, error) {
return t.res.Stack, t.err
}
func TestGetAccountState(t *testing.T) {
ta := &testAct{}
neo := NewReader(ta)
ta.err = errors.New("")
_, err := neo.GetAccountState(util.Uint160{})
require.Error(t, err)
ta.err = nil
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make(42),
},
}
_, err = neo.GetAccountState(util.Uint160{})
require.Error(t, err)
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Null{},
},
}
st, err := neo.GetAccountState(util.Uint160{})
require.NoError(t, err)
require.Nil(t, st)
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make([]stackitem.Item{
stackitem.Make(100500),
stackitem.Make(42),
stackitem.Null{},
}),
},
}
st, err = neo.GetAccountState(util.Uint160{})
require.NoError(t, err)
require.Equal(t, &state.NEOBalance{
NEP17Balance: state.NEP17Balance{
Balance: *big.NewInt(100500),
},
BalanceHeight: 42,
}, st)
}
func TestGetAllCandidates(t *testing.T) {
ta := &testAct{}
neo := NewReader(ta)
ta.err = errors.New("")
_, err := neo.GetAllCandidates()
require.Error(t, err)
ta.err = nil
iid := uuid.New()
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.NewInterop(result.Iterator{
ID: &iid,
}),
},
}
_, err = neo.GetAllCandidates()
require.Error(t, err)
// Session-based iterator.
sid := uuid.New()
ta.res = &result.Invoke{
Session: sid,
State: "HALT",
Stack: []stackitem.Item{
stackitem.NewInterop(result.Iterator{
ID: &iid,
}),
},
}
iter, err := neo.GetAllCandidates()
require.NoError(t, err)
k, err := keys.NewPrivateKey()
require.NoError(t, err)
ta.res = &result.Invoke{
Stack: []stackitem.Item{
stackitem.Make([]stackitem.Item{
stackitem.Make(k.PublicKey().Bytes()),
stackitem.Make(100500),
}),
},
}
vals, err := iter.Next(10)
require.NoError(t, err)
require.Equal(t, 1, len(vals))
require.Equal(t, result.Validator{
PublicKey: *k.PublicKey(),
Votes: 100500,
}, vals[0])
ta.err = errors.New("")
_, err = iter.Next(1)
require.Error(t, err)
err = iter.Terminate()
require.Error(t, err)
// Value-based iterator.
ta.err = nil
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.NewInterop(result.Iterator{
Values: []stackitem.Item{
stackitem.Make(k.PublicKey().Bytes()),
stackitem.Make(100500),
},
}),
},
}
iter, err = neo.GetAllCandidates()
require.NoError(t, err)
ta.err = errors.New("")
err = iter.Terminate()
require.NoError(t, err)
}
func TestGetCandidates(t *testing.T) {
ta := &testAct{}
neo := NewReader(ta)
ta.err = errors.New("")
_, err := neo.GetCandidates()
require.Error(t, err)
ta.err = nil
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make([]stackitem.Item{}),
},
}
cands, err := neo.GetCandidates()
require.NoError(t, err)
require.Equal(t, 0, len(cands))
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{stackitem.Make(42)},
}
_, err = neo.GetCandidates()
require.Error(t, err)
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make([]stackitem.Item{
stackitem.Make(42),
}),
},
}
_, err = neo.GetCandidates()
require.Error(t, err)
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make([]stackitem.Item{
stackitem.Make([]stackitem.Item{}),
}),
},
}
_, err = neo.GetCandidates()
require.Error(t, err)
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make([]stackitem.Item{
stackitem.Make([]stackitem.Item{
stackitem.Null{},
stackitem.Null{},
}),
}),
},
}
_, err = neo.GetCandidates()
require.Error(t, err)
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make([]stackitem.Item{
stackitem.Make([]stackitem.Item{
stackitem.Make("some"),
stackitem.Null{},
}),
}),
},
}
_, err = neo.GetCandidates()
require.Error(t, err)
k, err := keys.NewPrivateKey()
require.NoError(t, err)
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make([]stackitem.Item{
stackitem.Make([]stackitem.Item{
stackitem.Make(k.PublicKey().Bytes()),
stackitem.Null{},
}),
}),
},
}
_, err = neo.GetCandidates()
require.Error(t, err)
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make([]stackitem.Item{
stackitem.Make([]stackitem.Item{
stackitem.Make(k.PublicKey().Bytes()),
stackitem.Make("canbeabigint"),
}),
}),
},
}
_, err = neo.GetCandidates()
require.Error(t, err)
}
func TestGetKeys(t *testing.T) {
ta := &testAct{}
neo := NewReader(ta)
k, err := keys.NewPrivateKey()
require.NoError(t, err)
for _, m := range []func() (keys.PublicKeys, error){neo.GetCommittee, neo.GetNextBlockValidators} {
ta.err = errors.New("")
_, err := m()
require.Error(t, err)
ta.err = nil
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make([]stackitem.Item{stackitem.Make(k.PublicKey().Bytes())}),
},
}
ks, err := m()
require.NoError(t, err)
require.NotNil(t, ks)
require.Equal(t, 1, len(ks))
require.Equal(t, k.PublicKey(), ks[0])
}
}
func TestGetInts(t *testing.T) {
ta := &testAct{}
neo := NewReader(ta)
meth := []func() (int64, error){
neo.GetGasPerBlock,
neo.GetRegisterPrice,
}
ta.err = errors.New("")
for _, m := range meth {
_, err := m()
require.Error(t, err)
}
ta.err = nil
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make(42),
},
}
for _, m := range meth {
val, err := m()
require.NoError(t, err)
require.Equal(t, int64(42), val)
}
}
func TestUnclaimedGas(t *testing.T) {
ta := &testAct{}
neo := NewReader(ta)
ta.err = errors.New("")
_, err := neo.UnclaimedGas(util.Uint160{}, 100500)
require.Error(t, err)
ta.err = nil
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make([]stackitem.Item{}),
},
}
_, err = neo.UnclaimedGas(util.Uint160{}, 100500)
require.Error(t, err)
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make(42),
},
}
val, err := neo.UnclaimedGas(util.Uint160{}, 100500)
require.NoError(t, err)
require.Equal(t, big.NewInt(42), val)
}
func TestIntSetters(t *testing.T) {
ta := new(testAct)
neo := New(ta)
meth := []func(int64) (util.Uint256, uint32, error){
neo.SetGasPerBlock,
neo.SetRegisterPrice,
}
ta.err = errors.New("")
for _, m := range meth {
_, _, err := m(42)
require.Error(t, err)
}
ta.err = nil
ta.txh = util.Uint256{1, 2, 3}
ta.vub = 42
for _, m := range meth {
h, vub, err := m(100)
require.NoError(t, err)
require.Equal(t, ta.txh, h)
require.Equal(t, ta.vub, vub)
}
}
func TestIntTransactions(t *testing.T) {
ta := new(testAct)
neo := New(ta)
for _, fun := range []func(int64) (*transaction.Transaction, error){
neo.SetGasPerBlockTransaction,
neo.SetGasPerBlockUnsigned,
neo.SetRegisterPriceTransaction,
neo.SetRegisterPriceUnsigned,
} {
ta.err = errors.New("")
_, err := fun(1)
require.Error(t, err)
ta.err = nil
ta.tx = &transaction.Transaction{Nonce: 100500, ValidUntilBlock: 42}
tx, err := fun(1)
require.NoError(t, err)
require.Equal(t, ta.tx, tx)
}
}
func TestVote(t *testing.T) {
ta := new(testAct)
neo := New(ta)
k, err := keys.NewPrivateKey()
require.NoError(t, err)
ta.err = errors.New("")
_, _, err = neo.Vote(util.Uint160{}, nil)
require.Error(t, err)
_, _, err = neo.Vote(util.Uint160{}, k.PublicKey())
require.Error(t, err)
_, err = neo.VoteTransaction(util.Uint160{}, nil)
require.Error(t, err)
_, err = neo.VoteTransaction(util.Uint160{}, k.PublicKey())
require.Error(t, err)
_, err = neo.VoteUnsigned(util.Uint160{}, nil)
require.Error(t, err)
_, err = neo.VoteUnsigned(util.Uint160{}, k.PublicKey())
require.Error(t, err)
ta.err = nil
ta.txh = util.Uint256{1, 2, 3}
ta.vub = 42
h, vub, err := neo.Vote(util.Uint160{}, nil)
require.NoError(t, err)
require.Equal(t, ta.txh, h)
require.Equal(t, ta.vub, vub)
h, vub, err = neo.Vote(util.Uint160{}, k.PublicKey())
require.NoError(t, err)
require.Equal(t, ta.txh, h)
require.Equal(t, ta.vub, vub)
ta.tx = &transaction.Transaction{Nonce: 100500, ValidUntilBlock: 42}
tx, err := neo.VoteTransaction(util.Uint160{}, nil)
require.NoError(t, err)
require.Equal(t, ta.tx, tx)
tx, err = neo.VoteUnsigned(util.Uint160{}, k.PublicKey())
require.NoError(t, err)
require.Equal(t, ta.tx, tx)
}
func TestRegisterCandidate(t *testing.T) {
ta := new(testAct)
neo := New(ta)
k, err := keys.NewPrivateKey()
require.NoError(t, err)
pk := k.PublicKey()
ta.rer = errors.New("")
_, _, err = neo.RegisterCandidate(pk)
require.Error(t, err)
_, err = neo.RegisterCandidateTransaction(pk)
require.Error(t, err)
_, err = neo.RegisterCandidateUnsigned(pk)
require.Error(t, err)
ta.rer = nil
ta.txh = util.Uint256{1, 2, 3}
ta.vub = 42
ta.rre = &result.Invoke{
GasConsumed: 100500,
}
ta.res = &result.Invoke{
State: "HALT",
Stack: []stackitem.Item{
stackitem.Make(42),
},
}
h, vub, err := neo.RegisterCandidate(pk)
require.NoError(t, err)
require.Equal(t, ta.txh, h)
require.Equal(t, ta.vub, vub)
ta.tx = &transaction.Transaction{Nonce: 100500, ValidUntilBlock: 42}
tx, err := neo.RegisterCandidateTransaction(pk)
require.NoError(t, err)
require.Equal(t, ta.tx, tx)
tx, err = neo.RegisterCandidateUnsigned(pk)
require.NoError(t, err)
require.Equal(t, ta.tx, tx)
ta.ser = errors.New("")
_, err = neo.RegisterCandidateTransaction(pk)
require.Error(t, err)
ta.err = errors.New("")
_, err = neo.RegisterCandidateUnsigned(pk)
require.Error(t, err)
}
func TestUnregisterCandidate(t *testing.T) {
ta := new(testAct)
neo := New(ta)
k, err := keys.NewPrivateKey()
require.NoError(t, err)
pk := k.PublicKey()
ta.err = errors.New("")
_, _, err = neo.UnregisterCandidate(pk)
require.Error(t, err)
_, err = neo.UnregisterCandidateTransaction(pk)
require.Error(t, err)
_, err = neo.UnregisterCandidateUnsigned(pk)
require.Error(t, err)
ta.err = nil
ta.txh = util.Uint256{1, 2, 3}
ta.vub = 42
h, vub, err := neo.UnregisterCandidate(pk)
require.NoError(t, err)
require.Equal(t, ta.txh, h)
require.Equal(t, ta.vub, vub)
ta.tx = &transaction.Transaction{Nonce: 100500, ValidUntilBlock: 42}
tx, err := neo.UnregisterCandidateTransaction(pk)
require.NoError(t, err)
require.Equal(t, ta.tx, tx)
tx, err = neo.UnregisterCandidateUnsigned(pk)
require.NoError(t, err)
require.Equal(t, ta.tx, tx)
}