forked from cosmos/cosmos-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
init.go
183 lines (159 loc) · 4.63 KB
/
init.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package server
import (
"encoding/json"
"fmt"
"io/ioutil"
"github.com/spf13/cobra"
"github.com/tendermint/go-crypto/keys"
"github.com/tendermint/go-crypto/keys/words"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
cfg "github.com/tendermint/tendermint/config"
tmtypes "github.com/tendermint/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// InitCmd will initialize all files for tendermint,
// along with proper app_options.
// The application can pass in a function to generate
// proper options. And may want to use GenerateCoinKey
// to create default account(s).
func InitCmd(gen GenOptions, logger log.Logger) *cobra.Command {
cmd := initCmd{
gen: gen,
logger: logger,
}
return &cobra.Command{
Use: "init",
Short: "Initialize genesis files",
RunE: cmd.run,
}
}
// GenOptions can parse command-line and flag to
// generate default app_options for the genesis file.
// This is application-specific
type GenOptions func(args []string) (json.RawMessage, error)
// GenerateCoinKey returns the address of a public key,
// along with the secret phrase to recover the private key.
// You can give coins to this address and return the recovery
// phrase to the user to access them.
func GenerateCoinKey() (sdk.Address, string, error) {
// construct an in-memory key store
codec, err := words.LoadCodec("english")
if err != nil {
return nil, "", err
}
keybase := keys.New(
dbm.NewMemDB(),
codec,
)
// generate a private key, with recovery phrase
info, secret, err := keybase.Create("name", "pass", keys.AlgoEd25519)
if err != nil {
return nil, "", err
}
addr := info.PubKey.Address()
return addr, secret, nil
}
type initCmd struct {
gen GenOptions
logger log.Logger
}
func (c initCmd) run(cmd *cobra.Command, args []string) error {
// Run the basic tendermint initialization,
// set up a default genesis with no app_options
config, err := tcmd.ParseConfig()
if err != nil {
return err
}
err = c.initTendermintFiles(config)
if err != nil {
return err
}
// no app_options, leave like tendermint
if c.gen == nil {
return nil
}
// Now, we want to add the custom app_options
options, err := c.gen(args)
if err != nil {
return err
}
// And add them to the genesis file
genFile := config.GenesisFile()
return addGenesisOptions(genFile, options)
}
// This was copied from tendermint/cmd/tendermint/commands/init.go
// so we could pass in the config and the logger.
func (c initCmd) initTendermintFiles(config *cfg.Config) error {
// private validator
privValFile := config.PrivValidatorFile()
var privValidator *tmtypes.PrivValidatorFS
if cmn.FileExists(privValFile) {
privValidator = tmtypes.LoadPrivValidatorFS(privValFile)
c.logger.Info("Found private validator", "path", privValFile)
} else {
privValidator = tmtypes.GenPrivValidatorFS(privValFile)
privValidator.Save()
c.logger.Info("Generated private validator", "path", privValFile)
}
// genesis file
genFile := config.GenesisFile()
if cmn.FileExists(genFile) {
c.logger.Info("Found genesis file", "path", genFile)
} else {
genDoc := tmtypes.GenesisDoc{
ChainID: cmn.Fmt("test-chain-%v", cmn.RandStr(6)),
}
genDoc.Validators = []tmtypes.GenesisValidator{{
PubKey: privValidator.GetPubKey(),
Power: 10,
}}
if err := genDoc.SaveAs(genFile); err != nil {
return err
}
c.logger.Info("Generated genesis file", "path", genFile)
}
return nil
}
// GenesisDoc involves some tendermint-specific structures we don't
// want to parse, so we just grab it into a raw object format,
// so we can add one line.
type GenesisDoc map[string]json.RawMessage
func addGenesisOptions(filename string, options json.RawMessage) error {
bz, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
var doc GenesisDoc
err = json.Unmarshal(bz, &doc)
if err != nil {
return err
}
doc["app_state"] = options
out, err := json.MarshalIndent(doc, "", " ")
if err != nil {
return err
}
return ioutil.WriteFile(filename, out, 0600)
}
// GetGenesisJSON returns a new tendermint genesis with Basecoin app_options
// that grant a large amount of "mycoin" to a single address
// TODO: A better UX for generating genesis files
func GetGenesisJSON(pubkey, chainID, denom, addr string, options string) string {
return fmt.Sprintf(`{
"accounts": [{
"address": "%s",
"coins": [
{
"denom": "%s",
"amount": 9007199254740992
}
]
}],
"plugin_options": [
"coin/issuer", {"app": "sigs", "addr": "%s"}%s
]
}`, addr, denom, addr, options)
}