github.com/ylsGit/go-ethereum@v1.6.5/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  	"errors"
    36  	"fmt"
    37  	"math/big"
    38  	"strconv"
    39  )
    40  
    41  const uintBits = 32 << (uint64(^uint(0)) >> 63)
    42  
    43  var (
    44  	ErrEmptyString   = errors.New("empty hex string")
    45  	ErrMissingPrefix = errors.New("missing 0x prefix for hex data")
    46  	ErrSyntax        = errors.New("invalid hex")
    47  	ErrEmptyNumber   = errors.New("hex number has no digits after 0x")
    48  	ErrLeadingZero   = errors.New("hex number has leading zero digits after 0x")
    49  	ErrOddLength     = errors.New("hex string has odd length")
    50  	ErrUint64Range   = errors.New("hex number does not fit into 64 bits")
    51  	ErrUintRange     = fmt.Errorf("hex number does not fit into %d bits", uintBits)
    52  	ErrBig256Range   = errors.New("hex number does not fit into 256 bits")
    53  )
    54  
    55  // Decode decodes a hex string with 0x prefix.
    56  func Decode(input string) ([]byte, error) {
    57  	if len(input) == 0 {
    58  		return nil, ErrEmptyString
    59  	}
    60  	if !has0xPrefix(input) {
    61  		return nil, ErrMissingPrefix
    62  	}
    63  	b, err := hex.DecodeString(input[2:])
    64  	if err != nil {
    65  		err = mapError(err)
    66  	}
    67  	return b, err
    68  }
    69  
    70  // MustDecode decodes a hex string with 0x prefix. It panics for invalid input.
    71  func MustDecode(input string) []byte {
    72  	dec, err := Decode(input)
    73  	if err != nil {
    74  		panic(err)
    75  	}
    76  	return dec
    77  }
    78  
    79  // Encode encodes b as a hex string with 0x prefix.
    80  func Encode(b []byte) string {
    81  	enc := make([]byte, len(b)*2+2)
    82  	copy(enc, "0x")
    83  	hex.Encode(enc[2:], b)
    84  	return string(enc)
    85  }
    86  
    87  // DecodeUint64 decodes a hex string with 0x prefix as a quantity.
    88  func DecodeUint64(input string) (uint64, error) {
    89  	raw, err := checkNumber(input)
    90  	if err != nil {
    91  		return 0, err
    92  	}
    93  	dec, err := strconv.ParseUint(raw, 16, 64)
    94  	if err != nil {
    95  		err = mapError(err)
    96  	}
    97  	return dec, err
    98  }
    99  
   100  // MustDecodeUint64 decodes a hex string with 0x prefix as a quantity.
   101  // It panics for invalid input.
   102  func MustDecodeUint64(input string) uint64 {
   103  	dec, err := DecodeUint64(input)
   104  	if err != nil {
   105  		panic(err)
   106  	}
   107  	return dec
   108  }
   109  
   110  // EncodeUint64 encodes i as a hex string with 0x prefix.
   111  func EncodeUint64(i uint64) string {
   112  	enc := make([]byte, 2, 10)
   113  	copy(enc, "0x")
   114  	return string(strconv.AppendUint(enc, i, 16))
   115  }
   116  
   117  var bigWordNibbles int
   118  
   119  func init() {
   120  	// This is a weird way to compute the number of nibbles required for big.Word.
   121  	// The usual way would be to use constant arithmetic but go vet can't handle that.
   122  	b, _ := new(big.Int).SetString("FFFFFFFFFF", 16)
   123  	switch len(b.Bits()) {
   124  	case 1:
   125  		bigWordNibbles = 16
   126  	case 2:
   127  		bigWordNibbles = 8
   128  	default:
   129  		panic("weird big.Word size")
   130  	}
   131  }
   132  
   133  // DecodeBig decodes a hex string with 0x prefix as a quantity.
   134  // Numbers larger than 256 bits are not accepted.
   135  func DecodeBig(input string) (*big.Int, error) {
   136  	raw, err := checkNumber(input)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  	if len(raw) > 64 {
   141  		return nil, ErrBig256Range
   142  	}
   143  	words := make([]big.Word, len(raw)/bigWordNibbles+1)
   144  	end := len(raw)
   145  	for i := range words {
   146  		start := end - bigWordNibbles
   147  		if start < 0 {
   148  			start = 0
   149  		}
   150  		for ri := start; ri < end; ri++ {
   151  			nib := decodeNibble(raw[ri])
   152  			if nib == badNibble {
   153  				return nil, ErrSyntax
   154  			}
   155  			words[i] *= 16
   156  			words[i] += big.Word(nib)
   157  		}
   158  		end = start
   159  	}
   160  	dec := new(big.Int).SetBits(words)
   161  	return dec, nil
   162  }
   163  
   164  // MustDecodeBig decodes a hex string with 0x prefix as a quantity.
   165  // It panics for invalid input.
   166  func MustDecodeBig(input string) *big.Int {
   167  	dec, err := DecodeBig(input)
   168  	if err != nil {
   169  		panic(err)
   170  	}
   171  	return dec
   172  }
   173  
   174  // EncodeBig encodes bigint as a hex string with 0x prefix.
   175  // The sign of the integer is ignored.
   176  func EncodeBig(bigint *big.Int) string {
   177  	nbits := bigint.BitLen()
   178  	if nbits == 0 {
   179  		return "0x0"
   180  	}
   181  	return fmt.Sprintf("%#x", bigint)
   182  }
   183  
   184  func has0xPrefix(input string) bool {
   185  	return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
   186  }
   187  
   188  func checkNumber(input string) (raw string, err error) {
   189  	if len(input) == 0 {
   190  		return "", ErrEmptyString
   191  	}
   192  	if !has0xPrefix(input) {
   193  		return "", ErrMissingPrefix
   194  	}
   195  	input = input[2:]
   196  	if len(input) == 0 {
   197  		return "", ErrEmptyNumber
   198  	}
   199  	if len(input) > 1 && input[0] == '0' {
   200  		return "", ErrLeadingZero
   201  	}
   202  	return input, nil
   203  }
   204  
   205  const badNibble = ^uint64(0)
   206  
   207  func decodeNibble(in byte) uint64 {
   208  	switch {
   209  	case in >= '0' && in <= '9':
   210  		return uint64(in - '0')
   211  	case in >= 'A' && in <= 'F':
   212  		return uint64(in - 'A' + 10)
   213  	case in >= 'a' && in <= 'f':
   214  		return uint64(in - 'a' + 10)
   215  	default:
   216  		return badNibble
   217  	}
   218  }
   219  
   220  func mapError(err error) error {
   221  	if err, ok := err.(*strconv.NumError); ok {
   222  		switch err.Err {
   223  		case strconv.ErrRange:
   224  			return ErrUint64Range
   225  		case strconv.ErrSyntax:
   226  			return ErrSyntax
   227  		}
   228  	}
   229  	if _, ok := err.(hex.InvalidByteError); ok {
   230  		return ErrSyntax
   231  	}
   232  	if err == hex.ErrLength {
   233  		return ErrOddLength
   234  	}
   235  	return err
   236  }