github.com/klaytn/klaytn@v1.10.2/cmd/kgen/main.go (about) 1 // Copyright 2019 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The klaytn library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "crypto/ecdsa" 21 "crypto/rand" 22 "encoding/json" 23 "fmt" 24 "io/ioutil" 25 "net" 26 "os" 27 "path" 28 29 "github.com/klaytn/klaytn/cmd/utils" 30 "github.com/klaytn/klaytn/cmd/utils/nodecmd" 31 "github.com/klaytn/klaytn/common" 32 "github.com/klaytn/klaytn/crypto" 33 "github.com/klaytn/klaytn/log" 34 "github.com/klaytn/klaytn/networks/p2p/discover" 35 "gopkg.in/urfave/cli.v1" 36 ) 37 38 type validatorInfo struct { 39 Address common.Address 40 Nodekey string 41 NodeInfo string 42 } 43 44 const ( 45 dirKeys = "keys" // directory name where the created files are stored. 46 ) 47 48 var ( 49 logger = log.NewModuleLogger(log.CMDKGEN) 50 fileFlag = cli.BoolFlag{ 51 Name: "file", 52 Usage: `Generate a nodekey and a Klaytn node information as files`, 53 } 54 portFlag = cli.IntFlag{ 55 Name: "port", 56 Usage: `Specify a tcp port number`, 57 Value: 32323, 58 } 59 ipFlag = cli.StringFlag{ 60 Name: "ip", 61 Usage: `Specify an ip address`, 62 Value: "0.0.0.0", 63 } 64 ) 65 66 func init() { 67 cli.AppHelpTemplate = utils.KgenHelpTemplate 68 cli.HelpPrinter = utils.NewHelpPrinter(nil) 69 } 70 71 func main() { 72 app := cli.NewApp() 73 app.Name = "kgen" 74 app.Usage = "The command line interface to generate nodekey information for Klaytn" 75 app.Copyright = "Copyright 2018-2019 The klaytn Authors" 76 app.Action = genNodeKey 77 app.Flags = []cli.Flag{ 78 fileFlag, 79 ipFlag, 80 portFlag, 81 } 82 app.Commands = []cli.Command{ 83 nodecmd.VersionCommand, 84 } 85 app.HideVersion = true 86 // app.CustomAppHelpTemplate = kgenHelper 87 if err := app.Run(os.Args); err != nil { 88 fmt.Fprintln(os.Stderr, err) 89 os.Exit(1) 90 } 91 } 92 93 // writeNodeKeyInfoToFile writes `nodekey` and `node_info.json` as files under the `parentDir` folder. 94 // The validator is a json format file containing address, nodekey and nodeinfo. 95 func writeNodeKeyInfoToFile(validator *validatorInfo, parentDir string, nodekey string) error { 96 parentPath := path.Join("", parentDir) 97 err := os.MkdirAll(parentPath, os.ModePerm) 98 if err != nil { 99 return err 100 } 101 102 nodeKeyFilePath := path.Join(parentPath, "nodekey") 103 if err = ioutil.WriteFile(nodeKeyFilePath, []byte(nodekey), os.ModePerm); err != nil { 104 return err 105 } 106 fmt.Println("Created : ", nodeKeyFilePath) 107 108 str, err := json.MarshalIndent(validator, "", "\t") 109 if err != nil { 110 return err 111 } 112 validatorInfoFilePath := path.Join(parentPath, "node_info.json") 113 if err = ioutil.WriteFile(validatorInfoFilePath, []byte(str), os.ModePerm); err != nil { 114 return err 115 } 116 117 fmt.Println("Created : ", validatorInfoFilePath) 118 return nil 119 } 120 121 // makeNodeInfo creates a validator with the given parameters. 122 func makeNodeInfo(nodeAddr common.Address, nodeKey string, privKey *ecdsa.PrivateKey, ip string, port uint16) *validatorInfo { 123 return &validatorInfo{ 124 Address: nodeAddr, 125 Nodekey: nodeKey, 126 NodeInfo: discover.NewNode( 127 discover.PubkeyID(&privKey.PublicKey), 128 net.ParseIP(ip), 129 0, 130 port, 131 nil, 132 discover.NodeTypeUnknown).String(), 133 } 134 } 135 136 // genNodeKey creates a validator which is printed as json format or is stored into files(nodekey, validator). 137 func genNodeKey(ctx *cli.Context) error { 138 pk, nk, addr, err := generateNodeInfoContents() 139 if err != nil { 140 return err 141 } 142 ip := ctx.String(ipFlag.Name) 143 if net.ParseIP(ip).To4() == nil { 144 return fmt.Errorf("IP address is not valid") 145 } 146 port := ctx.Uint(portFlag.Name) 147 if port > 65535 { 148 return fmt.Errorf("invalid port number") 149 } 150 nodeinfo := makeNodeInfo(addr, nk, pk, ip, uint16(port)) 151 if ctx.Bool(fileFlag.Name) { 152 if err := writeNodeKeyInfoToFile(nodeinfo, dirKeys, nk); err != nil { 153 return err 154 } 155 } else { 156 str, err := json.MarshalIndent(nodeinfo, "", "\t") 157 if err != nil { 158 return err 159 } 160 fmt.Println(string(str)) 161 } 162 return nil 163 } 164 165 // randomBytes creates random bytes as long as `len`. 166 func randomBytes(len int) ([]byte, error) { 167 b := make([]byte, len) 168 _, _ = rand.Read(b) 169 170 return b, nil 171 } 172 173 // randomHex creates a random 32-bytes hexadecimal string. 174 func randomHex() string { 175 b, _ := randomBytes(32) 176 return common.BytesToHash(b).Hex() 177 } 178 179 // generateNodeInfoContents generates contents of a validator. 180 func generateNodeInfoContents() (*ecdsa.PrivateKey, string, common.Address, error) { 181 nodekey := randomHex()[2:] // truncate `0x` prefix 182 183 key, err := crypto.HexToECDSA(nodekey) 184 if err != nil { 185 logger.Error("Failed to generate key", "err", err) 186 return nil, "", common.Address{}, err 187 } 188 189 addr := crypto.PubkeyToAddress(key.PublicKey) 190 191 return key, nodekey, addr, nil 192 }