github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/common/hexutil/hexutil.go (about)

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