jsonrpc

package
v1.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 28, 2025 License: MIT Imports: 11 Imported by: 0

Documentation

Index

Constants

View Source
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
)
View Source
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
)
View Source
const Version2 = Version("2.0")

Variables

View Source
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

View Source
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 IDFromInt

func IDFromInt(id int) ID

IDFromInt creates an ID from an integer value.

func IDFromStr

func IDFromStr(id string) ID

IDFromStr creates an ID from a string value.

func (ID) Equal

func (id ID) Equal(other ID) bool

Equal returns true if two IDs represent the same value. Compares the underlying values, not pointer addresses.

func (ID) IsEmpty

func (id ID) IsEmpty() bool

IsEmpty returns true when the ID is unset (both pointers are nil).

func (ID) MarshalJSON

func (id ID) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler interface. Priority order: integers as JSON numbers, strings as JSON strings, unset as null.

func (ID) String

func (id ID) String() string

String returns the ID as a string representation. Priority order: integers first, then strings, then "null" for unset IDs.

func (*ID) UnmarshalJSON

func (id *ID) UnmarshalJSON(data []byte) error

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

func BuildParamsFromString(stringParam string) (Params, error)

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

func BuildParamsFromStringAndBool(stringParam string, boolParam bool) (Params, error)

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

func BuildParamsFromStringAndObject(stringParam string, objectParam map[string]any) (Params, error)

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

func BuildParamsFromStringArray(params [2]string) (Params, error)

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

func BuildParamsFromUint64AndObject(uint64Param uint64, objectParam map[string]any) (Params, error)

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

func (p Params) IsEmpty() bool

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

func (p Params) MarshalJSON() ([]byte, error)

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

func (p *Params) UnmarshalJSON(data []byte) error

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 GetJsonRpcReqFromServicePayload

func GetJsonRpcReqFromServicePayload(servicePayload protocol.Payload) (Request, error)

func (Request) BuildPayload

func (r Request) BuildPayload() (protocol.Payload, error)

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

func (r Request) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler interface. Always includes the ID field for JSON-RPC 2.0 compliance. Unset IDs are automatically serialized as null.

func (*Request) SetParams

func (r *Request) SetParams(params []byte)

SetParams sets the params field directly from a byte array

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

func GetErrorResponse(id ID, errCode int, errMsg string, errData map[string]string) Response

GetErrorResponse is a helper function that builds a JSONRPC Response using the supplied ID and error values.

func NewErrResponseBatchMarshalFailure

func NewErrResponseBatchMarshalFailure(err error) Response

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

func NewErrResponseEmptyEndpointResponse(requestID ID) Response

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

func NewErrResponseInternalErr(requestID ID, err error) Response

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

func NewErrResponseInvalidRequest(requestID ID, err error) Response

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

func NewErrResponseNoEndpointResponse(requestID ID) Response

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

func (r Response) GetRecommendedHTTPStatusCode() int

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 (r Response) GetResultAsBytes() ([]byte, error)

func (*Response) IsError

func (r *Response) IsError() bool

func (*Response) UnmarshalJSON

func (r *Response) UnmarshalJSON(data []byte) error

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

func (r Response) UnmarshalResult(v any) error

UnmarshalResult unmarshals the result into the provided value

func (Response) Validate

func (r Response) Validate(reqID ID) error

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.

type Version

type Version string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL