Skip to content

Commit

Permalink
chore(SPV-846): move error structures into go-paymail
Browse files Browse the repository at this point in the history
  • Loading branch information
pawellewandowski98 committed Jul 3, 2024
1 parent e745b1a commit d809aa4
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 55 deletions.
74 changes: 35 additions & 39 deletions errors/definitions.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package errors

import (
"github.com/bitcoin-sv/spv-wallet/models"
)

// How the Codes are generated?
// 1. "error" - like mandatory prefix for all error codes
// 2. (optional) {error group} - e.g. "configuration", "capabilities", "spv"
Expand All @@ -13,129 +9,129 @@ import (
// CONFIG ERRORS
var (
// ErrDomainMissing is the error for missing domain
ErrDomainMissing = models.SPVError{Message: "domain is missing", StatusCode: 500, Code: "error-configuration-domain-missing"}
ErrDomainMissing = SPVError{Message: "domain is missing", StatusCode: 500, Code: "error-configuration-domain-missing"}

// ErrPortMissing is when the port is not found
ErrPortMissing = models.SPVError{Message: "missing a port", StatusCode: 500, Code: "error-configuration-port-missing"}
ErrPortMissing = SPVError{Message: "missing a port", StatusCode: 500, Code: "error-configuration-port-missing"}

// ErrServiceNameMissing is when the service name is not found
ErrServiceNameMissing = models.SPVError{Message: "missing service name", StatusCode: 500, Code: "error-configuration-service-name-missing"}
ErrServiceNameMissing = SPVError{Message: "missing service name", StatusCode: 500, Code: "error-configuration-service-name-missing"}

// ErrCapabilitiesMissing is when the capabilities struct is nil or not set
ErrCapabilitiesMissing = models.SPVError{Message: "missing capabilities struct", StatusCode: 500, Code: "error-configuration-capabilities-missing"}
ErrCapabilitiesMissing = SPVError{Message: "missing capabilities struct", StatusCode: 500, Code: "error-configuration-capabilities-missing"}

// ErrBsvAliasMissing is when the bsv alias version is missing
ErrBsvAliasMissing = models.SPVError{Message: "missing bsv alias version", StatusCode: 500, Code: "error-configuration-bsv-alias-missing"}
ErrBsvAliasMissing = SPVError{Message: "missing bsv alias version", StatusCode: 500, Code: "error-configuration-bsv-alias-missing"}

// ErrServiceProviderNil is the error for having a nil service provider
ErrServiceProviderNil = models.SPVError{Message: "service provider is nil", StatusCode: 500, Code: "error-configuration-service-provider-nil"}
ErrServiceProviderNil = SPVError{Message: "service provider is nil", StatusCode: 500, Code: "error-configuration-service-provider-nil"}
)

// CAPABILITY ERRORS
var (
//ErrPrefixOrDomainMissing is when the prefix or domain is missing
ErrPrefixOrDomainMissing = models.SPVError{Message: "prefix or domain is missing", StatusCode: 400, Code: "error-capabilities-prefix-or-domain-missing"}
ErrPrefixOrDomainMissing = SPVError{Message: "prefix or domain is missing", StatusCode: 400, Code: "error-capabilities-prefix-or-domain-missing"}

//ErrDomainUnknown is when the domain is not in the list of allowed domains
ErrDomainUnknown = models.SPVError{Message: "paymail domain is unknown", StatusCode: 400, Code: "error-capabilities-domain-unknown"}
ErrDomainUnknown = SPVError{Message: "paymail domain is unknown", StatusCode: 400, Code: "error-capabilities-domain-unknown"}

//ErrCastingNestedCapabilities is when the nested capabilities cannot be cast
ErrCastingNestedCapabilities = models.SPVError{Message: "failed to cast nested capabilities", StatusCode: 500, Code: "error-capabilities-nested-capabilities-failed-to-cast"}
ErrCastingNestedCapabilities = SPVError{Message: "failed to cast nested capabilities", StatusCode: 500, Code: "error-capabilities-nested-capabilities-failed-to-cast"}
)

// PARSING ERRORS
var (
// ErrCannotBindRequest is when request body cannot be bind into struct
ErrCannotBindRequest = models.SPVError{Message: "cannot bind request body", StatusCode: 400, Code: "error-bind-body-invalid"}
ErrCannotBindRequest = SPVError{Message: "cannot bind request body", StatusCode: 400, Code: "error-bind-body-invalid"}

// ErrProcessingHex is when error occurred during processing hex
ErrProcessingHex = models.SPVError{Message: "cannot process hex", StatusCode: 400, Code: "error-processing-hex"}
ErrProcessingHex = SPVError{Message: "cannot process hex", StatusCode: 400, Code: "error-processing-hex"}

// ErrProcessingBEEF is when error occurred during processing beef
ErrProcessingBEEF = models.SPVError{Message: "cannot process beef", StatusCode: 400, Code: "error-processing-beef"}
ErrProcessingBEEF = SPVError{Message: "cannot process beef", StatusCode: 400, Code: "error-processing-beef"}
)

// PAYMAIL ERRORS
var (
// ErrCouldNotFindPaymail is when could not find paymail
ErrCouldNotFindPaymail = models.SPVError{Message: "invalid paymail", StatusCode: 400, Code: "error-paymail-not-found"}
ErrCouldNotFindPaymail = SPVError{Message: "invalid paymail", StatusCode: 400, Code: "error-paymail-not-found"}
)

// INVALID FIELD ERRORS
var (
// ErrInvalidPaymail is when the paymail is invalid
ErrInvalidPaymail = models.SPVError{Message: "invalid paymail", StatusCode: 400, Code: "error-paymail-invalid"}
ErrInvalidPaymail = SPVError{Message: "invalid paymail", StatusCode: 400, Code: "error-paymail-invalid"}

// ErrInvalidPubKey is when the pubkey is invalid
ErrInvalidPubKey = models.SPVError{Message: "invalid pubkey", StatusCode: 400, Code: "error-pubkey-invalid"}
ErrInvalidPubKey = SPVError{Message: "invalid pubkey", StatusCode: 400, Code: "error-pubkey-invalid"}

// ErrInvalidSignature is when the signature is invalid
ErrInvalidSignature = models.SPVError{Message: "invalid signature", StatusCode: 400, Code: "error-signature-invalid"}
ErrInvalidSignature = SPVError{Message: "invalid signature", StatusCode: 400, Code: "error-signature-invalid"}

// ErrInvalidScript is when the script is invalid
ErrInvalidScript = models.SPVError{Message: "invalid script", StatusCode: 400, Code: "error-script-invalid"}
ErrInvalidScript = SPVError{Message: "invalid script", StatusCode: 400, Code: "error-script-invalid"}

// ErrInvalidTimestamp is when the timestamp is invalid
ErrInvalidTimestamp = models.SPVError{Message: "invalid timestamp", StatusCode: 400, Code: "error-timestamp-invalid"}
ErrInvalidTimestamp = SPVError{Message: "invalid timestamp", StatusCode: 400, Code: "error-timestamp-invalid"}

// ErrInvalidSenderHandle is when the sender handle is invalid
ErrInvalidSenderHandle = models.SPVError{Message: "invalid sender handle", StatusCode: 400, Code: "error-sender-handle-invalid"}
ErrInvalidSenderHandle = SPVError{Message: "invalid sender handle", StatusCode: 400, Code: "error-sender-handle-invalid"}
)

// MISSING FIELD ERRORS

var (
// ErrMissingFieldReference is when the reference field is required but missing
ErrMissingFieldReference = models.SPVError{Message: "missing required field: reference", StatusCode: 400, Code: "error-missing-field-reference"}
ErrMissingFieldReference = SPVError{Message: "missing required field: reference", StatusCode: 400, Code: "error-missing-field-reference"}

// ErrMissingFieldHex is when the hex field is required but missing
ErrMissingFieldHex = models.SPVError{Message: "missing required field: hex", StatusCode: 400, Code: "error-missing-field-hex"}
ErrMissingFieldHex = SPVError{Message: "missing required field: hex", StatusCode: 400, Code: "error-missing-field-hex"}

// ErrMissingFieldBEEF is when the beef field is required but missing
ErrMissingFieldBEEF = models.SPVError{Message: "missing required field: beef", StatusCode: 400, Code: "error-missing-field-beef"}
ErrMissingFieldBEEF = SPVError{Message: "missing required field: beef", StatusCode: 400, Code: "error-missing-field-beef"}

// ErrMissingFieldSignature is when the signature field is required but missing
ErrMissingFieldSignature = models.SPVError{Message: "missing required field: signature", StatusCode: 400, Code: "error-missing-field-signature"}
ErrMissingFieldSignature = SPVError{Message: "missing required field: signature", StatusCode: 400, Code: "error-missing-field-signature"}

// ErrMissingFieldPubKey is when the pubkey field is required but missing
ErrMissingFieldPubKey = models.SPVError{Message: "missing required field: pubkey", StatusCode: 400, Code: "error-missing-field-pubkey"}
ErrMissingFieldPubKey = SPVError{Message: "missing required field: pubkey", StatusCode: 400, Code: "error-missing-field-pubkey"}

// ErrMissingFieldSatoshis is when the satoshis field is required but missing
ErrMissingFieldSatoshis = models.SPVError{Message: "missing required field: satoshis", StatusCode: 400, Code: "error-missing-field-satoshis"}
ErrMissingFieldSatoshis = SPVError{Message: "missing required field: satoshis", StatusCode: 400, Code: "error-missing-field-satoshis"}
)

// EMPTY FIELDS ERRORS
var (
// ErrSenderHandleEmpty is when the server handle is empty
ErrSenderHandleEmpty = models.SPVError{Message: "empty sender handle", StatusCode: 400, Code: "error-sender-handle-empty"}
ErrSenderHandleEmpty = SPVError{Message: "empty sender handle", StatusCode: 400, Code: "error-sender-handle-empty"}

// ErrDtEmpty is when the dt field is empty
ErrDtEmpty = models.SPVError{Message: "empty dt", StatusCode: 400, Code: "error-dt-empty"}
ErrDtEmpty = SPVError{Message: "empty dt", StatusCode: 400, Code: "error-dt-empty"}
)

// SPV ERRORS
var (
// ErrNoOutputs is when there are no outputs
ErrNoOutputs = models.SPVError{Message: "invalid output, no outputs", StatusCode: 417, Code: "error-spv-no-outputs"}
ErrNoOutputs = SPVError{Message: "invalid output, no outputs", StatusCode: 417, Code: "error-spv-no-outputs"}

// ErrNoInputs is when there are no inputs
ErrNoInputs = models.SPVError{Message: "invalid input, no inputs", StatusCode: 417, Code: "error-spv-no-inputs"}
ErrNoInputs = SPVError{Message: "invalid input, no inputs", StatusCode: 417, Code: "error-spv-no-inputs"}

// ErrInvalidParentTransactions is when the parent transactions are invalid
ErrInvalidParentTransactions = models.SPVError{Message: "invalid parent transactions, no matching transactions for input", StatusCode: 417, Code: "error-spv-parent-tx-invalid"}
ErrInvalidParentTransactions = SPVError{Message: "invalid parent transactions, no matching transactions for input", StatusCode: 417, Code: "error-spv-parent-tx-invalid"}

// ErrLockTimeAndSequence is when the locktime and sequence are invalid
ErrLockTimeAndSequence = models.SPVError{Message: "nLocktime is set and nSequence is not max, therefore this could be a non-final tx which is not currently supported", StatusCode: 417, Code: "error-spv-locktime-sequence-invalid"}
ErrLockTimeAndSequence = SPVError{Message: "nLocktime is set and nSequence is not max, therefore this could be a non-final tx which is not currently supported", StatusCode: 417, Code: "error-spv-locktime-sequence-invalid"}

// ErrOutputValueTooHigh is when the satoshis output is too high on a transaction
ErrOutputValueTooHigh = models.SPVError{Message: "invalid input and output sum, outputs can not be larger than inputs", StatusCode: 417, Code: "error-spv-output-value-too-high"}
ErrOutputValueTooHigh = SPVError{Message: "invalid input and output sum, outputs can not be larger than inputs", StatusCode: 417, Code: "error-spv-output-value-too-high"}

// ErrBUMPAncestorNotPresent is when the input mined ancestor is not present in BUMPs
ErrBUMPAncestorNotPresent = models.SPVError{Message: "invalid BUMP - input mined ancestor is not present in BUMPs", StatusCode: 417, Code: "error-spv-bump-ancestor-not-present"}
ErrBUMPAncestorNotPresent = SPVError{Message: "invalid BUMP - input mined ancestor is not present in BUMPs", StatusCode: 417, Code: "error-spv-bump-ancestor-not-present"}

// ErrBUMPCouldNotFindMinedParent is when the mined parent for input could not be found
ErrBUMPCouldNotFindMinedParent = models.SPVError{Message: "invalid BUMP - cannot find mined parent for input", StatusCode: 417, Code: "error-spv-bump-mined-parent-not-found"}
ErrBUMPCouldNotFindMinedParent = SPVError{Message: "invalid BUMP - cannot find mined parent for input", StatusCode: 417, Code: "error-spv-bump-mined-parent-not-found"}

// ErrNoMatchingTransactionsForInput is when no matching transaction for input can be found
ErrNoMatchingTransactionsForInput = models.SPVError{Message: "invalid parent transactions, no matching transactions for input", StatusCode: 417, Code: "error-spv-bump-ancestor-not-present"}
ErrNoMatchingTransactionsForInput = SPVError{Message: "invalid parent transactions, no matching transactions for input", StatusCode: 417, Code: "error-spv-bump-ancestor-not-present"}
)
21 changes: 21 additions & 0 deletions errors/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package errors

// SPVError is extended error which holds information about http status and code that should be returned
type SPVError struct {
Code string
Message string
StatusCode int
}

// ResponseError is an error which will be returned in HTTP response
type ResponseError struct {
Code string `json:"code"`
Message string `json:"message"`
}

const UnknownErrorCode = "error-unknown"

// Error returns the error message string for SPVError, satisfying the error interface
func (e SPVError) Error() string {
return e.Message
}
11 changes: 5 additions & 6 deletions errors/http_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package errors

import (
"errors"
"github.com/bitcoin-sv/spv-wallet/models"
"github.com/gin-gonic/gin"
)

Expand All @@ -12,16 +11,16 @@ func ErrorResponse(c *gin.Context, err error) {
c.JSON(statusCode, response)
}

func getError(err error) (models.ResponseError, int) {
func getError(err error) (ResponseError, int) {
if err == nil {
return models.ResponseError{Code: models.UnknownErrorCode, Message: "No error information available"}, 500
return ResponseError{Code: UnknownErrorCode, Message: "No error information available"}, 500
}

var errDetails models.SPVError
var errDetails SPVError
ok := errors.As(err, &errDetails)
if !ok {
return models.ResponseError{Code: models.UnknownErrorCode, Message: "Unable to get information about error"}, 500
return ResponseError{Code: UnknownErrorCode, Message: "Unable to get information about error"}, 500
}

return models.ResponseError{Code: errDetails.Code, Message: errDetails.Message}, errDetails.StatusCode
return ResponseError{Code: errDetails.Code, Message: errDetails.Message}, errDetails.StatusCode
}
6 changes: 1 addition & 5 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
module github.com/bitcoin-sv/go-paymail

go 1.22.4
go 1.21.5

require (
github.com/bitcoin-sv/spv-wallet/models v1.0.0-beta.14
github.com/bitcoinschema/go-bitcoin/v2 v2.0.5
github.com/gin-gonic/gin v1.10.0
github.com/go-resty/resty/v2 v2.13.1
Expand Down Expand Up @@ -54,6 +53,3 @@ require (
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

// TODO: remove this
replace github.com/bitcoin-sv/spv-wallet/models => ./../spv-wallet/models
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
github.com/bitcoin-sv/spv-wallet/models v1.0.0-beta.14 h1:R3okOqBHBOSDL5rZf4/REmZIEnKeAugqMNYOb2l6aXI=
github.com/bitcoin-sv/spv-wallet/models v1.0.0-beta.14/go.mod h1:VsUb0ZRA6Emr8+VDEq5SbOyzwvfKb+32Lkb9dM+n20o=
github.com/bitcoin-sv/spv-wallet/models v1.0.0-beta.14.0.20240626082725-2c073c5330a6 h1:ZTEHuSNbXszs+5TKN0uiW6DY7JdWIM5m6NQpBJZyre4=
github.com/bitcoin-sv/spv-wallet/models v1.0.0-beta.14.0.20240626082725-2c073c5330a6/go.mod h1:u3gnRDS3uHWZNM2qbYATTpN+mAphyozCJrYIKGwBX7k=
github.com/bitcoinschema/go-bitcoin/v2 v2.0.5 h1:Sgh5Eb746Zck/46rFDrZZEXZWyO53fMuWYhNoZa1tck=
github.com/bitcoinschema/go-bitcoin/v2 v2.0.5/go.mod h1:JjO1ivfZv6vhK0uAXzyH08AAHlzNMAfnyK1Fiv9r4ZA=
github.com/bitcoinsv/bsvd v0.0.0-20190609155523-4c29707f7173 h1:2yTIV9u7H0BhRDGXH5xrAwAz7XibWJtX2dNezMeNsUo=
Expand Down
2 changes: 1 addition & 1 deletion spv/bump_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func findMinedAncestors(tx *bt.Tx, ancestors []*beef.TxData) (map[string]*beef.T
func findMinedAncestorsForInput(input *bt.Input, ancestors []*beef.TxData, ma map[string]*beef.TxData) error {
parent := findParentForInput(input, ancestors)
if parent == nil {
return errors.ErrBUMPCouldNotFindMindParent
return errors.ErrBUMPCouldNotFindMinedParent
}

if !parent.Unmined() {
Expand Down

0 comments on commit d809aa4

Please sign in to comment.