Status: future optional module family.
The crypto RPC edge track is a future Fluxheim module family for running blockchain-aware RPC gateways in front of local nodes or hosted-compatible upstreams. It should be designed as focused compile-time modules, not as part of the default web/proxy build.
The first concrete target is eth: native Ethereum/EVM JSON-RPC reverse
proxying, bounded caching, and node-health-aware routing. A later eth-ens
review can evaluate ENS contenthash routing, but that should remain separate
until the Ethereum RPC edge module is stable. Bitcoin, Cardano, and XRPL can use
the same broad architecture later, but their finality, method policy, and
transport models are different enough that they should be separate modules.
Long-term feature shape:
chain-edge-core = ["proxy", "cache", "dep:serde_json", "dep:sha2"]
eth = ["chain-edge-core"]
eth-ens = ["eth"] # planned review only; exact dependencies not selected yet
eth-verify = ["eth"] # future proof-verification/co-processing review
btc = ["chain-edge-core"] # future review
ada = ["chain-edge-core"] # future review
xrpl = ["chain-edge-core"] # future review
profile-ethereum-rpc = ["proxy", "cache", "eth", "tls-rustls", "security"]
profile-ethereum-verified-rpc = [
"proxy",
"cache",
"eth",
"eth-verify",
"tls-rustls",
"security",
]chain-edge-core should hold only shared primitives:
- bounded JSON-RPC request parsing;
- batch limits;
- method policy dispatch;
- cache-key framework;
- upstream health snapshots;
- retry safety classification;
- no-secret logging/tracing helpers;
- WebSocket sticky-routing primitives.
It must not contain Ethereum-, Bitcoin-, Cardano-, or XRPL-specific cache rules. Each chain module owns its own method allow-list, finality model, cache admission rules, health probes, and WebSocket/subscription behavior.
Ethereum/EVM is the cleanest first target because dApps commonly use standard
HTTP/WebSocket JSON-RPC, redundant POST traffic is common, and the execution API
exposes block tags such as finalized, safe, latest, and pending. Those
tags make cache safety easier to reason about than a generic blockchain proxy.
Initial Ethereum-focused feature shape:
eth = ["proxy", "cache", "dep:serde_json", "dep:sha2"]
eth-ens = ["eth"] # planned review only; exact dependencies not selected yet
profile-ethereum-rpc = ["proxy", "cache", "eth", "tls-rustls", "security"]eth and any future crypto RPC module must remain absent from default, PHP,
static-site, cache-edge, proxy-edge, privacy, and load-balancer builds unless
selected explicitly. The default reverse proxy must not parse JSON-RPC bodies or
pull chain-specific dependencies.
Possible later dependencies, after license/advisory review:
alloy-rpc-typesor narrow Alloy crates for Ethereum JSON-RPC types;alloy-provideronly if Fluxheim needs client-side calls beyond simple health probes;- a small local JSON-RPC classifier if the supported cacheable method set stays narrow enough to audit.
Avoid exposing third-party Ethereum types in public Fluxheim config. Config should stay plain TOML with strings, numbers, durations, and byte sizes.
eth-verify must be a separate compile-time feature because proof verification
adds consensus, trie, precompile, and ZK-related dependencies that should not be
pulled into a normal RPC cache/proxy build.
Candidate vhost-level config:
[[vhosts]]
name = "eth-mainnet"
hosts = ["rpc.example.test"]
[vhosts.eth]
enabled = true
chain_id = 1
upstreams = ["reth-a:8545", "erigon-b:8545"]
max_json_body_bytes = "2MiB"
cache_enabled = true
cache_finalized = true
finality_depth = 64
health_poll_secs = 5
health_max_block_lag = 3
retry_on_rpc_error = true
websocket_enabled = falseRoute-scoped eth config may be useful later, but the first implementation
should keep one eth policy per vhost to reduce routing ambiguity and cache
key mistakes.
Stable first scope:
- Accept
POSTrequests with bounded JSON bodies only. - Require
Content-Typecompatible with JSON unless an explicit compatibility flag is enabled. - Parse JSON-RPC 2.0 single calls and batched calls.
- Reject or pass through malformed JSON according to policy:
- strict mode rejects malformed JSON before upstream;
- compatibility mode passes malformed requests to upstream without caching.
- Build cache keys from chain id, method, normalized params, and finality state.
- Never cache responses with JSON-RPC
errorunless an explicit method policy says the error is immutable and safe. - Normalize upstream response handling so Fluxheim can remove hop-by-hop headers and apply existing response policy.
- Support multi-provider upstream pools so applications are not coupled to one centralized RPC provider.
Batch behavior should be conservative. A batch is cacheable only when every call in the batch is individually cacheable under the current policy. Mixed cacheable/non-cacheable batches should pass through without storing, or be split only after a later design proves response ordering and error behavior.
Ethereum JSON-RPC is POST-heavy, so normal HTTP cache semantics are not enough.
The eth module should cache only methods whose result can be tied to an
immutable identifier, a finalized/safe tag, or an old-enough block number.
Initial cacheable candidates:
eth_getBlockByHasheth_getBlockByNumberwhen the block parameter is:- an explicit block number older than the configured finality depth;
finalized;- optionally
safe, with a shorter TTL than finalized;
eth_getBlockTransactionCountByHasheth_getBlockTransactionCountByNumberunder the same block-number policy;eth_getTransactionByHash, with conservative TTL and optional negative-cache controls;eth_getTransactionReceipt, with conservative TTL until finalized and long TTL after the containing block is known finalized;eth_getLogsonly when the block range is bounded and entirely finalized or older than the configured finality depth.
Do not cache in the first stable implementation:
eth_sendRawTransaction,eth_sendTransaction, signing methods, account methods, txpool/debug/admin methods;eth_call,eth_estimateGas,eth_feeHistory,eth_gasPrice, and priority-fee methods, unless a later method policy includes explicit block tags and TTL rules;- requests using
latestorpending, except where a method has an explicit short-lived local policy; - WebSocket subscription messages.
The execution API distinguishes finalized, safe, latest, and pending.
The eth cache policy should use those tags directly instead of guessing that
all block-number queries are immutable.
The module should maintain a small per-upstream view of:
chain_id;- latest observed block number;
- finalized block number when available;
- safe block number when available;
- sync status from
eth_syncing; - last successful probe time;
- current health state and error counters.
Cache admission should prefer response-derived block numbers when available. If
the module cannot determine whether a response is finality-safe, it should pass
through without storing. For chains that do not expose useful finalized data,
operators may configure a finality_depth fallback, but this should be clearly
documented as chain-specific risk.
Initial selection should integrate with the 1.5 load-balancer line when
available, but the eth module can still start with a small local health model:
- reject unhealthy upstreams when
eth_syncingreports active syncing; - reject or de-prioritize upstreams whose
eth_blockNumberlags the vhost median or best upstream by more thanhealth_max_block_lag; - verify
eth_chainIdmatches config before serving traffic; - retry idempotent read-only calls on transport errors, timeout, HTTP 5xx, or JSON-RPC error classes selected by policy;
- never retry transaction-submission methods by default.
Selection policies:
- round-robin among healthy nodes;
- power-of-two choices with active request count;
- sticky selection for WebSocket sessions;
- optional fallback to hosted providers only when explicitly configured.
Decentralization goals:
- let operators mix local execution clients, community RPC nodes, and hosted providers in one policy;
- verify upstream
chain_id, sync state, and block lag before serving traffic; - detect repeated provider-side denial, lag, or method-specific failure and route read traffic to healthier alternatives;
- support optional quorum/compare mode for selected immutable reads, where Fluxheim asks multiple upstreams and only caches/returns data when responses agree;
- keep hosted-provider fallback explicit so Fluxheim does not silently centralize traffic that was meant to stay local.
WebSocket support should be beta after HTTP JSON-RPC caching is stable.
Rules:
eth_subscribesessions are never cacheable.- A WebSocket connection must stay pinned to one upstream.
- If the upstream disconnects, Fluxheim should close the downstream connection rather than silently resubscribe unless an explicit resubscribe policy exists.
- Health and load-balancer state can influence new WebSocket connection placement, not in-flight subscription routing.
The module must include:
- max JSON body size;
- max batch length;
- max method name length;
- max params depth/size where practical;
- method allow/deny lists;
- per-method rate limits where
securityor a future rate-limit module is enabled; - request and response timeout controls;
- response size limit;
- cache-key length and cardinality bounds;
- optional stripping of sensitive request headers before upstream;
- no logging of full request params by default, because params may include addresses, calldata, signatures, or business-sensitive contract state.
Do not expose upstream execution clients directly to arbitrary debug/admin namespaces through a broad allow-list. The default policy should allow only standard public read methods and explicitly selected write methods.
Crypto RPC privacy is a separate problem from caching and load balancing. A normal reverse proxy can hide the user's IP address from the upstream provider, but the gateway itself can still see the requester, method, params, timing, and response unless the design deliberately removes or blinds that information.
Initial privacy-preserving controls should be practical and honest:
- never log full params, responses, calldata, signatures, addresses, or transaction hashes by default;
- strip client-identifying headers before upstream unless explicitly allowed;
- support cache-only answers for finalized/immutable data, where Fluxheim can answer without contacting an upstream for that request;
- provide a privacy mode that rejects non-cacheable or identifying methods rather than forwarding them;
- keep metrics cardinality-safe and avoid labels for addresses, hashes, contracts, ENS names, or raw method params;
- document retention behavior for access logs, traces, cache metadata, and upstream health probes.
"Verifiably anonymized" RPC should remain research/beta until Fluxheim can state and test a real threat model. Candidate future designs:
- blind or relay-based read queries where the public gateway cannot link the external client identity to the upstream query;
- split trust between a privacy relay and a cache/proxy node;
- anonymous credential or token-bucket rate limiting that does not identify the caller to the RPC gateway;
- differential privacy or aggregation for high-level metrics;
- privacy-preserving audit proofs showing that request bodies and identifying headers were not logged.
Fluxheim must not claim that a deployment is fully anonymous merely because it uses multiple upstreams or strips logs. The hard claim is: can the gateway operator, upstream provider, and observers link user, query, timing, and response? Until the answer is defensible, the feature should be documented as privacy-reducing or privacy-preserving, not verifiably anonymous.
eth-verify is a later Ethereum-specific verification track. It should not be
part of the first stable eth cache/proxy release.
Goal: allow Fluxheim to verify selected blockchain-derived data at the edge before returning or caching it. Instead of trusting one RPC provider's response, Fluxheim can fetch proofs, verify them against a trusted block header or light-client state, and then return data with stronger integrity guarantees.
Candidate verification modes:
- Ethereum account/storage proof verification through
eth_getProofusing Merkle-Patricia trie proofs against a known state root. - Receipt or transaction inclusion checks against block bodies/receipts roots where proof material is available and bounded.
- Header verification through an embedded or sidecar light client such as a Helios-style model.
- ZK proof verification for application-specific state claims where a mature verifier and proof format exist.
- Quorum plus proof mode, where Fluxheim compares multiple upstream responses and verifies proof material before cache admission.
Candidate config shape:
[vhosts.eth.verify]
enabled = true
mode = "light-client"
require_proofs_for = ["eth_getProof"]
trusted_checkpoint = "0x..."
max_proof_bytes = "1MiB"
max_verification_time_ms = 50
fail_closed = trueSecurity model:
- Verification must be explicit per method or route.
- Verification failure must default to fail-closed for protected methods.
- Proof size, proof depth, execution time, and cache memory impact must be bounded.
- Verified cache entries must record the verified block hash/number, state root, proof type, and verification policy version.
- Stale light-client checkpoints must make protected verification unavailable rather than silently falling back to provider trust.
- Metrics must report verification result classes without labeling addresses, storage slots, transaction hashes, or raw proof identifiers.
Dependency guidance:
- Do not implement cryptographic proof systems from scratch.
- Prefer mature, reviewed Ethereum/light-client libraries once their license,
advisory, maintenance, and
unsafeprofile are acceptable. - Keep proof engines behind Fluxheim-owned interfaces so
ethcan remain a lightweight RPC cache/proxy wheneth-verifyis not compiled.
Open questions:
- Whether verification should run in-process, in a worker pool, or in a separate sidecar to isolate expensive proof work.
- How to represent verified responses to downstream clients without inventing a misleading trust signal.
- How to combine proof verification with privacy-preserving RPC modes, since proof requests can themselves reveal the queried account/storage key.
- Whether ZK proof verification belongs in
eth-verifyor a later genericproof-verifymodule that can be shared by non-Ethereum chains.
Exit criteria before stable eth-verify:
- Light-client/header trust model is documented and tested.
- Malformed, oversized, deeply nested, and inconsistent proofs fail safely.
- Verification timeout/cancellation is covered by tests.
- Verified cache admission rejects mismatched state roots, wrong block headers, stale checkpoints, and unverified provider responses.
- Default and
eth-only builds prove verification code and dependencies are absent.
Metrics should be cardinality-safe:
- requests by method, vhost, route, result class, and cache outcome;
- upstream health state and block lag;
- retry count and selected retry reason;
- JSON parse failures;
- cache admission/rejection reason;
- WebSocket active sessions, if enabled.
Avoid labels for account addresses, transaction hashes, block hashes, raw contract addresses, or ENS names.
Tracing should record method names and policy decisions only. Full params and responses should be redacted unless an explicit local debug mode is enabled.
Recommended sequence:
- Documentation-only design and config schema stub.
- HTTP JSON-RPC classifier with no caching, only pass-through and metrics.
- Chain health probes and upstream failover for read-only calls.
- Cache key generation and memory/disk cache integration for whitelisted finalized/immutable methods.
- Conservative
eth_getLogssupport with bounded finalized ranges. - WebSocket pass-through and sticky upstream selection as beta.
- Hosted-provider fallback and quota-aware routing.
Exit criteria for stable eth:
- default builds prove
ethis absent; --features ethandprofile-ethereum-rpcbuilds pass;- malformed JSON, oversized batches, unknown methods, and oversized responses are covered by tests;
- cache tests prove
latestandpendingare not stored by default; - finalized/old block responses are cached with stable cache keys;
- transaction submission methods are never retried or cached by default;
- upstream chain-id mismatch rejects traffic before serving requests;
- health probes eject syncing or lagging nodes;
- docs include migration examples for Geth, Erigon, Reth, and hosted fallback.
eth-ens is intentionally separate from eth.
Concept:
- resolve ENS names through the registry/resolver path;
- read
contenthash()records; - decode IPFS, Arweave, or other supported contenthash values;
- proxy to a configured local gateway or redirect to a configured public gateway;
- cache resolver/contenthash answers with TTL and block/finality awareness.
Open design constraints:
- Browsers do not normally resolve raw
.ethnames through DNS. - Public ACME certificates are not issued for raw
.ethnames. - Fluxheim can only route a
.ethhost when traffic reaches Fluxheim with that Host header, or when an operator uses a gateway domain pattern such as{name}.eth.example.test. - ENS resolution adds more dependencies, ABI handling, name normalization, and phishing/confusable-name risks than the basic RPC proxy.
- Gatewaying IPFS/Arweave introduces content-type, range, cache, abuse, and origin-authenticity questions.
For that reason, eth-ens should be reviewed after the eth module is stable.
It should not block the first Ethereum RPC proxy/cache release.
Bitcoin Core also exposes JSON-RPC, so a Fluxheim edge module could proxy,
cache, and health-check selected Bitcoin RPC methods. This should be separate
from eth because Bitcoin's safety model is based on confirmations and chain
depth, not Ethereum's finalized/safe tags.
Potential cacheable candidates:
getblockhash;getblock;getblockheader;getrawtransactionwhen the operator understandstxindexand historical availability;- selected mempool-independent chain metadata.
Default deny/pass-through candidates:
- wallet methods;
- mining/template methods;
- node/admin/network-control methods;
- raw transaction submission unless explicitly enabled and never retried by default.
Open design points:
- confirmation-depth policy for cache admission;
- handling pruned nodes and missing historical data;
- optional ZMQ integration for invalidation or tip tracking;
- authentication to local Bitcoin Core RPC without leaking credentials in logs or metrics.
Cardano support is feasible, but it is not a small variation of Ethereum RPC. Cardano infrastructure commonly exposes Ogmios, cardano-db-sync, GraphQL, Blockfrost/Koios-compatible APIs, or custom provider APIs. Ogmios is the most natural low-level candidate because it exposes a WebSocket JSON interface to Cardano node mini-protocols.
Potential cacheable areas:
- block queries at known chain points;
- transaction lookup;
- protocol parameters at stable epochs;
- selected UTXO queries when tied to a known point.
Open design points:
- chain points, slots, epochs, and rollback handling;
- WebSocket session semantics for Ogmios;
- UTXO-state cache invalidation;
- whether Fluxheim should target Ogmios first or a higher-level provider API.
For that reason, ada should be reviewed after eth proves the shared
chain-edge core abstractions.
XRPL exposes HTTP JSON-RPC and WebSocket APIs and has a useful distinction between current/open ledgers and validated ledgers. That makes it a good future candidate for the chain-edge family, but it should own XRPL-specific method and ledger validation policy.
Potential cacheable candidates:
- ledger lookups for validated ledger indexes;
- transaction lookup in validated ledgers;
- account/object queries pinned to validated ledger indexes.
Default non-cacheable or sticky behavior:
- transaction submission;
- current/open ledger queries;
- WebSocket subscriptions and pushed events.
Open design points:
- validated-ledger health probes;
- sticky WebSocket subscription placement;
- full-history vs non-full-history node behavior;
- preventing account/ledger identifiers from becoming high-cardinality metrics labels.
- Ethereum JSON-RPC API overview: https://ethereum.org/developers/docs/apis/json-rpc/
- Ethereum execution API block tags and
eth_getBlockByNumber: https://ethereum.github.io/execution-apis/api/methods/eth_getBlockByNumber/ - ENS resolver interfaces and
contenthash: https://docs.ens.domains/resolvers/interfaces/ - ENS decentralized website hosting: https://docs.ens.domains/dweb/intro/
- ENS public resolver and EIP-1577 contenthash support: https://docs.ens.domains/resolvers/public/