> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/ethereum/go-ethereum/llms.txt
> Use this file to discover all available pages before exploring further.

# rpc client

> Low-level JSON-RPC client for Ethereum nodes.

Package `rpc` implements the JSON-RPC 2.0 client transport layer. `ethclient` is built on top of it. Use the `rpc` package directly when you need to call methods that `ethclient` does not expose — for example, Geth-specific `debug_*`, `admin_*`, or `txpool_*` namespaces.

```
import "github.com/ethereum/go-ethereum/rpc"
```

## Connecting

```go theme={null}
func Dial(rawurl string) (*Client, error)
func DialContext(ctx context.Context, rawurl string) (*Client, error)
func DialOptions(ctx context.Context, rawurl string, options ...ClientOption) (*Client, error)
```

Supported URL schemes:

| Scheme                    | Transport                                      |
| ------------------------- | ---------------------------------------------- |
| `http` / `https`          | HTTP (request/response only; no subscriptions) |
| `ws` / `wss`              | WebSocket (supports subscriptions)             |
| *(no scheme / bare path)* | Unix domain socket / Windows named pipe (IPC)  |

```go theme={null}
// HTTP
client, err := rpc.Dial("http://localhost:8545")

// WebSocket
client, err := rpc.Dial("ws://localhost:8546")

// IPC
client, err := rpc.Dial("/var/run/geth.ipc")
```

## Making a single call

```go theme={null}
// Call sends a request and unmarshals the result into `result`.
// Pass nil to discard the result.
func (c *Client) Call(result interface{}, method string, args ...interface{}) error

// CallContext is the same but respects context cancellation and deadlines.
func (c *Client) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error
```

```go theme={null}
var blockNumber hexutil.Uint64
if err := client.Call(&blockNumber, "eth_blockNumber"); err != nil {
    log.Fatal(err)
}
fmt.Println("block:", uint64(blockNumber))
```

`result` must be a pointer (or nil). Any value accepted by `encoding/json.Unmarshal` works.

## Batch calls

Send multiple requests in a single round-trip:

```go theme={null}
// BatchElem is one element in a batch.
type BatchElem struct {
    Method string
    Args   []interface{}
    Result interface{} // must be a non-nil pointer
    Error  error       // set by BatchCall if the server returned an error for this element
}

func (c *Client) BatchCall(b []BatchElem) error
func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error
```

```go theme={null}
var (
    balance hexutil.Big
    nonce   hexutil.Uint64
)

batch := []rpc.BatchElem{
    {
        Method: "eth_getBalance",
        Args:   []interface{}{addr, "latest"},
        Result: &balance,
    },
    {
        Method: "eth_getTransactionCount",
        Args:   []interface{}{addr, "latest"},
        Result: &nonce,
    },
}

if err := client.BatchCall(batch); err != nil {
    log.Fatal(err) // I/O-level error
}

// Check per-element errors
for _, elem := range batch {
    if elem.Error != nil {
        log.Printf("%s error: %v", elem.Method, elem.Error)
    }
}

fmt.Println("balance:", balance.ToInt())
fmt.Println("nonce:", uint64(nonce))
```

<Note>
  `BatchCall` returns only transport-level errors. Application-level errors (e.g. method not found) are set on `BatchElem.Error` for each element individually.
</Note>

## Subscriptions

Subscriptions are only supported over WebSocket and IPC connections. Calling `Subscribe` on an HTTP client returns `ErrNotificationsUnsupported`.

```go theme={null}
// Subscribe calls "<namespace>_subscribe" with the given args.
// Notifications are delivered to channel.
func (c *Client) Subscribe(
    ctx context.Context,
    namespace string,
    channel interface{},
    args ...interface{},
) (*ClientSubscription, error)

// EthSubscribe is a convenience wrapper for the "eth" namespace.
func (c *Client) EthSubscribe(
    ctx context.Context,
    channel interface{},
    args ...interface{},
) (*ClientSubscription, error)
```

```go theme={null}
headers := make(chan map[string]interface{})
sub, err := client.EthSubscribe(ctx, headers, "newHeads")
if err != nil {
    log.Fatal(err)
}
defer sub.Unsubscribe()

for {
    select {
    case h := <-headers:
        fmt.Println("new head:", h["number"])
    case err := <-sub.Err():
        log.Fatal(err)
    }
}
```

`ClientSubscription` methods:

```go theme={null}
func (sub *ClientSubscription) Unsubscribe()
func (sub *ClientSubscription) Err() <-chan error
```

## Checking available methods

```go theme={null}
func (c *Client) SupportedModules() (map[string]string, error)
```

Returns a map of `"namespace" → "version"` for all API namespaces the node exposes.

## When to use rpc vs ethclient

| Use case                                                           | Package                                          |
| ------------------------------------------------------------------ | ------------------------------------------------ |
| Standard `eth_*` methods with typed return values                  | `ethclient`                                      |
| Custom or Geth-specific namespaces (`debug`, `admin`, `txpool`, …) | `rpc`                                            |
| Batch multiple `eth_*` calls in one round-trip                     | `rpc`                                            |
| Need access to the underlying transport                            | `rpc` (retrieve via `ethclient.Client.Client()`) |

You can also mix both: get an `*ethclient.Client` for normal usage and call `client.Client()` to retrieve the underlying `*rpc.Client` when you need to call an unlisted method.

## Example: call a Geth admin method

```go theme={null}
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

func main() {
    // IPC gives access to admin/debug/txpool namespaces
    client, err := rpc.Dial("/var/run/geth.ipc")
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    // admin_nodeInfo — not available in ethclient
    var info map[string]interface{}
    if err := client.CallContext(context.Background(), &info, "admin_nodeInfo"); err != nil {
        log.Fatal(err)
    }
    fmt.Println("enode:", info["enode"])

    // txpool_status
    var status struct {
        Pending string `json:"pending"`
        Queued  string `json:"queued"`
    }
    if err := client.Call(&status, "txpool_status"); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("pending: %s  queued: %s\n", status.Pending, status.Queued)
}
```

## Error types

```go theme={null}
var (
    ErrClientQuit                = errors.New("client is closed")
    ErrNoResult                  = errors.New("JSON-RPC response has no result")
    ErrMissingBatchResponse      = errors.New("response batch did not contain a response to this call")
    ErrSubscriptionQueueOverflow = errors.New("subscription queue overflow")
)
```

The client also exposes the `rpc.Error` and `rpc.DataError` interfaces so callers can inspect JSON-RPC error codes and data fields. `ethclient.RevertErrorData` is a convenience wrapper that extracts the ABI-encoded revert reason from a call error.
