-
Notifications
You must be signed in to change notification settings - Fork 0
Edge RPC
The RPC service sends Ethereum-compatible JSON-RPC 2.0 requests through a Goldsky Edge endpoint. It supports individual calls and batches over HTTPS. Edge RPC is a data plane; it uses an endpoint-specific Edge API key, not the project API token used by the REST control plane.
Goldsky documents Edge RPC as HTTPS only. There is no WebSocket endpoint, and eth_subscribe / eth_unsubscribe are not supported. For chain-state watching, use polling with filter methods or select a streaming product such as Turbo Pipelines or Mirror.1
Provision an endpoint and store its key securely as described in Edge Endpoints. Then provide the key when constructing the client.
client, err := goldsky.NewClient(
os.Getenv("GOLDSKY_API_KEY"),
goldsky.WithEdgeAPIKey(os.Getenv("GOLDSKY_EDGE_API_KEY")),
goldsky.WithTimeout(20*time.Second),
)
if err != nil {
return err
}The Edge key is included in the endpoint URL as a query parameter. The SDK keeps it out of error strings and internal retry logs, but an application must still avoid logging client.RPC.EndpointURL(...) or full outbound URLs.
Use client.SetEdgeAPIKey(nextKey) to rotate the key while other goroutines use the same client.
Call validates that a key, a positive chain ID, and a non-empty method are present. When result is non-nil, the SDK decodes the JSON-RPC result field into it.
var blockHex string
err := client.RPC.Call(ctx, 1, "eth_blockNumber", nil, &blockHex)
if err != nil {
return err
}
number, err := strconv.ParseUint(strings.TrimPrefix(blockHex, "0x"), 16, 64)
if err != nil {
return fmt.Errorf("unexpected block number %q: %w", blockHex, err)
}
fmt.Println("latest Ethereum block:", number)The chain ID is the numeric EVM chain identifier. Discover current supported networks with client.Catalogs.EdgeNetworks(ctx) instead of guessing them in a multi-chain application.
Pass any JSON-decodable Go target. For evolving or method-specific shapes, json.RawMessage keeps the response available for a later decoder.
var raw json.RawMessage
if err := client.RPC.Call(ctx, 1, "eth_getBlockByNumber", []any{"latest", false}, &raw); err != nil {
return err
}
fmt.Println(string(raw))Batching reduces round trips when multiple independent methods target the same chain. JSON-RPC batch responses may arrive in any order. The SDK matches responses back to the input calls by request ID and returns them in input order.
var blockHex, chainHex string
responses, err := client.RPC.Batch(ctx, 1, []goldsky.RPCBatchCall{
{Method: "eth_blockNumber", Result: &blockHex},
{Method: "eth_chainId", Result: &chainHex},
})
if err != nil {
return err // HTTP, transport, or response decoding failure
}
for i, response := range responses {
if response.Error != nil {
log.Printf("call %d failed: %s", i, response.Error)
}
}
fmt.Println("block", blockHex, "chain", chainHex)A non-nil error from Batch means the HTTP envelope or decoding failed. A per-method JSON-RPC error is stored in the corresponding RPCResponse.Error, so a batch can have both successful and unsuccessful calls.
For a single call, use errors.As to inspect *goldsky.RPCError.
var balance string
err := client.RPC.Call(ctx, 1, "eth_getBalance", []any{"not-an-address", "latest"}, &balance)
if err != nil {
var rpcErr *goldsky.RPCError
if errors.As(err, &rpcErr) {
return fmt.Errorf("RPC method rejected (%d): %s", rpcErr.Code, rpcErr.Message)
}
return err
}RPCError includes JSON-RPC Code, Message, and optional raw Data. Do not assume that an application-level method error should receive the same retry policy as an HTTP 5xx response. Validate the request and method semantics first.
Non-2xx HTTP responses become *goldsky.ProblemDetails, while network errors and malformed JSON become *goldsky.TransportError. These are the same high-level types used elsewhere in the SDK. See Errors, Retries, and Pagination.
The REST retry configuration does not wrap RPC requests. For a replayable read, your application may add a short, context-aware retry policy. Do not automatically retry potentially stateful JSON-RPC operations without understanding the method’s effects.
Because WebSockets and subscriptions are not available, use filter-based polling when the application needs to observe changing EVM state.
var filterID string
if err := client.RPC.Call(ctx, 1, "eth_newBlockFilter", nil, &filterID); err != nil {
return err
}
for {
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(5 * time.Second):
var changes []string
if err := client.RPC.Call(ctx, 1, "eth_getFilterChanges", []any{filterID}, &changes); err != nil {
return err
}
for _, blockHash := range changes {
process(blockHash)
}
}
}Production polling should account for filter lifecycle, backoff, failure recovery, and application-level deduplication. For high-volume or durable streaming, use Goldsky’s product designed for streaming rather than an ever-growing RPC poller.
| Control | Reason |
|---|---|
| Keep the Edge key in a secret manager. | It authenticates endpoint use and is included in URL query strings. |
| Never log full RPC URLs. | Query strings expose key. |
| Use deadlines per RPC workload. | Prevents indefinitely blocked calls. |
| Use batches for independent calls to the same chain. | Reduces network overhead while preserving response alignment. |
Check RPCResponse.Error for each batch item. |
HTTP success does not make every method successful. |
| Use HTTPS polling, not WebSocket subscriptions. | Edge RPC does not support subscriptions. |