默克尔树证书 (MTC) 用户指南
v5.0.2.55+ 引入的后量子安全签名压缩方案 —
cc mtc命令使用手册。涵盖 DID 批量发布、Skill Marketplace 上架、verifier 守护进程配置,以及与 libp2p / 文件系统多种传输模式的实操。
最后更新: 2026-05-02(v0.5:Phase 0–4 全部落地,含 federation 多签 + libp2p gossipsub auto-discovery) · 另见:设计文档站 — MTC 落地方案、
docs/design/默克尔树证书_MTC_落地方案.md
1. 这是什么 / 为什么
ChainlessChain 即将切换到后量子安全签名(FIPS 205 / SLH-DSA)。但单条 SLH-DSA-128f 签名 ≈ 17 KB,而 DID 文档每周更新一次会让 DHT 流量从 5 GB 涨到 170 GB(10K 用户规模)。
MTC(Merkle Tree Certificates) 借鉴 IETF PLANTS WG 协议,把 N 条证书装进一棵 Merkle 树,CA 只对树根(tree head)签一次。每条证书携带物从 17 KB 降到 ~700 B,节省约 97%。
| 场景 | 朴素 SLH-DSA-128f | MTC(每条 envelope) | 节省 |
|---|---|---|---|
| 单 DID 文档 | ~17 KB | ~700 B | 96% |
| 1 K 批次 | ~17 MB | ~700 KB | 96% |
| 8 K 批次 | ~136 MB | ~5.6 MB | 96% |
当前实现状态:默认 Ed25519(classical,64 B/sig);通过 --alg slh-dsa-128f 可启用 FIPS 205 SLH-DSA-SHA2-128F 后量子签名(17 KB/sig,依赖 @noble/post-quantum@0.6.1)。cc mtc verify 多算法 dispatcher 自动识别 landmark trust anchor 算法。
2. 适用场景
- 需要批量发布 DID 文档到 P2P 网络的去中心化身份运营者
- 在 Marketplace 上架 / 验证大量技能的开发者
- 需要离线验证证书包含性的合规审计员
- 部署 verifier 守护进程接收 + 持久化批次的节点运维
所有命令为 Headless 模式,无需桌面应用。
3. 核心概念(30 秒)
producer (MTCA) verifier
├ 收集 N 条证书 ├ 订阅 transport
├ 构 Merkle 树 ├ 接收 landmark + 验签
├ 签 tree_head ├ 缓存到 LandmarkCache
├ 打 landmark.json │ (磁盘持久化)
├ 每条出 envelope.json └ 拿 envelope.json:
└ publish 到 transport 重算 inclusion proof
vs landmark 树根 → ✓| 概念 | 说明 |
|---|---|
| MTCA | Merkle Tree Certificate Authority — 收集证书、建树、签树根的角色 |
| landmark | 已签的树头快照,含 root_hash + tree_size + 签名 + 信任锚 |
| envelope | 单条证书 + inclusion proof(leaf_index, audit_path) |
| tree_head_id | tree_head 的 SHA-256 哈希(envelope 引用它,不内嵌全文) |
| transport | landmark 分发通道:InMemory / Filesystem / Libp2p |
4. 命令速查
# 签发批次(3 种来源)
cc mtc batch <input.json> --namespace <ns> --issuer <issuer> # 通用
cc mtc batch-dids --namespace <ns> --issuer <issuer> # 从 DID DB
cc mtc batch-skills --namespace <ns> --issuer <issuer> # 从本地 skills
# Marketplace publisher 守护进程(v0.4 新)
cc mtc publish-skills --namespace-prefix <prefix> --issuer <issuer> \
--out <dir> --state-file <path> [--once | --interval <s>]
# Federation MTCA — 多签 + 服务发现(v0.5 新)
cc mtc federation join <fed-id> --member-id <m> [--alg ed25519|slh-dsa-128f]
cc mtc federation leave <fed-id> --member-id <m> [--keep-key]
cc mtc federation status [<fed-id>]
cc mtc batch* / publish-skills --federation <id> [--threshold <M>] # M-of-N
cc mtc federation discover <fed-id>
--transport filesystem --drop-zone <dir> # 或
--transport libp2p --listen <maddr> --connect <peer-maddr>
[--member-id <m>] [--ttl <s>] [--once]
# Federation 治理(v0.7 新,see design 联邦治理 v1)
cc mtc federation invite <fed-id> <candidate-member-id> --actor <m> --candidate-pubkey-id <id>
cc mtc federation vote <fed-id> <candidate-member-id> --actor <m> --decision approve|reject
cc mtc federation propose-revoke <fed-id> <target-id> --actor <m> --reason <text>
cc mtc federation confirm-revoke <fed-id> <target-id> --actor <m> [--reason key-compromise]
cc mtc federation rotate-key <fed-id> --actor <m> --new-pubkey-id <id> [--new-alg <alg>]
cc mtc federation propose-threshold <fed-id> <new-M> --actor <m>
cc mtc federation fork <fed-id> <new-fed-id> --actor <m> --members <id1,id2,...>
cc mtc federation merge <fed-id> <other-fed-id> <new-fed-id> --actor <m>
cc mtc federation governance-log <fed-id> [--events-only] [--json]
cc mtc federation confirm-threshold <fed-id> --actor <m> [--no-quorum-check]
# 跨成员 governance.log 同步(v0.8/v0.9)
cc mtc federation governance-publish <fed> --drop-zone <dir> # 推到共享目录
cc mtc federation governance-pull <fed> --drop-zone <dir> [--verify] # 从共享目录拉
cc mtc federation governance-sync-serve <fed> --drop-zone <dir> # daemon 自动 publish+pull
[--interval <s>] [--verify] [--once]
cc mtc federation governance-sync-libp2p <fed> # daemon: gossipsub 同步
--listen <maddr> [--connect <peer>] [--interval <s>] [--verify] [--once]
# 验证
cc mtc verify <envelope.json> --landmark <landmark.json>
# 检查
cc mtc landmark inspect <landmark.json>
# Verifier 守护进程(订阅 + 持久化)
cc mtc serve --transport={libp2p,filesystem} [...] --cache-dir <dir>
# Audit 双轨脚手架(v0.4 新,off-by-default — 待法务出函后启用)
cc audit mtc {enable | disable | config | set-interval <s>} # 配置
cc audit mtc {emit | reconcile | reconcile-check <id> | status} # 双轨流转
# 跨链桥 MTC 集成(v0.6 新,opt-in via --mtc,see design 跨链桥设计 v1)
cc crosschain mtc-status # 配置 + trust anchors + staging/batches
cc crosschain mtc-trust-anchor add <chain> <pubkey-id> --alg --issuer
cc crosschain mtc-trust-anchor list [<chain>]
cc crosschain mtc-trust-anchor remove <chain> <pubkey-id>
cc crosschain mtc-envelope --input <ops.json> --src-chain --dst-chain --batch-seq
cc crosschain mtc-verify <envelope> <landmark>
cc crosschain mtc-batch # 关 staging 中所有 op 为批次(按 chain-pair 分组)
cc crosschain bridge|swap|send ... --mtc # 在原命令成功后写一条 staging op
cc crosschain mtc-serve [--interval <s>] [--once] # daemon: 周期性 close batch(v0.7 新)
# v0.11 — 多跳桥 / gas-aware / SLA / 跨联邦互信 / 离线审计
cc crosschain mtc-multihop-build --input <legs.json> [--out <path>] # envelope-of-envelope
cc crosschain mtc-multihop-verify <wrapper> --landmarks <lms.json>
cc crosschain mtc-gas-check <chain> --staged-count <n> [--current-gas-usd <usd>]
cc crosschain mtc-sla [--json] # cc sla 兼容形状
cc mtc federation cross-trust-create <host> <trusted> --threshold <m> --member <id:pubkey>
cc mtc federation cross-trust-validate <anchor.json>
cc mtc federation audit <fed> [--summary | --json] # 离线第三方审计
# v0.12 — 链上治理锚定(Q-COMP-3 2026-05-03 法务出函解锁)
cc mtc federation governance-anchor <fed> --actor <m> --chain-store <dir> [--chain-name <name>]
cc mtc federation governance-verify-anchor <fed> --chain-store <dir> # 对比链上 vs 本地哈希5. 实操:从 DID DB 发布批次
5.1 创建一些 DID 身份
cc did create --name Alice
cc did create --name Bob
cc did list --json5.2 构造批次
cc mtc batch-dids \
--namespace mtc/v1/did/000001 \
--issuer mtca:cc:zQ3shMyMTCA \
--out ./mtc-out输出示例:
⚠ STOPGAP — tree-head signed with Ed25519 (will switch to SLH-DSA when @noble/post-quantum lands).
✔ Batched 2 DID(s)
Namespace: mtc/v1/did/000001
Tree size: 2
Root hash: sha256:mTzhpZFwRun73V7EBgk0z5l-srzAwlL1dF6NLwwclxU
Tree head ID: sha256:EVWfR9goXamzZ1xfjXj1h9HnE2cgdVZwDD7ZeTSc6k4
Landmark: ./mtc-out/landmark.json
Envelopes: 2 files in ./mtc-out
Subjects:
did:chainless:zQ3shAlice...
did:chainless:zQ3shBob..../mtc-out/ 目录结构:
landmark.json ← 树根签名快照(含信任锚)
envelope-000000.json ← Alice 的证书
envelope-000001.json ← Bob 的证书5.3 复用密钥(推荐)
每次 batch-dids 默认生成新 Ed25519 密钥对,导致 verifier 无法跨批次共享信任锚。生产用法应固定密钥:
cc mtc batch-dids \
--namespace mtc/v1/did/000002 \
--issuer mtca:cc:zQ3shMyMTCA \
--secret-key-file ~/.chainlesschain/mtc/mtca.key.hex \
--out ./mtc-out-v2首次会创建 mtca.key.hex(mode 0600,仅 owner 可读);后续运行复用同一密钥 → 信任锚相同 → verifier 一份配置走天下。
5.4 选择签名算法(v0.4 / Phase 1.6)
所有 cc mtc batch* + cc mtc publish-skills 都支持 --alg:
# 默认(classical Ed25519,64 B/sig,全网最快)
cc mtc batch-dids --namespace mtc/v1/did/000001 --issuer mtca:cc:zQ3sh... --alg ed25519
# 后量子(FIPS 205 SLH-DSA-SHA2-128F,17 KB/sig,opt-in)
cc mtc batch-dids --namespace mtc/v1/did/000001 --issuer mtca:cc:zQ3sh... --alg slh-dsa-128f--secret-key-file 自动适配密钥长度(Ed25519 = 32 B,SLH-DSA = 64 B),文件首次创建时按所选算法生成。已存的 Ed25519 key 与 SLH-DSA key 不互通(不同算法的 trust anchor 单独签发)。
cc mtc verify 是多算法 dispatcher,自动按 landmark trust_anchors 内 alg 字段识别后选用对应 verifier,无需 --alg 提示。
5.5 过滤特定 DID
cc mtc batch-dids \
--namespace mtc/v1/did/000003 \
--issuer mtca:cc:zQ3shMyMTCA \
--did did:chainless:zQ3shAlice... \
--out ./mtc-out-alice-only可重复 --did 选择多条,省略则包含所有身份。
6. 实操:验证 envelope
最小例子:本机签 + 本机验
cc mtc verify ./mtc-out/envelope-000000.json \
--landmark ./mtc-out/landmark.json成功输出:
⚠ STOPGAP — tree-head signed with Ed25519 (...)
✔ Envelope verified
Subject: did:chainless:zQ3shAlice...
Kind: did-document
Tree size: 2
Issuer: mtca:cc:zQ3shMyMTCA关键错误码(按 MTC_数据格式_v1.md §11 完整列出):
| Code | 退出码 | 含义 | 可恢复 |
|---|---|---|---|
LANDMARK_MISS | 2 | 本地 cache 没找到对应 tree_head_id | 拉新 landmark |
LANDMARK_EXPIRED | 2 | tree_head 已过期 | 拉新 landmark |
ROOT_MISMATCH | 2 | inclusion proof 重算根 ≠ 声明根 | ❌ 视为伪造 |
BAD_TREE_HEAD_SIG | 2 | 树头签名验签失败 | ❌ 信任锚不匹配 |
MTCA_DOUBLE_SIGNED | 2 | 同 namespace+tree_size 看到不同根 | ❌ split-view 攻击 |
测试时可加 --now <ISO> 模拟过期:
cc mtc verify envelope.json --landmark landmark.json \
--now 2027-01-01T00:00:00Z # 模拟未来时间,触发 LANDMARK_EXPIRED7. 实操:Marketplace 技能批次
# 全部技能
cc mtc batch-skills \
--namespace mtc/v1/skill/000001 \
--issuer mtca:cc:zQ3shMarket \
--secret-key-file ~/.chainlesschain/mtc/marketplace.key.hex \
--out ./skill-batch
# 只发指定技能
cc mtc batch-skills \
--namespace mtc/v1/skill/000002 \
--issuer mtca:cc:zQ3shMarket \
--skill ai-doc-creator \
--skill code-reviewer每条 leaf 包含技能 manifest 的 content_hash(id+displayName+description+version+category 的 JCS canonical)+ subject skill:cc:<id>@<version>。
8. 实操:守护进程 verifier
cc mtc serve 是 verifier daemon 模式:订阅 transport → 拉 landmark → 验签 → 持久化到 LandmarkCache → 显示统计。
8.1 文件系统 drop-zone(最简单)
适合局域网共享目录、USB 同步、离线环境。
节点 A(producer):
# 生成批次到共享目录
cc mtc batch-dids --namespace mtc/v1/did/000001 \
--issuer mtca:cc:zQ3shMTCA \
--secret-key-file ~/.chainlesschain/mtc/mtca.key.hex \
--out ./output
# 推到 drop-zone
cp ./output/landmark.json /shared/mtc-drop/content/
# (或写一个 cc mtc publish-to <drop-zone> 的小脚本)节点 B(verifier):
cc mtc serve \
--transport=filesystem \
--drop-zone /shared/mtc-drop \
--prefix mtc/v1/did \
--cache-dir ~/.chainlesschain/mtc/cache输出:
✔ filesystem transport watching /shared/mtc-drop
subscribed: mtc/v1/did
[1] mtc/v1/did/000001 tree_size=2 cid=fs:abc...--exit-after <n> 在收到 N 条后自动退出(CI 用);省略则常驻。
8.2 Libp2p direct 模式
适合直连两节点的 P2P 场景。
节点 A:
cc mtc serve --transport=libp2p \
--listen /ip4/0.0.0.0/tcp/9000 \
--prefix mtc/v1/did \
--cache-dir ~/.chainlesschain/mtc/cache
# 启动时打印自己的多址:/ip4/127.0.0.1/tcp/9000/p2p/12D3KooW...节点 B(连节点 A):
cc mtc serve --transport=libp2p \
--connect /ip4/<A的IP>/tcp/9000/p2p/<A的peerid> \
--prefix mtc/v1/didA 调用 cc mtc batch-dids 后,需自己 publish;目前 publish-to-libp2p 是 Phase 2 工作,当前可手工把 landmark 喂进 transport。
8.3 Libp2p gossipsub 模式
订阅 topic 即 namespace prefix。适合多节点广播场景。
cc mtc serve --transport=libp2p --mode=gossipsub \
--listen /ip4/0.0.0.0/tcp/9000 \
--connect <已知节点的多址> \
--prefix mtc/v1/did配置 D=1 + floodPublish 适配低密度网络(2 节点也能跑)。
8.4 Marketplace publisher 守护进程(v0.4)
cc mtc publish-skills 是 producer 端守护进程:扫描本地 CLISkillLoader.loadAll(),对技能集合做 fingerprint(id+version+category+activation+description 的 JCS canonical → SHA-256),与状态文件对比,仅当指纹变化时才生成新批次。重复运行不会产生重复批次。
# 一次性发布(CI / cron 用)
cc mtc publish-skills \
--namespace-prefix mtc/v1/skill \
--issuer mtca:cc:zQ3shMarket \
--out ~/.chainlesschain/marketplace-batches \
--state-file ~/.chainlesschain/marketplace-state.json \
--secret-key-file ~/.chainlesschain/mtc/marketplace.key.hex \
--once
# 守护模式(10 分钟一次,长期运行)
cc mtc publish-skills \
--namespace-prefix mtc/v1/skill \
--issuer mtca:cc:zQ3shMarket \
--out ~/.chainlesschain/marketplace-batches \
--state-file ~/.chainlesschain/marketplace-state.json \
--interval 600输出(首次发布):
{
"iteration": "published",
"seq": "000001",
"namespace": "mtc/v1/skill/000001",
"tree_head_id": "sha256:...",
"tree_size": 139,
"batch_dir": "~/.chainlesschain/marketplace-batches/000001",
"landmark_path": "~/.chainlesschain/marketplace-batches/000001/landmark.json",
"envelope_paths": ["..."]
}输出(无变化):
{ "iteration": "skipped", "reason": "fingerprint unchanged", "last_seq": 1, "fingerprint": "sha256:..." }状态文件(mtc-skill-publish-state/v1)使用原子写(temp + rename),即使进程崩溃也不会污染。如果该文件被外部损坏,下次启动会显式报错而非静默重置到 seq 0。
与
cc mtc serve --transport=filesystem配合:把--out指到 verifier 节点能访问的共享目录(NFS / SMB / USB),verifier 即可订阅mtc/v1/skill自动 ingest 新批次的 landmark。
9. 持久化与重启恢复
--cache-dir <dir> 启用磁盘镜像。目录结构:
~/.chainlesschain/mtc/cache/
mtc/v1/did/000001/sha256_abc.json ← snapshot 1
mtc/v1/did/000002/sha256_def.json ← snapshot 2
...cc mtc serve 启动时自动 loadFromDisk():
- ✅ 重新校验每个 snapshot 的签名(用当前信任锚)
- ❌ 篡改文件、密钥变更后的旧文件 → 跳过 + 计入失败列表
- 启动日志:
cache: loaded N prior snapshots, M failed
10. 与现有功能的关系
| 现有功能 | MTC 影响 |
|---|---|
cc did create/list/resolve | 不变,DID 生成 + 本地存储完全独立 |
cc did publish(未来) | 默认走 MTC 路径;--no-mtc 兜底单签 |
cc marketplace publish | Phase 2 改为入 MTCA 队列;publisher daemon cc mtc publish-skills v0.4 已落地 |
cc audit emit(v1) | 不变,沿用现有 Ed25519 链式哈希审计;cc audit mtc emit v0.4 是平行的 MTC 双轨脚手架 |
cc audit mtc *(v0.4 新) | 双轨签名:实时 Ed25519 + 关批 MTC;off-by-default,等保口径出函后单 flag 启用 |
| 现有 Ed25519 签名 | 长期保留作为 fallback 路径 |
11. 常见问题
Q: 现在签出来的 landmark 包含 SLH-DSA 签名吗?
A: 不,目前 stopgap 是 Ed25519。代码已为 SLH-DSA-128f 预留接口(signatureVerifier DI),等 @noble/post-quantum npm 上线即切换。所有 stopgap 落地的命令都会显示 ⚠ STOPGAP 警告。
Q: 不同节点之间的 verifier 如何信任同一 MTCA?
A: landmark 文件自带 trust_anchors[](含公钥 JWK)。verifier 用 makeVerifierFromLandmark(landmark) 提取 → 信任传递在 landmark 内部完成,不需要预装信任根。前提是首份 landmark 通过可信通道(带外)送达。
Q: 批次大小 N 怎么选?
A: 当前默认 = 输入条目数。生产建议:
- DID:8192 / 批,每周关一次(推荐与 IETF 节奏对齐)
- Skill:1024 / 批,每月关一次
- Audit(未来):1024 / 批,每小时关一次(合规复核中)
Q: split-view 攻击会被检测吗?
A: 会。LandmarkCache.ingest() 在 namespace + tree_size 相同时强制要求 root_hash 一致;不一致即抛 MTCA_DOUBLE_SIGNED。详见 设计文档 §10.1 威胁模型。
12. 实操:企业审计双轨脚手架(v0.4)
cc audit mtc * 是 Phase 2 audit 路径的双轨签名脚手架:
- Track 1(实时):每条事件 emit 时立刻写一个 staging 文件,附带 Ed25519 签名(content_hash 上签),毫秒级落盘 + 密码学防篡改。
- Track 2(最终):定期或手动调 reconcile 关批,把 staging 中所有事件聚合成 Merkle 树,签 tree_head,输出 landmark + 每事件 envelope(含 inclusion proof)。
✅ 2026-05-01 法务出函已收到(Q-COMP-1 等保三级最终性窗口 + Q-COMP-2 T/ZGCMCA 023—2025 条款)。脚手架默认仍
enabled=false——cc audit mtc emit在 disabled 状态下会拒绝写入(除非--force);由各租户在自己的环境通过cc audit mtc enable --interval <60|3600>显式启用,60s 严判 / 3600s 宽松路径按出函具体口径选择。
12.1 启用与配置
# 查看默认配置(不会启用)
cc audit mtc config --json
# 启用(自定义 namespace + 1 小时批次)
cc audit mtc enable \
--namespace mtc/v1/audit/org-acme \
--issuer mtca:cc:zQ3shAuditMTCA \
--interval 3600
# 切换到 1 分钟严判路径(如果法务要求 sub-minute 最终性)
cc audit mtc set-interval 60
# 关闭
cc audit mtc disable12.2 提交事件 + 关批 + 校验
# 事件入队(Track 1:立刻签 + 落盘到 staging/)
cc audit mtc emit \
--type auth --operation login \
--actor alice --risk-level low
# 查看队列
cc audit mtc status
# 关批(Track 2:构树 + 签 tree_head + 输出 envelope + 清空 staging)
cc audit mtc reconcile
# 反查事件落在哪个批次
cc audit mtc reconcile-check 20260501123456-abcdef01234512.3 文件布局
启用后,配置目录(默认 ~/.chainlesschain/audit-mtc/):
audit-mtc/
├── config.json # enabled / batch_interval_seconds / namespace / issuer
├── keys/issuer.hex # Ed25519 私钥,0o600
├── staging/ # 待批的事件(Track 1 已签)
│ └── 20260501123456-abc.json
└── batches/
└── 000001/
├── manifest.json # batch_id / event_ids / tree_head_id
├── landmark.json # 整批的 MTC landmark
└── envelope-<event-id>.json # 每事件一份,含 inclusion proof12.4 幂等性保证
reconcile在 staging 为空时是 no-op(返回{ skipped: true, reason: "no staged events" }),可放心丢到 cron。- 关批用 atomic rename(写到
batches/.<seq>.tmp/再 rename);崩溃后下次启动会清理 leftover tmp 目录。 - staging 文件只在 rename 成功后才删除——保证不会丢事件。
- staging 文件名 / event_id / schema 三处都验签,外部丢进 staging 的伪事件会被 reconcile 跳过并记入
manifest.malformed_skipped。
12.5 验证脚本(独立校验链路)
任何持有 landmark 的第三方都能离线校验整批:
import {
LandmarkCache, verify, ed25519,
} from "@chainlesschain/core-mtc";
import fs from "node:fs";
const landmark = JSON.parse(fs.readFileSync("batches/000001/landmark.json", "utf-8"));
const cache = new LandmarkCache({
signatureVerifier: ed25519.makeVerifierFromLandmark(landmark),
});
cache.ingest(landmark);
// 任选一个 envelope
const envelope = JSON.parse(fs.readFileSync("batches/000001/envelope-XXX.json", "utf-8"));
const r = verify(envelope, cache);
console.log(r.ok ? "✓ 该事件确实在批次内" : `✗ ${r.code}`);13. Federation MTCA — 多签 + 服务发现(v0.5)
13.1 设计
不同于单 MTCA 模式(一个节点对树根签一次),federation 模式让 N 个独立节点各自签发同一棵树根;landmark 内嵌 signatures[] + threshold。Verifier 在 ≥ threshold 个签名验证通过时才接受。等保三级"多签防一人作弊"语义自然落到这条路径。
支持异构成员(部分 Ed25519 + 部分 SLH-DSA)— federation 内每个成员独立选算法,verifier 多算法 dispatcher 自动识别。
13.2 加入 / 退出本地 federation 注册表
# 加入 — 生成密钥(或复用 --key-file)+ 写入 ~/.chainlesschain/federation/members.json
cc mtc federation join fed-acme --member-id node-a --alg ed25519
cc mtc federation join fed-acme --member-id pqc-node --alg slh-dsa-128f
# 查看
cc mtc federation status fed-acme
# 退出(默认连同密钥文件一起删;--keep-key 保留)
cc mtc federation leave fed-acme --member-id node-a密钥安全:每成员 secret key 落盘于 ~/.chainlesschain/federation/keys/<fed>.<member>.hex(mode 0o600)。wx 独占创建防止并发 join 写冲突。
13.3 用 federation 发布批次(M-of-N)
cc mtc batch / batch-dids / batch-skills / publish-skills 全部支持 --federation <id> + --threshold <M>:
# 3-of-3 强制全签
cc mtc batch-dids \
--namespace mtc/v1/did/000001 \
--issuer mtca:cc:fed-acme \
--federation fed-acme \
--out ./mtc-out
# 2-of-3 容许一节点离线
cc mtc publish-skills \
--namespace-prefix mtc/v1/skill \
--issuer mtca:cc:fed-marketplace \
--federation fed-marketplace --threshold 2 \
--out ~/.chainlesschain/marketplace-batches \
--state-file ~/.chainlesschain/marketplace-state.jsoncc mtc verify 自动识别 federated landmark — 没有额外标志要传。
13.4 服务发现 — Filesystem drop-zone
最简单的跨进程发现:所有成员读写一个共享目录(NFS / Syncthing / SMB / USB)。每节点定期把自签 announce 写到 <drop-zone>/federation-announces/<fed-id>/,其他节点扫描 + 验签 + 入 cache。
# Node A
cc mtc federation discover fed-acme \
--transport filesystem \
--drop-zone /shared/fed-zone \
--member-id node-a \
--ttl 600 --scan-interval 30
# Node B(listen-only,纯订阅不发布)
cc mtc federation discover fed-acme \
--transport filesystem \
--drop-zone /shared/fed-zoneAnnounce TTL 默认 600s,重新发布间隔 = TTL/3。Listen-only 模式(不带 --member-id)让 verifier 节点只读订阅。
13.5 服务发现 — libp2p gossipsub(真 P2P 自动发现)
# Bootstrap node
cc mtc federation discover fed-acme \
--transport libp2p \
--listen /ip4/0.0.0.0/tcp/9100 \
--member-id node-a
# 启动时打印自己的多址:/ip4/127.0.0.1/tcp/9100/p2p/12D3...
# 后续节点连接 bootstrap
cc mtc federation discover fed-acme \
--transport libp2p \
--listen /ip4/0.0.0.0/tcp/0 \
--connect /ip4/<bootstrap-ip>/tcp/9100/p2p/<bootstrap-peerid> \
--member-id node-bTopic 命名:mtc-federation/v1/<federation-id>。Mesh 形成后所有成员互相 announce,无需 bootstrap 节点之外的协调。Per-event 验签 + TTL 自动失效 + pubkey-id 去重在 cache 层兜底。
13.6 Bug 审计 + 安全说明
- 签名重放保护:announce 自签 prefix 域分离
mtc/v1/federation-announce\n,与 tree-head 签名前缀不冲突。 - TTL 防陈旧:cache TTL-evicting;过期 announce 直接拒收(除非
verifyMemberAnnounce(ann, { allowExpired: true }))。 - 节点泄漏防护:libp2p mode
try/catch包整个 init,异常路径上node.close()兜底。 - scan 重入锁:filesystem mode 的
setInterval在 scan 还没结束时不重入。
13.7 联邦治理 walkthrough(v0.7+v0.9)
服务发现解决"找到成员",治理解决"谁能签、何时签、怎么撤"。所有治理事件签名后追加到本地 ~/.chainlesschain/federation/governance/<fed-id>.jsonl。完整设计见 设计文档站 — MTC 联邦治理 v1。
# 1. 创建联邦 + 加入两个成员
cc mtc federation join fed-acme --member-id alice --alg ed25519
cc mtc federation join fed-acme --member-id bob --alg ed25519
# 2. 邀请第三个候选(候选期权重 0.5,30 天后自动转正)
cc mtc federation invite fed-acme carol --actor alice \
--candidate-pubkey-id sha256:abc...
# 3. 投票(threshold 内累计 approve 满足时入正式名单)
cc mtc federation vote fed-acme carol --actor alice --decision approve
cc mtc federation vote fed-acme carol --actor bob --decision approve
# 4. 提升 threshold(quorum-gated,v0.9 新)
cc mtc federation propose-threshold fed-acme 3 --actor alice
cc mtc federation confirm-threshold fed-acme --actor alice
# ↑ confirm-threshold 默认 pre-flight 检查匹配的 propose-threshold 存在,
# 否则非零退出。--no-quorum-check 可显式跳过(不推荐生产使用)。
# 5. 撤销(同样 quorum-gated)
cc mtc federation propose-revoke fed-acme bob --actor alice --reason inactive
cc mtc federation confirm-revoke fed-acme bob --actor alice
# 6. 旋转密钥
cc mtc federation rotate-key fed-acme --actor alice \
--new-pubkey-id sha256:def... --new-alg ed25519
# 7. 查看 effective state(replay 整条 governance.log)
cc mtc federation governance-log fed-acme --jsonreplayGovernanceLog 是纯函数还原:成员名单、threshold、待投票邀请、撤销 / 阈值提案的状态机。verifier 检查 landmark 时 reply 当下成员名单 ≥ threshold 个有效签名才接受批次。
13.8 跨成员 governance.log 同步(v0.8/v0.9)
问题:每成员的 governance.log 只在本地,其他成员若不主动同步就感知不到事件。 v0.8 方案:governance-publish / governance-pull 通过文件系统共享目录(NFS / Syncthing / SMB / USB / S3 mount)跨主机同步。 v0.9 方案:governance-sync-serve 自动 daemon 化;governance-sync-libp2p 走 libp2p gossipsub 真 P2P 通道。
# 文件系统通道(v0.8)— 操作员手动 publish + 手动 pull
cc mtc federation governance-publish fed-acme --drop-zone /shared/fed-zone
# ↑ atomic write 一文件一事件到 <drop-zone>/<fed>/<event_id>.json,幂等
cc mtc federation governance-pull fed-acme --drop-zone /shared/fed-zone --verify
# ↑ dedupe by event_id;--verify 检查每事件签名(actor 公钥需在本地 federation
# members 注册表里)。
# 文件系统自动 daemon(v0.9)— 周期性 publish + pull
cc mtc federation governance-sync-serve fed-acme \
--drop-zone /shared/fed-zone --interval 30 --verify
# ↑ SIGINT/SIGTERM graceful;--once 单次模式适合 cron / 测试。
# libp2p gossipsub 通道(v0.9)— 真 P2P 同步
# Bootstrap 节点
cc mtc federation governance-sync-libp2p fed-acme \
--listen /ip4/0.0.0.0/tcp/9200 --interval 60 --verify
# 后续节点连接 bootstrap
cc mtc federation governance-sync-libp2p fed-acme \
--listen /ip4/0.0.0.0/tcp/0 \
--connect /ip4/<bootstrap-ip>/tcp/9200/p2p/<bootstrap-peerid>Topic 命名:mtc-federation-governance/v1/<federation-id>(与 landmark 通道 mtc-federation/v1/<id> 隔离)。<dir>/<fed>.libp2p-pos.json 记录已 publish 的 event_id 高水位,避免重复广播;接收侧 dedupe + verify + append 到本地 governance.log。
生产部署提示:在 packages/cli/scripts/service/ 提供四种 supervisor 模板 — cc-fed-governance-sync.service (systemd Linux) / cc-bridge-mtc.service / cc-bridge-mtc.nssm.txt / cc-bridge-mtc.taskscheduler.xml (Windows) / com.chainlesschain.bridge-mtc.plist (launchd macOS)。操作员手动 install,不接 npm postinstall。
13.9 治理 GUI(v0.8+v0.9,桌面 + web)
桌面 V6 widget:FederationGovernanceWidget(联邦治理 widget)+ BridgeMtcStatusWidget(跨链桥状态 widget)通过 electronAPI.mtc.getFederationGovernance / electronAPI.mtc.getBridgeStatus IPC 拉数据,列出所有联邦的 status / threshold / 成员(活跃 + 候选)/ 待投票 / 待撤销 / 归档 / 泄漏密钥。
Web Panel + Web Shell (Mtc.vue):
- "审计 MTC" tab — config / staging / batches 摘要
- "Marketplace publisher" tab — publish-status 历史
- "MTC verify" tab — 调
cc mtc verify <env> --landmark <lm> - "跨链桥 MTC" tab — 桥配置 + 信任锚表
- "联邦治理" tab — 输入 fed-id 加载 governance-log,渲染状态卡 / 成员表 / 待投票列表 / 事件时间线
- 操作型治理子 tabs(v0.9):邀请 / 投票 / 改 threshold / 撤销 / 跨成员同步 — 全部通过
ws.execute('mtc federation ...')调用本机 CLI 子进程。签名密钥永远不进入 web 渲染进程;GUI 只负责给 CLI 命令拼参数。
- 操作型治理子 tabs(v0.9):邀请 / 投票 / 改 threshold / 撤销 / 跨成员同步 — 全部通过
安全设计要点:web 端永远不持有 federation member secret key。任何治理操作 = 本机 CLI 调用 = 信任根落到操作员桌面环境的
~/.chainlesschain/federation/keys/。这条边界在Mtc.vue操作型治理面板顶部 a-alert 显式说明。
14. 进阶:核心库直接调用
import {
MerkleTree, leafHash, jcs, encodeHashStr, sha256,
LandmarkCache, verify, ed25519,
TREE_HEAD_SIG_PREFIX,
} from '@chainlesschain/core-mtc';
// 构造证据
const leaves = items.map(it => leafHash(jcs(it)));
const tree = new MerkleTree(leaves);
const root = tree.root();
const proof = tree.prove(0); // [Buffer, Buffer, ...]
// 签 tree_head
const keys = ed25519.generateKeyPair();
const treeHead = { schema: 'mtc-tree-head/v1', /* ... */ };
const signingInput = Buffer.concat([TREE_HEAD_SIG_PREFIX, jcs(treeHead)]);
const signature = ed25519.signTreeHead(signingInput, { ...keys, issuer: '...' });
// 验证
const cache = new LandmarkCache({
signatureVerifier: ed25519.makeVerifierFromLandmark(landmark),
});
cache.ingest(landmark);
const result = verify(envelope, cache);完整 API 参考详见 设计文档站 MTC 数据格式规范。
