-
Notifications
You must be signed in to change notification settings - Fork 47
/
cmd_sigs.go
109 lines (96 loc) · 2.79 KB
/
cmd_sigs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package main
import (
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"github.com/iov-one/weave/cmd/bnsd/client"
"github.com/iov-one/weave/crypto"
"github.com/iov-one/weave/x/sigs"
)
func cmdSignTransaction(
input io.Reader,
output io.Writer,
args []string,
) error {
fl := flag.NewFlagSet("", flag.ExitOnError)
fl.Usage = func() {
fmt.Fprint(flag.CommandLine.Output(), `
Sign given transaction. This is decoding a transaction data from standard
input, adds a signature and writes back to standard output signed transaction
content.
`)
fl.PrintDefaults()
}
var (
tmAddrFl = fl.String("tm", env("BNSCLI_TM_ADDR", "https://bns.NETWORK.iov.one:443"),
"Tendermint node address. Use proper NETWORK name. You can use BNSCLI_TM_ADDR environment variable to set it.")
keyPathFl = fl.String("key", env("BNSCLI_PRIV_KEY", os.Getenv("HOME")+"/.bnsd.priv.key"),
"Path to the private key file that transaction should be signed with. You can use BNSCLI_PRIV_KEY environment variable to set it.")
)
fl.Parse(args)
if *keyPathFl == "" {
return errors.New("private key is required")
}
key, err := decodePrivateKey(*keyPathFl)
if err != nil {
return fmt.Errorf("cannot load private key: %s", err)
}
tx, _, err := readTx(input)
if err != nil {
return fmt.Errorf("cannot read transaction: %s", err)
}
genesis, err := fetchGenesis(*tmAddrFl)
if err != nil {
return fmt.Errorf("cannot fetch genesis: %s", err)
}
bnsClient := client.NewClient(client.NewHTTPConnection(*tmAddrFl))
aNonce := client.NewNonce(bnsClient, key.PublicKey().Address())
if seq, err := aNonce.Next(); err != nil {
return fmt.Errorf("cannot get the next sequence number: %s", err)
} else {
sig, err := sigs.SignTx(key, tx, genesis.ChainID, seq)
if err != nil {
return fmt.Errorf("cannot sign transaction: %s", err)
}
tx.Signatures = append(tx.Signatures, sig)
}
_, err = writeTx(output, tx)
return err
}
func decodePrivateKey(filepath string) (*crypto.PrivateKey, error) {
data, err := ioutil.ReadFile(filepath)
if err != nil {
return nil, fmt.Errorf("cannot read %q file: %s", filepath, err)
}
if len(data) != 64 {
return nil, errors.New("invalid key length")
}
key := &crypto.PrivateKey{
Priv: &crypto.PrivateKey_Ed25519{Ed25519: data},
}
return key, nil
}
func fetchGenesis(serverURL string) (*genesis, error) {
resp, err := http.Get(serverURL + "/genesis")
if err != nil {
return nil, fmt.Errorf("cannot fetch: %s", err)
}
defer resp.Body.Close()
var payload struct {
Result struct {
Genesis genesis `json:"genesis"`
} `json:"result"`
}
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
return nil, fmt.Errorf("cannot decode response: %s", err)
}
return &payload.Result.Genesis, nil
}
type genesis struct {
ChainID string `json:"chain_id"`
}