diff --git a/cli/executor_test.go b/cli/executor_test.go index 3fe1347c6..4867633fe 100644 --- a/cli/executor_test.go +++ b/cli/executor_test.go @@ -6,6 +6,7 @@ import ( "errors" "io" "io/ioutil" + "strings" "testing" "time" @@ -19,6 +20,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/network" "github.com/nspcc-dev/neo-go/pkg/rpc/server" "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/vm" "github.com/stretchr/testify/require" "github.com/urfave/cli" "go.uber.org/zap" @@ -177,3 +179,29 @@ func (e *executor) run(args ...string) error { e.Err.Reset() return e.CLI.Run(args) } + +func (e *executor) checkTxPersisted(t *testing.T) { + line, err := e.Out.ReadString('\n') + require.NoError(t, err) + + line = strings.TrimSpace(line) + h, err := util.Uint256DecodeStringLE(line) + require.NoError(t, err, "can't decode tx hash: %s", line) + + tx := e.GetTransaction(t, h) + aer, err := e.Chain.GetAppExecResult(tx.Hash()) + require.NoError(t, err) + require.Equal(t, vm.HaltState, aer.VMState) +} + +func generateKeys(t *testing.T, n int) ([]*keys.PrivateKey, keys.PublicKeys) { + privs := make([]*keys.PrivateKey, n) + pubs := make(keys.PublicKeys, n) + for i := range privs { + var err error + privs[i], err = keys.NewPrivateKey() + require.NoError(t, err) + pubs[i] = privs[i].PublicKey() + } + return privs, pubs +} diff --git a/cli/multisig_test.go b/cli/multisig_test.go new file mode 100644 index 000000000..0d163764d --- /dev/null +++ b/cli/multisig_test.go @@ -0,0 +1,85 @@ +package main + +import ( + "encoding/hex" + "math/big" + "os" + "path" + "testing" + + "github.com/nspcc-dev/neo-go/pkg/crypto/hash" + "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/smartcontract" + "github.com/stretchr/testify/require" +) + +// Test signing of multisig transactions. +// 1. Transfer funds to a created multisig address. +// 2. Transfer from multisig to another account. +func TestSignMultisigTx(t *testing.T) { + e := newExecutor(t, true) + defer e.Close(t) + + privs, pubs := generateKeys(t, 3) + script, err := smartcontract.CreateMultiSigRedeemScript(2, pubs) + require.NoError(t, err) + multisigHash := hash.Hash160(script) + multisigAddr := address.Uint160ToString(multisigHash) + + // Create 2 wallets participating in multisig. + tmpDir := os.TempDir() + wallet1Path := path.Join(tmpDir, "multiWallet1.json") + defer os.Remove(wallet1Path) + wallet2Path := path.Join(tmpDir, "multiWallet2.json") + defer os.Remove(wallet2Path) + + addAccount := func(w string, wif string) { + e.In.WriteString("acc\rpass\rpass\r") + e.Run(t, "neo-go", "wallet", "init", "--wallet", w) + e.Run(t, "neo-go", "wallet", "import-multisig", + "--wallet", w, + "--wif", wif, + "--min", "2", + hex.EncodeToString(pubs[0].Bytes()), + hex.EncodeToString(pubs[1].Bytes()), + hex.EncodeToString(pubs[2].Bytes())) + } + addAccount(wallet1Path, privs[0].WIF()) + addAccount(wallet2Path, privs[1].WIF()) + + // Transfer funds to the multisig. + e.In.WriteString("one\r") + e.Run(t, "neo-go", "wallet", "nep5", "multitransfer", + "--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr, + "--wallet", validatorWallet, + "--from", validatorAddr, + "neo:"+multisigAddr+":4", + "gas:"+multisigAddr+":1") + e.checkTxPersisted(t) + + // Sign and transfer funds to another account. + priv, err := keys.NewPrivateKey() + require.NoError(t, err) + + txPath := path.Join(tmpDir, "multisigtx.json") + defer os.Remove(txPath) + e.In.WriteString("pass\r") + e.Run(t, "neo-go", "wallet", "nep5", "transfer", + "--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr, + "--wallet", wallet1Path, "--from", multisigAddr, + "--to", priv.Address(), "--token", "neo", "--amount", "1", + "--out", txPath) + + e.In.WriteString("pass\r") + e.Run(t, "neo-go", "wallet", "multisig", "sign", + "--unittest", "--rpc-endpoint", "http://"+e.RPC.Addr, + "--wallet", wallet2Path, "--addr", multisigAddr, + "--in", txPath, "--out", txPath) + e.checkTxPersisted(t) + + b, _ := e.Chain.GetGoverningTokenBalance(priv.GetScriptHash()) + require.Equal(t, big.NewInt(1), b) + b, _ = e.Chain.GetGoverningTokenBalance(multisigHash) + require.Equal(t, big.NewInt(3), b) +} diff --git a/cli/nep5_test.go b/cli/nep5_test.go index 4e25f46e2..2f879ecc3 100644 --- a/cli/nep5_test.go +++ b/cli/nep5_test.go @@ -6,14 +6,11 @@ import ( "os" "path" "strconv" - "strings" "testing" - "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/client" "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/stretchr/testify/require" ) @@ -82,15 +79,7 @@ func TestNEP5Transfer(t *testing.T) { e.In.WriteString("one\r") e.Run(t, args...) - line, err := e.Out.ReadString('\n') - require.NoError(t, err) - h, err := util.Uint256DecodeStringLE(strings.TrimSpace(line)) - require.NoError(t, err, "can't decode tx hash: %s", line) - - tx := e.GetTransaction(t, h) - aer, err := e.Chain.GetAppExecResult(tx.Hash()) - require.NoError(t, err) - require.Equal(t, vm.HaltState, aer.VMState) + e.checkTxPersisted(t) sh, err := address.StringToUint160(w.Accounts[0].Address) require.NoError(t, err) @@ -99,12 +88,7 @@ func TestNEP5Transfer(t *testing.T) { } func TestNEP5MultiTransfer(t *testing.T) { - privs := make([]*keys.PrivateKey, 3) - for i := range privs { - var err error - privs[i], err = keys.NewPrivateKey() - require.NoError(t, err) - } + privs, _ := generateKeys(t, 3) e := newExecutor(t, true) defer e.Close(t) @@ -120,15 +104,7 @@ func TestNEP5MultiTransfer(t *testing.T) { e.In.WriteString("one\r") e.Run(t, args...) - line, err := e.Out.ReadString('\n') - require.NoError(t, err) - h, err := util.Uint256DecodeStringLE(strings.TrimSpace(line)) - require.NoError(t, err, "can't decode tx hash: %s", line) - - tx := e.GetTransaction(t, h) - aer, err := e.Chain.GetAppExecResult(tx.Hash()) - require.NoError(t, err) - require.Equal(t, vm.HaltState, aer.VMState) + e.checkTxPersisted(t) b, _ := e.Chain.GetGoverningTokenBalance(privs[0].GetScriptHash()) require.Equal(t, big.NewInt(42), b) diff --git a/cli/wallet/multisig.go b/cli/wallet/multisig.go index 87bd2dffc..58cf2012c 100644 --- a/cli/wallet/multisig.go +++ b/cli/wallet/multisig.go @@ -3,7 +3,6 @@ package wallet import ( "encoding/json" "fmt" - "io" "io/ioutil" "github.com/nspcc-dev/neo-go/cli/options" @@ -60,7 +59,7 @@ func signMultisig(ctx *cli.Context) error { if !ok { return cli.NewExitError("verifiable item is not a transaction", 1) } - printTxInfo(ctx.App.Writer, tx) + fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE()) priv := acc.PrivateKey() sign := priv.Sign(tx.GetSignedPart()) @@ -116,7 +115,3 @@ func writeParameterContext(c *context.ParameterContext, filename string) error { } return nil } - -func printTxInfo(w io.Writer, t *transaction.Transaction) { - fmt.Fprintf(w, "Hash: %s\n", t.Hash().StringLE()) -} diff --git a/cli/wallet_test.go b/cli/wallet_test.go index 4662d93a5..de9649684 100644 --- a/cli/wallet_test.go +++ b/cli/wallet_test.go @@ -98,14 +98,7 @@ func TestWalletInit(t *testing.T) { require.NoError(t, actual.Decrypt("somepass")) }) t.Run("Multisig", func(t *testing.T) { - privs := make([]*keys.PrivateKey, 4) - pubs := make(keys.PublicKeys, 4) - for i := range privs { - var err error - privs[i], err = keys.NewPrivateKey() - require.NoError(t, err) - pubs[i] = privs[i].PublicKey() - } + privs, pubs := generateKeys(t, 4) cmd := []string{"neo-go", "wallet", "import-multisig", "--wallet", walletPath,