Documentation
¶
Index ¶
- Constants
- Variables
- func ParseJSONRPCFromRequestBody(logger polylog.Logger, requestBody []byte) (map[ID]Request, bool, error)
- func ValidateAndBuildBatchResponse(logger polylog.Logger, responses []json.RawMessage, ...) ([]byte, error)
- type BatchRequest
- type HTTPResponse
- type ID
- type Method
- type Params
- func BuildParamsFromEmptyObject() Params
- func BuildParamsFromObjectAndString(objectParam map[string]string, stringParam string) (Params, error)
- func BuildParamsFromString(stringParam string) (Params, error)
- func BuildParamsFromStringAndBool(stringParam string, boolParam bool) (Params, error)
- func BuildParamsFromStringAndObject(stringParam string, objectParam map[string]any) (Params, error)
- func BuildParamsFromStringArray(params [2]string) (Params, error)
- func BuildParamsFromUint64AndObject(uint64Param uint64, objectParam map[string]any) (Params, error)
- type Request
- type Response
- func GetErrorResponse(id ID, errCode int, errMsg string, errData map[string]string) Response
- func NewErrResponseBatchMarshalFailure(err error) Response
- func NewErrResponseEmptyEndpointResponse(requestID ID) Response
- func NewErrResponseInternalErr(requestID ID, err error) Response
- func NewErrResponseInvalidRequest(requestID ID, err error) Response
- func NewErrResponseNoEndpointResponse(requestID ID) Response
- func (r Response) GetObservation() *qos.JsonRpcResponse
- func (r Response) GetRecommendedHTTPStatusCode() int
- func (r Response) GetResultAsBytes() ([]byte, error)
- func (r *Response) IsError() bool
- func (r *Response) UnmarshalJSON(data []byte) error
- func (r Response) UnmarshalResult(v any) error
- func (r Response) Validate(reqID ID) error
- type ResponseError
- type Version
Constants ¶
const ( // DEV_NOTE: Intentionallly using Non-reserved JSONRPC error code for internal errors. // Allows distinguishing errors coming from PATH from backend server errors. // e.g. // -32000: indicates a backend server (ETH, Solana, etc.) returned the error. // -31001: indicates PATH consturcted the JSONRPC error response (e.g. if the endpoint payload failed to parse as a JSONRPC response) ResponseCodeDefaultInternalErr = -31001 // JSON-RPC server error code; https://www.jsonrpc.org/specification#error_object ResponseCodeBackendServerErr = -31002 // Indicates a backend server error: e.g. payload could not be parsed into a valid JSON-RPC response. ResponseCodeDefaultBadRequest = -32600 // JSON-RPC error code indicating bad user request )
const ( // HTTP status code 400 bad request is used if the request cannot be deserialized into JSONRPC. HTTPStatusRequestValidationFailureUnmarshalFailure = http.StatusBadRequest // TODO_MVP(@adshmh): Remove the error below once the qos interface is updated to replace ParseHTTPRequest with ParseRequest, decoupling the QoS service from the HTTP request. // HTTP status code 500 internal server error is used if reading the HTTP request's body fails HTTPStatusRequestValidationFailureReadHTTPBodyFailure = http.StatusInternalServerError // HTTP status codes returned on response validation failure: no response received HTTPStatusResponseValidationFailureNoResponse = http.StatusInternalServerError // HTTP status codes returned on response validation failure: empty response received HTTPStatusResponseValidationFailureEmptyResponse = http.StatusInternalServerError )
const Version2 = Version("2.0")
Variables ¶
var ( ErrBatchResponseLengthMismatch = errors.New("batch response length mismatch") ErrBatchResponseMissingIDs = errors.New("batch response missing required IDs") ErrBatchResponseEmpty = errors.New("empty batch response not allowed per JSON-RPC specification") ErrBatchResponseMarshalFailure = errors.New("failed to marshal batch response") )
Batch validation errors - standard Go error variables
var HTTPHeadersApplicationJSON = map[string]string{
"Content-Type": "application/json",
}
HTTPHeadersApplicationJSON is the `Content-Type` HTTP header used in all JSONRPC responses.
Functions ¶
func ParseJSONRPCFromRequestBody ¶
func ParseJSONRPCFromRequestBody( logger polylog.Logger, requestBody []byte, ) (map[ID]Request, bool, error)
TODO_MVP(@adshmh): Add a JSON-RPC request validator to reject invalid/unsupported method calls early in request flow.
ParseJSONRPCFromRequestBody parses HTTP request bodies into JSON-RPC request structures. Supports both single requests and batch requests according to the JSON-RPC 2.0 specification. Returns a normalized map of JSON-RPC requests keyed by ID.
Reference: https://www.jsonrpc.org/specification#batch
func ValidateAndBuildBatchResponse ¶
func ValidateAndBuildBatchResponse( logger polylog.Logger, responses []json.RawMessage, servicePayloads map[ID]protocol.Payload, ) ([]byte, error)
ValidateBatchResponse validates and constructs a batch response according to JSON-RPC 2.0 specification.
It performs comprehensive validation including:
- Empty batch handling per JSON-RPC spec (returns empty payload)
- Response length matches request length
- All request IDs are present in responses
- Proper JSON array construction
Returns the marshaled JSON byte array for the response payload. Note that response validation of the individual responses is not performed here; this is handled in the unmarshalResponse function inside the respective QoS package.
Types ¶
type BatchRequest ¶
type BatchRequest struct {
Requests []Request
}
func (*BatchRequest) BuildResponseBytes ¶
func (br *BatchRequest) BuildResponseBytes(jsonrpcResponses []Response) []byte
TODO_UPNEXT(@adshmh): Validate responses in the batch
BuildResponseBytes constructs a Batch JSONRPC response from the slice of response payloads.
func (*BatchRequest) GetRequestsPayloads ¶
func (br *BatchRequest) GetRequestsPayloads() [][]byte
TODO_UPNEXT(@adshmh): Validate ID values, e.g. for duplicate values, when unmarshaling.
GetRequestPayloads returns the slice of serialized forms of JSONRPC requests.
func (*BatchRequest) UnmarshalJSON ¶
func (br *BatchRequest) UnmarshalJSON(data []byte) error
Custom unmarshaller to support requests of the format `[{"jsonrpc":"2.0","id":1},{"jsonrpc":"2.0","id":2}]`
type HTTPResponse ¶
type HTTPResponse struct {
// responResponsePayloadsePayload contains the serialized response body.
ResponsePayload []byte
// HTTPStatusCode is the HTTP status code to be returned.
// If not explicitly set, defaults to http.StatusOK (200).
HTTPStatusCode int
}
httpResponse encapsulates an HTTP response to be returned to the client including payload data and status code.
func (HTTPResponse) GetHTTPHeaders ¶
func (r HTTPResponse) GetHTTPHeaders() map[string]string
GetHTTPHeaders returns the set of headers for the HTTP response. As of PR #72, the only header returned for JSONRPC is `Content-Type`.
func (HTTPResponse) GetHTTPStatusCode ¶
func (hr HTTPResponse) GetHTTPStatusCode() int
GetHTTPStatusCode returns the HTTP status code for this response. If no status code was explicitly set, returns http.StatusOK (200). StatusOK is returned by default from JSONRPC QoS because it is the responsibility of the QoS service to decide on the HTTP status code returned to the client.
func (HTTPResponse) GetPayload ¶
func (hr HTTPResponse) GetPayload() []byte
GetPayload returns the response payload as a byte slice.
type ID ¶
type ID struct {
// contains filtered or unexported fields
}
ID represents a JSON-RPC request/response identifier.
JSON-RPC 2.0 specification requirements:
- Must be String, Number, or NULL
- Server must echo the same value in Response
- Should not be NULL in normal operation
- Numbers must not contain fractional parts
Reference: https://www.jsonrpc.org/specification#id
func (ID) Equal ¶
Equal returns true if two IDs represent the same value. Compares the underlying values, not pointer addresses.
func (ID) MarshalJSON ¶
MarshalJSON implements json.Marshaler interface. Priority order: integers as JSON numbers, strings as JSON strings, unset as null.
func (ID) String ¶
String returns the ID as a string representation. Priority order: integers first, then strings, then "null" for unset IDs.
func (*ID) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler interface. Handles JSON-RPC ID values according to specification:
- null or "" → unset ID (both pointers nil)
- integers → stored in intID
- strings → stored in strID
type Method ¶
type Method string
Method is the method specified by a JSONRPC request. See the following link for more details: https://www.jsonrpc.org/specification
type Params ¶
type Params struct {
// contains filtered or unexported fields
}
Params represents the 'params' field in a JSON-RPC request. It accepts any valid JSON data, including:
- Objects (single or array)
- Strings (single or array)
- Basic Go types (single value or array, can be mixed types)
Params only validates JSON formatting - it does not perform method-specific validation. Individual request handlers must implement their own parameter validation logic.
See the below link on JSONRPC spec for more details: https://www.jsonrpc.org/specification#parameter_structures
func BuildParamsFromEmptyObject ¶
func BuildParamsFromEmptyObject() Params
BuildParamsFromEmptyObject builds a Params object from an empty object. Results in params: {}
func BuildParamsFromObjectAndString ¶
func BuildParamsFromObjectAndString(objectParam map[string]string, stringParam string) (Params, error)
BuildParamsFromObjectAndString builds a Params object from a map and a string.
For example, for an EVM `eth_call` request, the params would look like: params - [{"to":"0xdAC17F958D2ee523a2206206994597C13D831ec7","data":"0x18160ddd"}, "latest"]
Used for eth_call
func BuildParamsFromString ¶
BuildParamsFromString builds a Params object from a single string.
For example, for an EVM `eth_getBalance` request, the params would look like: params - ["0x28C6c06298d514Db089934071355E5743bf21d60"]
Used for eth_getTransactionReceipt and eth_getTransactionByHash
func BuildParamsFromStringAndBool ¶
BuildParamsFromStringAndBool builds a Params object from a single string and a boolean.
For example, for an EVM `eth_getBlockByNumber` request, the params would look like: params - ["0xe71e1d", false]
Used for eth_getBlockByNumber
func BuildParamsFromStringAndObject ¶
BuildParamsFromStringAndObject builds a Params object from a single string and a map.
For example, for a Solana `getSignaturesForAddress` request, the params would look like: params - ["Vote111111111111111111111111111111111111111",{"limit":1}]
Used for getSignaturesForAddress
func BuildParamsFromStringArray ¶
BuildParamsFromStringArray builds a Params object from an array of strings.
For example, for an EVM `eth_getBalance` request, the params would look like: params - ["0x28C6c06298d514Db089934071355E5743bf21d60", "0xe71e1d"]]
Used for eth_getBalance, eth_getTransactionCount, and eth_getTransactionReceipt
func BuildParamsFromUint64AndObject ¶
BuildParamsFromUint64AndObject builds a Params object from a single uint64 and a map.
For example, for a Solana `getBlock` request, the params would look like: params - [430, {"encoding": "json", "transactionDetails": "full", "maxSupportedTransactionVersion": 0}]
Used for getBlock
func (Params) IsEmpty ¶
IsEmpty returns true when params contains no data. The JSON marshaler uses this to completely omit the params field from the JSON output when empty.
func (Params) MarshalJSON ¶
Custom marshaler allows Params to be serialized while keeping rawMessage private. This is needed because Go's default JSON marshaler only processes public fields, but we want to keep rawMessage private to enforce JSON-RPC 2.0 validation during unmarshaling.
func (*Params) UnmarshalJSON ¶
Custom unmarshaler ensures incoming data complies with JSON-RPC 2.0 specification
type Request ¶
type Request struct {
ID ID `json:"id"` // Always include in JSON
JSONRPC Version `json:"jsonrpc"`
Method Method `json:"method"`
Params Params `json:"params,omitempty"`
}
Request represents a JSON-RPC 2.0 request.
Specification requirements:
- jsonrpc: must be "2.0"
- method: string containing the method name
- params: structured values (array or object), optional
- id: identifier for correlation, always included (null if unset)
Reference: https://www.jsonrpc.org/specification#request_object
func (Request) GetObservation ¶
func (r Request) GetObservation() *qos.JsonRpcRequest
GetObservation returns a qos.JsonRpcRequest struct that can be used by QoS services to populate observation fields.
func (Request) MarshalJSON ¶
MarshalJSON implements json.Marshaler interface. Always includes the ID field for JSON-RPC 2.0 compliance. Unset IDs are automatically serialized as null.
type Response ¶
type Response struct {
// ID member is required.
// It must be the same as the value of the id member in the Request Object.
// If there was an error in detecting the id in the Request object (e.g. Parse error/Invalid Request), it MUST be Null.
ID ID `json:"id"`
// Version must be exactly "2.0"
Version Version `json:"jsonrpc"`
// Result captures the result field of the JSONRPC spec.
// It is allowed to be any arbitrary value as permitted by the spec.
// It is required on success and must not exist if there was an error invoking the method.
// Using a pointer to json.RawMessage to distinguish between absent field vs explicit null.
Result *json.RawMessage `json:"result,omitempty"`
// Error captures the error field of the JSONRPC spec.
// Is is required on error and must not exist if there was no error triggered during invocation.
Error *ResponseError `json:"error,omitempty"`
}
Response captures all the fields of a JSONRPC response. See the following link for more details: https://www.jsonrpc.org/specification#response_object
Design decisions: • Result uses *json.RawMessage to distinguish field absence vs explicit null • Pointer nil = field omitted in JSON (invalid per spec) • Pointer to null bytes = {"result":null} (valid for methods like eth_getTransactionReceipt) • json.RawMessage avoids double marshaling and preserves original JSON structure • Custom UnmarshalJSON handles the edge case where JSON null becomes Go nil
func GetErrorResponse ¶
GetErrorResponse is a helper function that builds a JSONRPC Response using the supplied ID and error values.
func NewErrResponseBatchMarshalFailure ¶
NewErrResponseBatchMarshalFailure creates a JSON-RPC error response for batch response marshaling failures. This occurs when individual responses are valid but combining them into a JSON array fails. Uses null ID per JSON-RPC spec for batch-level errors that cannot be correlated to specific requests.
func NewErrResponseEmptyEndpointResponse ¶
NewErrResponseEmptyEndpointResponse creates a JSON-RPC error response for empty endpoint responses:
- Preserves original request ID
- Marks error as retryable for safe client retry
func NewErrResponseInternalErr ¶
NewErrResponseInternalErr creates a JSON-RPC error response when an internal error has occurred (e.g. reading HTTP request's body) Marks the error as retryable to allow clients to safely retry their request.
func NewErrResponseInvalidRequest ¶
NewErrResponseInvalidRequest returns a JSON-RPC error response for malformed or invalid requests. The error indicates the request cannot be processed due to issues like:
- Failed JSON-RPC deserialization
- Missing required JSON-RPC fields (e.g. `method`)
- Unsupported JSON-RPC method
If the request contains a valid JSON-RPC ID, it is included in the error response. The error is marked as permanent since retrying without correcting the request will fail.
func NewErrResponseNoEndpointResponse ¶
NewErrResponseNoEndpointResponse creates a JSON-RPC error response for the case where no endpoint response was received at all. This response:
- Preserves the original request ID
- Marks error as retryable for safe client retry
- Provides actionable message for clients
func (Response) GetObservation ¶
func (r Response) GetObservation() *qos.JsonRpcResponse
GetObservation builds and returns an observation.qos.JsonRpcResponse struct Used to populate observation fields. Truncates the result
func (Response) GetRecommendedHTTPStatusCode ¶
GetRecommendedHTTPStatusCode maps a JSON-RPC error response code to an HTTP status code. DEV_NOTE: This is an opinionated implementation pattern not strictly defined in the JSONRPC specification. See #179 or docusaurus/docs/develop/path/http_status_code.md for more details.
func (Response) GetResultAsBytes ¶
func (*Response) UnmarshalJSON ¶
TODO_TECHDEBT(@adshmh): Validate the results JSONRPC result struct: - Return an error if invalid: e.g. if missing both result and error fields. - Define and use exported errors for each validation failure scenario. - Add a method to construct an observation of type observation.qos.JsonRpcResponseValidationError from the above error.
UnmarshalJSON implements custom unmarshaling to handle the result field presence detection
func (Response) UnmarshalResult ¶
UnmarshalResult unmarshals the result into the provided value
type ResponseError ¶
type ResponseError struct {
// A Number that indicates the error type that occurred.
Code int `json:"code"`
// A String providing a short description of the error.
Message string `json:"message"`
// A Primitive or Structured value that contains additional information about the error.
// This may be omitted.
// The value of this member is defined by the Server (e.g. detailed error information, nested errors etc.).
Data any `json:"data,omitempty"`
}
ResponseError captures a JSONRPC response error struct See the following link for more details: https://www.jsonrpc.org/specification#error_object
func (ResponseError) GetObservation ¶
func (re ResponseError) GetObservation() *qos.JsonRpcResponseError
GetObservation builds and returns an observation.qos.JsonRpcResponseError struct. Used to populate observation fields.