github.com/Finschia/finschia-sdk@v0.48.1/server/rosetta/lib/errors/errors.go (about)

     1  package errors
     2  
     3  // errors.go contains all the errors returned by the adapter implementation
     4  // plus some extra utilities to parse those errors
     5  
     6  import (
     7  	"fmt"
     8  
     9  	grpccodes "google.golang.org/grpc/codes"
    10  	grpcstatus "google.golang.org/grpc/status"
    11  
    12  	"github.com/coinbase/rosetta-sdk-go/types"
    13  )
    14  
    15  // ListErrors lists all the registered errors
    16  func ListErrors() []*types.Error {
    17  	return registry.list()
    18  }
    19  
    20  // SealAndListErrors seals the registry and lists its errors
    21  func SealAndListErrors() []*types.Error {
    22  	registry.seal()
    23  	return registry.list()
    24  }
    25  
    26  // Error defines an error that can be converted to a Rosetta API error.
    27  type Error struct {
    28  	rosErr *types.Error
    29  }
    30  
    31  func (e *Error) Error() string {
    32  	if e.rosErr == nil {
    33  		return ErrUnknown.Error()
    34  	}
    35  	return fmt.Sprintf("rosetta: (%d) %s", e.rosErr.Code, e.rosErr.Message)
    36  }
    37  
    38  // Is implements errors.Is for *Error, two errors are considered equal
    39  // if their error codes are identical
    40  func (e *Error) Is(err error) bool {
    41  	// assert it can be casted
    42  	rosErr, ok := err.(*Error)
    43  	if rosErr == nil || !ok {
    44  		return false
    45  	}
    46  	// check that both *Error's are correctly initialized to avoid dereference panics
    47  	if rosErr.rosErr == nil || e.rosErr == nil {
    48  		return false
    49  	}
    50  	// messages are equal if their error codes match
    51  	return rosErr.rosErr.Code == e.rosErr.Code
    52  }
    53  
    54  // WrapError wraps the rosetta error with additional context
    55  func WrapError(err *Error, msg string) *Error {
    56  	return &Error{rosErr: &types.Error{
    57  		Code:        err.rosErr.Code,
    58  		Message:     err.rosErr.Message,
    59  		Description: err.rosErr.Description,
    60  		Retriable:   err.rosErr.Retriable,
    61  		Details: map[string]interface{}{
    62  			"info": msg,
    63  		},
    64  	}}
    65  }
    66  
    67  // ToRosetta attempts to converting an error into a rosetta
    68  // error, if the error cannot be converted it will be parsed as unknown
    69  func ToRosetta(err error) *types.Error {
    70  	// if it's null or not known
    71  	rosErr, ok := err.(*Error)
    72  	if rosErr == nil || !ok {
    73  		return ToRosetta(WrapError(ErrUnknown, ErrUnknown.Error()))
    74  	}
    75  	return rosErr.rosErr
    76  }
    77  
    78  // FromGRPCToRosettaError converts a gRPC error to rosetta error
    79  func FromGRPCToRosettaError(err error) *Error {
    80  	status, ok := grpcstatus.FromError(err)
    81  	if !ok {
    82  		return WrapError(ErrUnknown, err.Error())
    83  	}
    84  	switch status.Code() {
    85  	case grpccodes.NotFound:
    86  		return WrapError(ErrNotFound, status.Message())
    87  	case grpccodes.FailedPrecondition:
    88  		return WrapError(ErrBadArgument, status.Message())
    89  	case grpccodes.InvalidArgument:
    90  		return WrapError(ErrBadArgument, status.Message())
    91  	case grpccodes.Internal:
    92  		return WrapError(ErrInternal, status.Message())
    93  	default:
    94  		return WrapError(ErrUnknown, status.Message())
    95  	}
    96  }
    97  
    98  func RegisterError(code int32, message string, retryable bool, description string) *Error {
    99  	e := &Error{rosErr: &types.Error{
   100  		Code:        code,
   101  		Message:     message,
   102  		Description: &description,
   103  		Retriable:   retryable,
   104  		Details:     nil,
   105  	}}
   106  	registry.add(e)
   107  	return e
   108  }
   109  
   110  // Default error list
   111  var (
   112  	// ErrUnknown defines an unknown error, if this is returned it means
   113  	// the library is ignoring an error
   114  	ErrUnknown = RegisterError(0, "unknown", false, "unknown error")
   115  	// ErrOffline is returned when there is an attempt to query an endpoint in offline mode
   116  	ErrOffline = RegisterError(1, "cannot query endpoint in offline mode", false, "returned when querying an online endpoint in offline mode")
   117  	// ErrNetworkNotSupported is returned when there is an attempt to query a network which is not supported
   118  	ErrNetworkNotSupported = RegisterError(2, "network is not supported", false, "returned when querying a non supported network")
   119  	// ErrCodec is returned when there's an error while marshalling or unmarshalling data
   120  	ErrCodec = RegisterError(3, "encode/decode error", true, "returned when there are errors encoding or decoding information to and from the node")
   121  	// ErrInvalidOperation is returned when the operation supplied to rosetta is not a valid one
   122  	ErrInvalidOperation = RegisterError(4, "invalid operation", false, "returned when the operation is not valid")
   123  	// ErrInvalidTransaction is returned when the provided hex bytes of a TX are not valid
   124  	ErrInvalidTransaction = RegisterError(5, "invalid transaction", false, "returned when the transaction is invalid")
   125  	// ErrInvalidAddress is returned when the byte of the address are bad
   126  	ErrInvalidAddress = RegisterError(7, "invalid address", false, "returned when the address is malformed")
   127  	// ErrInvalidPubkey is returned when the public key is invalid
   128  	ErrInvalidPubkey = RegisterError(8, "invalid pubkey", false, "returned when the public key is invalid")
   129  	// ErrInterpreting is returned when there are errors interpreting the data from the node, most likely related to breaking changes, version incompatibilities
   130  	ErrInterpreting = RegisterError(9, "error interpreting data from node", false, "returned when there are issues interpreting requests or response from node")
   131  	ErrInvalidMemo  = RegisterError(11, "invalid memo", false, "returned when the memo is invalid")
   132  	// ErrBadArgument is returned when the request is malformed
   133  	ErrBadArgument = RegisterError(400, "bad argument", false, "request is malformed")
   134  	// ErrNotFound is returned when the required object was not found
   135  	// retry is set to true because something that is not found now
   136  	// might be found later, example: a TX
   137  	ErrNotFound = RegisterError(404, "not found", true, "returned when the node does not find what the client is asking for")
   138  	// ErrInternal is returned when the node is experiencing internal errors
   139  	ErrInternal = RegisterError(500, "internal error", false, "returned when the node experiences internal errors")
   140  	// ErrBadGateway is returned when there are problems interacting with the nodes
   141  	ErrBadGateway = RegisterError(502, "bad gateway", true, "return when the node is unreachable")
   142  	// ErrNotImplemented is returned when a method is not implemented yet
   143  	ErrNotImplemented = RegisterError(14, "not implemented", false, "returned when querying an endpoint which is not implemented")
   144  	// ErrUnsupportedCurve is returned when the curve specified is not supported
   145  	ErrUnsupportedCurve = RegisterError(15, "unsupported curve, expected secp256k1", false, "returned when using an unsupported crypto curve")
   146  )