Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 63 additions & 80 deletions protocol/shannon/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package shannon

import (
"context"
"crypto/x509"
"errors"
"strings"
"crypto/tls"
"net"

pathhttp "github.com/pokt-network/path/network/http"
protocolobservations "github.com/pokt-network/path/observation/protocol"
Expand All @@ -13,80 +15,39 @@ var (
// Unsupported gateway mode
errProtocolContextSetupUnsupportedGatewayMode = errors.New("unsupported gateway mode")

// ** Network errors **
// endpoint configuration error:
// - TLS certificate verification error.
// - DNS error on lookup of endpoint URL.
errRelayEndpointConfig = errors.New("endpoint configuration error")

// endpoint timeout
errRelayEndpointTimeout = errors.New("timeout waiting for endpoint response")
// PATH manually canceled the context for the request.
// E.g. Parallel requests were made and one succeeded so the other was canceled.
errContextCanceled = errors.New("context canceled manually")

// HTTP relay request failed - wraps net/http package errors
errSendHTTPRelay = errors.New("HTTP relay request failed")

// ** Centralized gateway mode errors **

// Centralized gateway mode: Error getting onchain data for app
errProtocolContextSetupCentralizedAppFetchErr = errors.New("error getting onchain data for app owned by the gateway")
// Centralized gateway mode app does not delegate to the gateway.
errProtocolContextSetupCentralizedAppDelegation = errors.New("centralized gateway mode app does not delegate to the gateway")
// Centralized gateway mode: no active sessions could be retrieved for the service.
errProtocolContextSetupCentralizedNoSessions = errors.New("no active sessions could be retrieved for the service")
// Centralized gateway mode: no owned apps found for the service.
// === Network & relay errors ===
errRelayEndpointConfig = errors.New("endpoint configuration error") // TLS/DNS/config issues
errRelayEndpointTimeout = errors.New("timeout waiting for endpoint response")
errContextCanceled = errors.New("context canceled manually") // PATH-initiated cancel
errSendHTTPRelay = errors.New("HTTP relay request failed")
errMalformedEndpointPayload = errors.New("endpoint returned malformed payload")

// === Gateway mode errors ===
errProtocolContextSetupCentralizedAppFetchErr = errors.New("error getting onchain data for app owned by the gateway")
errProtocolContextSetupCentralizedAppDelegation = errors.New("centralized gateway mode app does not delegate to the gateway")
errProtocolContextSetupCentralizedNoSessions = errors.New("no active sessions could be retrieved for the service")
errProtocolContextSetupCentralizedNoAppsForService = errors.New("ZERO owned apps found for service")

// Delegated gateway mode: could not extract app from HTTP request.
errProtocolContextSetupGetAppFromHTTPReq = errors.New("error getting the selected app from the HTTP request")
// Delegated gateway mode: could not fetch session for app from the full node
errProtocolContextSetupFetchSession = errors.New("error getting a session from the full node for app")
// Delegated gateway mode: gateway does not have delegation for the app.
errProtocolContextSetupAppDoesNotDelegate = errors.New("gateway does not have delegation for app")
// Delegated gateway mode: app is not staked for the service.
errProtocolContextSetupAppNotStaked = errors.New("app is not staked for the service")

// ** Request context setup errors **

// No endpoints available for the service.
// Can be due to one or more of the following:
// - Any of the gateway mode errors above.
// - Error fetching a session for an app.
errProtocolContextSetupNoEndpoints = errors.New("no endpoints found for service: relay request will fail")
// Selected endpoint is no longer available.
// Can happen due to:
// - Bug in endpoint selection logic.
// - Endpoint sanctioned due to an observation while selection logic was running.
errRequestContextSetupInvalidEndpointSelected = errors.New("selected endpoint is not available: relay request will fail")
// Error initializing a signer for the current gateway mode.
errRequestContextSetupErrSignerSetup = errors.New("error getting the permitted signer: relay request will fail")

// The endpoint returned a malformed payload.
// Helps track more fine-grained metrics on endpoint errors.
errMalformedEndpointPayload = errors.New("endpoint returned malformed payload")

// The endpoint returned a non-2XX response.
errEndpointNon2XXHTTPStatusCode = errors.New("endpoint returned non-2xx HTTP status code")

// ** Websocket errors **

// Error creating a Websocket connection.
errCreatingWebSocketConnection = errors.New("error creating Websocket connection")

// Error signing the relay request in a websocket message.
errRelayRequestWebsocketMessageSigningFailed = errors.New("error signing relay request in websocket message")

// Error validating the relay response in a websocket message.
errProtocolContextSetupGetAppFromHTTPReq = errors.New("error getting the selected app from the HTTP request")
errProtocolContextSetupFetchSession = errors.New("error getting a session from the full node for app")
errProtocolContextSetupAppDoesNotDelegate = errors.New("gateway does not have delegation for app")
errProtocolContextSetupAppNotStaked = errors.New("app is not staked for the service")

// === Request context setup errors ===
errProtocolContextSetupNoEndpoints = errors.New("no endpoints found for service: relay request will fail")
errRequestContextSetupInvalidEndpointSelected = errors.New("selected endpoint is not available: relay request will fail")
errRequestContextSetupErrSignerSetup = errors.New("error getting the permitted signer: relay request will fail")

// === Websocket errors ===
errCreatingWebSocketConnection = errors.New("error creating Websocket connection")
errRelayRequestWebsocketMessageSigningFailed = errors.New("error signing relay request in websocket message")
errRelayResponseInWebsocketMessageValidationFailed = errors.New("error validating relay response in websocket message")
)

// extractErrFromRelayError:
// • Analyzes errors returned during relay operations
// • Matches errors to predefined types through:
// - Primary: Error comparison (with unwrapping)
// - Fallback: String analysis for unrecognized types
// - Primary: errors.Is / errors.As (robust, works with wrapped errors)
// - Secondary: Type-specific matching for network/config errors
//
// • Centralizes error recognition logic to avoid duplicate string matching
// • Provides fine-grained HTTP error classification
Expand All @@ -101,17 +62,16 @@ func extractErrFromRelayError(err error) error {
return errRelayEndpointConfig
}

// http endpoint timeout
if strings.Contains(err.Error(), context.DeadlineExceeded.Error()) { // "context deadline exceeded"
// Context-based errors (robust, works recursively through wrapped errors)
if errors.Is(err, context.DeadlineExceeded) {
return errRelayEndpointTimeout
}

// Endpoint's backend service returned a non 2xx HTTP status code.
if strings.Contains(err.Error(), "non 2xx HTTP status code") {
if errors.Is(err, pathhttp.ErrRelayEndpointHTTPError) {
return pathhttp.ErrRelayEndpointHTTPError
}
// context canceled manually
if strings.Contains(err.Error(), "context canceled") {

if errors.Is(err, context.Canceled) {
return errContextCanceled
}

Expand All @@ -126,15 +86,38 @@ func extractErrFromRelayError(err error) error {
// - Error verifying endpoint's TLS certificate
// - Error on DNS lookup of endpoint's URL.
func isEndpointNetworkConfigError(err error) bool {
errStr := err.Error()
switch {
case strings.Contains(errStr, "dial tcp: lookup"):
// Use errors.As for robust type matching (works with wrapped errors)
// Covers common DNS, connection, and TLS issues

// DNS resolution errors
if errors.As(err, &net.DNSError{}) {
return true
case strings.Contains(errStr, "tls: failed to verify certificate"):
}

// General network operation errors (dial, read, write, connect, etc.)
var opErr *net.OpError
if errors.As(err, &opErr) {
return true
}

// Common x509 certificate validation errors
if errors.As(err, &x509.HostnameError{}) {
return true
}
if errors.As(err, &x509.UnknownAuthorityError{}) {
return true
}
if errors.As(err, &x509.CertificateInvalidError{}) {
return true
default:
return false
}

// TLS handshake / record-level errors not covered by x509
var tlsRecordErr *tls.RecordHeaderError
if errors.As(err, &tlsRecordErr) {
return true
}

return false
}

// isMalformedEndpointPayloadError returns true if the error indicates a malformed endpoint payload.
Expand Down