github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/common/hexutil/hexutil.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 /* 18 Package hexutil implements hex encoding with 0x prefix. 19 This encoding is used by the Ethereum RPC API to transport binary data in JSON payloads. 20 21 Encoding Rules 22 23 All hex data must have prefix "0x". 24 25 For byte slices, the hex data must be of even length. An empty byte slice 26 encodes as "0x". 27 28 Integers are encoded using the least amount of digits (no leading zero digits). Their 29 encoding may be of uneven length. The number zero encodes as "0x0". 30 */ 31 package hexutil 32 33 import ( 34 "encoding/hex" 35 "fmt" 36 "math/big" 37 "strconv" 38 ) 39 40 const uintBits = 32 << (uint64(^uint(0)) >> 63) 41 42 // Errors 43 var ( 44 ErrEmptyString = &decError{"empty hex string"} 45 ErrSyntax = &decError{"invalid hex string"} 46 ErrMissingPrefix = &decError{"hex string without 0x prefix"} 47 ErrOddLength = &decError{"hex string of odd length"} 48 ErrEmptyNumber = &decError{"hex string \"0x\""} 49 ErrLeadingZero = &decError{"hex number with leading zero digits"} 50 ErrUint64Range = &decError{"hex number > 64 bits"} 51 ErrUintRange = &decError{fmt.Sprintf("hex number > %d bits", uintBits)} 52 ErrBig256Range = &decError{"hex number > 256 bits"} 53 ) 54 55 type decError struct{ msg string } 56 57 func (err decError) Error() string { return err.msg } 58 59 // Decode decodes a hex string with 0x prefix. 60 func Decode(input string) ([]byte, error) { 61 if len(input) == 0 { 62 return nil, ErrEmptyString 63 } 64 if !has0xPrefix(input) { 65 return nil, ErrMissingPrefix 66 } 67 // better compatible with odd size string 68 if len(input)%2 != 0 { 69 input = "0x0" + input[2:] 70 } 71 72 b, err := hex.DecodeString(input[2:]) 73 if err != nil { 74 err = mapError(err) 75 } 76 return b, err 77 } 78 79 // MustDecode decodes a hex string with 0x prefix. It panics for invalid input. 80 func MustDecode(input string) []byte { 81 dec, err := Decode(input) 82 if err != nil { 83 panic(err) 84 } 85 return dec 86 } 87 88 // Encode encodes b as a hex string with 0x prefix. 89 func Encode(b []byte) string { 90 enc := make([]byte, len(b)*2+2) 91 copy(enc, "0x") 92 hex.Encode(enc[2:], b) 93 return string(enc) 94 } 95 96 // DecodeUint64 decodes a hex string with 0x prefix as a quantity. 97 func DecodeUint64(input string) (uint64, error) { 98 raw, err := checkNumber(input) 99 if err != nil { 100 return 0, err 101 } 102 dec, err := strconv.ParseUint(raw, 16, 64) 103 if err != nil { 104 err = mapError(err) 105 } 106 return dec, err 107 } 108 109 // MustDecodeUint64 decodes a hex string with 0x prefix as a quantity. 110 // It panics for invalid input. 111 func MustDecodeUint64(input string) uint64 { 112 dec, err := DecodeUint64(input) 113 if err != nil { 114 panic(err) 115 } 116 return dec 117 } 118 119 // EncodeUint64 encodes i as a hex string with 0x prefix. 120 func EncodeUint64(i uint64) string { 121 enc := make([]byte, 2, 10) 122 copy(enc, "0x") 123 return string(strconv.AppendUint(enc, i, 16)) 124 } 125 126 var bigWordNibbles int 127 128 func init() { 129 // This is a weird way to compute the number of nibbles required for big.Word. 130 // The usual way would be to use constant arithmetic but go vet can't handle that. 131 b, _ := new(big.Int).SetString("FFFFFFFFFF", 16) 132 switch len(b.Bits()) { 133 case 1: 134 bigWordNibbles = 16 135 case 2: 136 bigWordNibbles = 8 137 default: 138 panic("weird big.Word size") 139 } 140 } 141 142 // DecodeBig decodes a hex string with 0x prefix as a quantity. 143 // Numbers larger than 256 bits are not accepted. 144 func DecodeBig(input string) (*big.Int, error) { 145 raw, err := checkNumber(input) 146 if err != nil { 147 return nil, err 148 } 149 if len(raw) > 64 { 150 return nil, ErrBig256Range 151 } 152 words := make([]big.Word, len(raw)/bigWordNibbles+1) 153 end := len(raw) 154 for i := range words { 155 start := end - bigWordNibbles 156 if start < 0 { 157 start = 0 158 } 159 for ri := start; ri < end; ri++ { 160 nib := decodeNibble(raw[ri]) 161 if nib == badNibble { 162 return nil, ErrSyntax 163 } 164 words[i] *= 16 165 words[i] += big.Word(nib) 166 } 167 end = start 168 } 169 dec := new(big.Int).SetBits(words) 170 return dec, nil 171 } 172 173 // MustDecodeBig decodes a hex string with 0x prefix as a quantity. 174 // It panics for invalid input. 175 func MustDecodeBig(input string) *big.Int { 176 dec, err := DecodeBig(input) 177 if err != nil { 178 panic(err) 179 } 180 return dec 181 } 182 183 // EncodeBig encodes bigint as a hex string with 0x prefix. 184 func EncodeBig(bigint *big.Int) string { 185 if sign := bigint.Sign(); sign == 0 { 186 return "0x0" 187 } else if sign > 0 { 188 return "0x" + bigint.Text(16) 189 } else { 190 return "-0x" + bigint.Text(16)[1:] 191 } 192 } 193 194 func has0xPrefix(input string) bool { 195 return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X') 196 } 197 198 func checkNumber(input string) (raw string, err error) { 199 if len(input) == 0 { 200 return "", ErrEmptyString 201 } 202 if !has0xPrefix(input) { 203 return "", ErrMissingPrefix 204 } 205 input = input[2:] 206 if len(input) == 0 { 207 return "", ErrEmptyNumber 208 } 209 if len(input) > 1 && input[0] == '0' { 210 return "", ErrLeadingZero 211 } 212 return input, nil 213 } 214 215 const badNibble = ^uint64(0) 216 217 func decodeNibble(in byte) uint64 { 218 switch { 219 case in >= '0' && in <= '9': 220 return uint64(in - '0') 221 case in >= 'A' && in <= 'F': 222 return uint64(in - 'A' + 10) 223 case in >= 'a' && in <= 'f': 224 return uint64(in - 'a' + 10) 225 default: 226 return badNibble 227 } 228 } 229 230 func mapError(err error) error { 231 if err, ok := err.(*strconv.NumError); ok { 232 switch err.Err { 233 case strconv.ErrRange: 234 return ErrUint64Range 235 case strconv.ErrSyntax: 236 return ErrSyntax 237 } 238 } 239 if _, ok := err.(hex.InvalidByteError); ok { 240 return ErrSyntax 241 } 242 if err == hex.ErrLength { 243 return ErrOddLength 244 } 245 return err 246 }