code.vegaprotocol.io/vega@v0.79.0/cmd/vega/commands/init.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package commands 17 18 import ( 19 "context" 20 "errors" 21 "fmt" 22 "os" 23 "path/filepath" 24 "time" 25 26 "code.vegaprotocol.io/vega/core/config" 27 "code.vegaprotocol.io/vega/core/config/encoding" 28 "code.vegaprotocol.io/vega/core/nodewallets/registry" 29 vgjson "code.vegaprotocol.io/vega/libs/json" 30 "code.vegaprotocol.io/vega/logging" 31 "code.vegaprotocol.io/vega/paths" 32 33 tmcfg "github.com/cometbft/cometbft/config" 34 tmos "github.com/cometbft/cometbft/libs/os" 35 tmrand "github.com/cometbft/cometbft/libs/rand" 36 "github.com/cometbft/cometbft/p2p" 37 "github.com/cometbft/cometbft/privval" 38 "github.com/cometbft/cometbft/types" 39 "github.com/jessevdk/go-flags" 40 ) 41 42 type InitCmd struct { 43 config.VegaHomeFlag 44 config.OutputFlag 45 config.Passphrase `long:"nodewallet-passphrase-file"` 46 47 Force bool `description:"Erase existing vega configuration at the specified path" long:"force" short:"f"` 48 49 NoTendermint bool `description:"Disable tendermint configuration generation" long:"no-tendermint"` 50 TendermintHome string `default:"$HOME/.cometbft" description:"Directory for tendermint config and data" long:"tendermint-home" required:"true"` 51 TendermintKey string `choice:"ed25519" choice:"secp256k1" default:"ed25519" description:"Key type to generate privval file with" long:"tendermint-key"` 52 } 53 54 var initCmd InitCmd 55 56 func (opts *InitCmd) Usage() string { 57 return "<full | validator>" 58 } 59 60 func (opts *InitCmd) Execute(args []string) error { 61 logger := logging.NewLoggerFromConfig(logging.NewDefaultConfig()) 62 defer logger.AtExit() 63 64 if len(args) != 1 { 65 return errors.New("require exactly 1 parameter mode, expected modes [validator, full, seed]") 66 } 67 68 mode, err := encoding.NodeModeFromString(args[0]) 69 if err != nil { 70 return err 71 } 72 73 output, err := opts.GetOutput() 74 if err != nil { 75 return err 76 } 77 78 vegaPaths := paths.New(opts.VegaHome) 79 80 // a nodewallet will be required only for a validator node 81 var nwRegistry *registry.Loader 82 if mode == encoding.NodeModeValidator { 83 pass, err := opts.Get("node wallet", true) 84 if err != nil { 85 return err 86 } 87 88 nwRegistry, err = registry.NewLoader(vegaPaths, pass) 89 if err != nil { 90 return err 91 } 92 } 93 94 cfgLoader, err := config.InitialiseLoader(vegaPaths) 95 if err != nil { 96 return fmt.Errorf("couldn't initialise configuration loader: %w", err) 97 } 98 99 configExists, err := cfgLoader.ConfigExists() 100 if err != nil { 101 return fmt.Errorf("couldn't verify configuration presence: %w", err) 102 } 103 104 if configExists && !opts.Force { 105 return fmt.Errorf("configuration already exists at `%s` please remove it first or re-run using -f", cfgLoader.ConfigFilePath()) 106 } 107 108 if configExists && opts.Force { 109 if output.IsHuman() { 110 logger.Info("removing existing configuration", logging.String("path", cfgLoader.ConfigFilePath())) 111 } 112 cfgLoader.Remove() 113 } 114 115 cfg := config.NewDefaultConfig() 116 cfg.NodeMode = mode 117 cfg.SetDefaultMaxMemoryPercent() 118 119 if err := cfgLoader.Save(&cfg); err != nil { 120 return fmt.Errorf("couldn't save configuration file: %w", err) 121 } 122 123 if output.IsHuman() { 124 logger.Info("configuration generated successfully", 125 logging.String("path", cfgLoader.ConfigFilePath())) 126 } 127 128 if !initCmd.NoTendermint { 129 tmCfg := tmcfg.DefaultConfig() 130 tmCfg.SetRoot(os.ExpandEnv(initCmd.TendermintHome)) 131 // add a few defaults 132 tmCfg.P2P.MaxPacketMsgPayloadSize = 16384 133 tmCfg.P2P.SendRate = 20000000 134 tmCfg.P2P.RecvRate = 20000000 135 tmCfg.Mempool.Size = 10000 136 tmCfg.Mempool.CacheSize = 20000 137 tmCfg.Consensus.TimeoutCommit = 0 * time.Second 138 tmCfg.Consensus.SkipTimeoutCommit = true 139 tmCfg.Consensus.CreateEmptyBlocksInterval = 1 * time.Second 140 tmCfg.Storage.DiscardABCIResponses = true 141 tmcfg.EnsureRoot(tmCfg.RootDir) 142 // then rewrite the config to apply the changes, EnsureRoot create the config, but with a default config 143 tmcfg.WriteConfigFile(filepath.Join(tmCfg.RootDir, tmcfg.DefaultConfigDir, tmcfg.DefaultConfigFileName), tmCfg) 144 if err := initTendermintConfiguration(output, logger, tmCfg); err != nil { 145 return fmt.Errorf("couldn't initialise tendermint %w", err) 146 } 147 } 148 149 if output.IsJSON() { 150 if mode == encoding.NodeModeValidator { 151 return vgjson.Print(struct { 152 ConfigFilePath string `json:"configFilePath"` 153 NodeWalletConfigFilePath string `json:"nodeWalletConfigFilePath"` 154 }{ 155 ConfigFilePath: cfgLoader.ConfigFilePath(), 156 NodeWalletConfigFilePath: nwRegistry.RegistryFilePath(), 157 }) 158 } 159 return vgjson.Print(struct { 160 ConfigFilePath string `json:"configFilePath"` 161 }{ 162 ConfigFilePath: cfgLoader.ConfigFilePath(), 163 }) 164 } 165 166 return nil 167 } 168 169 func initTendermintConfiguration(output config.Output, logger *logging.Logger, config *tmcfg.Config) error { 170 // private validator 171 privValKeyFile := config.PrivValidatorKeyFile() 172 privValStateFile := config.PrivValidatorStateFile() 173 var pv *privval.FilePV 174 if tmos.FileExists(privValKeyFile) { 175 pv = privval.LoadFilePV(privValKeyFile, privValStateFile) 176 if output.IsHuman() { 177 logger.Info("Found private validator", 178 logging.String("keyFile", privValKeyFile), 179 logging.String("stateFile", privValStateFile), 180 ) 181 } 182 } else { 183 pv = privval.GenFilePV(privValKeyFile, privValStateFile) 184 pv.Save() 185 if output.IsHuman() { 186 logger.Info("Generated private validator", 187 logging.String("keyFile", privValKeyFile), 188 logging.String("stateFile", privValStateFile), 189 ) 190 } 191 } 192 193 nodeKeyFile := config.NodeKeyFile() 194 if tmos.FileExists(nodeKeyFile) { 195 if output.IsHuman() { 196 logger.Info("Found node key", logging.String("path", nodeKeyFile)) 197 } 198 } else { 199 if _, err := p2p.LoadOrGenNodeKey(nodeKeyFile); err != nil { 200 return err 201 } 202 if output.IsHuman() { 203 logger.Info("Generated node key", logging.String("path", nodeKeyFile)) 204 } 205 } 206 207 // genesis file 208 genFile := config.GenesisFile() 209 if tmos.FileExists(genFile) { 210 if output.IsHuman() { 211 logger.Info("Found genesis file", logging.String("path", genFile)) 212 } 213 } else { 214 genDoc := types.GenesisDoc{ 215 ChainID: fmt.Sprintf("test-chain-%v", tmrand.Str(6)), 216 GenesisTime: time.Now().Round(0).UTC(), 217 ConsensusParams: types.DefaultConsensusParams(), 218 } 219 pubKey, err := pv.GetPubKey() 220 if err != nil { 221 return fmt.Errorf("can't get pubkey: %w", err) 222 } 223 genDoc.Validators = []types.GenesisValidator{{ 224 Address: pubKey.Address(), 225 PubKey: pubKey, 226 Power: 10, 227 }} 228 229 if err := genDoc.SaveAs(genFile); err != nil { 230 return err 231 } 232 if output.IsHuman() { 233 logger.Info("Generated genesis file", logging.String("path", genFile)) 234 } 235 } 236 237 return nil 238 } 239 240 func Init(ctx context.Context, parser *flags.Parser) error { 241 initCmd = InitCmd{} 242 243 var ( 244 short = "Initializes a vega node" 245 long = "Generate the minimal configuration required for a vega node to start. You must specify 'full' or 'validator'" 246 ) 247 _, err := parser.AddCommand("init", short, long, &initCmd) 248 return err 249 }