Polygon RPC latency is often caused by the dual-layer Bor/Heimdall architecture, archive node data volume, and expensive queries like eth_getLogs over wide ranges. This article explains the mechanics, provides a reproducible benchmark script, and offers a decision tree for moving from shared to dedicated infrastructure.
Direct Answer: Why Polygon RPC Feels Slow
If your Polygon RPC calls feel slow, the cause is usually one of three things: the node you are hitting is overloaded (shared endpoint), your query is expensive (e.g., eth_getLogs over a wide block range), or the node is an archive node that must read from disk. Polygon's architecture—Bor (EVM) and Heimdall (Tendermint-based)—adds an extra layer of block finality checks that can increase response times for certain methods. In this guide, we'll break down the mechanics, show you how to measure latency with a simple script, and give you a decision tree for when to move from a shared to a dedicated Polygon node.
The most common culprit is not the network itself but the query pattern. For example, eth_getLogs with a range of 100,000 blocks can take seconds or even minutes on a shared node. Similarly, eth_call that simulates complex contract interactions can be CPU-intensive. Understanding these factors is the first step to fixing slow RPC responses.
- Bor (EVM) processes transactions and smart contracts; Heimdall handles checkpoints and syncs with Ethereum.
- Archive nodes store all historical state, making queries like
eth_getBalanceat old blocks slower. - Shared endpoints are subject to rate limiting and noisy neighbors, causing variable latency.
- Heavy methods like
eth_getLogs,eth_call, andeth_estimateGasare the most likely to be slow.
Polygon Architecture: Bor and Heimdall
Polygon PoS runs two layers: Bor (the block producer layer, an EVM-compatible chain) and Heimdall (the validator layer, based on Tendermint). Heimdall periodically commits checkpoints to Ethereum, and Bor produces blocks. When you send an RPC request, it goes to a Bor node, which may need to consult Heimdall for finality information. This adds a small overhead compared to a single-layer chain like Ethereum.
For most RPC methods (e.g., eth_blockNumber, eth_getBalance), the latency is dominated by the node's database and CPU. However, methods that require state access (like eth_call) or log filtering (eth_getLogs) are more expensive. The Polygon technology documentation provides details on the architecture, but the key takeaway is that Bor nodes are not optimized for heavy analytical queries.
Additionally, if you are using a public RPC endpoint, you are sharing resources with many other users. A single heavy query from another user can degrade performance for everyone. This is why dedicated nodes are often recommended for production workloads.
Archive vs. Full Nodes: The Data Factor
Polygon offers both full nodes (which prune historical state) and archive nodes (which store all state). Archive nodes are necessary for queries that access historical data, such as eth_getBalance at an old block number or eth_getLogs for past events. However, archive nodes have much larger disk I/O requirements, which can increase latency for every request.
If your application only needs recent data, a full node is faster and cheaper. But if you need to query historical state, you must use an archive node. On shared endpoints, you often don't know which type you are hitting, and the provider may route you to an archive node by default, adding unnecessary overhead.
When benchmarking, always check the node type. You can do this by calling eth_getBalance at a very old block and comparing the response time to a recent block. If the old block is significantly slower, you are likely on an archive node.
- Full nodes prune state older than a certain threshold (e.g., 128 blocks).
- Archive nodes store all state, enabling historical queries but increasing disk I/O.
- For production, choose the node type based on your query patterns.
Heavy Queries: eth_getLogs, eth_call, and More
The most common cause of slow Polygon RPC responses is the query itself. eth_getLogs is notorious for being slow when you request logs over a wide block range or with complex filter topics. The node must scan every block in the range and match the filter, which is CPU and I/O intensive. Similarly, eth_call executes a smart contract function without creating a transaction, and if the function is complex (e.g., a loop over many storage slots), it can take seconds.
eth_estimateGas is also expensive because it simulates the transaction. And fetching many confirmations (e.g., waiting for 10 or more blocks) can make your application feel slow, even if the RPC itself is fast. The fix is to optimize your query patterns: limit block ranges, use pagination, and cache results.
For example, instead of calling eth_getLogs for a range of 100,000 blocks, break it into smaller ranges (e.g., 10,000 blocks) and process them in parallel. This reduces the load on the node and improves overall throughput.
- eth_getLogs: use smaller block ranges and specific topics to reduce scan time.
- eth_call: avoid complex functions that loop over large arrays.
- eth_estimateGas: use it sparingly; consider using a fixed gas limit for simple transactions.
- Confirmations: wait for only the required number of blocks (e.g., 2-3 for most use cases).
How to Measure Polygon RPC Latency: A Reproducible Script
To diagnose slow RPC, you need to measure it. Below is a bash script that uses curl and time to benchmark three common methods: eth_blockNumber, eth_getBalance, and eth_getLogs. It outputs the time taken for each call. Run it against your endpoint to get a baseline.
The script is self-contained and uses standard tools. Replace YOUR_RPC_URL with your endpoint. It will print the response and the elapsed time in seconds. For eth_getLogs, it uses a range of 1000 blocks, which is moderate; adjust as needed.
#!/bin/bash
# Polygon RPC Latency Benchmark
# Usage: ./benchmark.sh <RPC_URL>
RPC_URL=${1:?Usage: $0 <RPC_URL>}
# Function to time a JSON-RPC call
time_call() {
local method=$1
local params=$2
local start=$(date +%s%N)
local response=$(curl -s -X POST -H "Content-Type: application/json" \
--data "{\"jsonrpc\":\"2.0\",\"method\":\"$method\",\"params\":$params,\"id\":1}" \
$RPC_URL)
local end=$(date +%s%N)
local elapsed=$(echo "scale=3; ($end - $start) / 1000000000" | bc)
echo "$method: $elapsed seconds"
echo "Response: $response"
echo "---"
}
# 1. eth_blockNumber (lightweight)
time_call "eth_blockNumber" "[]"
# 2. eth_getBalance for a known address at latest block (state access)
# Use a popular address like Vitalik's (0x...)
time_call "eth_getBalance" "[\"0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B\",\"latest\"]"
# 3. eth_getLogs for a range of 1000 blocks (heavy)
# Replace contract address and topics as needed; here we use a dummy filter
time_call "eth_getLogs" "[{\"fromBlock\":\"0x1\",\"toBlock\":\"0x3e8\",\"address\":\"0x0000000000000000000000000000000000000000\"}]"Expected Results and How to Verify
When you run the script, you should see that eth_blockNumber is the fastest (typically under 100 ms on a healthy node), eth_getBalance is slightly slower (100-300 ms), and eth_getLogs is the slowest (can be seconds). These are not official benchmarks; they are illustrative. You should run the script multiple times and at different times of day to get a sense of variability.
To verify if your node is the bottleneck, compare the results against a known fast endpoint, such as the OnFinality Polygon network page or a public endpoint. If your endpoint is consistently slower, it may be overloaded or misconfigured. Also, check the node's sync status: if it is not fully synced, it may return errors or slow responses.
For eth_getLogs, if the response time is proportional to the block range, that's expected. If it's disproportionately slow, the node might be an archive node or have disk I/O issues. You can also test with a smaller range (e.g., 100 blocks) to see the baseline.
- Run the script 5 times and take the median to reduce noise.
- Compare against a public endpoint like https://polygon-rpc.com (but note it may be rate-limited).
- Check the node's sync status with
eth_syncing; if it returns true, the node is not ready.
Common Failures and Fixes
If your eth_getLogs call times out, it's often because the block range is too large. The fix is to reduce the range or use pagination. Some providers have a maximum range (e.g., 10,000 blocks); check your provider's documentation. If you need logs over a long period, consider using an indexing service like The Graph or a custom indexer.
Another common issue is rate limiting on shared endpoints. If you see HTTP 429 errors, you are being throttled. The fix is to either reduce your request rate or move to a dedicated node. OnFinality's API service offers higher rate limits and dedicated options.
For eth_call, if you get an error like "execution reverted", it's not a latency issue but a contract logic issue. However, if the call takes too long, it might be because the contract is doing heavy computation. In that case, consider using a static call with a gas limit or optimizing the contract.
Finally, if you are fetching many confirmations (e.g., 20 blocks), your application will feel slow even if the RPC is fast. Reduce the number of confirmations to the minimum required for your security model.
- Timeout on eth_getLogs: reduce block range or use pagination.
- HTTP 429: implement backoff or upgrade to a dedicated node.
- eth_call reverts: check contract logic, not RPC latency.
- High confirmations: lower the threshold to improve perceived speed.
Tradeoffs and Limitations
While moving to a dedicated node can reduce latency, it comes with costs and operational overhead. You are responsible for keeping the node synced, monitoring its health, and scaling it as your traffic grows. OnFinality offers managed dedicated nodes that handle these tasks, but you should evaluate the tradeoff between cost and performance.
Also, note that even a dedicated node can be slow if your queries are inefficient. Optimizing your query patterns is often more effective than upgrading hardware. For example, caching eth_getBalance results for a short period can dramatically reduce load.
Finally, latency is not the only metric to consider. Reliability and uptime are equally important. A fast node that goes down frequently is worse than a slower but stable one. Use a provider with a good SLA, like OnFinality's pricing page shows.
- Dedicated nodes cost more but offer consistent performance.
- Query optimization can reduce latency without changing infrastructure.
- Consider reliability and uptime alongside latency.
Next Steps and Further Reading
Now that you understand the causes of Polygon RPC latency, you can take action. Start by benchmarking your current endpoint, then optimize your queries. If you still see issues, consider moving to a dedicated node.
For more in-depth guidance, check out our general RPC latency fixes article, which covers techniques applicable to any chain. You can also explore the OnFinality learn hub for more tutorials. If you're ready to upgrade, visit our pricing page to see dedicated node options.
Remember, the key to low latency is a combination of good infrastructure and efficient queries. By following the steps in this article, you can ensure your Polygon RPC calls are as fast as possible.