DCP Infrastructure Services¶
Optional HTTP microservices that complement the DCP Reference Gateway. Each service runs independently and can be deployed individually or together via Docker Compose.
Architecture¶
┌─────────────────────┐
│ DCP Reference │
│ Gateway (:3000) │
│ Verification + │
│ Key Registry + │
│ Policy Engine │
└──────────┬──────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
┌─────────▼──────────┐ ┌─────▼──────────┐ ┌──────▼──────────┐
│ Anchor Service │ │ Transparency │ │ Revocation │
│ (:3001) │ │ Log (:3002) │ │ Service (:3003)│
│ │ │ │ │ │
│ Bundle hash → │ │ Append-only │ │ V1: agent-level│
│ Local records │ │ Merkle tree + │ │ V2: kid-level │
│ (L2 planned) │ │ inclusion │ │ + emergency │
│ │ │ proofs │ │ + short-lived │
└────────────────────┘ └────────────────┘ └─────────────────┘
Services¶
| Service | Port | Status | Description |
|---|---|---|---|
| Anchor | 3001 | Partial | Local bundle hash records with planned L2 blockchain anchoring. Merkle batching works in-memory; on-chain submission is not implemented, so records carry tx_hash: null. |
| Transparency Log | 3002 | Functional | CT-style append-only log: RFC 6962 Merkle tree, inclusion proofs, Ed25519-signed tree heads. In-memory storage. |
| Revocation | 3003 | Functional | Agents register keys with their signed passport; V1 agent-level and V2 kid-level revocations must be signed by those keys; emergency panic button. In-memory storage by default, with optional file persistence. |
Quick Start¶
# Run all services with Docker Compose
(cd docker && docker compose up)
# Or run individually from the root of a checkout, after building the workspace SDK
# and installing the root package (the revocation service imports @dcp-ai/sdk):
# (cd sdks/typescript && npm install && npm run build) && npm install
node services/anchor/index.js
node services/transparency-log/index.js
node services/revocation/index.js
Data Flow¶
- Agent registers via Gateway (
POST /v2/passport/register), and the operator registers it with the Revocation service (POST /v2/register, operator token), both with its self-signed passport - Intent declared and policy evaluated (
POST /v2/intent/declare) - Bundle signed and verified (
POST /v2/bundle/verify) - Hash submitted to the Anchor service (
POST /anchor) for local recording or batching; on-chain submission is not implemented - Hash logged in transparency log (
POST /add) - Revocation checked before accepting bundles:
GET /v2/check/kid/:kidcovers kid-level, emergency and expiry revocations of every kid registered withPOST /v2/register, and answers 404 (registered: false, status unknown) for any other kid;GET /check/:agent_idcovers agent-level ones.
Authentication¶
- Revocation writes are signed: registration by the passport's own keys, revocations by the keys registered to the agent. Reads are not: the lists it serves (
/list,/v2/list,/.well-known/dcp-revocations.json) carry no signature, so a verifier trusts the service's URL and transport for them. Registering a newagent_idalso needs the operator token, so nobody can claim someone else's first. Emergency revocation needs the pre-image of the registered token. - New
agent_ids are registered by the operator, on the gateway (POST /v2/passport/register) and on the revocation service (POST /v2/register); re-registering is self-service, signed by the agent's keys. - Anchor
POST /flushand Transparency LogPOST /gossip/peersrequireAuthorization: Bearer <OPERATOR_TOKEN>; withoutOPERATOR_TOKENthey stay locked. The log fetches its peers itself, so an open peer list would let anyone point it at internal URLs. - Request bodies are capped at 1 MB. Rate limits (registrations and emergency revocations, the gateway's POSTs) key on the socket address; set
TRUST_PROXY=trueonly behind a proxy that appends the client IP toX-Forwarded-For. - Registries refuse new entries when full (507) instead of evicting them: the revocation service caps agents (
MAX_AGENTS), the gateway caps keys (MAX_REGISTERED_KEYS,MAX_KEYS_PER_AGENTover an agent's lifetime) and keeps 4 retired keys per agent. Keys and signatures must be canonical base64 of their algorithm's exact size. The transparency log only trusts tree heads signed by pinned peers (GOSSIP_PEERS=<url>#<key>).
Persistence¶
By default, services keep their state in memory. Unless persistence is configured, that state does not survive a restart, a deploy, a crash or a stopped machine:
- Revocation: forgetting revocations un-revokes agents. Set
REVOCATION_STATE_PATHto keep registrations and revocations in a file across restarts (the Compose stack does, on a volume); without it,deploy/fly/revocation.tomlonly keeps one machine running so idling does not wipe it, and deploys still do. - Transparency Log: a restart starts a new, empty tree, so earlier STHs and proofs no longer match it. Its Fly config already keeps one machine running.
- Anchor: pending hashes and records are lost; its Fly config still scales to zero, which is harmless while nothing is anchored on-chain.
For production, add persistent storage (SQLite, PostgreSQL), plus a Fly volume where needed. Other limitations:
- Anchor: integrate with ethers.js and a real L2 RPC endpoint. The
DCPAnchor.solcontract is incontracts/ethereum/. - Revocation: consider CRL (Certificate Revocation List) or OCSP-style distribution for high-availability deployments.
Environment Variables¶
See individual service READMEs for configuration details: - Anchor - Transparency Log - Revocation