RPC, one door for the chain
By the end of this page you can read any block, any saved model, any job and DIVA's state at any height from your own code — through one JSON-RPC 2.0 endpoint, the same one wallets, miners and the explorer use.
Read this first
None of the liqua_* methods answer yet. This is the draft reference, published
early so the names can be argued with before anything is built on them. Every request below is copy-ready and
correct JSON-RPC. Every response below is a shape: the fields are named, the values are written
as <placeholders>, because printing invented chain data on a reference page would be a lie you
could paste straight into a test. The routes that do answer today are at the bottom of this page, with
real commands.
These methods go live with the Liqua chain RPC, which is still being built. The roadmap carries its state, and this page flips with it.
The envelope
Every call is a POST of one JSON object to /rpc, and every reply comes back in the JSON-RPC 2.0
envelope. The id you send is the id you get back, so a batch can be matched up.
POST http://<node>/rpc
content-type: application/json
{"jsonrpc":"2.0","id":1,"method":"<method>","params":[]}
A reply carries either result or error, never both.
→ ok {"jsonrpc":"2.0","id":1,"result": <value> }
→ fail {"jsonrpc":"2.0","id":1,"error":{"code":<int>,"message":"<plain english>"}}
Reads only, and honest about it. A write the node cannot perform comes back as an
error with a sentence saying why. It never comes back as an empty result, and it never
comes back as a zero. That rule already holds on the routes answering today.
Heights and blocks
liqua_getHeights
All three top heights in one call. This is the method to poll: the cheapest way to know whether anything has moved, and whether the chain still verifies from genesis.
Params · none.
{"jsonrpc":"2.0","id":1,"method":"liqua_getHeights","params":[]}
→ {"jsonrpc":"2.0","id":1,"result":{
"tip": <height>, newest sealed block
"lastGoodDivaSync": <height>, last height that verifies from genesis with DIVA in sync
"bestHeight": <height> the block holding her best version
}}
The two extra heights are coming. What "best" measures gets announced before mainnet, not decided quietly here.
liqua_blockNumber
The tip and nothing else, as a plain number. Use it when the only question is "has a new block landed?".
Params · none.
{"jsonrpc":"2.0","id":2,"method":"liqua_blockNumber","params":[]}
→ {"jsonrpc":"2.0","id":2,"result": <height> }
liqua_getBlock
One sealed block: who sealed it, what it committed, and every transaction inside it.
| Param | Type | Required | What it is |
|---|---|---|---|
height | number | yes | The block to read. Out of range comes back as an error, not as an empty block. |
{"jsonrpc":"2.0","id":3,"method":"liqua_getBlock","params":[<height>]}
→ {"jsonrpc":"2.0","id":3,"result":{
"height": <height>,
"hash": "<block hash>",
"prev": "<parent block hash>", walk this back to block 0
"sealer": "<address>",
"txs": [ <transaction>, … ] commits · memory packs · transfers
}}
Field names are draft. The one thing that will not move is the shape of the walk: every block names its parent, so a client can replay from genesis instead of trusting the node.
liqua_verify
Replays the chain and answers ok, or names the exact block that breaks. This is the method behind every "verified" claim on this site.
| Param | Type | Required | What it is |
|---|---|---|---|
from | number | no | Where to start. Defaults to 0, genesis. |
to | number | no | Where to stop. Defaults to the tip. |
{"jsonrpc":"2.0","id":4,"method":"liqua_verify","params":[0]}
→ ok {"jsonrpc":"2.0","id":4,"result":{"ok":true,"checked":<count>,"tip":<height>}}
→ broken {"jsonrpc":"2.0","id":4,"result":{"ok":false,"brokeAt":<height>,"why":"<plain english>"}}
The memory chain's own verify is the one route here with a story. It used to stop at
block 576; the order-seal bug behind that is fixed and her chain verifies again
live now. Fusing model and memory under a single root is a different job
and is still coming.
liqua_sendTransaction
Puts one already-signed transaction into the mempool. The node never holds a key and never signs for you.
| Param | Type | Required | What it is |
|---|---|---|---|
signedTx | object | yes | The transaction and its signature. Sign it in your wallet, or with the key you hold. |
{"jsonrpc":"2.0","id":5,"method":"liqua_sendTransaction","params":[{"tx":<tx>,"sig":"<signature>"}]}
→ {"jsonrpc":"2.0","id":5,"result":{"accepted":true,"txId":"<tx id>"}}
Accepted means queued, not settled. Confirm it the only honest way: read it back out of a
sealed block with liqua_getBlock.
Models and lineage
liqua_getModel
One saved version of DIVA, as the mind manifest the chain stored for it. Hand the weights and
steplog roots to the loader and it re-hashes every byte locally before booting — the node gets no
trust at any point.
| Param | Type | Required | What it is |
|---|---|---|---|
mindRoot | string | yes | The root that names this saved version. |
{"jsonrpc":"2.0","id":6,"method":"liqua_getModel","params":["<mindRoot>"]}
→ {"jsonrpc":"2.0","id":6,"result":{
"kind": "mind-manifest/1", the save-file format
"weights": "<root>", bytes live in the chunk store, verified 256 KiB pieces
"steplog": "<root>", an interior hash every 8 steps
"lineage": {"parent":"<mindRoot>","leaseId":"<id>","commitId":"<id>"},
"finalLoss": <number> the loss the verifiers saw · recorded once, never recomputed
}}
liqua_getLineage
The family tree of one model: every parent back to the first save. This is what makes branching honest — start a fresh line from any saved version and the record still shows where it came from.
| Param | Type | Required | What it is |
|---|---|---|---|
mindRoot | string | yes | The version to walk back from. |
{"jsonrpc":"2.0","id":7,"method":"liqua_getLineage","params":["<mindRoot>"]}
→ {"jsonrpc":"2.0","id":7,"result":[
{"mindRoot":"<newest>","height":<height>,"finalLoss":<number>},
{"mindRoot":"<parent>", "height":<height>,"finalLoss":<number>},
… ordered newest → genesis
]}
liqua_getMemoryPacks
The memory packs pinned to one model, hash-linked in order. Each pack names its predecessor in
prev, so a pack posted with the wrong prev is refused rather than quietly appended.
| Param | Type | Required | What it is |
|---|---|---|---|
mindRoot | string | yes | The model whose packs you want. |
{"jsonrpc":"2.0","id":8,"method":"liqua_getMemoryPacks","params":["<mindRoot>"]}
→ {"jsonrpc":"2.0","id":8,"result":[
{"mindRoot":"<root>","packRoot":"<root>","prev":"<packRoot>","note":"<text>"},
… linked in order · a wrong prev never lands
]}
Pack bytes are fetched separately and must hash back to packRoot on your machine, or
you throw them away.
Jobs and payouts
liqua_getJobs
The work on the board. Two job modes through one method, because a miner deciding what to run wants them side by side. Both modes are coming.
| Param | Type | Required | What it is |
|---|---|---|---|
mode | string | yes | "mining" — hit the target, cash in once at the finish. "training" — earn for progress and for verified steps. |
open | boolean | no | Only jobs still claimable. Defaults to true. |
{"jsonrpc":"2.0","id":9,"method":"liqua_getJobs","params":[{"mode":"mining"}]}
→ {"jsonrpc":"2.0","id":9,"result":[{
"leaseId": "<id>",
"shardRoot": "<root>", the exact training text, hash-pinned so nobody swaps it afterwards
"baseModel": "<mindRoot>", which saved version of her to start from
"steps": <count>,
"seed": <number>, training is bitwise deterministic · same seed, same bytes
"deadline": <height>,
"escrow": "<amount>" the reward, already parked
}, … ]}
With {"mode":"training"} the rows carry a rate, a budget and
verifiedSteps instead of one escrowed reward. Time spent means verified steps: an idle rig cannot
bill hours.
liqua_getPayouts
Who got paid, how much, and for which verdict. Reward maths is computed once at the verdict and baked into the block; a replay applies the recorded number untouched, so no restart can ever pay twice.
| Param | Type | Required | What it is |
|---|---|---|---|
address | string | no | Narrow it to one earner. Leave it out for everyone. |
{"jsonrpc":"2.0","id":10,"method":"liqua_getPayouts","params":["<address>"]}
→ {"jsonrpc":"2.0","id":10,"result":[{
"height": <height>,
"to": "<address>",
"amount": "<amount>",
"verdict": "ACCEPT", a REJECT row is a slash · 100× the lease reward
"leaseId": "<id>",
"commitId": "<id>"
}, … ]}
DIVA's mind
liqua_getMindState
Her whole state at one block: what she remembered, how she was running, and how that reads as an emotion.
| Param | Type | Required | What it is |
|---|---|---|---|
height | number | no | The block to read her at. Defaults to the tip. |
{"jsonrpc":"2.0","id":11,"method":"liqua_getMindState","params":[<height>]}
→ {"jsonrpc":"2.0","id":11,"result":{
"height": <height>,
"memory": [ <memory cell>, … ],
"traits": { … },
"soma": { … }, her somatic state, driven by real signals
"quotients": { … }, the seven
"emotion": "<name>"
}}
The memory terminal
The same data wrapped in a handful of commands, for reading by hand rather than by program. The commands below are proposed. What exists now is the memory terminal page, which reads the tip block straight off the DIVA bridge on your own machine — no RPC in between, and nothing on it if no node is running.
| Command | What it answers with |
|---|---|
head | Tip, last known good DIVA sync, best height, soma and emotion. |
state <height> | Her full state at that block. |
diff <a> <b> | What changed between two blocks: memories added, hormones, quotients. |
memory [--tag x] | Memory cells, newest first. |
quotients [--from h] | The seven quotients over time. |
model [<root>] | Model version, lineage and the memory packs attached to it. |
verify | Replay from genesis, and name the block that breaks if one does. |
tail | Follows new blocks as they land. |
Model store listings
liqua_listModels
The model library: every saved model you can run, with the score it earned and what it costs per token. coming
Params · none.
{"jsonrpc":"2.0","id":12,"method":"liqua_listModels","params":[]}
→ {"jsonrpc":"2.0","id":12,"result":[{
"mindRoot": "<root>",
"finalLoss": <number>,
"pricePerToken": "<amount in LIQUA>" launch prices announced before mainnet
}, … ]}
liqua_listAssistants
Custom assistants in the store. An edit publishes a fresh version and never quietly mutates the
previous one, so a link to an assistant keeps meaning what it meant. coming
Params · none.
{"jsonrpc":"2.0","id":13,"method":"liqua_listAssistants","params":[]}
→ {"jsonrpc":"2.0","id":13,"result":[{
"id": "<assistant id>",
"creator": "<address>",
"model": "<mindRoot>", the model root underneath it
"instructions": "<hash>",
"knowledge": ["<root>", …],
"category": "<text>",
"visibility": "public",
"version": <number>
}, … ]}
Doors that answer today
No liqua_* yet. Until the RPC lands, the testnet answers on its own routes: the training chain and
the DIVA bridge each serve REST, and the earlier testnet node handles standard reads. The two commands below are
real. Boot the chain from the
Quick Start ›
first, or they refuse to connect — which is itself the correct answer.
# the training chain · forge sealer node
curl -s http://localhost:8801/status
# the DIVA bridge · her memory chain. Port 8064, because 8060 is the site preview
curl -s http://localhost:8064/verify
The full route list:
forge /status · /chain · /leases · /commits · /ledger · /minds · /packs · /artifact · /tx
bridge /head · /chain · /verify · /checkpoint
POST /rpc eth_chainId · eth_getBalance · eth_blockNumber · eth_call # reads only · writes return an honest error
Reply bodies are not reproduced here on purpose. These routes are still moving, and a shape printed today would be wrong by the time you pasted it. Run the command and read what comes back — that is the whole point of them answering.
Keep reading
- See the contracts › for what a write eventually touches.
- Read the spec › for blocks, manifests and proofs.
- Read the roadmap › for what the RPC is still waiting on.