github.com/amazechain/amc@v0.1.3/modules/rpc/jsonrpc/util.go (about)

     1  // Copyright 2022 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package jsonrpc
    18  
    19  import (
    20  	"encoding/hex"
    21  	"fmt"
    22  	"github.com/amazechain/amc/common/types"
    23  	"strconv"
    24  )
    25  
    26  const uintBits = 32 << (uint64(^uint(0)) >> 63)
    27  
    28  var (
    29  	ErrEmptyString   = &decError{"empty hex string"}
    30  	ErrSyntax        = &decError{"invalid hex string"}
    31  	ErrMissingPrefix = &decError{"hex string without 0x prefix"}
    32  	ErrOddLength     = &decError{"hex string of odd length"}
    33  	ErrEmptyNumber   = &decError{"hex string \"0x\""}
    34  	ErrLeadingZero   = &decError{"hex number with leading zero digits"}
    35  	ErrUint64Range   = &decError{"hex number > 64 bits"}
    36  	ErrUintRange     = &decError{fmt.Sprintf("hex number > %d bits", uintBits)}
    37  	ErrBig256Range   = &decError{"hex number > 256 bits"}
    38  )
    39  
    40  const badNibble = ^uint64(0)
    41  
    42  type decError struct{ msg string }
    43  
    44  func (err decError) Error() string { return err.msg }
    45  
    46  func DecodeUint64(input string) (uint64, error) {
    47  	raw, err := checkNumber(input)
    48  	if err != nil {
    49  		return 0, err
    50  	}
    51  	dec, err := strconv.ParseUint(raw, 16, 64)
    52  	if err != nil {
    53  		err = mapError(err)
    54  	}
    55  	return dec, err
    56  }
    57  
    58  func mapError(err error) error {
    59  	if err, ok := err.(*strconv.NumError); ok {
    60  		switch err.Err {
    61  		case strconv.ErrRange:
    62  			return ErrUint64Range
    63  		case strconv.ErrSyntax:
    64  			return ErrSyntax
    65  		}
    66  	}
    67  	if _, ok := err.(hex.InvalidByteError); ok {
    68  		return ErrSyntax
    69  	}
    70  	if err == hex.ErrLength {
    71  		return ErrOddLength
    72  	}
    73  	return err
    74  }
    75  
    76  func has0xPrefix(input string) bool {
    77  	return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
    78  }
    79  
    80  func checkNumber(input string) (raw string, err error) {
    81  	if len(input) == 0 {
    82  		return "", ErrEmptyString
    83  	}
    84  	if !has0xPrefix(input) {
    85  		return "", ErrMissingPrefix
    86  	}
    87  	input = input[2:]
    88  	if len(input) == 0 {
    89  		return "", ErrEmptyNumber
    90  	}
    91  	if len(input) > 1 && input[0] == '0' {
    92  		return "", ErrLeadingZero
    93  	}
    94  	return input, nil
    95  }
    96  
    97  func bytesHave0xPrefix(input []byte) bool {
    98  	return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
    99  }
   100  
   101  func checkText(input []byte, wantPrefix bool) ([]byte, error) {
   102  	if len(input) == 0 {
   103  		return nil, nil // empty strings are allowed
   104  	}
   105  	if bytesHave0xPrefix(input) {
   106  		input = input[2:]
   107  	} else if wantPrefix {
   108  		return nil, ErrMissingPrefix
   109  	}
   110  	if len(input)%2 != 0 {
   111  		return nil, ErrOddLength
   112  	}
   113  	return input, nil
   114  }
   115  
   116  func UnmarshalFixedText(typname string, input, out []byte) error {
   117  	raw, err := checkText(input, true)
   118  	if err != nil {
   119  		return err
   120  	}
   121  	if len(raw)/2 != len(out) {
   122  		return fmt.Errorf("hex string has length %d, want %d for %s", len(raw), len(out)*2, typname)
   123  	}
   124  	// Pre-verify syntax before modifying out.
   125  	for _, b := range raw {
   126  		if decodeNibble(b) == badNibble {
   127  			return ErrSyntax
   128  		}
   129  	}
   130  	hex.Decode(out, raw)
   131  	return nil
   132  }
   133  
   134  func decodeNibble(in byte) uint64 {
   135  	switch {
   136  	case in >= '0' && in <= '9':
   137  		return uint64(in - '0')
   138  	case in >= 'A' && in <= 'F':
   139  		return uint64(in - 'A' + 10)
   140  	case in >= 'a' && in <= 'f':
   141  		return uint64(in - 'a' + 10)
   142  	default:
   143  		return badNibble
   144  	}
   145  }
   146  func UnmarshalText(h types.Hash, input []byte) error {
   147  	return UnmarshalFixedText("Hash", input, h[:])
   148  }
   149  
   150  func IsTemporaryError(err error) bool {
   151  	tempErr, ok := err.(interface {
   152  		Temporary() bool
   153  	})
   154  	return ok && tempErr.Temporary() || isPacketTooBig(err)
   155  }