Skip to content

Commit

Permalink
feat(SPV-1106): add headers errors
Browse files Browse the repository at this point in the history
  • Loading branch information
dzolt-4chain committed Oct 23, 2024
1 parent 5730152 commit 94b4a4b
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 86 deletions.
38 changes: 32 additions & 6 deletions bhserrors/definitions.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package bhserrors

// ////////////////////////////////// AUTH ERRORS
// ////////////////////////////////// GENERIC ERRORS

// ErrGeneric is a generic error that something went wrong
var ErrGeneric = BHSError{Message: "Something went wrong. Internal server error", StatusCode: 500, Code: "ErrGeneric"}
var ErrGeneric = BHSError{Message: "Internal server error", StatusCode: 500, Code: "ErrGeneric"}

// ErrBindBody is an error when it fails to bind JSON body
var ErrBindBody = BHSError{Message: "Error during bind JSON body", StatusCode: 400, Code: "ErrBindBody"}

// ////////////////////////////////// AUTH ERRORS

Expand All @@ -19,6 +22,9 @@ var ErrInvalidAccessToken = BHSError{Message: "Invalid access token", StatusCode
// ErrUnauthorized is a generic error when user is unauthorized to make a request
var ErrUnauthorized = BHSError{Message: "Not authorized", StatusCode: 401, Code: "ErrUnauthorized"}

// ErrAdminTokenNotFound is when admin token was not found in Block Header Service
var ErrAdminTokenNotFound = BHSError{Message: "Admin token not found", StatusCode: 401, Code: "ErrAdminTokenNotFound"}

// ////////////////////////////////// MERKLE ROOTS ERRORS

// ErrMerklerootNotFound is when provided merkleroot from user was not found in Block Header Service's database
Expand All @@ -30,10 +36,7 @@ var ErrMerklerootNotInLongestChain = BHSError{Message: "Provided merkleroot is n
// ErrInvalidBatchSize is when user provided incorrect batchSize
var ErrInvalidBatchSize = BHSError{Message: "batchSize must be 0 or a positive integer", Code: "ErrInvalidBatchSize", StatusCode: 400}

// ////////////////////////////////// TOKEN ERRORS

// ErrAdminTokenNotFound is when admin token was not found in Block Header Service
var ErrAdminTokenNotFound = BHSError{Message: "Admin token not found", StatusCode: 401, Code: "ErrAdminTokenNotFound"}
// ////////////////////////////////// ACCESS ERRORS

// ErrTokenNotFound is when token was not found in Block Header Service
var ErrTokenNotFound = BHSError{Message: "Token not found", StatusCode: 404, Code: "ErrTokenNotFound"}
Expand All @@ -43,3 +46,26 @@ var ErrCreateToken = BHSError{Message: "Failed to create new token", StatusCode:

// ErrDeleteToken is when delete token fails
var ErrDeleteToken = BHSError{Message: "Failed to delete token", StatusCode: 400, Code: "ErrDeleteToken"}

// ////////////////////////////////// HEADERS ERRORS

// ErrAncestorHashHigher is when ancestor hash height is heigher than requested header
var ErrAncestorHashHigher = BHSError{Message: "Ancestor header height can not be higher than requested header height", StatusCode: 400, Code: "ErrAncestorHashHigher"}

// ErrAncestorNotFound is when ancestor for a given hash was not found
var ErrAncestorNotFound = BHSError{Message: "Failed to get ancestor with given hash ", StatusCode: 400, Code: "ErrAncestorNotFound"}

// ErrHeadersNotPartOfTheSameChain is when provided headers are not part of the same chain
var ErrHeadersNotPartOfTheSameChain = BHSError{Message: "the headers provided are not part of the same chain", StatusCode: 400, Code: "ErrHeadersNotPartOfTheSameChain"}

// ErrHeaderWithGivenHashes is when getting header with given hashes fails
var ErrHeaderWithGivenHashes = BHSError{Message: "Error during getting headers with given hashes", StatusCode: 400, Code: "ErrHeaderWithGivenHashes"}

// ErrHeaderNotFound is when hash could not be found
var ErrHeaderNotFound = BHSError{Message: "Header not found", StatusCode: 404, Code: "ErrHeaderNotFound"}

// ErrHeaderNotFound is when hash could not be found for given range
var ErrHeadersForGivenRangeNotFound = BHSError{Message: "Could not find headers in given range", StatusCode: 404, Code: "ErrHeadersForGivenRangeNotFound"}

// ErrHeaderStopHeightNotFound is when stop height for given heade was not found
var ErrHeaderStopHeightNotFound = BHSError{Message: "Could not find stop height for given header", StatusCode: 404, Code: "ErrHeaderStopHeightNotFound"}
4 changes: 2 additions & 2 deletions bhserrors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ type BHSError struct {
cause error
}

// responseError is an error which will be returned in HTTP response
type responseError struct {
// ResponseError is an error which will be returned in HTTP response
type ResponseError struct {
Code string `json:"code"`
Message string `json:"message"`
}
Expand Down
2 changes: 1 addition & 1 deletion bhserrors/http_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func AbortWithErrorResponse(c *gin.Context, err error, log *zerolog.Logger) {
c.AbortWithStatusJSON(statusCode, response)
}

func mapAndLog(err error, log *zerolog.Logger) (model responseError, statusCode int) {
func mapAndLog(err error, log *zerolog.Logger) (model ResponseError, statusCode int) {
model.Code = UnknownErrorCode
model.Message = "Internal server error"
statusCode = 500
Expand Down
23 changes: 7 additions & 16 deletions database/sql/headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,7 @@ func (h *HeadersDb) Count(ctx context.Context) (int, error) {
func (h *HeadersDb) GetHeaderByHash(ctx context.Context, hash string) (*dto.DbBlockHeader, error) {
var bh dto.DbBlockHeader
if err := h.db.GetContext(ctx, &bh, h.db.Rebind(sqlHeader), hash); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, errors.New("could not find hash")
}
return nil, errors.Wrapf(err, "failed to get blockhash using hash %s", hash)
return nil, bhserrors.ErrHeaderNotFound.Wrap(err)
}
return &bh, nil
}
Expand All @@ -303,10 +300,7 @@ func (h *HeadersDb) GetHeaderByHeight(ctx context.Context, height int32, state s
func (h *HeadersDb) GetHeaderByHeightRange(from int, to int) ([]*dto.DbBlockHeader, error) {
var bh []*dto.DbBlockHeader
if err := h.db.Select(&bh, h.db.Rebind(sqlHeaderByHeightRange), from, to); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, errors.New("could not find headers in given range")
}
return nil, errors.Wrapf(err, "failed to get headers using given range from: %d to: %d", from, to)
return nil, bhserrors.ErrHeadersForGivenRangeNotFound.Wrap(err)
}
return bh, nil
}
Expand Down Expand Up @@ -345,10 +339,7 @@ func (h *HeadersDb) GenesisExists(_ context.Context) bool {
func (h *HeadersDb) GetPreviousHeader(ctx context.Context, hash string) (*dto.DbBlockHeader, error) {
var bh dto.DbBlockHeader
if err := h.db.GetContext(ctx, &bh, h.db.Rebind(sqlSelectPreviousBlock), hash); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, errors.New("could not find header")
}
return nil, errors.Wrapf(err, "failed to get prev header using hash %s", hash)
return nil, bhserrors.ErrHeaderNotFound.Wrap(err)
}
return &bh, nil
}
Expand All @@ -371,10 +362,10 @@ func (h *HeadersDb) GetTip(_ context.Context) (*dto.DbBlockHeader, error) {
func (h *HeadersDb) GetAncestorOnHeight(hash string, height int32) (*dto.DbBlockHeader, error) {
var bh []*dto.DbBlockHeader
if err := h.db.Select(&bh, h.db.Rebind(sqlSelectAncestorOnHeight), hash, int(height), int(height)); err != nil {
return nil, errors.Wrapf(err, "failed to get ancestors using given hash: %s ", hash)
return nil, bhserrors.ErrAncestorNotFound.Wrap(err)
}
if len(bh) == 0 {
return nil, errors.New("could not find ancestors for a providen hash")
return nil, bhserrors.ErrAncestorNotFound
}
return bh[0], nil
}
Expand All @@ -392,10 +383,10 @@ func (h *HeadersDb) GetAllTips() ([]*dto.DbBlockHeader, error) {
func (h *HeadersDb) GetChainBetweenTwoHashes(low string, high string) ([]*dto.DbBlockHeader, error) {
var bh []*dto.DbBlockHeader
if err := h.db.Select(&bh, h.db.Rebind(sqlChainBetweenTwoHashes), high, low, low); err != nil {
return nil, errors.Wrapf(err, "failed to get headers using given range from: %s to: %s", low, high)
return nil, bhserrors.ErrHeadersForGivenRangeNotFound.Wrap(err)
}
if len(bh) == 0 {
return nil, errors.New("could not find headers in given range")
return nil, bhserrors.ErrHeadersForGivenRangeNotFound
}
return bh, nil
}
Expand Down
6 changes: 3 additions & 3 deletions internal/tests/testrepository/header_testrepository.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (r *HeaderTestRepository) GetHeaderByHeightRange(from int, to int) ([]*doma
return filteredHeaders, nil
}

return nil, errors.New("could not find headers in given range")
return nil, bhserrors.ErrHeadersForGivenRangeNotFound
}

// GetLongestChainHeadersFromHeight returns from db the headers from "longest chain" starting from given height.
Expand Down Expand Up @@ -133,7 +133,7 @@ func (r *HeaderTestRepository) GetHeaderByHash(hash string) (*domains.BlockHeade
if header != nil {
return header, nil
}
return nil, errors.New("could not find hash")
return nil, bhserrors.ErrHeaderNotFound
}

// GenesisExists check if genesis header is in db.
Expand Down Expand Up @@ -363,7 +363,7 @@ func (r *HeaderTestRepository) GetHeadersStopHeight(hashStop string) (int, error
return int(header.Height), nil
}
}
return 0, errors.New("could not find stop height")
return 0, bhserrors.ErrHeaderStopHeightNotFound
}

// FillWithLongestChain fills the test header repository
Expand Down
2 changes: 1 addition & 1 deletion service/chain_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func (cs *chainService) createHeader(hash *domains.BlockHash, bs *domains.BlockH

func (cs *chainService) previousHeader(bs *domains.BlockHeaderSource) (*domains.BlockHeader, error) {
h, err := cs.Repositories.Headers.GetHeaderByHash(bs.PrevBlock.String())
if h == nil && err != nil && err.Error() == "could not find hash" {
if h == nil && err != nil && err.Error() == "Header not found" {
return domains.NewOrphanPreviousBlockHeader(), nil
}
return h, err
Expand Down
9 changes: 5 additions & 4 deletions service/header_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"math"
"time"

"github.com/bitcoin-sv/block-headers-service/bhserrors"
"github.com/bitcoin-sv/block-headers-service/config"
"github.com/bitcoin-sv/block-headers-service/domains"
"github.com/bitcoin-sv/block-headers-service/internal/chaincfg"
Expand Down Expand Up @@ -128,20 +129,20 @@ func (hs *HeaderService) GetHeaderAncestorsByHash(hash string, ancestorHash stri

// Check possible errors
if err != nil || err2 != nil {
return nil, errors.New("error during getting headers with given hashes")
return nil, bhserrors.ErrHeaderWithGivenHashes
} else if ancestorHeader.Height > reqHeader.Height {
return nil, errors.New("ancestor header height can not be higher than requested header heght")
return nil, bhserrors.ErrAncestorHashHigher
} else if ancestorHeader.Height == reqHeader.Height {
return make([]*domains.BlockHeader, 0), nil
}

a, err := hs.repo.Headers.GetAncestorOnHeight(reqHeader.Hash.String(), ancestorHeader.Height)
if err != nil {
return nil, errors.New("the headers provided are not part of the same chain")
return nil, bhserrors.ErrHeadersNotPartOfTheSameChain.Wrap(err)
}

if a.Hash != ancestorHeader.Hash {
return nil, errors.New("the headers provided are not part of the same chain")
return nil, bhserrors.ErrHeadersNotPartOfTheSameChain
}

// Get headers from db
Expand Down
19 changes: 11 additions & 8 deletions transports/http/endpoints/api/headers/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@ import (
"net/http"
"strconv"

"github.com/bitcoin-sv/block-headers-service/bhserrors"
"github.com/bitcoin-sv/block-headers-service/config"
"github.com/bitcoin-sv/block-headers-service/service"
router "github.com/bitcoin-sv/block-headers-service/transports/http/endpoints/routes"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog"
)

type handler struct {
service service.Headers
log *zerolog.Logger
}

// NewHandler creates new endpoint handler.
func NewHandler(s *service.Services) router.APIEndpoints {
return &handler{service: s.Headers}
return &handler{service: s.Headers, log: s.Logger}
}

// RegisterAPIEndpoints registers routes that are part of service API.
Expand Down Expand Up @@ -48,7 +51,7 @@ func (h *handler) getHeaderByHash(c *gin.Context) {
if err == nil {
c.JSON(http.StatusOK, newBlockHeaderResponse(bh))
} else {
c.JSON(http.StatusBadRequest, err.Error())
bhserrors.ErrorResponse(c, err, h.log)
}
}

Expand Down Expand Up @@ -77,10 +80,10 @@ func (h *handler) getHeaderByHeight(c *gin.Context) {
if err == nil {
c.JSON(http.StatusOK, mapToBlockHeadersResponses(bh))
} else {
c.JSON(http.StatusBadRequest, err.Error())
bhserrors.ErrorResponse(c, err, h.log)
}
} else {
c.JSON(http.StatusBadRequest, err.Error())
bhserrors.ErrorResponse(c, err, h.log)
}
}

Expand All @@ -103,7 +106,7 @@ func (h *handler) getHeaderAncestorsByHash(c *gin.Context) {
if err == nil {
c.JSON(http.StatusOK, mapToBlockHeadersResponses(ancestors))
} else {
c.JSON(http.StatusBadRequest, err.Error())
bhserrors.ErrorResponse(c, err, h.log)
}
}

Expand All @@ -120,14 +123,14 @@ func (h *handler) getHeaderAncestorsByHash(c *gin.Context) {
func (h *handler) getCommonAncestor(c *gin.Context) {
var body []string
if err := c.BindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, err.Error())
bhserrors.ErrorResponse(c, bhserrors.ErrBindBody.Wrap(err), h.log)
} else {
ancestor, err := h.service.GetCommonAncestor(body)

if err == nil {
c.JSON(http.StatusOK, newBlockHeaderResponse(ancestor))
} else {
c.JSON(http.StatusBadRequest, err.Error())
bhserrors.ErrorResponse(c, err, h.log)
}
}
}
Expand All @@ -150,6 +153,6 @@ func (h *handler) getHeadersState(c *gin.Context) {
headerStateResponse := newBlockHeaderStateResponse(bh)
c.JSON(http.StatusOK, headerStateResponse)
} else {
c.JSON(http.StatusBadRequest, err.Error())
bhserrors.ErrorResponse(c, err, h.log)
}
}
Loading

0 comments on commit 94b4a4b

Please sign in to comment.