Skip to content

Rpc_nodes

RPC Nodes (Remote Procedure Call nodes) are specialized blockchain nodes that expose APIs for external applications to interact with the blockchain. Understanding RPC nodes is essential as they’re commonly used in production environments.


An RPC node is a full node that provides API endpoints for:

┌─────────────────────────────────────────────────────────────────────────────┐
│ RPC NODE FUNCTION │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ External Applications │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ dApp │ │ Wallet │ │ Explorer│ │Trading │ │ Bot │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │ │ │
│ └─────────────┴─────────────┴─────────────┴─────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ RPC NODE │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ JSON-RPC │ │ WebSocket │ │ REST API │ │ │
│ │ │ Server │ │ Server │ │ Server │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │
│ │ │ │ │ │ │
│ │ └────────────────┼────────────────┘ │ │
│ │ ▼ │ │
│ │ ┌─────────────┐ │ │
│ │ │ Full Node │ │ │
│ │ │ (Execution) │ │ │
│ │ └──────┬──────┘ │ │
│ └───────────────────────────┼────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ P2P NETWORK │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Use CaseDescription
dAppsConnect frontend to blockchain
WalletsQuery balances, broadcast transactions
ExplorersDisplay transaction history
Trading BotsExecute automated trades
AnalyticsTrack on-chain metrics

JSON-RPC is a stateless, lightweight remote procedure call (RPC) protocol for JSON-encoded messages.

{
"jsonrpc": "2.0",
"method": "method_name",
"params": ["param1", "param2"],
"id": 1
}
{
"jsonrpc": "2.0",
"result": "returned_value",
"id": 1
}
{
"jsonrpc": "2.0",
"error": {
"code": -32600,
"message": "Invalid Request"
},
"id": 1
}

┌─────────────────────────────────────────────────────────────────────────────┐
│ ETHEREUM JSON-RPC METHODS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ BLOCKS & HEADERS │
│ ────────────────────────────────────────────────────────────────────── │
│ eth_blockNumber → Get latest block number │
│ eth_getBlockByNumber → Get block by number │
│ eth_getBlockByHash → Get block by hash │
│ eth_getBlockTransactionCountByNumber → Count txs in block │
│ │
│ TRANSACTIONS │
│ ────────────────────────────────────────────────────────────────────── │
│ eth_sendRawTransaction → Broadcast signed transaction │
│ eth_getTransactionByHash → Get transaction by hash │
│ eth_getTransactionReceipt → Get transaction receipt │
│ eth_estimateGas → Estimate gas needed │
│ │
│ STATE & BALANCES │
│ ────────────────────────────────────────────────────────────────────── │
│ eth_getBalance → Get account balance │
│ eth_getCode → Get contract bytecode │
│ eth_getStorageAt → Get storage slot value │
│ eth_call → Execute call without mining │
│ │
│ ACCOUNTS │
│ ────────────────────────────────────────────────────────────────────── │
│ eth_accounts → List available accounts │
│ eth_sign → Sign message │
│ │
│ NETWORK │
│ ────────────────────────────────────────────────────────────────────── │
│ net_version → Get network ID │
│ net_peerCount → Get peer count │
│ eth_protocolVersion → Get protocol version │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Terminal window
# Get latest block number
curl -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_blockNumber",
"params": [],
"id": 1
}'
# Response:
# {"jsonrpc":"2.0","result":"0x10d4f1e","id":1}
# = 17720222 in decimal
Terminal window
# Get block by number (latest)
curl -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_getBlockByNumber",
"params": ["latest", false],
"id": 1
}'
Terminal window
# Get account balance
curl -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_getBalance",
"params": ["0x742d35Cc6634C0532925a3b844Bc9e7595f1e3E4", "latest"],
"id": 1
}'
Terminal window
# Send transaction (broadcast signed tx)
curl -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_sendRawTransaction",
"params": ["0x..."],
"id": 1
}'

Terminal window
# Start Geth as RPC node
geth \
--syncmode snap \
--http \
--http.addr 0.0.0.0 \
--http.port 8545 \
--http.api eth,net,web3,debug,txpool \
--http.corsdomain "*" \
--ws \
--ws.addr 0.0.0.0 \
--ws.port 8546 \
--ws.api eth,net,web3 \
--ws.origins "*" \
--datadir /data/ethereum \
--maxpeers 100
Terminal window
geth \
--syncmode snap \
--http \
--http.addr 127.0.0.1 \
--http.port 8545 \
--http.api eth,net,web3,debug,txpool \
--http.vhosts "localhost,yourdomain.com" \
--http.ratelimit 1000 \
--http.ratelimitburst 2000 \
--ws \
--ws.addr 127.0.0.1 \
--ws.port 8546 \
--ws.api eth,net,web3 \
--ws.origins "https://your-dapp.com" \
--ws.ratelimit 500 \
--datadir /data/ethereum \
--port 30303 \
--maxpeers 100 \
--cache 8192

┌─────────────────────────────────────────────────────────────────┐
│ HTTP VS WEBSOCKET │
├─────────────────────────────────────────────────────────────────┤
│ │
│ HTTP/RPC WebSocket │
│ ───────── ──────── │
│ Request-Response Persistent Connection │
│ One-time calls Real-time updates │
│ Polling needed Push-based notifications │
│ Good for queries Good for live data │
│ │
│ Use Cases: Use Cases: │
│ - Get balance - Transaction confirmations │
│ - Send tx - New block notifications │
│ - Query history - Mempool updates │
│ │
└─────────────────────────────────────────────────────────────────┘
// Connect to WebSocket
const ws = new WebSocket('ws://localhost:8546');
// Subscribe to new blocks
ws.onopen = () => {
ws.send(JSON.stringify({
jsonrpc: '2.0',
method: 'eth_subscribe',
params: ['newHeads'],
id: 1
}));
};
// Receive new blocks
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
console.log('New block:', message.params.result);
};

If WebSocket isn’t available, use long polling:

// Simple polling for new blocks
async function pollBlock() {
while (true) {
const response = await fetch('https://your-rpc.com', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_blockNumber',
params: [],
id: 1
})
});
const data = await response.json();
console.log('Block:', parseInt(data.result, 16));
await sleep(15000); // Poll every 15 seconds
}
}

  • Prevent abuse
  • Protect node resources
  • Ensure fair access
  • DDoS protection
Terminal window
# Example: Ngnix rate limiting
limit_req_zone $binary_remote_addr zone=eth_rpc:10m rate=100r/s;
server {
location / {
limit_req zone=eth_rpc burst=200;
proxy_pass http://localhost:8545;
}
}
upstream geth_backend {
server 127.0.0.1:8545;
}
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
limit_req_zone $binary_remote_addr zone=eth_call_limit:10m rate=50r/s;
server {
listen 443 ssl http2;
server_name rpc.yourdomain.com;
ssl_certificate /etc/ssl/certs/your-cert.crt;
ssl_certificate_key /etc/ssl/private/your-key.key;
# Rate limiting
limit_req zone=api_limit burst=200 nodelay;
location / {
proxy_pass http://geth_backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}

┌─────────────────────────────────────────────────────────────────────────────┐
│ LOAD BALANCED RPC │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ Load Balancer │ │
│ │ (Nginx/HAProxy) │
│ └────────┬────────┘ │
│ │ │
│ ┌───────────────────────────┼───────────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ RPC Node 1 │ │ RPC Node 2 │ │ RPC Node 3 │ │
│ │ (Geth) │ │ (Erigon) │ │ (Geth) │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
frontend eth_rpc
bind :443 ssl crt /etc/ssl/certs/server.pem
default_backend geth_nodes
backend geth_nodes
balance roundrobin
option httpchk GET /health
server geth1 10.0.0.1:8545 check inter 5s rise 2 fall 3
server geth2 10.0.0.2:8545 check inter 5s rise 2 fall 3
server geth3 10.0.0.3:8545 check inter 5s rise 2 fall 3

ProviderURLNotes
Infurahttps://mainnet.infura.io/v3/YOUR_KEYFree tier available
Alchemyhttps://eth-mainnet.g.alchemy.com/v2/YOUR_KEYFree tier available
Ankrhttps://rpc.ankr.com/ethFree, rate limited
Cloudflarehttps://cloudflare-eth.comFree
QuickNodehttps://rpc-mainnet.moonvail.xyzFree tier
NetworkRPC URL
Sepoliahttps://rpc.sepolia.org
Goerlihttps://rpc.goerli.org
Holeskyhttps://rpc.holesky.ethpandaops.io

QuestionAnswer
What is an RPC node?A node that exposes APIs for external applications
Difference between HTTP and WebSocket?HTTP is request-response; WebSocket is persistent connection
How to protect RPC endpoints?Rate limiting, authentication, TLS
What is JSON-RPC?JSON-based remote procedure call protocol

  • RPC nodes expose APIs for blockchain interaction
  • JSON-RPC is the standard protocol
  • WebSockets enable real-time updates
  • Production needs: rate limiting, load balancing, security
  • Popular providers: Infura, Alchemy, Ankr

In Chapter 19: JSON-RPC API Methods, we’ll explore more detailed API methods.


Last Updated: 2026-02-20