DEV Community

Cover image for Calling Bitcoin, Litecoin and Decred JSON-RPC without running a node
Olenza
Olenza

Posted on

Calling Bitcoin, Litecoin and Decred JSON-RPC without running a node

I run full nodes for nine chains on one server in a datacenter. For a while I used them only for my own projects. Running a node is the boring part of most crypto side projects, and it is also the part that breaks: disk fills up, a release changes a flag, sync falls behind for a day. So I put a gateway in front of mine and opened it up. It's called Olenza Node.

This post shows what calling it looks like for Bitcoin, Litecoin and Decred, with real requests and responses, and what it can't do.

The shape of a call

Every chain has one endpoint:

POST https://node.olenza.io/v1/rpc/{chain}
Enter fullscreen mode Exit fullscreen mode

{chain} is one of btc, eth, ltc, doge, bch, xec, zec, dcr, xmr. The body is a normal JSON-RPC request for that chain's node. The key goes in a header. The gateway does not translate anything: Bitcoin speaks Bitcoin Core RPC, Decred speaks dcrd, Monero speaks monerod.

export OLENZA_KEY=olz_xxx   # your key from account.olenza.io

curl https://node.olenza.io/v1/rpc/btc \
  -H "X-API-Key: $OLENZA_KEY" \
  --data '{"jsonrpc":"1.0","id":1,"method":"getblockcount","params":[]}'
Enter fullscreen mode Exit fullscreen mode
{"result":970203,"error":null,"id":1}
Enter fullscreen mode Exit fullscreen mode

Authorization: Bearer olz_xxx works too. If your client can't set headers, the key can go in the path (/v1/rpc/btc/olz_xxx). The header is better, because your own proxy or shell history may keep the URL.

Bitcoin: fee estimate and mempool

curl https://node.olenza.io/v1/rpc/btc \
  -H "X-API-Key: $OLENZA_KEY" \
  --data '{"jsonrpc":"1.0","id":1,"method":"estimatesmartfee","params":[6]}'
Enter fullscreen mode Exit fullscreen mode
{"result":{"feerate":0.00001000,"blocks":6},"error":null,"id":1}
Enter fullscreen mode Exit fullscreen mode
curl https://node.olenza.io/v1/rpc/btc \
  -H "X-API-Key: $OLENZA_KEY" \
  --data '{"jsonrpc":"1.0","id":1,"method":"getmempoolinfo","params":[]}'
Enter fullscreen mode Exit fullscreen mode
{"result":{"loaded":true,"size":2515,"bytes":697554,"usage":4230912,
 "total_fee":0.02143948,"maxmempool":300000000,"mempoolminfee":0.00001000,
 "minrelaytxfee":0.00001000,"incrementalrelayfee":0.00001000,
 "unbroadcastcount":0,"fullrbf":false},"error":null,"id":1}
Enter fullscreen mode Exit fullscreen mode

Bitcoin has 45 methods open: blocks, transactions, mempool, fee estimation, PSBT tools, sendrawtransaction, testmempoolaccept. Wallet, peer and node-control methods are closed.

Litecoin: same dialect, MWEB visible in getblockchaininfo

curl https://node.olenza.io/v1/rpc/ltc \
  -H "X-API-Key: $OLENZA_KEY" \
  --data '{"jsonrpc":"1.0","id":1,"method":"getblockchaininfo","params":[]}'
Enter fullscreen mode Exit fullscreen mode

Trimmed response:

{"result":{"chain":"main","blocks":3190632,"headers":3190632,
 "initialblockdownload":false,"pruned":false,
 "softforks":{
   "taproot":{"type":"bip8","active":true,"height":2257920},
   "mweb":{"type":"bip8","active":true,"height":2265984}}},
 "error":null,"id":1}
Enter fullscreen mode Exit fullscreen mode
curl https://node.olenza.io/v1/rpc/ltc \
  -H "X-API-Key: $OLENZA_KEY" \
  --data '{"jsonrpc":"1.0","id":1,"method":"estimatesmartfee","params":[6]}'
Enter fullscreen mode Exit fullscreen mode
{"result":{"feerate":0.00000999,"blocks":6},"error":null,"id":1}
Enter fullscreen mode Exit fullscreen mode

Litecoin has 42 methods open.

Decred: the staking calls

Decred is where a hosted node saves the most work, because dcrd has calls that Bitcoin-style nodes don't: tickets, votes, treasury. 47 methods are open.

Ticket price right now:

curl https://node.olenza.io/v1/rpc/dcr \
  -H "X-API-Key: $OLENZA_KEY" \
  --data '{"jsonrpc":"1.0","id":1,"method":"getstakedifficulty","params":[]}'
Enter fullscreen mode Exit fullscreen mode
{"jsonrpc":"1.0","result":{"current":275.77403247,"next":275.77403247},"error":null,"id":1}
Enter fullscreen mode Exit fullscreen mode

Treasury balance (in atoms, 1 DCR = 100,000,000 atoms):

curl https://node.olenza.io/v1/rpc/dcr \
  -H "X-API-Key: $OLENZA_KEY" \
  --data '{"jsonrpc":"1.0","id":1,"method":"gettreasurybalance","params":[]}'
Enter fullscreen mode Exit fullscreen mode
{"jsonrpc":"1.0","result":{"hash":"345339d9…534fc120","height":1121329,"balance":88191381920627},"error":null,"id":1}
Enter fullscreen mode Exit fullscreen mode

That is about 881,914 DCR. getcoinsupply, getticketpoolvalue, livetickets, ticketsforaddress, getvoteinfo and gettreasuryspendvotes are there too. dcrd has no address history index, so for an address you get existsaddress and ticketsforaddress, not a transaction list.

Batches

Send an array and you get an array back. Each call in the batch counts as one unit, so this costs 2:

curl https://node.olenza.io/v1/rpc/btc \
  -H "X-API-Key: $OLENZA_KEY" \
  --data '[{"jsonrpc":"1.0","id":1,"method":"getblockcount","params":[]},
           {"jsonrpc":"1.0","id":2,"method":"getbestblockhash","params":[]}]'
Enter fullscreen mode Exit fullscreen mode
[{"result":970203,"error":null,"id":1},
 {"result":"00000000000000000001411305f8c4987a46839f5e5c7109adcd5847f6f3820a","error":null,"id":2}]
Enter fullscreen mode Exit fullscreen mode

The free plan allows batches of up to 5 calls (Starter 20, Pro 50). A bigger batch is refused with BATCH_TOO_LARGE. Monero is the exception: monerod doesn't take batches at all, so for xmr you send one call per request. The gateway refuses an array there with INVALID_REQUEST and doesn't charge for it.

What you see when you're refused

A closed method:

{"error":{"code":-32601,"data":{"reason":"METHOD_NOT_ALLOWED"},
 "message":"method \"getwalletinfo\" is not available"},"id":null,"jsonrpc":"2.0"}
Enter fullscreen mode Exit fullscreen mode

No key:

{"error":{"code":-32001,"data":{"reason":"MISSING_API_KEY"},
 "message":"an API key is required"},"id":null,"jsonrpc":"2.0"}
Enter fullscreen mode Exit fullscreen mode

error.data.reason is a stable code, so you can switch on it. The full list is in the docs.

Every response also carries your limits, so you never have to guess:

x-ratelimit-limit: 10
x-ratelimit-remaining: 8
x-ratelimit-reset: 1
x-quota-daily-limit: 10000
x-quota-daily-remaining: 9926
x-quota-monthly-limit: 300000
x-quota-monthly-remaining: 299924
x-request-id: c2ab92cbe93db0e4
Enter fullscreen mode Exit fullscreen mode

Limits and price

  • Free: 10,000 calls a day, 300,000 a month, 5 requests a second (burst 10), all nine chains. Every call is one unit, whatever the method.
  • Starter: $25 a month. Pro: $79 a month. Paying 6 or 12 months up front takes 25% or 50% off.
  • When you hit a limit you get HTTP 429 with Retry-After. Errors on our side (node down, node syncing, gateway busy) are not charged.
  • Some heavy calls have a per-request cap, for example eth_getLogs covers at most 10,000 blocks per call. Over the cap you get RANGE_TOO_LARGE and page through instead. The docs list each one.
  • Payment is in crypto: BTC, LTC or USDT through BTCPay, or LTC, ETH, USDT or USDC sent directly.

What it is not

I'd rather say this up front:

  • It's one person's project, run from one server. I watch it, it has alerting, and the status page is public, but there is no team on call and no SLA.
  • No wallet RPC, no peer or node-control methods, no scantxoutset.
  • Bitcoin-style nodes have no address index. For "all transactions of an address" you need an indexer. Olenza Explorer has a REST API for that (separate free plan: 5,000 calls a day), but that's another post.
  • Monero only exposes /json_rpc methods. The binary endpoints a light wallet syncs from are not open.
  • Ethereum runs on an Erigon archive node, so eth_call and trace_* work at any height, but trace_* on old blocks is slow.

Why bother

If you're building a small tool, a bot, a payment check or a dashboard, and you need a few thousand calls a day to a real node for an odd chain like Decred or eCash, there are not many places that sell that. I wanted one.

To try it, make a free key at https://account.olenza.io (email sign-up) and paste one of the curl lines above.

Docs: https://olenza.io/docs (also as OpenAPI and as llms.txt)
Methods per chain: https://node.olenza.io
Pricing: https://olenza.io/pricing
Status: https://olenza.io/status

If something answers wrong, or a method you need is closed for no good reason, tell me in the comments. I read all of them.

Top comments (0)