Add proxy routing mode for blockchain APIs - #352
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a configurable routing strategy to the blockchain RPC client so chain families can either use the existing per-chain node pools or route all calls through a single proxy endpoint (with the chain identifier appended to the URL).
Changes:
- Introduces
RoutingMode<C, V>and replacesBlockchainClient’s per-chain selector +max_retriesfields with a singleroutingfield. - Updates EVM and Solana client call sites to use the new
execute_rpc_call(identifier, ...)API. - Updates node-selection documentation and provides updated TOML examples for the new routing schema.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| runtime/plaid/src/apis/blockchain/common/mod.rs | Adds RoutingMode, updates config schema, and refactors execute_rpc_call to dispatch based on routing mode. |
| runtime/plaid/src/apis/blockchain/evm/mod.rs | Updates EVM RPC methods to call the new execute_rpc_call signature. |
| runtime/plaid/src/apis/blockchain/solana/mod.rs | Updates Solana RPC methods to call the new execute_rpc_call signature and adjusts tests for the new config shape. |
| runtime/plaid/src/apis/blockchain/common/node_selection.rs | Documents sticky RoundRobin behavior (advance index only on failure). |
| runtime/plaid/resources/jrp_config/apis.toml | Updates example configuration to the new routing schema and adds proxy-mode examples. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Suppressed comments (1)
runtime/plaid/src/apis/blockchain/common/mod.rs:260
- Proxy routing builds the RPC URL via string concatenation (
format!("{}/{identifier}", url.as_str().trim_end_matches('/'))), which can produce invalid URLs (e.g., if the base URL contains a query/fragment) and does not percent-encode the identifier as a path segment. Prefer usingUrlAPIs to append a path segment safely.
RoutingMode::Proxy { url } => {
// Append the chain identifier as a path segment
let rpc = format!("{}/{identifier}", url.as_str().trim_end_matches('/'));
trace!(
"RPC call [{}] via proxy on behalf of module [{module}]",
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Suppressed comments (2)
runtime/plaid/src/apis/blockchain/common/mod.rs:259
- Building the proxy RPC URL via string concatenation can produce an invalid endpoint when the base URL contains a query/fragment (e.g.
https://proxy?token=xbecomeshttps://proxy?token=x/<id>), and it also skips percent-encoding the identifier as a path segment. UseUrlpath segment manipulation instead so the identifier is appended in the path correctly.
RoutingMode::Proxy { url } => {
// Append the chain identifier as a path segment
let rpc = format!("{}/{identifier}", url.as_str().trim_end_matches('/'));
trace!(
runtime/plaid/src/apis/blockchain/common/mod.rs:294
- If
max_retriesis configured as 0, the retry loop never runs and the call fails immediately withAllNodesFailedwithout attempting any node. Clamp to at least 1 attempt (or reject 0 at config load) to avoid this surprising behavior.
let mut last_error = BlockchainError::AllNodesFailed;
for attempt in 1..=*max_retries {
let Some(node) = selector.select_node() else {
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Suppressed comments (1)
runtime/plaid/src/apis/blockchain/common/mod.rs:273
- Proxy routing builds the RPC URL via string concatenation (
format!("{}/{identifier}", url.as_str().trim_end_matches('/'))), which does not percent-encode the identifier as a path segment and will also produce an invalid URL if the configured base URL includes a query or fragment (the identifier gets appended after?…). Sinceurlis already aUrl, construct the request URL by mutating path segments on a clonedUrland passrpc_url.as_str()to the request executor.
RoutingMode::Proxy { url } => {
// Append the chain identifier as a path segment
let rpc = format!("{}/{identifier}", url.as_str().trim_end_matches('/'));
trace!(
"RPC call [{}] via proxy on behalf of module [{module}]",
Summary
Introduces a
RoutingModeenum for the blockchain RPC client that supports two mutually exclusive routing strategies: per-chain node pools (the existing behavior) and a single proxy endpoint. In proxy mode, every chain routes through one URL with the chain identifier appended as a path segment, so arbitrary chain IDs work without per-chain configuration.Changes
RoutingMode<C, V>enum inruntime/plaid/src/apis/blockchain/common/mod.rswithNodesandProxyvariants, deserialized via atypetag.BlockchainClient.node_selectorandmax_retriesfields with a singleroutingfield.get_node_selector;execute_rpc_callnow dispatches on routing mode.deserialize_chainsto be generic over value type and added adeserialize_urlhelper.node_selection.rs.runtime/plaid/resources/jrp_config/apis.tomlto the newroutingschema and added commented proxy-mode examples for EVM and Solana.Rationale
Proxy mode removes the need to enumerate every chain and its node pool, which is impractical when supporting arbitrary chain identifiers. Keeping node mode as the default preserves existing behavior and avoids forcing a migration on users who manage their own node pools.
Breaking Changes
chainsandmax_retriesare replaced by aroutingblock withtype = "nodes"(per-chainchainsandmax_retriesnested inside) ortype = "proxy"with aurl. Existing configs must be updated to the new structure.