code.vegaprotocol.io/vega@v0.79.0/cmd/vega/commands/genesis/new_validator.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 genesis 17 18 import ( 19 "encoding/base64" 20 "errors" 21 "fmt" 22 23 "code.vegaprotocol.io/vega/core/nodewallets" 24 vgtm "code.vegaprotocol.io/vega/core/tendermint" 25 "code.vegaprotocol.io/vega/core/validators" 26 vgjson "code.vegaprotocol.io/vega/libs/json" 27 "code.vegaprotocol.io/vega/logging" 28 "code.vegaprotocol.io/vega/paths" 29 30 tmjson "github.com/cometbft/cometbft/libs/json" 31 tmtypes "github.com/cometbft/cometbft/types" 32 "github.com/jessevdk/go-flags" 33 ) 34 35 var ErrAppendAndReplaceAreMutuallyExclusive = errors.New("--append and --replace and mutually exclusive") 36 37 type newValidatorCmd struct { 38 Config nodewallets.Config 39 40 TmHome string `description:"The home path of tendermint" long:"tm-home" short:"t"` 41 Country string `description:"The country from which the validator operates" long:"country" required:"true"` 42 InfoURL string `description:"The URL from which people can get to know the validator" long:"info-url" required:"true"` 43 Name string `description:"The name of the validator node" long:"name" required:"true"` 44 AvatarURL string `description:"An URL to an avatar for the validator" long:"avatar-url"` 45 ShouldAppend bool `description:"Append the generated validator to the existing validators in the genesis file" long:"append"` 46 ShouldReplace bool `description:"Replace the existing validators by the generated validator in the genesis file" long:"replace"` 47 } 48 49 func (opts *newValidatorCmd) Execute(_ []string) error { 50 if err := opts.Validate(); err != nil { 51 return err 52 } 53 54 log := logging.NewLoggerFromConfig(logging.NewDefaultConfig()) 55 defer log.AtExit() 56 57 pass, err := genesisCmd.PassphraseFile.Get("node wallet", false) 58 if err != nil { 59 return err 60 } 61 62 vegaPaths := paths.New(genesisCmd.VegaHome) 63 64 if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil { 65 return err 66 } 67 68 vegaKey, ethAddress, walletID, err := loadNodeWalletPubKey(opts.Config, vegaPaths, pass) 69 if err != nil { 70 return err 71 } 72 73 tmConfig := vgtm.NewConfig(opts.TmHome) 74 75 pubKey, err := tmConfig.PublicValidatorKey() 76 if err != nil { 77 return err 78 } 79 80 validatorDataDoc := tmtypes.GenesisValidator{ 81 Address: pubKey.Address(), 82 PubKey: pubKey, 83 Power: 10, 84 Name: opts.Name, 85 } 86 87 b64TmPubKey := base64.StdEncoding.EncodeToString(pubKey.Bytes()) 88 validatorDataState := validators.ValidatorData{ 89 ID: walletID, 90 VegaPubKey: vegaKey.value, 91 VegaPubKeyIndex: vegaKey.index, 92 TmPubKey: b64TmPubKey, 93 EthereumAddress: ethAddress, 94 Country: opts.Country, 95 InfoURL: opts.InfoURL, 96 Name: opts.Name, 97 AvatarURL: opts.AvatarURL, 98 } 99 100 if !opts.ShouldAppend && !opts.ShouldReplace { 101 marshalledGenesisDoc, err := tmjson.MarshalIndent(validatorDataDoc, "", " ") 102 if err != nil { 103 return err 104 } 105 fmt.Println("Info to add in genesis file under `validators` key") 106 fmt.Println(string(marshalledGenesisDoc)) 107 108 fmt.Println("Info to add in genesis file under `app_state.validators` key") 109 return vgjson.PrettyPrint(map[string]validators.ValidatorData{ 110 b64TmPubKey: validatorDataState, 111 }) 112 } 113 114 genesisDoc, genesisState, err := tmConfig.Genesis() 115 if err != nil { 116 return fmt.Errorf("couldn't get genesis file: %w", err) 117 } 118 119 if opts.ShouldAppend { 120 if _, ok := genesisState.Validators[b64TmPubKey]; ok { 121 return fmt.Errorf("validator with tendermint key \"%s\" is already registered under app_state.validators key", b64TmPubKey) 122 } 123 for _, validator := range genesisDoc.Validators { 124 if validator.PubKey.Equals(pubKey) { 125 return fmt.Errorf("validator with tendermint key \"%s\" is already registered under validators key", b64TmPubKey) 126 } 127 } 128 genesisDoc.Validators = append(genesisDoc.Validators, validatorDataDoc) 129 genesisState.Validators[b64TmPubKey] = validatorDataState 130 } else if opts.ShouldReplace { 131 genesisDoc.Validators = []tmtypes.GenesisValidator{validatorDataDoc} 132 genesisState.Validators = map[string]validators.ValidatorData{ 133 b64TmPubKey: validatorDataState, 134 } 135 } 136 137 if err = vgtm.AddAppStateToGenesis(genesisDoc, genesisState); err != nil { 138 return fmt.Errorf("couldn't add app_state to genesis: %w", err) 139 } 140 141 if err := tmConfig.SaveGenesis(genesisDoc); err != nil { 142 return fmt.Errorf("couldn't save genesis: %w", err) 143 } 144 145 prettifiedDoc, err := vgtm.Prettify(genesisDoc) 146 if err != nil { 147 return err 148 } 149 fmt.Println(prettifiedDoc) 150 return err 151 } 152 153 func (opts *newValidatorCmd) Validate() error { 154 if opts.ShouldAppend && opts.ShouldReplace { 155 return ErrAppendAndReplaceAreMutuallyExclusive 156 } 157 return nil 158 }