2020-08-14 08:19:22 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2020-08-24 11:00:05 +00:00
|
|
|
"encoding/hex"
|
2020-08-14 08:19:22 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
2020-08-17 08:12:21 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
2020-08-14 08:19:22 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/internal/testchain"
|
2020-08-17 08:12:21 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
2020-08-14 08:19:22 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/rpc/client"
|
2020-08-24 16:10:02 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
2020-08-14 08:19:22 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2020-08-17 08:12:21 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
2020-08-14 08:19:22 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestClient_NEP5(t *testing.T) {
|
|
|
|
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
|
|
|
defer chain.Close()
|
|
|
|
defer rpcSrv.Shutdown()
|
|
|
|
|
|
|
|
c, err := client.New(context.Background(), httpSrv.URL, client.Options{Network: netmode.UnitTestNet})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
h, err := util.Uint160DecodeStringLE(testContractHash)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
t.Run("Decimals", func(t *testing.T) {
|
|
|
|
d, err := c.NEP5Decimals(h)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.EqualValues(t, 2, d)
|
|
|
|
})
|
|
|
|
t.Run("TotalSupply", func(t *testing.T) {
|
|
|
|
s, err := c.NEP5TotalSupply(h)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.EqualValues(t, 1_000_000, s)
|
|
|
|
})
|
|
|
|
t.Run("Name", func(t *testing.T) {
|
|
|
|
name, err := c.NEP5Name(h)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "Rubl", name)
|
|
|
|
})
|
|
|
|
t.Run("Symbol", func(t *testing.T) {
|
|
|
|
sym, err := c.NEP5Symbol(h)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "RUB", sym)
|
|
|
|
})
|
|
|
|
t.Run("TokenInfo", func(t *testing.T) {
|
|
|
|
tok, err := c.NEP5TokenInfo(h)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, h, tok.Hash)
|
|
|
|
require.Equal(t, "Rubl", tok.Name)
|
|
|
|
require.Equal(t, "RUB", tok.Symbol)
|
|
|
|
require.EqualValues(t, 2, tok.Decimals)
|
|
|
|
})
|
|
|
|
t.Run("BalanceOf", func(t *testing.T) {
|
|
|
|
acc := testchain.PrivateKeyByID(0).GetScriptHash()
|
|
|
|
b, err := c.NEP5BalanceOf(h, acc)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.EqualValues(t, 877, b)
|
|
|
|
})
|
|
|
|
}
|
2020-08-17 08:12:21 +00:00
|
|
|
|
|
|
|
func TestAddNetworkFee(t *testing.T) {
|
|
|
|
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
|
|
|
defer chain.Close()
|
|
|
|
defer rpcSrv.Shutdown()
|
|
|
|
|
|
|
|
c, err := client.New(context.Background(), httpSrv.URL, client.Options{Network: testchain.Network()})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
getAccounts := func(t *testing.T, n int) []*wallet.Account {
|
|
|
|
accs := make([]*wallet.Account, n)
|
|
|
|
var err error
|
|
|
|
for i := range accs {
|
|
|
|
accs[i], err = wallet.NewAccount()
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
return accs
|
|
|
|
}
|
|
|
|
|
|
|
|
feePerByte := chain.FeePerByte()
|
|
|
|
|
|
|
|
t.Run("Invalid", func(t *testing.T) {
|
|
|
|
tx := transaction.New(testchain.Network(), []byte{byte(opcode.PUSH1)}, 0)
|
|
|
|
accs := getAccounts(t, 2)
|
|
|
|
tx.Signers = []transaction.Signer{{
|
|
|
|
Account: accs[0].PrivateKey().GetScriptHash(),
|
|
|
|
Scopes: transaction.CalledByEntry,
|
|
|
|
}}
|
|
|
|
require.Error(t, c.AddNetworkFee(tx, 10, accs[0], accs[1]))
|
|
|
|
})
|
|
|
|
t.Run("Simple", func(t *testing.T) {
|
|
|
|
tx := transaction.New(testchain.Network(), []byte{byte(opcode.PUSH1)}, 0)
|
|
|
|
accs := getAccounts(t, 1)
|
|
|
|
tx.Signers = []transaction.Signer{{
|
|
|
|
Account: accs[0].PrivateKey().GetScriptHash(),
|
|
|
|
Scopes: transaction.CalledByEntry,
|
|
|
|
}}
|
|
|
|
require.NoError(t, c.AddNetworkFee(tx, 10, accs[0]))
|
|
|
|
require.NoError(t, accs[0].SignTx(tx))
|
|
|
|
cFee, _ := core.CalculateNetworkFee(accs[0].Contract.Script)
|
|
|
|
require.Equal(t, int64(io.GetVarSize(tx))*feePerByte+cFee+10, tx.NetworkFee)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Multi", func(t *testing.T) {
|
|
|
|
tx := transaction.New(testchain.Network(), []byte{byte(opcode.PUSH1)}, 0)
|
2020-08-17 08:49:43 +00:00
|
|
|
accs := getAccounts(t, 4)
|
|
|
|
pubs := keys.PublicKeys{accs[1].PrivateKey().PublicKey(), accs[2].PrivateKey().PublicKey(), accs[3].PrivateKey().PublicKey()}
|
|
|
|
require.NoError(t, accs[1].ConvertMultisig(2, pubs))
|
|
|
|
require.NoError(t, accs[2].ConvertMultisig(2, pubs))
|
2020-08-17 08:12:21 +00:00
|
|
|
tx.Signers = []transaction.Signer{
|
|
|
|
{
|
|
|
|
Account: accs[0].PrivateKey().GetScriptHash(),
|
|
|
|
Scopes: transaction.CalledByEntry,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Account: hash.Hash160(accs[1].Contract.Script),
|
|
|
|
Scopes: transaction.Global,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
require.NoError(t, c.AddNetworkFee(tx, 10, accs[0], accs[1]))
|
|
|
|
require.NoError(t, accs[0].SignTx(tx))
|
|
|
|
require.NoError(t, accs[1].SignTx(tx))
|
2020-08-17 08:49:43 +00:00
|
|
|
require.NoError(t, accs[2].SignTx(tx))
|
2020-08-17 08:12:21 +00:00
|
|
|
cFee, _ := core.CalculateNetworkFee(accs[0].Contract.Script)
|
|
|
|
cFeeM, _ := core.CalculateNetworkFee(accs[1].Contract.Script)
|
|
|
|
require.Equal(t, int64(io.GetVarSize(tx))*feePerByte+cFee+cFeeM+10, tx.NetworkFee)
|
|
|
|
})
|
2020-08-24 11:00:05 +00:00
|
|
|
t.Run("Contract", func(t *testing.T) {
|
|
|
|
tx := transaction.New(testchain.Network(), []byte{byte(opcode.PUSH1)}, 0)
|
|
|
|
priv := testchain.PrivateKeyByID(0)
|
|
|
|
acc1, err := wallet.NewAccountFromWIF(priv.WIF())
|
|
|
|
require.NoError(t, err)
|
|
|
|
acc1.Contract.Deployed = true
|
|
|
|
acc1.Contract.Script, _ = hex.DecodeString(verifyContractAVM)
|
|
|
|
h, _ := util.Uint160DecodeStringLE(verifyContractHash)
|
|
|
|
tx.ValidUntilBlock = chain.BlockHeight() + 10
|
|
|
|
|
|
|
|
t.Run("Valid", func(t *testing.T) {
|
|
|
|
acc0, err := wallet.NewAccountFromWIF(priv.WIF())
|
|
|
|
require.NoError(t, err)
|
|
|
|
tx.Signers = []transaction.Signer{
|
|
|
|
{
|
|
|
|
Account: acc0.PrivateKey().GetScriptHash(),
|
|
|
|
Scopes: transaction.CalledByEntry,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Account: h,
|
|
|
|
Scopes: transaction.Global,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
require.NoError(t, c.AddNetworkFee(tx, 10, acc0, acc1))
|
|
|
|
require.NoError(t, acc0.SignTx(tx))
|
|
|
|
tx.Scripts = append(tx.Scripts, transaction.Witness{})
|
|
|
|
require.NoError(t, chain.VerifyTx(tx))
|
|
|
|
})
|
|
|
|
t.Run("Invalid", func(t *testing.T) {
|
|
|
|
acc0, err := wallet.NewAccount()
|
|
|
|
require.NoError(t, err)
|
|
|
|
tx.Signers = []transaction.Signer{
|
|
|
|
{
|
|
|
|
Account: acc0.PrivateKey().GetScriptHash(),
|
|
|
|
Scopes: transaction.CalledByEntry,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Account: h,
|
|
|
|
Scopes: transaction.Global,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
require.Error(t, c.AddNetworkFee(tx, 10, acc0, acc1))
|
|
|
|
})
|
|
|
|
t.Run("InvalidContract", func(t *testing.T) {
|
|
|
|
acc0, err := wallet.NewAccountFromWIF(priv.WIF())
|
|
|
|
require.NoError(t, err)
|
|
|
|
tx.Signers = []transaction.Signer{
|
|
|
|
{
|
|
|
|
Account: acc0.PrivateKey().GetScriptHash(),
|
|
|
|
Scopes: transaction.CalledByEntry,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Account: util.Uint160{},
|
|
|
|
Scopes: transaction.Global,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
require.Error(t, c.AddNetworkFee(tx, 10, acc0, acc1))
|
|
|
|
})
|
|
|
|
})
|
2020-08-17 08:12:21 +00:00
|
|
|
}
|
2020-08-17 12:09:59 +00:00
|
|
|
|
|
|
|
func TestSignAndPushInvocationTx(t *testing.T) {
|
|
|
|
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
|
|
|
defer chain.Close()
|
|
|
|
defer rpcSrv.Shutdown()
|
|
|
|
|
|
|
|
c, err := client.New(context.Background(), httpSrv.URL, client.Options{Network: testchain.Network()})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
priv := testchain.PrivateKey(0)
|
|
|
|
acc, err := wallet.NewAccountFromWIF(priv.WIF())
|
|
|
|
require.NoError(t, err)
|
|
|
|
h, err := c.SignAndPushInvocationTx([]byte{byte(opcode.PUSH1)}, acc, 30, 0, []transaction.Signer{{
|
|
|
|
Account: priv.GetScriptHash(),
|
|
|
|
Scopes: transaction.CalledByEntry,
|
|
|
|
}})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
mp := chain.GetMemPool()
|
|
|
|
tx, ok := mp.TryGetValue(h)
|
|
|
|
require.True(t, ok)
|
|
|
|
require.Equal(t, h, tx.Hash())
|
|
|
|
require.EqualValues(t, 30, tx.SystemFee)
|
|
|
|
}
|
2020-08-17 12:21:45 +00:00
|
|
|
|
|
|
|
func TestPing(t *testing.T) {
|
|
|
|
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
|
|
|
defer chain.Close()
|
|
|
|
|
|
|
|
c, err := client.New(context.Background(), httpSrv.URL, client.Options{Network: testchain.Network()})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.NoError(t, c.Ping())
|
|
|
|
require.NoError(t, rpcSrv.Shutdown())
|
|
|
|
httpSrv.Close()
|
|
|
|
require.Error(t, c.Ping())
|
|
|
|
}
|
2020-08-17 13:49:47 +00:00
|
|
|
|
|
|
|
func TestCreateTxFromScript(t *testing.T) {
|
|
|
|
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
|
|
|
defer chain.Close()
|
|
|
|
defer rpcSrv.Shutdown()
|
|
|
|
|
|
|
|
c, err := client.New(context.Background(), httpSrv.URL, client.Options{Network: testchain.Network()})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
priv := testchain.PrivateKey(0)
|
|
|
|
acc, err := wallet.NewAccountFromWIF(priv.WIF())
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Run("NoSystemFee", func(t *testing.T) {
|
|
|
|
tx, err := c.CreateTxFromScript([]byte{byte(opcode.PUSH1)}, acc, -1, 10)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, tx.ValidUntilBlock > chain.BlockHeight())
|
|
|
|
require.EqualValues(t, 30, tx.SystemFee) // PUSH1
|
|
|
|
require.True(t, len(tx.Signers) == 1)
|
|
|
|
require.Equal(t, acc.PrivateKey().GetScriptHash(), tx.Signers[0].Account)
|
|
|
|
})
|
|
|
|
t.Run("ProvideSystemFee", func(t *testing.T) {
|
|
|
|
tx, err := c.CreateTxFromScript([]byte{byte(opcode.PUSH1)}, acc, 123, 10)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, tx.ValidUntilBlock > chain.BlockHeight())
|
|
|
|
require.EqualValues(t, 123, tx.SystemFee)
|
|
|
|
require.True(t, len(tx.Signers) == 1)
|
|
|
|
require.Equal(t, acc.PrivateKey().GetScriptHash(), tx.Signers[0].Account)
|
|
|
|
})
|
|
|
|
}
|
2020-08-24 16:10:02 +00:00
|
|
|
|
|
|
|
func TestCreateNEP5TransferTx(t *testing.T) {
|
|
|
|
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
|
|
|
defer chain.Close()
|
|
|
|
defer rpcSrv.Shutdown()
|
|
|
|
|
|
|
|
c, err := client.New(context.Background(), httpSrv.URL, client.Options{Network: testchain.Network()})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
priv := testchain.PrivateKeyByID(0)
|
|
|
|
acc, err := wallet.NewAccountFromWIF(priv.WIF())
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
tx, err := c.CreateNEP5TransferTx(acc, util.Uint160{}, client.GasContractHash, 1000, 0)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, acc.SignTx(tx))
|
|
|
|
require.NoError(t, chain.VerifyTx(tx))
|
|
|
|
v := chain.GetTestVM(tx)
|
|
|
|
v.LoadScriptWithFlags(tx.Script, smartcontract.All)
|
|
|
|
require.NoError(t, v.Run())
|
|
|
|
}
|