2020-08-31 13:17:44 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2020-09-01 12:05:07 +00:00
|
|
|
"encoding/hex"
|
2020-09-02 10:17:13 +00:00
|
|
|
"encoding/json"
|
2020-09-02 08:43:25 +00:00
|
|
|
"math/big"
|
2020-08-31 13:17:44 +00:00
|
|
|
"os"
|
|
|
|
"path"
|
2020-09-01 11:55:10 +00:00
|
|
|
"strings"
|
2020-08-31 13:17:44 +00:00
|
|
|
"testing"
|
|
|
|
|
2020-09-01 12:05:07 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
2020-08-31 13:17:44 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
2020-09-02 09:20:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
2020-09-01 12:05:07 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
2020-09-02 09:20:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2020-08-31 13:17:44 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestWalletInit(t *testing.T) {
|
|
|
|
tmpDir := os.TempDir()
|
|
|
|
e := newExecutor(t, false)
|
|
|
|
defer e.Close(t)
|
|
|
|
|
|
|
|
walletPath := path.Join(tmpDir, "wallet.json")
|
|
|
|
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath)
|
|
|
|
defer os.Remove(walletPath)
|
|
|
|
|
|
|
|
t.Run("CreateAccount", func(t *testing.T) {
|
|
|
|
e.In.WriteString("testname\r")
|
|
|
|
e.In.WriteString("testpass\r")
|
|
|
|
e.In.WriteString("testpass\r")
|
|
|
|
e.Run(t, "neo-go", "wallet", "create", "--wallet", walletPath)
|
|
|
|
|
|
|
|
w, err := wallet.NewWalletFromFile(walletPath)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, w.Accounts, 1)
|
|
|
|
require.Equal(t, w.Accounts[0].Label, "testname")
|
|
|
|
require.NoError(t, w.Accounts[0].Decrypt("testpass"))
|
2020-09-01 12:10:45 +00:00
|
|
|
w.Close()
|
|
|
|
|
|
|
|
t.Run("RemoveAccount", func(t *testing.T) {
|
|
|
|
sh := w.Accounts[0].Contract.ScriptHash()
|
|
|
|
addr := w.Accounts[0].Address
|
|
|
|
e.In.WriteString("y\r")
|
|
|
|
e.Run(t, "neo-go", "wallet", "remove",
|
|
|
|
"--wallet", walletPath, addr)
|
|
|
|
w, err := wallet.NewWalletFromFile(walletPath)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Nil(t, w.GetAccount(sh))
|
|
|
|
w.Close()
|
|
|
|
})
|
2020-08-31 13:17:44 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Import", func(t *testing.T) {
|
|
|
|
t.Run("WIF", func(t *testing.T) {
|
|
|
|
priv, err := keys.NewPrivateKey()
|
|
|
|
require.NoError(t, err)
|
|
|
|
e.In.WriteString("test_account\r")
|
|
|
|
e.In.WriteString("qwerty\r")
|
|
|
|
e.In.WriteString("qwerty\r")
|
|
|
|
e.Run(t, "neo-go", "wallet", "import", "--wallet", walletPath,
|
|
|
|
"--wif", priv.WIF())
|
|
|
|
|
|
|
|
w, err := wallet.NewWalletFromFile(walletPath)
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer w.Close()
|
|
|
|
acc := w.GetAccount(priv.GetScriptHash())
|
|
|
|
require.NotNil(t, acc)
|
|
|
|
require.Equal(t, "test_account", acc.Label)
|
|
|
|
require.NoError(t, acc.Decrypt("qwerty"))
|
|
|
|
|
|
|
|
t.Run("AlreadyExists", func(t *testing.T) {
|
|
|
|
e.In.WriteString("test_account_2\r")
|
|
|
|
e.In.WriteString("qwerty2\r")
|
|
|
|
e.In.WriteString("qwerty2\r")
|
|
|
|
e.RunWithError(t, "neo-go", "wallet", "import",
|
|
|
|
"--wallet", walletPath, "--wif", priv.WIF())
|
|
|
|
})
|
|
|
|
})
|
|
|
|
t.Run("EncryptedWIF", func(t *testing.T) {
|
|
|
|
acc, err := wallet.NewAccount()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, acc.Encrypt("somepass"))
|
|
|
|
|
|
|
|
t.Run("InvalidPassword", func(t *testing.T) {
|
|
|
|
e.In.WriteString("password1\r")
|
|
|
|
e.RunWithError(t, "neo-go", "wallet", "import", "--wallet", walletPath,
|
|
|
|
"--wif", acc.EncryptedWIF)
|
|
|
|
})
|
|
|
|
|
|
|
|
e.In.WriteString("somepass\r")
|
|
|
|
e.Run(t, "neo-go", "wallet", "import", "--wallet", walletPath,
|
|
|
|
"--wif", acc.EncryptedWIF)
|
|
|
|
|
|
|
|
w, err := wallet.NewWalletFromFile(walletPath)
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer w.Close()
|
|
|
|
actual := w.GetAccount(acc.PrivateKey().GetScriptHash())
|
|
|
|
require.NotNil(t, actual)
|
|
|
|
require.NoError(t, actual.Decrypt("somepass"))
|
|
|
|
})
|
2020-09-01 12:05:07 +00:00
|
|
|
t.Run("Multisig", func(t *testing.T) {
|
2020-09-01 13:24:01 +00:00
|
|
|
privs, pubs := generateKeys(t, 4)
|
2020-09-01 12:05:07 +00:00
|
|
|
|
|
|
|
cmd := []string{"neo-go", "wallet", "import-multisig",
|
|
|
|
"--wallet", walletPath,
|
|
|
|
"--wif", privs[0].WIF(),
|
|
|
|
"--min", "2"}
|
|
|
|
t.Run("InvalidPublicKeys", func(t *testing.T) {
|
|
|
|
e.In.WriteString("multiacc\r")
|
|
|
|
e.In.WriteString("multipass\r")
|
|
|
|
e.In.WriteString("multipass\r")
|
|
|
|
defer e.In.Reset()
|
|
|
|
|
|
|
|
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[1].Bytes()),
|
|
|
|
hex.EncodeToString(pubs[1].Bytes()),
|
|
|
|
hex.EncodeToString(pubs[2].Bytes()),
|
|
|
|
hex.EncodeToString(pubs[3].Bytes()))...)
|
|
|
|
})
|
|
|
|
e.In.WriteString("multiacc\r")
|
|
|
|
e.In.WriteString("multipass\r")
|
|
|
|
e.In.WriteString("multipass\r")
|
|
|
|
e.Run(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()),
|
|
|
|
hex.EncodeToString(pubs[1].Bytes()),
|
|
|
|
hex.EncodeToString(pubs[2].Bytes()),
|
|
|
|
hex.EncodeToString(pubs[3].Bytes()))...)
|
|
|
|
|
|
|
|
script, err := smartcontract.CreateMultiSigRedeemScript(2, pubs)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
w, err := wallet.NewWalletFromFile(walletPath)
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer w.Close()
|
|
|
|
actual := w.GetAccount(hash.Hash160(script))
|
|
|
|
require.NotNil(t, actual)
|
|
|
|
require.NoError(t, actual.Decrypt("multipass"))
|
|
|
|
require.Equal(t, script, actual.Contract.Script)
|
|
|
|
})
|
2020-08-31 13:17:44 +00:00
|
|
|
})
|
|
|
|
}
|
2020-09-01 11:55:10 +00:00
|
|
|
|
|
|
|
func TestWalletExport(t *testing.T) {
|
|
|
|
e := newExecutor(t, false)
|
|
|
|
defer e.Close(t)
|
|
|
|
|
|
|
|
t.Run("Encrypted", func(t *testing.T) {
|
|
|
|
e.Run(t, "neo-go", "wallet", "export",
|
|
|
|
"--wallet", validatorWallet, validatorAddr)
|
|
|
|
line, err := e.Out.ReadString('\n')
|
|
|
|
require.NoError(t, err)
|
|
|
|
enc, err := keys.NEP2Encrypt(validatorPriv, "one")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, enc, strings.TrimSpace(line))
|
|
|
|
})
|
|
|
|
t.Run("Decrypted", func(t *testing.T) {
|
|
|
|
t.Run("NoAddress", func(t *testing.T) {
|
|
|
|
e.RunWithError(t, "neo-go", "wallet", "export",
|
|
|
|
"--wallet", validatorWallet, "--decrypt")
|
|
|
|
})
|
|
|
|
e.In.WriteString("one\r")
|
|
|
|
e.Run(t, "neo-go", "wallet", "export",
|
|
|
|
"--wallet", validatorWallet, "--decrypt", validatorAddr)
|
|
|
|
line, err := e.Out.ReadString('\n')
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, validatorWIF, strings.TrimSpace(line))
|
|
|
|
})
|
|
|
|
}
|
2020-09-02 08:43:25 +00:00
|
|
|
|
|
|
|
func TestClaimGas(t *testing.T) {
|
|
|
|
e := newExecutor(t, true)
|
|
|
|
defer e.Close(t)
|
|
|
|
|
2020-11-06 09:27:05 +00:00
|
|
|
const walletPath = "testdata/testwallet.json"
|
|
|
|
w, err := wallet.NewWalletFromFile(walletPath)
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer w.Close()
|
|
|
|
|
|
|
|
args := []string{
|
2020-11-24 08:14:25 +00:00
|
|
|
"neo-go", "wallet", "nep17", "multitransfer",
|
2020-11-06 09:27:05 +00:00
|
|
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
2020-09-02 08:43:25 +00:00
|
|
|
"--wallet", validatorWallet,
|
2020-11-06 09:27:05 +00:00
|
|
|
"--from", validatorAddr,
|
2020-12-13 18:05:49 +00:00
|
|
|
"NEO:" + w.Accounts[0].Address + ":1000",
|
|
|
|
"GAS:" + w.Accounts[0].Address + ":1000", // for tx send
|
2020-11-06 09:27:05 +00:00
|
|
|
}
|
|
|
|
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)
|
2020-09-02 08:43:25 +00:00
|
|
|
require.True(t, cl.Sign() > 0)
|
|
|
|
|
2020-11-06 09:27:05 +00:00
|
|
|
e.In.WriteString("testpass\r")
|
|
|
|
e.Run(t, "neo-go", "wallet", "claim",
|
|
|
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
|
|
|
"--wallet", walletPath,
|
|
|
|
"--address", w.Accounts[0].Address)
|
|
|
|
tx, height := e.checkTxPersisted(t)
|
|
|
|
balanceBefore.Sub(balanceBefore, big.NewInt(tx.NetworkFee+tx.SystemFee))
|
|
|
|
balanceBefore.Add(balanceBefore, cl)
|
|
|
|
|
|
|
|
balanceAfter := e.Chain.GetUtilityTokenBalance(h)
|
|
|
|
// 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))
|
|
|
|
}
|
2020-09-02 08:43:25 +00:00
|
|
|
}
|
2020-09-02 09:20:42 +00:00
|
|
|
|
|
|
|
func TestImportDeployed(t *testing.T) {
|
|
|
|
e := newExecutor(t, true)
|
|
|
|
defer e.Close(t)
|
|
|
|
|
|
|
|
e.In.WriteString("one\r")
|
|
|
|
e.Run(t, "neo-go", "contract", "deploy",
|
2020-10-14 15:13:20 +00:00
|
|
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
2020-09-02 09:20:42 +00:00
|
|
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
|
|
|
"--in", "testdata/verify.nef", "--manifest", "testdata/verify.manifest.json")
|
|
|
|
|
|
|
|
line, err := e.Out.ReadString('\n')
|
|
|
|
require.NoError(t, err)
|
|
|
|
line = strings.TrimSpace(strings.TrimPrefix(line, "Contract: "))
|
|
|
|
h, err := util.Uint160DecodeStringLE(line)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
e.checkTxPersisted(t)
|
|
|
|
|
|
|
|
tmpDir := os.TempDir()
|
|
|
|
walletPath := path.Join(tmpDir, "wallet.json")
|
|
|
|
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath)
|
|
|
|
defer os.Remove(walletPath)
|
|
|
|
|
|
|
|
priv, err := keys.NewPrivateKey()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
e.In.WriteString("acc\rpass\rpass\r")
|
|
|
|
e.Run(t, "neo-go", "wallet", "import-deployed",
|
2020-10-14 15:13:20 +00:00
|
|
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
2020-09-02 09:20:42 +00:00
|
|
|
"--wallet", walletPath, "--wif", priv.WIF(),
|
|
|
|
"--contract", h.StringLE())
|
|
|
|
|
|
|
|
w, err := wallet.NewWalletFromFile(walletPath)
|
|
|
|
defer w.Close()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(w.Accounts))
|
|
|
|
contractAddr := w.Accounts[0].Address
|
|
|
|
require.Equal(t, address.Uint160ToString(h), contractAddr)
|
|
|
|
require.True(t, w.Accounts[0].Contract.Deployed)
|
|
|
|
|
|
|
|
t.Run("Sign", func(t *testing.T) {
|
|
|
|
e.In.WriteString("one\r")
|
2020-11-24 08:14:25 +00:00
|
|
|
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
2020-10-14 15:13:20 +00:00
|
|
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
2020-09-02 09:20:42 +00:00
|
|
|
"--wallet", validatorWallet, "--from", validatorAddr,
|
2020-12-13 18:05:49 +00:00
|
|
|
"NEO:"+contractAddr+":10",
|
|
|
|
"GAS:"+contractAddr+":10")
|
2020-09-02 09:20:42 +00:00
|
|
|
e.checkTxPersisted(t)
|
|
|
|
|
|
|
|
privTo, err := keys.NewPrivateKey()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
e.In.WriteString("pass\r")
|
2020-11-24 08:14:25 +00:00
|
|
|
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
2020-10-14 15:13:20 +00:00
|
|
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
2020-09-02 09:20:42 +00:00
|
|
|
"--wallet", walletPath, "--from", contractAddr,
|
2020-12-13 18:05:49 +00:00
|
|
|
"--to", privTo.Address(), "--token", "NEO", "--amount", "1")
|
2020-09-02 09:20:42 +00:00
|
|
|
e.checkTxPersisted(t)
|
|
|
|
|
|
|
|
b, _ := e.Chain.GetGoverningTokenBalance(h)
|
|
|
|
require.Equal(t, big.NewInt(9), b)
|
|
|
|
b, _ = e.Chain.GetGoverningTokenBalance(privTo.GetScriptHash())
|
|
|
|
require.Equal(t, big.NewInt(1), b)
|
|
|
|
})
|
|
|
|
}
|
2020-09-02 10:17:13 +00:00
|
|
|
|
|
|
|
func TestWalletDump(t *testing.T) {
|
|
|
|
e := newExecutor(t, false)
|
|
|
|
defer e.Close(t)
|
|
|
|
|
2020-12-03 14:30:09 +00:00
|
|
|
cmd := []string{"neo-go", "wallet", "dump", "--wallet", "testdata/testwallet.json"}
|
|
|
|
e.Run(t, cmd...)
|
2020-09-02 10:17:13 +00:00
|
|
|
rawStr := strings.TrimSpace(e.Out.String())
|
|
|
|
w := new(wallet.Wallet)
|
|
|
|
require.NoError(t, json.Unmarshal([]byte(rawStr), w))
|
|
|
|
require.Equal(t, 1, len(w.Accounts))
|
|
|
|
require.Equal(t, "NNuJqXDnRqvwgzhSzhH4jnVFWB1DyZ34EM", w.Accounts[0].Address)
|
2020-12-03 14:30:09 +00:00
|
|
|
|
|
|
|
t.Run("with decrypt", func(t *testing.T) {
|
|
|
|
cmd = append(cmd, "--decrypt")
|
|
|
|
t.Run("invalid password", func(t *testing.T) {
|
|
|
|
e.In.WriteString("invalidpass\r")
|
|
|
|
e.RunWithError(t, cmd...)
|
|
|
|
})
|
|
|
|
|
|
|
|
e.In.WriteString("testpass\r")
|
|
|
|
e.Run(t, cmd...)
|
|
|
|
rawStr := strings.TrimSpace(e.Out.String())
|
|
|
|
w := new(wallet.Wallet)
|
|
|
|
require.NoError(t, json.Unmarshal([]byte(rawStr), w))
|
|
|
|
require.Equal(t, 1, len(w.Accounts))
|
|
|
|
require.Equal(t, "NNuJqXDnRqvwgzhSzhH4jnVFWB1DyZ34EM", w.Accounts[0].Address)
|
|
|
|
})
|
2020-09-02 10:17:13 +00:00
|
|
|
}
|
2020-12-03 14:33:52 +00:00
|
|
|
|
|
|
|
// Testcase is the wallet of privnet validator.
|
|
|
|
func TestWalletConvert(t *testing.T) {
|
|
|
|
tmpDir := path.Join(os.TempDir(), "neogo.test.convert")
|
|
|
|
require.NoError(t, os.Mkdir(tmpDir, os.ModePerm))
|
|
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
|
|
|
|
e := newExecutor(t, false)
|
|
|
|
defer e.Close(t)
|
|
|
|
|
|
|
|
outPath := path.Join(tmpDir, "wallet.json")
|
|
|
|
cmd := []string{"neo-go", "wallet", "convert"}
|
|
|
|
t.Run("missing wallet", func(t *testing.T) {
|
|
|
|
e.RunWithError(t, cmd...)
|
|
|
|
})
|
|
|
|
|
|
|
|
cmd = append(cmd, "--wallet", "testdata/wallets/testwallet_NEO2.json", "--out", outPath)
|
|
|
|
t.Run("invalid password", func(t *testing.T) {
|
|
|
|
// missing password
|
|
|
|
e.RunWithError(t, cmd...)
|
|
|
|
// invalid password
|
|
|
|
e.In.WriteString("two\r")
|
|
|
|
e.RunWithError(t, cmd...)
|
|
|
|
})
|
|
|
|
|
|
|
|
// 2 accounts.
|
|
|
|
e.In.WriteString("one\r")
|
|
|
|
e.In.WriteString("one\r")
|
|
|
|
e.Run(t, "neo-go", "wallet", "convert",
|
|
|
|
"--wallet", "testdata/wallets/testwallet_NEO2.json",
|
|
|
|
"--out", outPath)
|
|
|
|
|
|
|
|
actual, err := wallet.NewWalletFromFile(outPath)
|
|
|
|
require.NoError(t, err)
|
|
|
|
expected, err := wallet.NewWalletFromFile("testdata/wallets/testwallet_NEO3.json")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(actual.Accounts), len(expected.Accounts))
|
|
|
|
for _, exp := range expected.Accounts {
|
|
|
|
addr, err := address.StringToUint160(exp.Address)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
act := actual.GetAccount(addr)
|
|
|
|
require.NotNil(t, act)
|
|
|
|
require.Equal(t, exp, act)
|
|
|
|
}
|
|
|
|
}
|