Skip to content

Commit

Permalink
feat(SPV-846): refactor numeric error codes into strings (#245)
Browse files Browse the repository at this point in the history
Co-authored-by: chris-4chain <[email protected]>
  • Loading branch information
pawellewandowski98 and chris-4chain authored Jul 4, 2024
1 parent 545095a commit 5305b41
Show file tree
Hide file tree
Showing 10 changed files with 236 additions and 129 deletions.
13 changes: 6 additions & 7 deletions authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

"github.com/bitcoin-sv/spv-wallet-go-client/utils"
"github.com/bitcoin-sv/spv-wallet/models"
"github.com/bitcoin-sv/spv-wallet/models/apierrors"
"github.com/bitcoinschema/go-bitcoin/v2"
"github.com/libsv/go-bk/bec"
"github.com/libsv/go-bk/bip32"
Expand All @@ -18,7 +17,7 @@ import (
)

// SetSignature will set the signature on the header for the request
func setSignature(header *http.Header, xPriv *bip32.ExtendedKey, bodyString string) ResponseError {
func setSignature(header *http.Header, xPriv *bip32.ExtendedKey, bodyString string) error {
// Create the signature
authData, err := createSignature(xPriv, bodyString)
if err != nil {
Expand All @@ -28,7 +27,9 @@ func setSignature(header *http.Header, xPriv *bip32.ExtendedKey, bodyString stri
// Set the auth header
header.Set(models.AuthHeader, authData.XPub)

return setSignatureHeaders(header, authData)
setSignatureHeaders(header, authData)

return nil
}

// GetSignedHex will sign all the inputs using the given xPriv key
Expand Down Expand Up @@ -134,7 +135,7 @@ func getUnlockingScript(tx *bt.Tx, inputIndex uint32, privateKey *bec.PrivateKey
func createSignature(xPriv *bip32.ExtendedKey, bodyString string) (payload *models.AuthPayload, err error) {
// No key?
if xPriv == nil {
err = apierrors.ErrMissingXPriv
err = ErrMissingXpriv
return
}

Expand Down Expand Up @@ -199,7 +200,7 @@ func getSigningMessage(xPub string, auth *models.AuthPayload) string {
return fmt.Sprintf("%s%s%s%d", xPub, auth.AuthHash, auth.AuthNonce, auth.AuthTime)
}

func setSignatureHeaders(header *http.Header, authData *models.AuthPayload) ResponseError {
func setSignatureHeaders(header *http.Header, authData *models.AuthPayload) {
// Create the auth header hash
header.Set(models.AuthHeaderHash, authData.AuthHash)

Expand All @@ -211,6 +212,4 @@ func setSignatureHeaders(header *http.Header, authData *models.AuthPayload) Resp

// Set the signature
header.Set(models.AuthSignature, authData.Signature)

return nil
}
63 changes: 24 additions & 39 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,56 @@ package walletclient

import (
"encoding/json"
"errors"
"fmt"
"io"
"github.com/bitcoin-sv/spv-wallet/models"
"net/http"
)

// ErrAdminKey admin key not set
var ErrAdminKey = errors.New("an admin key must be set to be able to create an xpub")
var ErrAdminKey = models.SPVError{Message: "an admin key must be set to be able to create an xpub", StatusCode: 401, Code: "error-unauthorized-admin-key-not-set"}

// ErrNoClientSet is when no client is set
var ErrNoClientSet = errors.New("no transport client set")
// ErrMissingXpriv is when xpriv is missing
var ErrMissingXpriv = models.SPVError{Message: "xpriv missing", StatusCode: 401, Code: "error-unauthorized-xpriv-missing"}

// ResError is a struct which contain information about error
type ResError struct {
StatusCode int
Message string
}

// ResponseError is an interface for error
type ResponseError interface {
Error() string
GetStatusCode() int
}
// ErrCouldNotFindDraftTransaction is when draft transaction is not found
var ErrCouldNotFindDraftTransaction = models.SPVError{Message: "could not find draft transaction", StatusCode: 404, Code: "error-draft-transaction-not-found"}

// WrapError wraps an error into ResponseError
func WrapError(err error) ResponseError {
// WrapError wraps an error into SPVError
func WrapError(err error) error {
if err == nil {
return nil
}

return &ResError{
return &models.SPVError{
StatusCode: http.StatusInternalServerError,
Message: err.Error(),
Code: models.UnknownErrorCode,
}
}

// WrapResponseError wraps a http response into ResponseError
func WrapResponseError(res *http.Response) ResponseError {
// WrapResponseError wraps a http response into SPVError
func WrapResponseError(res *http.Response) error {
if res == nil {
return nil
}

var errorMsg string
var resError *models.ResponseError

err := json.NewDecoder(res.Body).Decode(&errorMsg)
err := json.NewDecoder(res.Body).Decode(&resError)
if err != nil {
// if EOF, then body is empty and we return response status as error message
if !errors.Is(err, io.EOF) {
errorMsg = fmt.Sprintf("spv-wallet error message can't be decoded. Reason: %s", err.Error())
}
errorMsg = res.Status
return WrapError(err)
}

return &ResError{
return &models.SPVError{
StatusCode: res.StatusCode,
Message: errorMsg,
Code: resError.Code,
Message: resError.Message,
}
}

// Error returns the error message
func (e *ResError) Error() string {
return e.Message
}

// GetStatusCode returns the status code of error
func (e *ResError) GetStatusCode() int {
return e.StatusCode
func CreateErrorResponse(code string, message string) error {
return &models.SPVError{
StatusCode: http.StatusInternalServerError,
Code: code,
Message: message,
}
}
4 changes: 2 additions & 2 deletions examples/go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions examples/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions examples/handle_exceptions/handle_exceptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ package main

import (
"context"
"errors"
"fmt"
"os"

walletclient "github.com/bitcoin-sv/spv-wallet-go-client"
"github.com/bitcoin-sv/spv-wallet-go-client/examples"
"github.com/bitcoin-sv/spv-wallet/models"
)

func main() {
Expand All @@ -24,8 +26,12 @@ func main() {

status, err := client.AdminGetStatus(ctx)
if err != nil {
fmt.Println("Response status: ", err.GetStatusCode())
fmt.Println("Content: ", err.Error())
var extendedErr models.ExtendedError
if errors.As(err, &extendedErr) {
fmt.Printf("Extended error: [%d] '%s': %s\n", extendedErr.GetStatusCode(), extendedErr.GetCode(), extendedErr.GetMessage())
} else {
fmt.Println("Error: ", err.Error())
}

os.Exit(1)
}
Expand Down
31 changes: 29 additions & 2 deletions go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 83 additions & 0 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 5305b41

Please sign in to comment.