cli/wallet: process non-out non-rpc calls to sign
And document the behavior better. Fixes #2664.
This commit is contained in:
parent
c316107c9f
commit
c2c10c111c
3 changed files with 70 additions and 19 deletions
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/context"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -162,13 +163,41 @@ func TestSignMultisigTx(t *testing.T) {
|
|||
require.Equal(t, vmstate.Halt.String(), res.State, res.FaultException)
|
||||
})
|
||||
|
||||
t.Run("console output", func(t *testing.T) {
|
||||
oldIn, err := os.ReadFile(txPath)
|
||||
require.NoError(t, err)
|
||||
e.In.WriteString("pass\r")
|
||||
e.Run(t, "neo-go", "wallet", "sign",
|
||||
"--wallet", wallet2Path, "--address", multisigAddr,
|
||||
"--in", txPath)
|
||||
newIn, err := os.ReadFile(txPath)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, oldIn, newIn)
|
||||
|
||||
pcOld := new(context.ParameterContext)
|
||||
require.NoError(t, json.Unmarshal(oldIn, pcOld))
|
||||
|
||||
jOut := e.Out.Bytes()
|
||||
pcNew := new(context.ParameterContext)
|
||||
require.NoError(t, json.Unmarshal(jOut, pcNew))
|
||||
|
||||
require.Equal(t, pcOld.Type, pcNew.Type)
|
||||
require.Equal(t, pcOld.Network, pcNew.Network)
|
||||
require.Equal(t, pcOld.Verifiable, pcNew.Verifiable)
|
||||
require.Equal(t, pcOld.Items[multisigHash].Script, pcNew.Items[multisigHash].Script)
|
||||
// It's completely signed after this, so parameters have signatures now as well.
|
||||
require.NotEqual(t, pcOld.Items[multisigHash].Parameters, pcNew.Items[multisigHash].Parameters)
|
||||
require.NotEqual(t, pcOld.Items[multisigHash].Signatures, pcNew.Items[multisigHash].Signatures)
|
||||
})
|
||||
|
||||
t.Run("sign, save and send", func(t *testing.T) {
|
||||
e.In.WriteString("pass\r")
|
||||
e.Run(t, "neo-go", "wallet", "sign",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", wallet2Path, "--address", multisigAddr,
|
||||
"--in", txPath, "--out", txPath)
|
||||
e.checkTxPersisted(t)
|
||||
|
||||
})
|
||||
t.Run("double-sign", func(t *testing.T) {
|
||||
e.In.WriteString("pass\r")
|
||||
e.RunWithError(t, "neo-go", "wallet", "sign",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package wallet
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||
|
@ -12,6 +13,11 @@ import (
|
|||
)
|
||||
|
||||
func signStoredTransaction(ctx *cli.Context) error {
|
||||
var (
|
||||
out = ctx.String("out")
|
||||
rpcNode = ctx.String(options.RPCEndpointFlag)
|
||||
addrFlag = ctx.Generic("address").(*flags.Address)
|
||||
)
|
||||
if err := cmdargs.EnsureNone(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -20,11 +26,11 @@ func signStoredTransaction(ctx *cli.Context) error {
|
|||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
c, err := paramcontext.Read(ctx.String("in"))
|
||||
pc, err := paramcontext.Read(ctx.String("in"))
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
addrFlag := ctx.Generic("address").(*flags.Address)
|
||||
|
||||
if !addrFlag.IsSet {
|
||||
return cli.NewExitError("address was not provided", 1)
|
||||
}
|
||||
|
@ -35,7 +41,7 @@ func signStoredTransaction(ctx *cli.Context) error {
|
|||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
tx, ok := c.Verifiable.(*transaction.Transaction)
|
||||
tx, ok := pc.Verifiable.(*transaction.Transaction)
|
||||
if !ok {
|
||||
return cli.NewExitError("verifiable item is not a transaction", 1)
|
||||
}
|
||||
|
@ -52,18 +58,27 @@ func signStoredTransaction(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
priv := acc.PrivateKey()
|
||||
sign := priv.SignHashable(uint32(c.Network), tx)
|
||||
if err := c.AddSignature(ch, acc.Contract, priv.PublicKey(), sign); err != nil {
|
||||
sign := priv.SignHashable(uint32(pc.Network), tx)
|
||||
if err := pc.AddSignature(ch, acc.Contract, priv.PublicKey(), sign); err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("can't add signature: %w", err), 1)
|
||||
}
|
||||
if out := ctx.String("out"); out != "" {
|
||||
if err := paramcontext.Save(c, out); err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to dump resulting transaction: %w", err), 1)
|
||||
// Not saving and not sending, print.
|
||||
if out == "" && rpcNode == "" {
|
||||
txt, err := json.MarshalIndent(pc, " ", " ")
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("can't display resulting context: %w", err), 1)
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, string(txt))
|
||||
return nil
|
||||
}
|
||||
if out != "" {
|
||||
if err := paramcontext.Save(pc, out); err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("can't save resulting context: %w", err), 1)
|
||||
}
|
||||
}
|
||||
if len(ctx.String(options.RPCEndpointFlag)) != 0 {
|
||||
if rpcNode != "" {
|
||||
for i := range tx.Signers {
|
||||
w, err := c.GetWitness(tx.Signers[i].Account)
|
||||
w, err := pc.GetWitness(tx.Signers[i].Account)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to construct witness for signer #%d: %w", i, err), 1)
|
||||
}
|
||||
|
|
|
@ -281,7 +281,14 @@ func NewCommands() []cli.Command {
|
|||
{
|
||||
Name: "sign",
|
||||
Usage: "cosign transaction with multisig/contract/additional account",
|
||||
UsageText: "sign -w wallet [--wallet-config path] --address <address> --in <file.in> --out <file.out> [-r <endpoint>]",
|
||||
UsageText: "sign -w wallet [--wallet-config path] --address <address> --in <file.in> [--out <file.out>] [-r <endpoint>]",
|
||||
Description: `Signs the given (in file.in) context (which must be a transaction
|
||||
signing context) for the given address using the given wallet. This command can
|
||||
output the resulting JSON (with additional signature added) right to the console
|
||||
(if no file.out and no RPC endpoint specified) or into a file (which can be the
|
||||
same as input one). If an RPC endpoint is given it'll also try to construct a
|
||||
complete transaction and send it via RPC (printing its hash if everything is OK).
|
||||
`,
|
||||
Action: signStoredTransaction,
|
||||
Flags: signFlags,
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue