Maximizing Performance — A Guide to Efficient RPC Requests with BlockEden.xyz
BlockEden.xyz gives you high‑throughput, multi‑chain RPC endpoints backed by a 99.9% SLA and a transparent Compute Unit (CU) pricing model. This guide distills proven techniques for lighter, faster, and cheaper calls so your dApp can scale without surprises.
1. Make the Right Call
Choosing the correct method and environment from the start is the most effective way to manage costs and performance. Before writing a single line of code, strategize your approach.
Know Each Method’s CU Cost
Every RPC method consumes a predetermined number of Compute Units (CUs). Heavy queries, such as historical log fetching with eth_getLogs
or account scanning with Solana's getProgramAccounts
, are significantly more expensive than simple state reads like eth_getBalance
.
Before implementing a feature, consult the Pricing page to understand the cost of each call. This allows you to budget your CU usage accurately and architect your application to favor more efficient methods, preventing unexpected bills as you scale.
Pick the Smallest Tool for the Job
Not every task requires a full node's power. Using the most direct and specialized tool for your data needs can dramatically reduce overhead.
- REST or GraphQL First: When you only need indexed or aggregated data (e.g., a user's token balances or transaction history), use BlockEden’s REST or GraphQL APIs. These are optimized for querying and are far more efficient than making multiple raw JSON-RPC calls and processing the results client-side.
- Use Chain-Specific SDKs: Prefer high-level Software Development Kits (SDKs) like
sui-ts-sdk
oraptos-sdk
over raw JSON-RPC requests where possible. These libraries often bundle multiple RPC calls into a single, optimized function, handle state management, and abstract away much of the complexity, leading to cleaner code and fewer requests.
Match Network and Environment
Maintain separate API keys for your mainnet, testnet, and staging environments. This simple practice offers critical benefits:
- Clean Logs: It keeps your production logs free from development and testing noise.
- Isolated Quotas: Rate limits and CU quotas for one environment won't impact another. A test script gone rogue won't throttle your production dApp.
- Enhanced Security: You can apply stricter security policies (like IP whitelisting) to your production key.
2. Optimise Every Request
Once you've chosen the right method, fine-tune the request itself to minimize its footprint. A well-crafted request is smaller, faster, and cheaper.
Filter Early and Aggressively
Always provide the most specific filters possible in your request parameters. Instead of fetching a large dataset and filtering it on the client, let the node do the work. This reduces data transfer, client-side memory usage, and CU consumption.
- For EVM chains: When using
eth_getLogs
, always specify a tight block range usingfromBlock
andtoBlock
. - For Solana: Use
memcmp
ordataSlice
filters withgetProgramAccounts
to narrow down results on the server.
Paginate and Chunk Large Scans
Never attempt to fetch unbounded data in a single request. Operations like crawling all NFTs in a collection, fetching a complete transaction history, or querying large tables over Aptos GraphQL must be broken into smaller pieces. Use pagination parameters like page
/limit
or cursor
/offset
to retrieve data in manageable chunks. This makes memory usage predictable and prevents request timeouts.
Cache Where Freshness Isn’t Critical
Many types of on-chain data change infrequently. Caching this data can eliminate a huge number of redundant RPC calls. Good candidates for caching include:
- Token metadata (name, symbol, decimals)
- Contract ABIs
- Resolved ENS names
Use a caching layer like Redis, Memcached, or even a simple in-browser localStorage
solution. Set a reasonable Time-to-Live (TTL) and consider invalidating the cache based on new block headers for a balance of freshness and performance.
Batch with Care
While JSON-RPC batching can reduce network round-trip latency by bundling multiple requests into one HTTP call, it's not a silver bullet. All requests in a batch are processed together, and the entire batch is blocked until the slowest request completes. Furthermore, each sub-call still consumes CUs individually.
For most read-heavy EVM workloads, opening parallel, single-shot requests over a persistent keep-alive connection often yields better overall throughput than batching. Always measure the performance of both approaches for your specific use case before committing to one.
3. Move from Polling to Push
Constantly asking "is it there yet?" is inefficient. A push-based model, where the server notifies you of changes, is superior for real-time applications.
WebSocket Subscriptions
Instead of polling a method like getEvents
or eth_getBlockByNumber
in a setInterval
loop, use WebSocket (WSS) endpoints. BlockEden exposes WSS for chains like Sui, Ethereum, and more. You can subscribe to new blocks, pending transactions, or specific log events. The server will push updates to your client as they happen, resulting in lower latency, reduced CU usage, and a more responsive user experience.
Streams (Early Access)
For advanced use cases requiring filtered, multi-chain, and cross-account data feeds, consider BlockEden Streams. This beta product delivers customized real-time data directly to your application over HTTP/2 server-push, abstracting away the complexity of managing multiple WebSocket connections. Join the beta to build sophisticated real-time monitoring and notification systems.
4. Handle Responses Robustly
A resilient dApp anticipates and gracefully handles network and service issues.
Treat HTTP Status ≠ 200 as Fatal
While most JSON-RPC errors are returned in the response body with an HTTP 200 OK
status, you must also handle transport-level errors. Any response with a 4xx
or 5xx
status code (e.g., 503 Service Unavailable
) indicates a problem with the request or the service itself. Treat these as fatal errors and trigger a retry mechanism, preferably with an exponential backoff delay to avoid overwhelming the service.
Respect CU Throttling
Your API key has a CU quota that resets every second. If you exceed this budget, the API will respond with an HTTP 429 Too Many Requests
status code. The response will also include a Retry-After
header indicating how many seconds to wait before sending another request. Your application logic must respect this header and pause accordingly. Continuously spamming an endpoint after being throttled can lead to temporary IP blocks.
Circuit-Break Long Outages
If your application experiences several consecutive failed requests to an endpoint, it's wise to implement a circuit breaker pattern. After N failures, the "breaker" trips, and your application stops trying to contact the service for a set period. This prevents your dApp from becoming stuck or unresponsive during a service outage and protects the user's wallet and experience.
5. Rate-Limit from the Client Side
A proactive way to avoid 429
errors is to implement client-side rate limiting. This simple sliding-window limiter in TypeScript ensures you stay within your CU budget.
const WINDOW_MS = 1000; // 1-second window
const CU_BUDGET = 300; // Example: Free tier burst budget
let spentCUs = 0;
// Reset the spent CUs at the start of each window
setInterval(() => (spentCUs = 0), WINDOW_MS);
/**
* A simple delay helper function.
* @param ms Milliseconds to wait.
*/
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
/**
* Wraps an RPC call to ensure it respects the CU budget.
* @param rpcFn A function that executes an RPC call and returns its CU cost.
*/
export async function safeRpcCall(rpcFn: () => Promise<number>) {
// The estimated cost of the function to be called
const estimatedCost = await rpcFn();
// If the call would exceed the budget, wait for the next window
if (spentCUs + estimatedCost > CU_BUDGET) {
await delay(WINDOW_MS);
}
// Increment the spent CUs for the current window
spentCUs += estimatedCost;
}
6. Secure Your Endpoint
Your API key is a credential. Protect it accordingly.
- Never Commit Keys to Git: Store API keys in environment variables (
.env
files) or a secrets management service (like AWS Secrets Manager or HashiCorp Vault). Use libraries likedotenv
to load them into your application at runtime. - Use Whitelists: In the BlockEden Dashboard, navigate to the Security tab for your key. Configure referrer whitelists for front-end applications and IP address whitelists for back-end services. This is a powerful and easy way to block unauthorized use of your key.
- Rotate Keys Periodically: Make key rotation a part of your regular maintenance or release cycle. If a key is ever compromised, you can quickly disable the old one and deploy a new one with minimal downtime.
7. Monitor & Iterate
You can't optimize what you can't measure. Use the tools at your disposal to keep an eye on performance and cost.
- Dashboard V3: The BlockEden Dashboard provides detailed analytics for each of your API keys. Check it weekly to monitor per-method CU consumption, p95 latency, and error rates. This is the best way to catch abnormal spikes in usage or performance regressions before they become major problems.
- Status Page: Subscribe to status.blockeden.xyz for real-time incident alerts and maintenance notifications. This allows you to be proactive and inform your users of any potential service degradation.
Quick Examples
Here are a few basic examples to get you started.
cURL (Ethereum Mainnet)
A simple eth_blockNumber
request using cURL.
curl -X POST https://api.blockeden.xyz/eth/mainnet/<API_KEY> \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'
Node.js (Sui)
Using the @mysten/sui.js
SDK to fetch objects owned by a wallet.
import { SuiClient } from '@mysten/sui.js/client';
const SUI_RPC_URL = 'https://api.blockeden.xyz/sui/mainnet/<API_KEY>';
const WALLET_ADDRESS = '0x...'; // Replace with the target wallet address
const client = new SuiClient({ url: SUI_RPC_URL });
async function getWalletObjects() {
try {
const objects = await client.getOwnedObjects({ owner: WALLET_ADDRESS });
console.log(objects);
} catch (error) {
console.error('Failed to fetch owned objects:', error);
}
}
getWalletObjects();
Wrap-Up
Efficient RPC usage is half art, half discipline. By internalizing these best practices, you can build dApps that are fast, economical, and dependable.
- Trim the payload.
- Reuse connections.
- Push events instead of polling.
- Watch your CU burn.
Follow the practices above and your BlockEden.xyz endpoints will stay fast, economical, and reliable as traffic climbs. For deeper questions, reach us on Discord or at hello@blockeden.xyz.