Invictus RPC is a reverse proxy for Ethereum/EVM RPC providers, that aims to provide a single resilliant endpoint that aggregates multiple providers, and allows failover and quorum.
Originally discussed in this issue which outlines it's goals and requirements.

Configuration looks like this:
{
"check_interval_seconds": 30,
"networks": {
"ethereum": {
"chain_id": 1,
"providers": [
{ "url": "https://eth.llamarpc.com", "priority": 2, "tiebreak_weight": 1 }
],
"block_majority_divider": 1
}
}
}
The configuration is dynamically loaded from the main branch of this repo. In case this fails, we fallback to the configuration file as of when the binary of invictus-rpc was built.
Priority match allows you to set a higher/lower priority for a provider if the request body string matches a certain sub-string.
For example, in providers:
{ "url": "https://eth.best-logs-provider.com", "priority_match": { "eth_getLogs": 99 }, "priority": 2, "tiebreak_weight": 1 }
On the top level of the config, you can provide an array of strings:
"inner_errors": [
"\"error\":{\"code\":-32601",
"\"error\":{\"code\":-32603",
"\"error\":{\"code\":-32000",
"\"we can't execute this request\""
],
If any of those are detected in the first 1024 bytes of the response body string and there are remaining retries, we will fallback to another provider.
All providers are periodically checked for quorum - only the ones in the quorum are considered for serving each request. From those, we take the ones with the highest priority, and if there's more than 1 with the highest priority, we choose randomly based on tiebreak_weight (which defaults to 1). For example, if there are 5 providers, but one is down, 4 will be considered. Let's say that two of them have the highest priority - they will serve all the requests, but one has tiebreak_weight of 2, the other the default of 1, so the first one will serve 2x more requests than the other.
This system allows us to fine-tune almost everything: we can implement fallback, but we can prioritize specific providers and load-balance at the same time.
tiebreak_weightrpc_getBlock (what we use to determine quorum), it can still be excluded if it's failing often (FailingOften); furthermore, once a provider fails during the quorum selection once, it can be, based on configuration, excluded from the next N quorum selections (FailedRecently); if a provider frequently returns a good response but is at a different block than the quorum, it will be excluded from selection for some time as wellFor chains with quick block times, please do not add more than 2 RPC providers. The reason for this is that with more than 2, they can all be at different blocks, leading to an inability to reach consensus. In case we can't reduce them to 2, 4 is better than 3 because it's more likely that at least 2 will be on the same block.
NOTE: we fixed this with the quorum fallback mode, but it's still a good practice to avoid 3 and either use 2 or 4.
When Invictus starts, there's a small period of time during which it might respond with "no quorum for network" - this only happens if it takes more than 10 seconds to get a quorum for a network OR if there's legitimately no good quorum for the network (all providers down).
Theoretically, the first case should never hapepn because each provider check is limited to 7 seconds.
/:network: JSON-RPC proxy for the given network. For example, https://invictus.ambire.com/ethereum is an Ethereum JSON-RPC proxy/:network/get/:method/:params: proxy for the given network but JSON-RPC requests are encoded entirely in the URL/:network/status: show the configuration and current quorum for the underlying providers for the given network/:network/configuratione-reficite: hot reload of the configuration; this will immediately re-set the quorum based on the new config/picturam: return global data structure of current invictus instanceThere are many reasons to exclude an RPC:
FailedRecently)FailingOften)FailingOften)curl 'http://localhost:1337/ethereum/get/eth_getBalance/\["0x77777777789A8BBEE6C64381e5E89E501fb0e4c8","latest"\]' | jq
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x66f1b821a9adda16"
}
curl -H "Content-Type: application/json" --data "{\"jsonrpc\":\"2.0\",\"method\":\"net_version\",\"params\":[],\"id\":1}" http://localhost:1337/ethereum
NOTE: this is a bit fiddly because the URL has to be correct, for example no whitespaces are allowed
NOTE: In GET mode, it's easier too pass invalid JSON. In this case, Ankr returns good feedback (tells you what's wrong about the JSON), while Infura/Alchemy do not (just say invalid JSON). Llama RPC returns feedback but not in JSON form.
Receipts:
cargo test --test receipt_checks -- --ignored --nocapture
Content type
Image
Digest
sha256:528e81fe6…
Size
920.5 MB
Last updated
1 day ago
docker pull adexnetwork/invictus-rpc