UTxO RPC (gRPC) Server
Dugite-node ships a native UTxO RPC gRPC server —
the emerging standard programmable interface for UTxO chains adopted by
Dolos, Demeter, and most Cardano indexers. The server is disabled by
default; opt in via the Rpc config block or CLI flags below.
Quick start
# Enable on the default port (50051), bind loopback only.
dugite-node run \
--config config/mainnet/config.json \
--topology config/mainnet/topology.json \
--database-path ./db-mainnet \
--socket-path ./node.sock \
--host-addr 0.0.0.0 --port 3001 \
--rpc-port 50051
# Verify it's up and list registered services.
grpcurl -plaintext localhost:50051 list
# Expect: utxorpc.v1alpha.{sync,query,submit,watch}.{Sync,Query,Submit,Watch}Service
# utxorpc.v1beta.{sync,query,submit,watch}.{Sync,Query,Submit,Watch}Service
# grpc.reflection.v1.ServerReflection
grpcurl -plaintext localhost:50051 utxorpc.v1beta.sync.SyncService/ReadTip
# {
# "tip": {
# "slot": "...",
# "hash": "...",
# "height": "..."
# }
# }
Services exposed
Every service ships in both v1alpha (for backwards compatibility
with older clients) and v1beta (current). The spec is pinned
in-tree at crates/dugite-rpc/proto/VERSION.
| Service | Method | Status |
|---|---|---|
SyncService | ReadTip | ✅ implemented |
SyncService | FetchBlock | ✅ implemented |
SyncService | DumpHistory | ✅ implemented |
SyncService | FollowTip (stream) | ✅ implemented |
QueryService | ReadParams | ✅ implemented |
QueryService | ReadUtxos | ✅ implemented |
QueryService | ReadGenesis | ✅ implemented (minimum-viable envelope) |
QueryService | ReadEraSummary | ✅ implemented |
QueryService | SearchUtxos | ✅ implemented (exact_address / payment_part / delegation_part / asset plus not / all_of / any_of composites) |
QueryService | ReadData | ✅ implemented (bounded scan: live inline datums + mempool tx witness sets) |
QueryService | ReadTx | ✅ implemented (bounded scan: mempool + last ~43 200 slots of VolatileDB) |
QueryService | ReadState | ✅ implemented (minimum-viable envelope: epoch + tip slot) |
SubmitService | SubmitTx | ✅ implemented |
SubmitService | ReadMempool | ✅ implemented |
SubmitService | WaitForTx (stream) | ✅ implemented |
SubmitService | WatchMempool (stream) | ✅ implemented |
SubmitService | EvalTx | ✅ implemented (per-redeemer ex_units + Plutus traces) |
WatchService | WatchTx (stream) | ✅ implemented (full TxPredicate filtering: address / asset / mint / not / all_of / any_of) |
Configuration
JSON config block
Add an Rpc block to config/<network>/config.json:
{
"Rpc": {
"Enabled": true,
"ListenAddr": "127.0.0.1",
"Port": 50051,
"MaxConcurrentStreams": 64,
"StreamBufferSize": 256,
"ReflectionEnabled": true,
"WebEnabled": false,
"AlphaEnabled": true,
"Tls": {
"CertPath": "/etc/dugite/tls/rpc.crt",
"KeyPath": "/etc/dugite/tls/rpc.key"
}
}
}
All fields are optional. Defaults:
| Field | Default | Notes |
|---|---|---|
Enabled | false | Server stays disabled unless this is true or a --rpc-* CLI flag is passed. |
ListenAddr | 127.0.0.1 | Loopback only — protects an unauthenticated TCP gRPC endpoint from the network. Set to 0.0.0.0 only if you've fronted it with TLS or a reverse proxy. |
Port | 50051 | The de-facto UTxO RPC port used by Dolos, Demeter, and others. |
MaxConcurrentStreams | 64 | HTTP/2 streams per connection. |
StreamBufferSize | 256 | Per-stream event buffer. Slow consumers exceeding this drop with RESOURCE_EXHAUSTED. |
ReflectionEnabled | true | Exposes grpc.reflection.v1.ServerReflection so grpcurl -plaintext :50051 list works without a schema bundle. |
WebEnabled | false | Accept gRPC-Web (HTTP/1.1) for browser dApps. Costs a small per-connection bookkeeping when enabled. |
AlphaEnabled | true | Expose v1alpha services alongside v1beta. Operators can pre-disable to test that their clients have migrated. |
Tls | absent | Optional TLS termination. PEM-encoded cert/key on disk; no hot-reload (config changes require a restart). |
CLI flags
CLI flags override the JSON config block:
| Flag | Behaviour |
|---|---|
--rpc-port <PORT> | Force-enable RPC on this port (overrides Rpc.Port). |
--rpc-host <IP> | Force-enable RPC on this address (overrides Rpc.ListenAddr). |
--no-rpc | Force-disable RPC, regardless of the config block. |
Precedence (highest first):
--no-rpc→ server disabled.--rpc-host/--rpc-port→ server enabled with CLI values overriding the config block.Rpc.Enabled = truein JSON → server enabled with config values.- Otherwise → server disabled.
Configuration editor (dugite-config)
The Rpc section is exposed read-only as a JSON Object in
dugite-config so operators can see what's
configured at a glance. Edit sub-fields directly in the config JSON.
TLS
For non-loopback deployments, set Tls.CertPath + Tls.KeyPath to
PEM-encoded files. Both files are read at startup; missing or
unreadable files fail-fast with an io::Error rather than letting
the server come up unsecured.
For mTLS, mutual auth, or rotating certificates, terminate TLS at a
reverse proxy (Envoy, nginx) and leave Dugite's Tls block absent.
Operations
Metrics
The RPC server emits standard Prometheus counters / histograms via the node's existing metrics endpoint:
dugite_rpc_requests_total{service, method, status}(counter)dugite_rpc_request_duration_seconds{service, method}(histogram)dugite_rpc_active_streams{service, method}(gauge)
Logging
Service-level events log at INFO or DEBUG under the
dugite_rpc::server target. Streaming RPCs log slow-consumer drops at
WARN with service / method labels.
Spec-bump workflow
The UTxO RPC .proto files are vendored at
crates/dugite-rpc/proto/utxorpc/ and pinned via
crates/dugite-rpc/proto/VERSION. To refresh:
just bump-utxorpc-spec v0.20.0 # replace with the desired tag
The script:
- Clones the tag from
https://github.com/utxorpc/specinto a tempdir. - Re-copies the Cardano-only subset (
cardano + sync + query + submit + watchfor bothv1alphaandv1beta;bitcoinandhandshakeintentionally omitted). - Rewrites
VERSIONwith the new tag + resolved commit + today's date. - Builds and tests
dugite-rpcso codegen breakage / golden-test drift surfaces before the resulting commit is pushed.
Bumps land as their own PRs alongside any code changes needed to track
upstream protobuf shape changes. The single-source-of-truth lives in
VERSION — out-of-sync bumps (e.g. files refreshed without VERSION
updated, or vice versa) are caught by code review against the diff.
Limitations
SearchUtxoswith a fully-wildcard predicate (nomatch/ combinators) is rejected withUNIMPLEMENTED: dugite refuses to materialise the entire UTxO set in a single response. Supply at least one selector (address / payment_part / delegation_part / asset / composite) so the result set is bounded.ReadTxwalks at most the last ~43 200 slots ofVolatileDB. A chain-wide tx index would extend the lookup window to immutable history; not built today.ReadDatascans the live UTxO set's inline datums and the mempool's witness-set datums. Witness-set datums from immutable blocks are not retained — clients that need them should consult the originating tx viaReadTx.ReadState'sAnyChainStateData.cardanois currently empty: the endpoint returns the ledger tip + epoch only. Per-query state projections (stake-pool distribution, DRep info) land on top of this stub.EvalTx's per-redeemerex_unitsare CEK-machine consumed values, not declared. Cost-model overrides are not yet read from protocol params — the CEK falls back to per-step defaults, which is conservative (over-approximates) and therefore safe for fee-estimation use cases but may diverge slightly from cardano-node on the high end.WatchTxfilters on tx output fields (produces/has_address/moves_asset) and minting (mints_asset) — but not on resolved inputs (consumes/has_certificate) since those require live UTxO lookups against pending mempool txs.FollowTipapply events carryAnyChainBlock.native_bytes(the raw block CBOR); clients that only need tip metadata can ignore the payload.
See also
- UTxO RPC spec
crates/dugite-rpc/proto/VERSION— the pinned spec tag.crates/dugite-rpc/tests/— golden + integration tests covering each service.