prysm-pulse/beacon-chain/rpc/eth/shared/errors.go
hyunchel cc2b4db582
Add state not found test case (#13034)
* beacon-chain:rpc/eth/shared: prevent mutiple error messages

This commit prevents the error writing function from writing multiple
JSON objects. An error message with more than one JSON object will not
unmarshal into the default error response.

* beacon-chain/rpc/eth/beacon: add a test case for missing state

This commit adds a test on beacon states finality checkpoints endpoint
to cover a case when state is not found.

* beacon-chain/rpc/eth: update error response to meet the spec

This commit updates error message on beacon states finality
checkpoints endpoint to ensure that the response complies to
Ethereum Beacon-API specification.

* beacon-chain/rpc/eth/shared: add build dependency

* beacon-chain/rpc/eth/shared: update test on state not found

---------

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
2023-10-13 17:21:38 +00:00

84 lines
3.0 KiB
Go

package shared
import (
"fmt"
"net/http"
"strings"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
http2 "github.com/prysmaticlabs/prysm/v4/network/http"
)
// DecodeError represents an error resulting from trying to decode an HTTP request.
// It tracks the full field name for which decoding failed.
type DecodeError struct {
path []string
err error
}
// NewDecodeError wraps an error (either the initial decoding error or another DecodeError).
// The current field that failed decoding must be passed in.
func NewDecodeError(err error, field string) *DecodeError {
de, ok := err.(*DecodeError)
if ok {
return &DecodeError{path: append([]string{field}, de.path...), err: de.err}
}
return &DecodeError{path: []string{field}, err: err}
}
// Error returns the formatted error message which contains the full field name and the actual decoding error.
func (e *DecodeError) Error() string {
return fmt.Sprintf("could not decode %s: %s", strings.Join(e.path, "."), e.err.Error())
}
// IndexedVerificationFailureError wraps a collection of verification failures.
type IndexedVerificationFailureError struct {
Message string `json:"message"`
Code int `json:"code"`
Failures []*IndexedVerificationFailure `json:"failures"`
}
func (e *IndexedVerificationFailureError) StatusCode() int {
return e.Code
}
// IndexedVerificationFailure represents an issue when verifying a single indexed object e.g. an item in an array.
type IndexedVerificationFailure struct {
Index int `json:"index"`
Message string `json:"message"`
}
// WriteStateFetchError writes an appropriate error based on the supplied argument.
// The argument error should be a result of fetching state.
func WriteStateFetchError(w http.ResponseWriter, err error) {
if _, ok := err.(*lookup.StateNotFoundError); ok {
http2.HandleError(w, "State not found", http.StatusNotFound)
return
}
if parseErr, ok := err.(*lookup.StateIdParseError); ok {
http2.HandleError(w, "Invalid state ID: "+parseErr.Error(), http.StatusBadRequest)
return
}
http2.HandleError(w, "Could not get state: "+err.Error(), http.StatusInternalServerError)
}
// WriteBlockFetchError writes an appropriate error based on the supplied argument.
// The argument error should be a result of fetching block.
func WriteBlockFetchError(w http.ResponseWriter, blk interfaces.ReadOnlySignedBeaconBlock, err error) bool {
if invalidBlockIdErr, ok := err.(*lookup.BlockIdParseError); ok {
http2.HandleError(w, "Invalid block ID: "+invalidBlockIdErr.Error(), http.StatusBadRequest)
return false
}
if err != nil {
http2.HandleError(w, "Could not get block from block ID: %s"+err.Error(), http.StatusInternalServerError)
return false
}
if err = blocks.BeaconBlockIsNil(blk); err != nil {
http2.HandleError(w, "Could not find requested block: %s"+err.Error(), http.StatusNotFound)
return false
}
return true
}