Networks
A network represents a chain (e.g., evm, solana, etc), and it is a logical grouping of upstreams.
Upstreams are configured separately, and on the first request to a network, the eRPC will automatically find any upstream that support that network.
You can configure failover behavior per network as follows:
projects:
- id: main
# (OPTIONAL) This array configures network-specific (a.k.a chain-specific) features.
# For each network "architecture" and corresponding network id (e.g. evm.chainId) is required.
# You don't need to define networks as they will be automatically detected from configured endpoints (lazy-loaded).
# Only provide network list if you want to customize features such as failsafe policies, rate limit budget, finality depth, etc.
networks:
- architecture: evm
# (OPTIONAL) When "evm" is used, "chainId" is required, so that rate limit budget or failsafe policies are properly applied.
evm:
# (REQUIRED) chainId is required when "evm" architecture is used.
chainId: 1
# (OPTIONAL) fallbackFinalityDepth is optional and allows to manually set a finality depth in case upstream does not support eth_getBlockByNumber(finalized).
# In case this fallback is used, finalized block will be 'LatestBlock - fallbackFinalityDepth'.
# Defining this fallback helps with increasing cache-hit rate and reducing redundant 'retry' attempts on empty responses, as we know which data is finalized.
# DEFAULT: auto-detect - via eth_getBlockByNumber(finalized).
fallbackFinalityDepth: 1024
# (OPTIONAL) Refer to "Selection Policy" section for more details.
# Here are default values used for selectionPolicy if not explicitly defined:
selectionPolicy:
# Every 1 minute evaluate which upstreams must be included,
# based on the arbitrary logic (e.g., <90% error rate and <10 block lag):
evalInterval: 1m
# To isolate selection evaluation and result to each "method" separately change this flag to true
evalPerMethod: false
# Freeform TypeScript-based logic to select upstreams to be included by returning them:
evalFunction: |
(upstreams, method) => {
const defaults = upstreams.filter(u => u.config.group !== 'fallback')
const fallbacks = upstreams.filter(u => u.config.group === 'fallback')
// Maximum allowed error rate.
const maxErrorRate = parseFloat(process.env.ROUTING_POLICY_MAX_ERROR_RATE || '0.7')
// Maximum allowed block head lag.
const maxBlockHeadLag = parseFloat(process.env.ROUTING_POLICY_MAX_BLOCK_HEAD_LAG || '10')
// Minimum number of healthy upstreams that must be included in default group.
const minHealthyThreshold = parseInt(process.env.ROUTING_POLICY_MIN_HEALTHY_THRESHOLD || '1')
// Filter upstreams that are healthy based on error rate and block head lag.
const healthyOnes = defaults.filter(
u => u.metrics.errorRate < maxErrorRate && u.metrics.blockHeadLag < maxBlockHeadLag
)
// If there are enough healthy upstreams, return them.
if (healthyOnes.length >= minHealthyThreshold) {
return healthyOnes
}
// If there are fallbacks defined, try to use them
if (fallbacks.length > 0) {
// Apply same health filtering as default rpcs
let healthyFallbacks = fallbacks.filter(
u => u.metrics.errorRate < maxErrorRate && u.metrics.blockHeadLag < maxBlockHeadLag
)
// If there are healthy fallbacks use them
if (healthyFallbacks.length > 0) {
return healthyFallbacks
}
}
// The reason all upstreams are returned is to be less harsh and still consider default nodes (in case they have intermittent issues)
// Order of upstreams does not matter as that will be decided by the upstream scoring mechanism
return upstreams
}
# When an upstream is excluded, you can give it a chance on a regular basis
# to handle a certain number of sample requests again, so that metrics are refreshed.
# For example, to see if error rate is improving after 5 minutes, or still too high.
# This is conceptually similar to how a circuit-breaker works in a "half-open" state.
# Resampling is not always needed because the "evm state poller" component will still make
# requests for the "latest" block, which still updates errorRate.
resampleExcluded: false
resampleInterval: 5m
resampleCount: 10
# (OPTIONAL) A network-level rate limit budget applied to all requests despite upstreams own rate-limits.
# For example even if upstreams can handle 1000 RPS, and network-level is limited to 100 RPS,
# the request will be rate-limited to 100 RPS.
rateLimitBudget: my-limiter-budget
# (OPTIONAL) Refer to "Failsafe" section for more details.
# Here are default values used for networks if not explicitly defined:
failsafe:
timeout:
# On network-level "timeout" is applied for the whole lifecycle of the request (including however many retries happens on upstream)
duration: 30s
retry:
# It is recommended to set a retry policy on network-level to make sure if one upstream is rate-limited,
# the request will be retried on another upstream.
maxAttempts: 3
delay: 100ms
jitter: 0ms
backoffMaxDelay: 1s
backoffFactor: 1.5
# Defining a "hedge" is highly-recommended on network-level because if upstream A is being slow for
# a specific request, it can start a new parallel hedged request to upstream B, for whichever responds faster.
hedge:
delay: 200ms
maxCount: 3
upstreams:
# Refer to "Upstreams" section to learn how to configure upstreams.
# ...
# ...
Default config and lazy-loading
Networks are lazy-loaded on first request for a network (if not explicitly defined in config). You can configure "networkDefaults" to set default values for all networks (both static or lazy-loaded):
projects:
- id: main
networkDefaults:
# (OPTIONAL) A network-level rate limit budget applied to all requests despite upstreams own rate-limits.
# For example even if upstreams can handle 1000 RPS, and network-level is limited to 100 RPS,
# the request will be rate-limited to 100 RPS.
# Defaults to no rate limit budget.
rateLimitBudget: "my-default-budget"
# (OPTIONAL) Refer to "Failsafe" section for more details.
# https://docs.erpc.cloud/config/failsafe
# If a network has its own failsafe defined, it will not take any of policies from networkDefaults.
# i.e. if network has only "timeout" policy, it will NOT get hedge/retry from networkDefaults (those will be disabled).
# Here are default values used for networkDefaults if not explicitly defined:
failsafe:
timeout:
duration: "30s"
hedge:
delay: "200ms"
maxCount: 3
retry:
maxAttempts: 3
delay: "100ms"
jitter: "0ms"
backoffMaxDelay: "1s"
backoffFactor: 1.5
# (OPTIONAL) Refer to "Selection Policy" section for more details about default values.
# https://docs.erpc.cloud/config/projects/selection-policies#config
selectionPolicy:
#...
# (OPTIONAL) Default directives to apply to all requests for this network.
# These can be overridden by request-specific directives via HTTP headers or query parameters.
# See https://docs.erpc.cloud/operation/directives for more details about each directive.
directiveDefaults:
retryEmpty: true # OPTIONAL (default: true)
retryPending: false # OPTIONAL (default: false)
skipCacheRead: false # OPTIONAL (default: false)
useUpstream: "alchemy-*|localnode-*" # OPTIONAL (default: *)
# (OPTIONAL) List of customizations per network if needed can be defined as usual:
# For each static network, first networkDefaults will be applied (deep object merge),
# then network-specific overrides can be applied.
networks:
# ...
If a network has its own failsafe:
defined, it will not take any of policies from networkDefaults.
e.g. if a network only has "timeout" policy, it will NOT get hedge/retry from networkDefaults (those will be disabled).
Architectures
evm
This type of network are generic EVM-based chains that support JSON-RPC protocol.
Roadmap
On some doc pages we like to share our ideas for related future implementations, feel free to open a PR if you're up for a challenge:
- Add support for more architectures (Solana, etc)