cosmos-sdk/x/auth/client/cli/sign.go
Alessio Treglia e6a8a4df55
Implement command/REST endpoint for offline tx sign off #1953
* Add sign CLI command to sign transactions generated with the
  --generate-only flag.
* Add /sign REST endpoint for Voyager support.

Redirect password prompt to STDERR to avoid messing up cli
commands output. As a rule of thumb, program's output should
always go to STDOUT, whilst errors&diagnostics go to STDERR
as per POSIX's philosophy and specs.
2018-09-07 12:57:50 +01:00

92 lines
2.5 KiB
Go

package cli
import (
"fmt"
"io/ioutil"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/spf13/cobra"
amino "github.com/tendermint/go-amino"
)
const (
flagAppend = "append"
flagPrintSigs = "print-sigs"
)
// GetSignCommand returns the sign command
func GetSignCommand(codec *amino.Codec, decoder auth.AccountDecoder) *cobra.Command {
cmd := &cobra.Command{
Use: "sign <file>",
Short: "Sign transactions",
Long: `Sign transactions created with the --generate-only flag.
Read a transaction from <file>, sign it, and print its JSON encoding.`,
RunE: makeSignCmd(codec, decoder),
Args: cobra.ExactArgs(1),
}
cmd.Flags().String(client.FlagName, "", "Name of private key with which to sign")
cmd.Flags().Bool(flagAppend, true, "Append the signature to the existing ones. If disabled, old signatures would be overwritten")
cmd.Flags().Bool(flagPrintSigs, false, "Print the addresses that must sign the transaction and those who have already signed it, then exit")
return cmd
}
func makeSignCmd(cdc *amino.Codec, decoder auth.AccountDecoder) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) (err error) {
stdTx, err := readAndUnmarshalStdTx(cdc, args[0])
if err != nil {
return
}
if viper.GetBool(flagPrintSigs) {
printSignatures(stdTx)
return nil
}
name := viper.GetString(client.FlagName)
cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(decoder)
txCtx := authctx.NewTxContextFromCLI()
newTx, err := utils.SignStdTx(txCtx, cliCtx, name, stdTx, viper.GetBool(flagAppend))
if err != nil {
return err
}
json, err := cdc.MarshalJSON(newTx)
if err != nil {
return err
}
fmt.Printf("%s\n", json)
return
}
}
func printSignatures(stdTx auth.StdTx) {
fmt.Println("Signers:")
for i, signer := range stdTx.GetSigners() {
fmt.Printf(" %v: %v\n", i, signer.String())
}
fmt.Println("")
fmt.Println("Signatures:")
for i, sig := range stdTx.GetSignatures() {
fmt.Printf(" %v: %v\n", i, sdk.AccAddress(sig.Address()).String())
}
return
}
func readAndUnmarshalStdTx(cdc *amino.Codec, filename string) (stdTx auth.StdTx, err error) {
var bytes []byte
if bytes, err = ioutil.ReadFile(filename); err != nil {
return
}
if err = cdc.UnmarshalJSON(bytes, &stdTx); err != nil {
return
}
return
}