cli: add tests for multisig sign

This test is also a good example of how to
create and sign multisig transaction from scratch.
This commit is contained in:
Evgenii Stratonikov 2020-09-01 16:24:01 +03:00
parent 9817da7c4e
commit 6e5a637da9
5 changed files with 118 additions and 41 deletions

View file

@ -6,6 +6,7 @@ import (
"errors" "errors"
"io" "io"
"io/ioutil" "io/ioutil"
"strings"
"testing" "testing"
"time" "time"
@ -19,6 +20,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/network" "github.com/nspcc-dev/neo-go/pkg/network"
"github.com/nspcc-dev/neo-go/pkg/rpc/server" "github.com/nspcc-dev/neo-go/pkg/rpc/server"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/urfave/cli" "github.com/urfave/cli"
"go.uber.org/zap" "go.uber.org/zap"
@ -177,3 +179,29 @@ func (e *executor) run(args ...string) error {
e.Err.Reset() e.Err.Reset()
return e.CLI.Run(args) 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
}

85
cli/multisig_test.go Normal file
View file

@ -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)
}

View file

@ -6,14 +6,11 @@ import (
"os" "os"
"path" "path"
"strconv" "strconv"
"strings"
"testing" "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/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/rpc/client" "github.com/nspcc-dev/neo-go/pkg/rpc/client"
"github.com/nspcc-dev/neo-go/pkg/util" "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/nspcc-dev/neo-go/pkg/wallet"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -82,15 +79,7 @@ func TestNEP5Transfer(t *testing.T) {
e.In.WriteString("one\r") e.In.WriteString("one\r")
e.Run(t, args...) e.Run(t, args...)
line, err := e.Out.ReadString('\n') e.checkTxPersisted(t)
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)
sh, err := address.StringToUint160(w.Accounts[0].Address) sh, err := address.StringToUint160(w.Accounts[0].Address)
require.NoError(t, err) require.NoError(t, err)
@ -99,12 +88,7 @@ func TestNEP5Transfer(t *testing.T) {
} }
func TestNEP5MultiTransfer(t *testing.T) { func TestNEP5MultiTransfer(t *testing.T) {
privs := make([]*keys.PrivateKey, 3) privs, _ := generateKeys(t, 3)
for i := range privs {
var err error
privs[i], err = keys.NewPrivateKey()
require.NoError(t, err)
}
e := newExecutor(t, true) e := newExecutor(t, true)
defer e.Close(t) defer e.Close(t)
@ -120,15 +104,7 @@ func TestNEP5MultiTransfer(t *testing.T) {
e.In.WriteString("one\r") e.In.WriteString("one\r")
e.Run(t, args...) e.Run(t, args...)
line, err := e.Out.ReadString('\n') e.checkTxPersisted(t)
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)
b, _ := e.Chain.GetGoverningTokenBalance(privs[0].GetScriptHash()) b, _ := e.Chain.GetGoverningTokenBalance(privs[0].GetScriptHash())
require.Equal(t, big.NewInt(42), b) require.Equal(t, big.NewInt(42), b)

View file

@ -3,7 +3,6 @@ package wallet
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
@ -60,7 +59,7 @@ func signMultisig(ctx *cli.Context) error {
if !ok { if !ok {
return cli.NewExitError("verifiable item is not a transaction", 1) 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() priv := acc.PrivateKey()
sign := priv.Sign(tx.GetSignedPart()) sign := priv.Sign(tx.GetSignedPart())
@ -116,7 +115,3 @@ func writeParameterContext(c *context.ParameterContext, filename string) error {
} }
return nil return nil
} }
func printTxInfo(w io.Writer, t *transaction.Transaction) {
fmt.Fprintf(w, "Hash: %s\n", t.Hash().StringLE())
}

View file

@ -98,14 +98,7 @@ func TestWalletInit(t *testing.T) {
require.NoError(t, actual.Decrypt("somepass")) require.NoError(t, actual.Decrypt("somepass"))
}) })
t.Run("Multisig", func(t *testing.T) { t.Run("Multisig", func(t *testing.T) {
privs := make([]*keys.PrivateKey, 4) privs, pubs := generateKeys(t, 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()
}
cmd := []string{"neo-go", "wallet", "import-multisig", cmd := []string{"neo-go", "wallet", "import-multisig",
"--wallet", walletPath, "--wallet", walletPath,