JSON-RPC overview

NULL exposes two JSON-RPC 2.0 services over HTTP: the node, nulld, for chain, mempool and mining data, and the wallet daemon, null-wallet-rpc, for addresses, balances, deposits and withdrawals. This page covers what they have in common. The method pages list every call.

A shielded-only chain

Integration guides for Bitcoin-like coins assume things that are not true here. Read this before you design a deposit or payout system.

  • The chain shows no addresses and no amounts. Every output is encrypted. No call returns the balance of an address or the transactions sent to an address. Deposits are found by trial-decrypting outputs with a viewing key, and the wallet daemon does that for you. That is why there are two services: the node holds no keys, and the wallet daemon holds the keys of one wallet.
  • Sending takes seconds. Every payment carries a zero-knowledge proof. Proving takes about a second for a small transaction and about five seconds for a 16-action one. Send calls (sendmany, consolidate) return an operation id at once, and you poll the operation until it is confirmed.
  • The node builds the coinbase. The coinbase is a shielded transaction with its own proof, so a pool cannot assemble it from a script. getblocktemplate takes your payout address, builds and proves the coinbase, and returns the exact header bytes to grind.
  • One key, many addresses. A wallet derives as many diversified addresses as you need from one key, and its viewing key detects payments to all of them. Give every customer their own deposit address; you never manage per-customer keys.
  • Batching is built in. A transaction holds up to 16 actions at a fixed fee of 10,000 units per action. One withdrawal can pay up to 15 recipients plus change.
  • Every output has a memo. A 512-byte encrypted memo travels with each output, readable only by the recipient and the sender.

Coinbase rewards mature after 100 blocks on mainnet. The network refuses reorganizations deeper than 200 blocks. See Exchanges and Mining pools for walk-throughs.


The two services

  • Name
    nulld
    Type
    node
    Description

    Serves chain, transaction, mempool, peer, mining and disclosure-verification methods on the address given to --rpc-http. Holds no keys. A mining pool needs only this service.

  • Name
    null-wallet-rpc
    Type
    wallet daemon
    Description

    Holds one wallet file. Syncs from a node through the node's control socket (--rpc, 127.0.0.1:18444 by default) and serves the wallet methods on its own listener with its own token, 127.0.0.1:18447 by default. An exchange runs one node and one or more wallet daemons, for example a hot wallet and a watch-only deposit wallet.

Both binaries ship in the release archives at github.com/NullNetProtocol/null-chain/releases.


Enable the node RPC

The node's JSON-RPC listener is off until you pass --rpc-http. It has no default address; these docs use 127.0.0.1:18446.

nulld run --network main --rpc-http 127.0.0.1:18446

The listener uses the same token as the control socket. Pass it with --rpc-token or the NULL_RPC_TOKEN variable. If you give none, the node generates one and writes it to rpc.token in its data directory. The default data directory is <user data>/main/chain/, where <user data> is ~/.local/share/null on Linux, ~/Library/Application Support/Null on macOS and %LOCALAPPDATA%\Null on Windows. With --datadir the token is written there instead. The node prints the token location at startup.

TOKEN=$(cat ~/.local/share/null/main/chain/rpc.token)

--blocknotify '<command>' runs a shell command on every new main-chain tip, with %s replaced by the block hash. See Run a node for the other flags.

Enable the wallet daemon

Create the wallet file first with nulld create (see Command line), then start the daemon:

export NULL_WALLET_PASSPHRASE='the wallet passphrase'
null-wallet-rpc --wallet /srv/hot/hot.redb --network main \
  --node 127.0.0.1:18444 \
  --node-token-file ~/.local/share/null/main/chain/rpc.token \
  --listen 127.0.0.1:18447
WALLET_TOKEN=$(cat /srv/hot/wallet-rpc.token)
  • Name
    --wallet
    Type
    path
    Description

    The wallet file. Defaults to <user data>/main/wallet.redb. The daemon refuses to start if the file does not exist.

  • Name
    --network
    Type
    main | test
    Description

    Defaults to main.

  • Name
    --node
    Type
    host:port
    Description

    The node's control socket. Defaults to 127.0.0.1:18444.

  • Name
    --node-token, --node-token-file
    Type
    string, path
    Description

    The node's token, or a file holding it. Also read from NULL_RPC_TOKEN. Defaults to the rpc.token a default nulld run writes.

  • Name
    --listen
    Type
    host:port
    Description

    Where the wallet JSON-RPC listens. Defaults to 127.0.0.1:18447.

  • Name
    --token
    Type
    string
    Description

    The token the wallet JSON-RPC demands. Also read from NULL_WALLET_RPC_TOKEN. If omitted, a random token is written to wallet-rpc.token next to the wallet file.

  • Name
    --sync-interval
    Type
    seconds
    Description

    Time between syncs from the node. Defaults to 2.

  • Name
    --light
    Type
    flag
    Description

    Scan compact blocks instead of full blocks. Faster, but memos are not recovered.

The wallet passphrase comes from NULL_WALLET_PASSPHRASE or an interactive prompt.


Transport and conventions

  • HTTP POST, JSON-RPC 2.0. One POST per connection, to any path. The body is a call object or a batch array, up to 32 MB. Every call carries "jsonrpc": "2.0" and a string method.
  • Authentication. Send Authorization: Bearer <token> on every request.
  • Parameters are positional (an array) or named (an object): {"params": [6200]} and {"params": {"height": 6200}} are the same call. params may be omitted when a method takes none. A null value counts as omitted.
  • Batches. Send an array of calls. The answers come back as an array in the same order, one per call. An empty array is an error.
  • Amounts are integers in the smallest unit, written as decimal strings so they never lose precision in a JSON number. 1 NULL is 100000000 units. The wallet daemon also accepts whole JSON numbers for amounts in requests.
  • Hex. Hashes, txids, nullifiers, keys, blocks and transactions are lowercase hex. Block hashes and txids are 32 bytes (64 hex characters).
  • Numbers. Heights, counts, sizes and timestamps (Unix seconds) are JSON numbers.
  • Compact targets are 8 hex characters without 0x, for example "1e11e4e5". Branch ids are 0x and 8 hex characters, for example "0x4d41494e".
  • Addresses are bech32m text: null1… on mainnet, tnull1… on testnet. Full viewing keys are nullview1… and tnullview1….
  • Confirmations count the block itself: a transaction in the tip block has 1.

Single call

curl -s http://127.0.0.1:18446/ \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"jsonrpc":"2.0","id":1,"method":"getblockhash","params":{"height":6200}}'

Response

{
  "jsonrpc": "2.0",
  "result": "0000041e3f6c9e069db217c9e40e047f0ef33e9113bb066fb106c1c83a7414f6",
  "id": 1
}

Batch

curl -s http://127.0.0.1:18446/ \
  -H "Authorization: Bearer $TOKEN" \
  -d '[{"jsonrpc":"2.0","id":"a","method":"getblockcount"},
       {"jsonrpc":"2.0","id":"b","method":"nosuchmethod"}]'

Response

[
  { "jsonrpc": "2.0", "result": 6206, "id": "a" },
  {
    "jsonrpc": "2.0",
    "error": { "code": -32601, "message": "unknown method nosuchmethod" },
    "id": "b"
  }
]

Errors

Transport failures get an HTTP error status with a JSON-RPC error body and "id": null: 400 for a malformed HTTP request, 405 for a method other than POST, 401 for a missing or wrong token. Everything else is HTTP 200 with either a result or an error object. An error has a numeric code and a message. Both services use the same codes.

  • Name
    -32700
    Type
    parse error
    Description

    The body is not JSON.

  • Name
    -32600
    Type
    invalid request
    Description

    Not a JSON-RPC 2.0 call: jsonrpc is not "2.0", method is missing or not a string, params is neither an array nor an object, or the batch is empty. Also sent for a malformed HTTP request (HTTP 400) and a non-POST method (HTTP 405).

  • Name
    -32601
    Type
    method not found
    Description

    Unknown method.

  • Name
    -32602
    Type
    invalid params
    Description

    A parameter is missing or has the wrong type, hex is invalid or the wrong length, or an address does not decode for this network.

  • Name
    -32603
    Type
    internal error
    Description

    The service failed while serving the call.

  • Name
    -32001
    Type
    unauthorized
    Description

    Token missing or wrong. Sent with HTTP 401.

  • Name
    -1
    Type
    not found
    Description

    The block, transaction, operation or output does not exist.

  • Name
    -2
    Type
    rejected
    Description

    The service refused the request; the message says why. Examples: an invalid block or transaction, insufficient funds, a watch-only wallet asked to spend, a node not ready to mine.

  • Name
    -3
    Type
    node stopped
    Description

    The node is shutting down.

Error response

{
  "jsonrpc": "2.0",
  "error": {
    "code": -1,
    "message": "block not found"
  },
  "id": 1
}

HTTP 401

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32001,
    "message": "unauthorized"
  },
  "id": null
}

Method index

  • Node methods: getblockchaininfo, getblockcount, getbestblockhash, getblockhash, getblock, getblockheader, getcompactblock, getrawtransaction, gettransactionstatus, sendrawtransaction, getrawmempool, getmempoolinfo, getnullifierstatus, getpeerinfo, getnetworkinfo, getconnectioncount, uptime, stop, help.
  • Mining methods: getmininginfo, getblocktemplate, submitblock.
  • Wallet methods: getwalletinfo, getnewaddress, listaddresses, getaddressinfo, validateaddress, exportviewingkey, getbalance, listunspent, listreceived, gettransaction, rescan, estimatefee, quotepayment, sendmany, getoperationstatus, listoperations, canceloperation, quoteconsolidation, consolidate, help.
  • Selective disclosure: getpaymentdisclosure and answerchallenge on the wallet daemon, verifypaymentdisclosure and createchallenge on the node.