Skip to main content
nodex-proxy converges a leafage-evm cluster into a single RPC endpoint. It decides by the request’s block context whether to send it to a State, Archive, or Native node, and takes on traffic governance duties such as rate limiting, mirroring, and observability.

Ports and paths

One process serves multiple chains at the same time; chains are distinguished by the chainId in the path. Hexadecimal IDs are normalized to decimal strings.
The admin API shares the port with JSON-RPC and can change routing state. This port should not be exposed outside the internal network, or it needs to be placed behind an external authentication layer.

Request lifecycle

Pre-processing runs in a fixed order:
Post-processing:

Node selection

First decide the node pool by block context, then pick a specific node within the pool by strategy. The chain head height comes from {chainId}/lastBlockNumber in etcd, maintained by consistency-checker. When the chain height is unknown, it conservatively selects an Archive node. The two pools fall back to each other: when the State pool is empty, the Archive pool is used, and vice versa. Within each pool, Available nodes are used first.

Load balancing strategies

Selects by weighted probability. Non-batch requests first filter candidate nodes by method routing rules, then select by weight. Nodes without an explicit weight default to 100.

Automatic retries

Service discovery

Watches an etcd prefix (etcd_prefix is configurable); the following key suffixes are interpreted as runtime data: The proxy watches PUT / DELETE events to add and remove nodes and update configuration in real time, with no restart needed.

Health check

A node that newly appears in etcd does not join the node pool immediately:
1

Probe

Send an RPC call to the node to verify reachability. State / Archive nodes use getLatestBlock, Native nodes use eth_blockNumber.
2

Retry

On failure, retry every 5 seconds until node_health_check_max_wait (default 300 seconds).
3

Join

Only after passing the check does the node enter the load balancing pool.

Version routing

When a request uses the base chain ID with no explicit version suffix, the proxy reads {chainId}/version from etcd and rewrites the request to the {chainId}-{version} node pool. This makes version switching transparent to clients.

Traffic governance

Usage reporting

Once usage is configured, RPC time is aggregated locally by the client-id request header and written to Kafka when 10000 aggregation keys or report_interval (default 5s) is reached.
  • usage is the aggregated time in milliseconds, with a minimum of 1.
  • A missing client-id is recorded as unknown.
  • Sending is best-effort: the last batch is sent on graceful shutdown; loss is acceptable when the process crashes or Kafka fails.
  • The current number of aggregation keys is reflected by jrpcx_usage_aggregation_keys.

Admin API

debug_chooseOneNode is useful when troubleshooting routing problems: it returns the node that would be selected under the current request conditions, without actually forwarding.

Metrics

Exposed at :8664/metrics, with common labels host, target, chain_id, chain_version. Some metrics carry extra labels:

Running

Multiple instances can connect to the same etcd cluster to scale horizontally, each maintaining its own local selector state.

Development