dig-rpc-protocol
The canonical DIG-node JSON-RPC protocol (formerly dig-rpc-types) — the single source of truth both
DIG node implementations (the digstore dig-node crate and the standalone
dig-node binary) depend on instead of hand-rolling json!({…}) shapes and
ad-hoc error codes.
Pure types: no I/O, no async, no server logic, no crypto. The
dig-rpc server crate and the node
implementations build on these types.
What's here
| Module | Contents |
|---|---|
envelope |
JSON-RPC 2.0 request/response, RequestId, Version |
error |
the canonical ErrorCode taxonomy, the RpcError envelope ({code, message, data:{code, origin}}), and the one constructor helper |
method |
the Method enum — stable wire names, per-method Tier, the mTLS peer allowlist |
tier |
the three access tiers (PublicRead / Peer / Control) |
types |
every method's params + results, field-for-field with the canonical node |
frames |
the shape-dispatched DHT + PEX peer wires |
openrpc |
the OpenRPC 1.2.6 document generator (the single discovery source) |
The full contract is in SPEC.md.
Full Protocol Interface (at-a-glance LLM reference)
All Methods (34 total)
| Method Name | Wire Name | Tier | Peer-Reachable | Summary |
|---|---|---|---|---|
GetContent |
dig.getContent |
PublicRead | ✓ | Read a verified window of a resource's ciphertext |
GetCapsule |
dig.getCapsule |
PublicRead | ✗ | Fetch the whole .dig module for (store, root) |
GetModule |
dig.getModule |
PublicRead | ✗ | Alias of dig.getCapsule |
GetManifest |
dig.getManifest |
PublicRead | ✗ | Fetch the public discovery manifest resource |
GetMetadata |
dig.getMetadata |
PublicRead | ✗ | Fetch the plaintext metadata manifest |
ListCapsules |
dig.listCapsules |
PublicRead | ✗ | List a store's confirmed capsules |
GetProof |
dig.getProof |
PublicRead | ✗ | Get the real inclusion proof + execution-proof status |
GetProofStatus |
dig.getProofStatus |
PublicRead | ✗ | Poll a real execution-proof job by id |
GetAnchoredRoot |
dig.getAnchoredRoot |
PublicRead | ✓ | Resolve a store's chain-anchored tip root |
GetCollection |
dig.getCollection |
PublicRead | ✓ | Get collection-level facts for NFT launcher ids |
ListCollectionItems |
dig.listCollectionItems |
PublicRead | ✓ | List resolved NFT collection items (paginated) |
Health |
dig.health |
PublicRead | ✗ | Liveness and capability summary |
Methods |
dig.methods |
PublicRead | ✗ | List the method names this node implements |
GetNetworkInfo |
dig.getNetworkInfo |
Peer | ✓ | This node's peer-network posture |
GetPeers |
dig.getPeers |
Peer | ✓ | The peers this node currently knows |
Announce |
dig.announce |
Peer | ✓ | Accept a peer announcement (peer_id + addresses) |
GetAvailability |
dig.getAvailability |
Peer | ✓ | Batch-check whether this node holds items |
ListInventory |
dig.listInventory |
Peer | ✓ | Enumerate the stores / roots this node serves |
FetchRange |
dig.fetchRange |
Peer | ✓ | Fetch a single verified range frame of a resource |
Stage |
dig.stage |
Control | ✗ | Compile a local folder into a capsule .dig in-process |
CacheGetConfig |
cache.getConfig |
Control | ✗ | Get the local-cache configuration |
CacheSetCapBytes |
cache.setCapBytes |
Control | ✗ | Set the local-cache size cap |
CacheClear |
cache.clear |
Control | ✗ | Clear the local cache |
CacheListCached |
cache.listCached |
Control | ✗ | List the durable cached modules |
CacheRemoveCached |
cache.removeCached |
Control | ✗ | Remove one cached capsule |
CacheFetchAndCache |
cache.fetchAndCache |
Control | ✗ | Fetch and cache one capsule |
CacheStats |
cache.stats |
Control | ✗ | Cache telemetry: cap + usage, entry count + bytes, eviction + hit/miss |
ControlPeerStatus |
control.peerStatus |
Control | ✗ | Snapshot the node's peer network |
ControlSubscribe |
control.subscribe |
Control | ✗ | Subscribe the node to a store (persisted watch + gap-fill) |
ControlUnsubscribe |
control.unsubscribe |
Control | ✗ | Unsubscribe the node from a store |
ControlListSubscriptions |
control.listSubscriptions |
Control | ✗ | List the node's persisted store subscriptions |
ControlPeersConnect |
control.peers.connect |
Control | ✗ | Dial a peer into the connected pool |
ControlPeersDisconnect |
control.peers.disconnect |
Control | ✗ | Drop a pooled peer by peer_id |
RpcDiscover |
rpc.discover |
Control | ✗ | Return the OpenRPC self-describe document |
Access Tiers: PublicRead = anonymous content reads (HTTPS / mTLS). Peer = mTLS peer surface (node↔node). Control = loopback / in-process only.
Peer-Reachable Methods (10 total): dig.getContent, dig.getNetworkInfo, dig.getPeers, dig.announce, dig.getAvailability, dig.listInventory, dig.fetchRange, dig.getAnchoredRoot, dig.getCollection, dig.listCollectionItems. All Control and non-peer PublicRead methods are never peer-reachable.
Error Codes (22 total)
| Code | Machine Code | Origin | Meaning |
|---|---|---|---|
-32700 |
PARSE_ERROR |
Node | Invalid JSON received |
-32600 |
INVALID_REQUEST |
Node | JSON is not a valid Request object |
-32601 |
METHOD_NOT_FOUND |
Node | Method does not exist / is not available |
-32602 |
INVALID_PARAMS |
Node | Invalid or missing method parameters |
-32603 |
INTERNAL_ERROR |
Node | Node failed to satisfy a well-formed call |
-32000 |
SERVER_ERROR |
Node | Generic server error (config/IO/chain failure) |
-32004 |
RESOURCE_UNAVAILABLE |
Node | Resource not available at requested root (genuine miss) |
-32005 |
ROOT_NOT_ANCHORED |
Node | Requested/served root is not chain-anchored (fail-closed) |
-32006 |
PEER_UNREACHABLE |
Peer | No NAT-traversal strategy reached the peer |
-32007 |
RANGE_NOT_SATISFIABLE |
Node | Byte range lies outside the resource |
-32008 |
CONTENT_REDIRECT |
Node | Content held elsewhere — data.redirect names holders |
-32010 |
UPSTREAM_ERROR |
Upstream | Upstream/proxy fetch failed |
-32011 |
STAGE_INVALID_INPUT |
Node | dig.stage: dir unreadable / walk budget exceeded |
-32012 |
STAGE_NO_FILES |
Node | dig.stage: no files to compile |
-32013 |
STAGE_OVER_CAP |
Node | dig.stage: input exceeds store cap |
-32014 |
STAGE_COMPILE_FAILED |
Node | dig.stage: compile / IO failure |
-32020 |
ONION_CIRCUIT_UNAVAILABLE |
Onion | Private read circuit could not be built/kept |
-32021 |
PRIVACY_REQUIRES_LOCAL_NODE |
Onion | Privacy mode requires local originator |
-32022 |
ONION_HOPS_OUT_OF_RANGE |
Onion | Hop count outside [2, 5] |
-32030 |
UNAUTHORIZED |
Control | Control-plane call not authorized (loopback gate failed) |
-32031 |
NOT_SUPPORTED |
Control | Control-plane method recognized but not supported |
-32032 |
CONTROL_ERROR |
Control | Control-plane runtime error |
Error Origins: Node = node's own read/serve path. Peer = peer-network layer. Upstream = upstream fetch (proxy/whole-store sync). Onion = private-retrieval layer. Control = loopback control plane.
Request/Response Envelope
JSON-RPC 2.0 strict:
Request: {"jsonrpc":"2.0","id":<num|str>,"method":"<wire_name>","params":<object|null>}
Response: {"jsonrpc":"2.0","id":<num|str>,"result":<any>} | {"jsonrpc":"2.0","id":<num|str>,"error":{"code":<int>,"message":"<str>","data":{"code":"<UPPER_SNAKE>","origin":"<str>",...}}}
Error Envelope Structure:
Interface Version
INTERFACE_VERSION is not yet versioned in the wire (future work). The protocol evolves via additive Method variants and ErrorCode assignments; both are #[non_exhaustive] so a client match-arm default (_ => …) handles future extensions.
Error taxonomy at a glance
Standard JSON-RPC codes plus the DIG protocol codes. The onion codes
-32020/-32021/-32022 are the published normative contract and keep their
numbers; the control-plane codes are -32030/-32031/-32032.
use ;
let e = of;
assert_eq!; // -32004
assert_eq!; // stable branch key
assert_eq!;
Method catalogue + discovery
use ;
assert_eq!;
assert_eq!;
assert!;
assert!; // control tier
let doc = openrpc_document; // OpenRPC 1.2.6
Features
| Flag | Default | Effect |
|---|---|---|
schema-export |
off | derive schemars::JsonSchema on every wire type (Go/TS codegen) |
Testing
cargo test --all-features # unit + conformance vectors
cargo llvm-cov --all-features # coverage (CI-gated ≥80%)
Licensed under Apache-2.0 OR MIT.