github.com/klaytn/klaytn@v1.12.1/cmd/utils/nodecmd/util.go (about) 1 // Modifications Copyright 2023 The klaytn Authors 2 // Copyright 2016 The go-ethereum Authors 3 // This file is part of go-ethereum. 4 // 5 // go-ethereum is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // go-ethereum is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 17 18 package nodecmd 19 20 import ( 21 "encoding/binary" 22 "encoding/hex" 23 "encoding/json" 24 "errors" 25 "fmt" 26 "os" 27 28 "github.com/klaytn/klaytn/accounts/keystore" 29 "github.com/klaytn/klaytn/blockchain/types" 30 "github.com/klaytn/klaytn/common" 31 "github.com/klaytn/klaytn/common/hexutil" 32 "github.com/klaytn/klaytn/consensus/istanbul" 33 "github.com/klaytn/klaytn/consensus/istanbul/backend" 34 "github.com/klaytn/klaytn/crypto" 35 "github.com/klaytn/klaytn/crypto/sha3" 36 "github.com/klaytn/klaytn/governance" 37 "github.com/klaytn/klaytn/params" 38 "github.com/klaytn/klaytn/rlp" 39 "github.com/urfave/cli/v2" 40 ) 41 42 const ( 43 DECODE_EXTRA = "decode-extra" 44 DECODE_VOTE = "decode-vote" 45 DECODE_GOV = "decode-gov" 46 DECRYPT_KEY = "decrypt-keystore" 47 ) 48 49 var ErrInvalidCmd = errors.New("Invalid command. Check usage through --help command") 50 51 var UtilCommand = &cli.Command{ 52 Name: "util", 53 Usage: "offline utility", 54 Category: "MISCELLANEOUS COMMANDS", 55 Subcommands: []*cli.Command{ 56 { 57 Name: DECODE_EXTRA, 58 Usage: "<header file (json format)>", 59 Action: action, 60 Description: "Decode header extra field", 61 }, 62 { 63 Name: DECODE_VOTE, 64 Usage: "<hex bytes>", 65 Action: action, 66 Description: "Decode header vote field", 67 }, 68 { 69 Name: DECODE_GOV, 70 Usage: "<hex bytes>", 71 Action: action, 72 Description: "Decode header governance field", 73 }, 74 { 75 Name: DECRYPT_KEY, 76 Usage: "<keystore path> <password>", 77 Action: action, 78 Description: "Decrypt keystore", 79 }, 80 }, 81 } 82 83 func action(ctx *cli.Context) error { 84 var ( 85 m map[string]interface{} 86 err error 87 ) 88 switch ctx.Command.Name { 89 case DECODE_EXTRA: 90 if ctx.Args().Len() != 1 { 91 return ErrInvalidCmd 92 } 93 m, err = decodeExtra(ctx.Args().Get(0)) 94 case DECODE_VOTE: 95 if ctx.Args().Len() != 1 { 96 return ErrInvalidCmd 97 } 98 m, err = decodeVote(hex2Bytes(ctx.Args().Get(0))) 99 case DECODE_GOV: 100 if ctx.Args().Len() != 1 { 101 return ErrInvalidCmd 102 } 103 m, err = decodeGov(hex2Bytes(ctx.Args().Get(0))) 104 case DECRYPT_KEY: 105 if ctx.Args().Len() != 2 { 106 return ErrInvalidCmd 107 } 108 keystorePath, passwd := ctx.Args().Get(0), ctx.Args().Get(1) 109 m, err = extractKeypair(keystorePath, passwd) 110 default: 111 return ErrInvalidCmd 112 } 113 if err == nil { 114 prettyPrint(m) 115 } 116 return err 117 } 118 119 func hex2Bytes(s string) []byte { 120 if data, err := hexutil.Decode(s); err == nil { 121 return data 122 } else { 123 panic(err) 124 } 125 } 126 127 func prettyPrint(m map[string]interface{}) { 128 if b, err := json.MarshalIndent(m, "", " "); err == nil { 129 fmt.Println(string(b)) 130 } else { 131 panic(err) 132 } 133 } 134 135 func extractKeypair(keystorePath, passwd string) (map[string]interface{}, error) { 136 keyjson, err := os.ReadFile(keystorePath) 137 if err != nil { 138 return nil, err 139 } 140 key, err := keystore.DecryptKey(keyjson, passwd) 141 if err != nil { 142 return nil, err 143 } 144 addr := key.GetAddress().String() 145 pubkey := key.GetPrivateKey().PublicKey 146 privkey := key.GetPrivateKey() 147 m := make(map[string]interface{}) 148 m["addr"] = addr 149 m["privkey"] = hex.EncodeToString(crypto.FromECDSA(privkey)) 150 m["pubkey"] = hex.EncodeToString(crypto.FromECDSAPub(&pubkey)) 151 return m, nil 152 } 153 154 func decodeGov(bytes []byte) (map[string]interface{}, error) { 155 var b []byte 156 m := make(map[string]interface{}) 157 if err := rlp.DecodeBytes(bytes, &b); err == nil { 158 if err := json.Unmarshal(b, &m); err == nil { 159 return m, nil 160 } else { 161 return nil, err 162 } 163 } else { 164 return nil, err 165 } 166 } 167 168 func parseHeaderFile(headerFile string) (*types.Header, common.Hash, error) { 169 header := new(types.Header) 170 bytes, err := os.ReadFile(headerFile) 171 if err != nil { 172 return nil, common.Hash{}, err 173 } 174 if err = json.Unmarshal(bytes, &header); err != nil { 175 return nil, common.Hash{}, err 176 } 177 var hash common.Hash 178 hasher := sha3.NewKeccak256() 179 rlp.Encode(hasher, types.IstanbulFilteredHeader(header, false)) 180 hasher.Sum(hash[:0]) 181 return header, hash, nil 182 } 183 184 func decodeExtra(headerFile string) (map[string]interface{}, error) { 185 header, sigHash, err := parseHeaderFile(headerFile) 186 if err != nil { 187 return nil, err 188 } 189 istanbulExtra, err := types.ExtractIstanbulExtra(header) 190 if err != nil { 191 return nil, err 192 } 193 validators := make([]string, len(istanbulExtra.Validators)) 194 for idx, addr := range istanbulExtra.Validators { 195 validators[idx] = addr.String() 196 } 197 proposer, err := istanbul.GetSignatureAddress(sigHash.Bytes(), istanbulExtra.Seal) 198 if err != nil { 199 return nil, err 200 } 201 committers, err := backend.RecoverCommittedSeals(istanbulExtra, header.Hash()) 202 if err != nil { 203 return nil, err 204 } 205 cSeals := make([]string, len(istanbulExtra.CommittedSeal)) 206 for i := 0; i < len(cSeals); i++ { 207 cSeals[i] = hexutil.Encode(istanbulExtra.CommittedSeal[i]) 208 } 209 210 m := make(map[string]interface{}) 211 m["hash"] = header.Hash().Hex() 212 m["sigHash"] = sigHash.Hex() 213 m["validators"] = validators 214 m["seal"] = hexutil.Encode(istanbulExtra.Seal) 215 m["committedSeal"] = cSeals 216 m["committers"] = committers 217 m["validatorSize"] = len(validators) 218 m["committedSealSize"] = len(cSeals) 219 m["proposer"] = proposer.String() 220 m["round"] = header.Round() 221 return m, nil 222 } 223 224 func decodeVote(bytes []byte) (map[string]interface{}, error) { 225 vote := new(governance.GovernanceVote) 226 m := make(map[string]interface{}) 227 if err := rlp.DecodeBytes(bytes, &vote); err == nil { 228 m["validator"] = vote.Validator.String() 229 m["key"] = vote.Key 230 switch governance.GovernanceKeyMap[vote.Key] { 231 case params.GovernanceMode, params.MintingAmount, params.MinimumStake, params.Ratio, params.Kip82Ratio: 232 m["value"] = string(vote.Value.([]uint8)) 233 case params.GoverningNode, params.GovParamContract: 234 m["value"] = common.BytesToAddress(vote.Value.([]uint8)).String() 235 case params.Epoch, params.CommitteeSize, params.UnitPrice, params.DeriveShaImpl, params.StakeUpdateInterval, 236 params.ProposerRefreshInterval, params.ConstTxGasHumanReadable, params.Policy, params.Timeout, 237 params.LowerBoundBaseFee, params.UpperBoundBaseFee, params.GasTarget, params.MaxBlockGasUsedForBaseFee, params.BaseFeeDenominator: 238 v := vote.Value.([]uint8) 239 v = append(make([]byte, 8-len(v)), v...) 240 m["value"] = binary.BigEndian.Uint64(v) 241 case params.UseGiniCoeff, params.DeferredTxFee: 242 v := vote.Value.([]uint8) 243 v = append(make([]byte, 8-len(v)), v...) 244 if binary.BigEndian.Uint64(v) != uint64(0) { 245 m["value"] = true 246 } else { 247 m["value"] = false 248 } 249 case params.AddValidator, params.RemoveValidator: 250 if v, ok := vote.Value.([]uint8); ok { 251 m["value"] = common.BytesToAddress(v) 252 } else if addresses, ok := vote.Value.([]interface{}); ok { 253 if len(addresses) == 0 { 254 return nil, governance.ErrValueTypeMismatch 255 } 256 var nodeAddresses []common.Address 257 for _, item := range addresses { 258 if in, ok := item.([]uint8); !ok || len(in) != common.AddressLength { 259 return nil, governance.ErrValueTypeMismatch 260 } 261 nodeAddresses = append(nodeAddresses, common.BytesToAddress(item.([]uint8))) 262 } 263 m["value"] = nodeAddresses 264 } else { 265 return nil, governance.ErrValueTypeMismatch 266 } 267 } 268 return m, nil 269 } else { 270 return nil, err 271 } 272 }