Skip to content

Commit

Permalink
Return status code in the relay
Browse files Browse the repository at this point in the history
  • Loading branch information
ricantar committed May 16, 2024
1 parent 8eba803 commit 5750431
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 95 deletions.
31 changes: 16 additions & 15 deletions provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ var (

const (
// 202 means the response was accepted but we don't know if it actually succeeded

Check failure on line 55 in provider/provider.go

View workflow job for this annotation

GitHub Actions / Lint

comment on exported const DefaultStatusCode should be of the form "DefaultStatusCode ..."
defaultStatusCode = 202
DefaultStatusCode = 202
// Use this contante to avoid the use of the hardcoded string result
// result is the field present in a successful response
resultText = "result"
Expand Down Expand Up @@ -824,37 +824,38 @@ func (p *Provider) DispatchWithCtx(ctx context.Context, appPublicKey, chain stri
}

// Relay does request to be relayed to a target blockchain
func (p *Provider) Relay(rpcURL string, input *RelayInput, options *RelayRequestOptions) (*RelayOutput, *RelayOutputErr) {
func (p *Provider) Relay(rpcURL string, input *RelayInput, options *RelayRequestOptions) (*RelayOutput, int, error) {
return p.RelayWithCtx(context.Background(), rpcURL, input, options)
}

// RelayWithCtx does request to be relayed to a target blockchain
func (p *Provider) RelayWithCtx(ctx context.Context, rpcURL string, input *RelayInput, options *RelayRequestOptions) (*RelayOutput, *RelayOutputErr) {
func (p *Provider) RelayWithCtx(ctx context.Context, rpcURL string, input *RelayInput, options *RelayRequestOptions) (*RelayOutput, int, error) {
rawOutput, reqErr := p.doPostRequest(ctx, rpcURL, input, ClientRelayRoute, http.Header{})

defer closeOrLog(rawOutput)

// this is the status from the request, if the request fail this will be returned as the final status
statusCode := extractStatusFromRequest(rawOutput, reqErr)

if reqErr != nil && !errors.Is(reqErr, errOnRelayRequest) {
return nil, &RelayOutputErr{Error: reqErr, StatusCode: statusCode}
return nil, statusCode, reqErr
}

bodyBytes, err := io.ReadAll(rawOutput.Body)
if err != nil {
return nil, &RelayOutputErr{Error: err, StatusCode: statusCode}
return nil, statusCode, err
}

if errors.Is(reqErr, errOnRelayRequest) {
return nil, &RelayOutputErr{Error: parseRelayErrorOutput(bodyBytes, input.Proof.ServicerPubKey), StatusCode: statusCode}
return nil, statusCode, parseRelayErrorOutput(bodyBytes, input.Proof.ServicerPubKey)
}

// The statusCode will be overwritten based on the response
return parseRelaySuccesfulOutput(bodyBytes)
}

func extractStatusFromRequest(rawOutput *http.Response, reqErr error) int {
statusCode := defaultStatusCode
statusCode := DefaultStatusCode

if reqErr != nil {
for key, status := range errorStatusCodesMap {
Expand Down Expand Up @@ -889,30 +890,30 @@ func extractStatusFromResponse(response string) int {
return code
}
}
return defaultStatusCode
return DefaultStatusCode
}

func parseRelaySuccesfulOutput(bodyBytes []byte) (*RelayOutput, *RelayOutputErr) {
func parseRelaySuccesfulOutput(bodyBytes []byte) (*RelayOutput, int, error) {
output := RelayOutput{}

status := DefaultStatusCode
err := json.Unmarshal(bodyBytes, &output)
if err != nil {
return nil, &RelayOutputErr{Error: err}
return nil, DefaultStatusCode, err
}

// Check if there's explicitly a result field, if there's on mark it as success, otherwise check what's the potential status.
// for REST chain that doesn't return result in any of the call will be defaulted to 202 in extractStatusFromResponse
if strings.Contains(output.Response, resultText) {
output.StatusCode = http.StatusOK
status = http.StatusOK
} else {
output.StatusCode = extractStatusFromResponse(output.Response)
status = extractStatusFromResponse(output.Response)
}

if !json.Valid([]byte(output.Response)) {
return nil, &RelayOutputErr{Error: ErrNonJSONResponse, StatusCode: output.StatusCode}
return nil, status, ErrNonJSONResponse
}

return &output, nil
return &output, status, nil
}

func parseRelayErrorOutput(bodyBytes []byte, servicerPubKey string) error {
Expand Down
44 changes: 22 additions & 22 deletions provider/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -768,30 +768,30 @@ func TestProvider_Relay(t *testing.T) {

mock.AddMockedResponseFromFile(http.MethodPost, fmt.Sprintf("%s%s", "https://dummy.com", ClientRelayRoute), http.StatusOK, "samples/client_relay.json")

relay, err := provider.Relay("https://dummy.com", &RelayInput{}, nil)
relay, _, err := provider.Relay("https://dummy.com", &RelayInput{}, nil)
c.Nil(err)
c.NotEmpty(relay)

mock.AddMockedResponseFromFile(http.MethodPost, fmt.Sprintf("%s%s", "https://dummy.com", ClientRelayRoute), http.StatusInternalServerError, "samples/client_relay.json")

relay, err = provider.Relay("https://dummy.com", &RelayInput{}, nil)
c.Equal(Err5xxOnConnection, err.Error)
c.Equal(http.StatusInternalServerError, err.StatusCode)
c.False(IsErrorCode(EmptyPayloadDataError, err.Error))
relay, statusCode, err := provider.Relay("https://dummy.com", &RelayInput{}, nil)
c.Equal(Err5xxOnConnection, err)
c.Equal(http.StatusInternalServerError, statusCode)
c.False(IsErrorCode(EmptyPayloadDataError, err))
c.Empty(relay)

mock.AddMockedResponseFromFile(http.MethodPost, fmt.Sprintf("%s%s", "https://dummy.com", ClientRelayRoute), http.StatusBadRequest, "samples/client_relay_error.json")

relay, err = provider.Relay("https://dummy.com", &RelayInput{Proof: &RelayProof{ServicerPubKey: "PJOG"}}, nil)
c.Equal("Request failed with code: 25, codespace: pocketcore and message: the payload data of the relay request is empty\nWith ServicerPubKey: PJOG", err.Error.Error())
c.True(IsErrorCode(EmptyPayloadDataError, err.Error))
c.Equal(http.StatusInternalServerError, err.StatusCode)
relay, statusCode, err = provider.Relay("https://dummy.com", &RelayInput{Proof: &RelayProof{ServicerPubKey: "PJOG"}}, nil)
c.Equal("Request failed with code: 25, codespace: pocketcore and message: the payload data of the relay request is empty\nWith ServicerPubKey: PJOG", err.Error())
c.True(IsErrorCode(EmptyPayloadDataError, err))
c.Equal(http.StatusInternalServerError, statusCode)
c.Empty(relay)

mock.AddMockedResponseFromFile(http.MethodPost, fmt.Sprintf("%s%s", "https://dummy.com", ClientRelayRoute), http.StatusOK, "samples/client_relay_non_json.json")

relay, err = provider.Relay("https://dummy.com", &RelayInput{}, nil)
c.Equal(ErrNonJSONResponse, err.Error)
relay, _, err = provider.Relay("https://dummy.com", &RelayInput{}, nil)
c.Equal(ErrNonJSONResponse, err)
c.Empty(relay)
}

Expand All @@ -805,29 +805,29 @@ func TestProvider_RelayWithCtx(t *testing.T) {

mock.AddMockedResponseFromFile(http.MethodPost, fmt.Sprintf("%s%s", "https://dummy.com", ClientRelayRoute), http.StatusOK, "samples/client_relay.json")

relay, err := provider.RelayWithCtx(context.Background(), "https://dummy.com", &RelayInput{}, nil)
relay, statusCode, err := provider.RelayWithCtx(context.Background(), "https://dummy.com", &RelayInput{}, nil)
c.Nil(err)
c.NotEmpty(relay)

mock.AddMockedResponseFromFile(http.MethodPost, fmt.Sprintf("%s%s", "https://dummy.com", ClientRelayRoute), http.StatusInternalServerError, "samples/client_relay.json")

relay, err = provider.RelayWithCtx(context.Background(), "https://dummy.com", &RelayInput{}, nil)
c.Equal(Err5xxOnConnection, err.Error)
c.Equal(http.StatusInternalServerError, err.StatusCode)
c.False(IsErrorCode(EmptyPayloadDataError, err.Error))
relay, statusCode, err = provider.RelayWithCtx(context.Background(), "https://dummy.com", &RelayInput{}, nil)
c.Equal(Err5xxOnConnection, err)
c.Equal(http.StatusInternalServerError, statusCode)
c.False(IsErrorCode(EmptyPayloadDataError, err))
c.Empty(relay)

mock.AddMockedResponseFromFile(http.MethodPost, fmt.Sprintf("%s%s", "https://dummy.com", ClientRelayRoute), http.StatusBadRequest, "samples/client_relay_error.json")

relay, err = provider.RelayWithCtx(context.Background(), "https://dummy.com", &RelayInput{Proof: &RelayProof{ServicerPubKey: "PJOG"}}, nil)
c.Equal("Request failed with code: 25, codespace: pocketcore and message: the payload data of the relay request is empty\nWith ServicerPubKey: PJOG", err.Error.Error())
c.True(IsErrorCode(EmptyPayloadDataError, err.Error))
c.Equal(http.StatusInternalServerError, err.StatusCode)
relay, statusCode, err = provider.RelayWithCtx(context.Background(), "https://dummy.com", &RelayInput{Proof: &RelayProof{ServicerPubKey: "PJOG"}}, nil)
c.Equal("Request failed with code: 25, codespace: pocketcore and message: the payload data of the relay request is empty\nWith ServicerPubKey: PJOG", err.Error())
c.True(IsErrorCode(EmptyPayloadDataError, err))
c.Equal(http.StatusInternalServerError, statusCode)
c.Empty(relay)

mock.AddMockedResponseFromFile(http.MethodPost, fmt.Sprintf("%s%s", "https://dummy.com", ClientRelayRoute), http.StatusOK, "samples/client_relay_non_json.json")

relay, err = provider.RelayWithCtx(context.Background(), "https://dummy.com", &RelayInput{}, nil)
c.Equal(ErrNonJSONResponse, err.Error)
relay, _, err = provider.RelayWithCtx(context.Background(), "https://dummy.com", &RelayInput{}, nil)
c.Equal(ErrNonJSONResponse, err)
c.Empty(relay)
}
11 changes: 2 additions & 9 deletions provider/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,8 @@ type RelayInput struct {

// RelayOutput represents the Relay RPC output
type RelayOutput struct {
Response string `json:"response"`
Signature string `json:"signature"`
StatusCode int `json:"statusCode"`
}

// RelayOutputErr represents the RPC output error
type RelayOutputErr struct {
Error error `json:"error"`
StatusCode int `json:"statusCode"`
Response string `json:"response"`
Signature string `json:"signature"`
}

// RelayMeta represents metadata of a relay
Expand Down
19 changes: 10 additions & 9 deletions relayer/relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"errors"
"math"
"math/big"
"net/http"

"golang.org/x/crypto/sha3"

Expand All @@ -35,7 +36,7 @@ var (

// Provider interface representing provider functions necessary for Relayer Package
type Provider interface {
RelayWithCtx(ctx context.Context, rpcURL string, input *provider.RelayInput, options *provider.RelayRequestOptions) (*provider.RelayOutput, *provider.RelayOutputErr)
RelayWithCtx(ctx context.Context, rpcURL string, input *provider.RelayInput, options *provider.RelayRequestOptions) (*provider.RelayOutput, int, error)
}

// Signer interface representing signer functions necessary for Relayer Package
Expand Down Expand Up @@ -172,37 +173,37 @@ func (r *Relayer) buildRelay(
}

// Relay does relay request with given input
func (r *Relayer) Relay(input *Input, options *provider.RelayRequestOptions) (*Output, *provider.RelayOutputErr) {
func (r *Relayer) Relay(input *Input, options *provider.RelayRequestOptions) (*Output, int, error) {
return r.RelayWithCtx(context.Background(), input, options)
}

// RelayWithCtx does relay request with given input
func (r *Relayer) RelayWithCtx(ctx context.Context, input *Input, options *provider.RelayRequestOptions) (*Output, *provider.RelayOutputErr) {
func (r *Relayer) RelayWithCtx(ctx context.Context, input *Input, options *provider.RelayRequestOptions) (*Output, int, error) {
err := r.validateRelayRequest(input)
if err != nil {
return nil, &provider.RelayOutputErr{Error: err}
return nil, http.StatusBadRequest, err
}

node, err := getNode(input)
if err != nil {
return nil, &provider.RelayOutputErr{Error: err}
return nil, provider.DefaultStatusCode, err
}

relayInput, err := r.buildRelay(node, input, options)
if err != nil {
return nil, &provider.RelayOutputErr{Error: err}
return nil, provider.DefaultStatusCode, err
}

relayOutput, relayErr := r.provider.RelayWithCtx(ctx, node.ServiceURL, relayInput, options)
relayOutput, statusCode, relayErr := r.provider.RelayWithCtx(ctx, node.ServiceURL, relayInput, options)
if relayErr != nil {
return nil, relayErr
return nil, statusCode, relayErr
}

return &Output{
RelayOutput: relayOutput,
Proof: relayInput.Proof,
Node: node,
}, nil
}, statusCode, nil
}

// GetRandomSessionNode returns a random node from given session
Expand Down
Loading

0 comments on commit 5750431

Please sign in to comment.