跳转至

Docker — DCP 基础设施

本文是英文版的参考译文,更新于 25/10/2026。如有出入,以英文版为准。标识符、命令和代码块保持原文,不作翻译。

用于把所有 DCP 服务部署为容器的 Docker Compose 配置。包括验证、锚定、透明日志和撤销。

快速开始

cd docker
docker compose up

docker compose up 会停留在前台:请在第二个终端中运行下面的检查,或者用 docker compose up -d 启动整个栈。这会在五个容器 中启动四个服务(两个透明日志):

容器 端口 说明
verification 3000 bundle 验证服务器
anchor 3001 锚定服务:只有本地记录,链上提交尚未实现
transparency-log-a 3002 透明日志 log-alpha,带 Merkle 证明
transparency-log-b 3012 透明日志 log-beta,log-alpha 的 gossip 对等节点
revocation 3003 智能体撤销服务

检查一切都在运行

curl http://localhost:3000/health
curl http://localhost:3001/health
curl http://localhost:3002/health
curl http://localhost:3012/health
curl http://localhost:3003/health

健康的应答只表示进程能响应 HTTP。它不检查持久化、锚定或 gossip(日志的 gossip_peers 统计的是已配置的对等节点,无论是否已 固定)。

服务

verification (:3000)

DCP(V1 + V2 + 第 3 阶段)的 Signed Bundle 验证服务器。下面两个验证请求是模板:{...} 和 ... 代表一个真实的已签名 bundle,因此不能按原样运行。本页末尾的完整示例改用一个测试夹具。

# V1 verification
curl -X POST http://localhost:3000/verify \
  -H "Content-Type: application/json" \
  -d '{"signed_bundle": {"bundle": {...}, "signature": {...}}, "public_key_b64": "..."}'

# V2 composite verification
curl -X POST http://localhost:3000/v2/bundle/verify \
  -H "Content-Type: application/json" \
  -d '{"signed_bundle": {"bundle": {"dcp_bundle_version":"2.0","manifest":{...},...}, "signature": {"composite_sig":{...},...}}}'

# Capability discovery
curl http://localhost:3000/.well-known/dcp-capabilities.json

anchor (:3001)

面向区块链的 bundle 哈希锚定服务。参见 services/anchor/README.md。

transparency-log (:3002)

带包含证明的只追加透明日志。参见 services/transparency-log/README.md。

revocation (:3003)

撤销的发布与查询服务。参见 services/revocation/README.md。

配置

环境变量

每个服务都通过 docker-compose.yml 中的环境变量配置:

verification

变量 默认值 说明
PORT 3000 HTTP 端口
VERIFIER_MODE hybrid_required V2 验证模式
ALLOW_V1_BUNDLES true 接受 V1 格式的 bundle
REQUIRE_SESSION_BINDING、REQUIRE_COMPOSITE_BINDING、MAX_KEY_AGE_DAYS、PQ_CHECKPOINT_INTERVAL、ADVISORY_POLL_INTERVAL_MS 在镜像中和此处设置 服务器目前还不会读取。 适用的是其内置策略(要求会话绑定和复合绑定,密钥年龄阈值为 365 天);可以通过 GET /v2/policy 查看

网关的 DCP-05 至 DCP-09 端点不需要令牌,也不验证签名;在前面没有你自己的授权时,不要把 3000 端口暴露给不受信任的客户端(docs/OPERATOR_GUIDE.md)。

anchor

变量 默认值 说明
PORT 3001 HTTP 端口
ANCHOR_MODE batch "individual" 或 "batch"
BATCH_INTERVAL_MS 60000 刷出间隔(毫秒)
ANCHOR_RPC_URL — L2 节点的 JSON-RPC URL
ANCHOR_PRIVATE_KEY — 钱包私钥
ANCHOR_CONTRACT — DCPAnchor 合约地址
OPERATOR_TOKEN — POST /flush 的 Bearer 令牌(从主机环境传入)

链上提交尚未实现,因此这三个 ANCHOR_* 链设置都不会被使用。

transparency-log

变量 默认值 说明
PORT 3002 HTTP 端口
LOG_ID 自动生成 此日志实例的唯一标识符
OPERATOR_KEY 临时 签署 STH 的密钥的 Ed25519 种子:64 个十六进制字符(openssl rand -hex 32),每个日志一个。其他任何值都会使服务停止
OPERATOR_TOKEN — POST /gossip/peers 的 Bearer 令牌(从主机环境传入)
GOSSIP_PEERS — 以逗号分隔的对等节点,每个为 <endpoint>#<base64 Ed25519 public key>(例如 http://log-b:3002#q1w2...);未固定的对等节点的树头会被忽略
GOSSIP_INTERVAL_MS 30000 Gossip 轮询间隔(毫秒)

要让 Compose 中的两个日志进行 gossip,请给每个日志一个固定的密钥,并固定对方的密钥。请在安装了根目录依赖的情况下,从仓库根目录 运行以下命令(它使用根目录 node_modules 中的 tweetnacl)。根目录下没有 compose 文件,因此请用 -f 指定这个文件:

export TLOG_ALPHA_OPERATOR_KEY=$(openssl rand -hex 32) TLOG_BETA_OPERATOR_KEY=$(openssl rand -hex 32)
pub() { node -e 'const n = require("tweetnacl"); console.log(Buffer.from(n.sign.keyPair.fromSeed(Buffer.from(process.argv[1], "hex")).publicKey).toString("base64"))' "$1"; }
export TLOG_ALPHA_PUBLIC_KEY=$(pub $TLOG_ALPHA_OPERATOR_KEY) TLOG_BETA_PUBLIC_KEY=$(pub $TLOG_BETA_OPERATOR_KEY)
docker compose -f docker/docker-compose.yml up

日志把树保存在内存中:固定的 OPERATOR_KEY 可以在重启之间保持同一个签名密钥,但重启后仍会从一棵空树开始。

revocation

变量 默认值 说明
PORT 3003 HTTP 端口
TRUST_PROXY — 仅在会把客户端 IP 追加到 X-Forwarded-For 的代理之后设为 true
REVOCATION_STATE_PATH 仅内存 只追加的状态文件。此 compose 文件把它设为 revocation-data 卷上的 /data/revocation-state.jsonl

验证和撤销服务也会读取 OPERATOR_TOKEN:用于网关的管理端点,以及在两者上登记新的 agent_id。在仓库根目录运行 OPERATOR_TOKEN=$(openssl rand -hex 32) docker compose -f docker/docker-compose.yml up 即可解锁它们;没有它时,它们返回 401。

状态:所有服务都把状态保存在内存中,在重启或 docker compose down 之后从空状态开始,revocation 除外。这里它的登记和撤销 会写入 revocation-data 卷,因此能在重启和 docker compose down 之后保留;docker compose down -v 会删除该卷,这些数据也随之 删除。

区块链锚定尚未实现

锚定服务不会向链上提交任何内容。docker-compose.yml 中被注释掉的 ANCHOR_RPC_URL、ANCHOR_PRIVATE_KEY 和 ANCHOR_CONTRACT 设置不会被读取(设置 ANCHOR_RPC_URL 只会记录一条警告),因此不要在那里放任何钱包密钥。记录保留在本地 内存中,tx_hash: null、onchain: false。

Dockerfile

Dockerfile 使用带有独立目标的多阶段构建:

Base: node:20-alpine
├── verification  → node server/index.js        (port 3000)
├── anchor        → node services/anchor/index.js      (port 3001)
├── transparency-log → node services/transparency-log/index.js (port 3002)
└── revocation    → node services/revocation/index.js  (port 3003)

单独构建

# Build a specific service (from the repo root: the build context is the repo)
docker build -f docker/Dockerfile --target anchor -t dcp-anchor .

# Run
docker run -p 3001:3001 -e ANCHOR_MODE=batch dcp-anchor

全部构建

# from the repo root
docker compose -f docker/docker-compose.yml build

健康检查

所有服务都配置了健康检查:

  • 间隔: 30 秒
  • 超时: 5 秒
  • 重试: 3 次
  • 命令: wget -qO- http://localhost:PORT/health
  • 重启策略: unless-stopped

检查通过只表示进程能响应 HTTP;它不能证明持久化、锚定、gossip 或生产就绪程度。

完整示例 — 验证一个 bundle

# Run from the repo root: the example files are under tests/.
# 1. Start services
docker compose -f docker/docker-compose.yml up -d

# 2. Verify a signed bundle (note: body must wrap in signed_bundle key)
curl -X POST http://localhost:3000/verify \
  -H "Content-Type: application/json" \
  -d "{\"signed_bundle\": $(cat tests/conformance/examples/citizenship_bundle.signed.json)}"

# 3. Take the bundle_hash the signature carries (computed over the canonical bundle) and anchor it
HASH=$(node -e 'console.log(require("./tests/conformance/examples/citizenship_bundle.signed.json").signature.bundle_hash)')
curl -X POST http://localhost:3001/anchor \
  -H "Content-Type: application/json" \
  -d "{\"bundle_hash\": \"$HASH\"}"

# 4. Add to transparency log (service on port 3002, route is /add)
curl -X POST http://localhost:3002/add \
  -H "Content-Type: application/json" \
  -d "{\"bundle_hash\": \"$HASH\"}"

# 5. Stop
docker compose -f docker/docker-compose.yml down

许可证

Apache-2.0