﻿---
title: "私有知识共识链：不发币、不公开，几百个席位共同维护一份知识和规则"
description: "设想一条只给几百个席位读写的链：不发币，不做交易，只记两样东西，一是成员共同维护的知识，每条都必须引用链上已经通过的知识，二是成员给自己定的规则，连“多少人同意才算通过”和“席位从 300 扩到 500”也在链上投票决定。顺着这个设想往下走：知识块和引用图长什么样、第一条知识从哪来、错了怎么推翻；Metamath、维基百科、Fabric、Besu、Tezos、Polkadot 这些已有系统各做了哪一部分；再用 CometBFT 搭一个原型实测引用和推翻、看一个三分之二的联盟能不能借扩容夺权，最后量一量共同维护一份记忆能让分歧少多少，又要为每条共识交多少“共识税”。"
pubDate: 2026-10-23
tags: ["区块链", "许可链", "链上治理", "知识表示", "智能体"]
hero: "./hero.svg"
refs:
  - id: metamath
    title: "Metamath"
    url: https://en.wikipedia.org/wiki/Metamath
    site: Wikipedia
    note: "set.mm 从 1992 年开始积累，每条定理只能由公理和前面的定理推出，网页上列出它依赖哪些公理、被哪些定理引用。"
  - id: mathlib-stats
    title: "Mathlib statistics"
    url: https://leanprover-community.github.io/mathlib_stats.html
    site: Lean community
    date: 2026-10-22
    note: "2026-10-22 抓取：约 139,557 个定义、291,055 条定理、772 位贡献者。"
  - id: wiki-nor
    title: "Wikipedia: No original research"
    url: https://en.wikipedia.org/wiki/Wikipedia:No_original_research
    site: Wikipedia
    note: "原创研究指“找不到可靠的已发表来源的材料”；举证责任在添加内容的人。"
  - id: nanopub
    title: "Nanopublications: A Growing Resource of Provenance-Centric Scientific Linked Data"
    url: https://arxiv.org/abs/1809.06532
    author: "Tobias Kuhn 等"
    site: arXiv
    date: 2018-09-18
    note: "一条纳米出版物 = 断言 + 出处 + 发布信息三个 RDF 命名图；已超过 1000 万条，多数来自生命科学。"
  - id: proofgold
    title: "Proofgold: Blockchain for Formal Methods"
    url: https://drops.dagstuhl.de/opus/volltexte/2022/17185/
    author: "Chad E. Brown, Cezary Kaliszyk, Thibault Gauthier, Josef Urban"
    site: FMBC 2022
    date: "2022"
    note: "高阶逻辑证明检查器是共识的一部分；PoS 加烧 Litecoin；交出证明就能领走命题上挂的赏金。"
  - id: origintrail
    title: "OriginTrail：DKG key concepts"
    url: https://docs.origintrail.io/key-concepts/dkg-key-concepts
    site: OriginTrail
    note: "Knowledge Asset 带可验证的出处和发布者；发布知识要付 TRAC，跑节点要质押 TRAC；不对内容真假做裁决。"
  - id: agrippa
    title: "Münchhausen trilemma"
    url: https://en.wikipedia.org/wiki/M%C3%BCnchhausen_trilemma
    site: Wikipedia
    note: "要求每个命题都给出理由，最后只能落到无穷后退、循环论证或不再论证的起点三者之一。"
  - id: iapws
    title: "IAPWS FAQ：What is the boiling point of water?"
    url: https://www.iapws.org/faq/boil.html
    site: IAPWS
    note: "VSMOW 水在一个标准大气压下：按 ITS-90 约 99.974 °C；严格按热力学温度约 99.984 °C。"
  - id: fabric-policies
    title: "Hyperledger Fabric：Policies"
    url: https://hyperledger-fabric.readthedocs.io/en/latest/policies/policies.html
    site: Hyperledger Fabric
    date: 2026-10-23
    note: "应用通道默认策略：Readers 为 `ANY Readers`，Writers 为 `ANY Writers`，Admins 为 `MAJORITY Admins`，Endorsement 为 `MAJORITY Endorsement`；每个配置项都挂一条修改策略（mod_policy），改它要凑够对应的签名。"
  - id: fabric-pdc
    title: "Hyperledger Fabric：Private data"
    url: https://hyperledger-fabric.readthedocs.io/en/latest/private-data/private-data.html
    site: Hyperledger Fabric
    date: 2026-10-23
    note: "通道内所有成员都能看到整本账；私有数据集合只把数据发给集合成员，其他节点和排序服务只拿到哈希。"
  - id: fabric-v3
    title: "Version 3.0 of Hyperledger Fabric, an LF Decentralized Trust Project, Now Available"
    url: https://www.lfdecentralizedtrust.org/announcements/version-3.0-of-hyperledger-fabric-an-lf-decentralized-trust-project-now-available
    site: LF Decentralized Trust
    date: 2024-09-16
    note: "3.0 起排序服务可以用 SmartBFT，容忍不到三分之一的排序节点作恶；此前只有 Raft，只防宕机、不防作恶。"
  - id: corda-wp
    title: "Corda: A Distributed Ledger（技术白皮书）"
    url: https://api.corda.net/en/pdf/corda-technical-whitepaper.pdf
    author: "Mike Hearn, Richard Gendal Brown"
    site: R3
    note: "数据按需知晓（need-to-know）分享，没有全网广播；公证人（notary）只负责“同一份状态没被花两次”。"
  - id: besu-qbft
    title: "Besu：Configure QBFT consensus"
    url: https://docs.besu-eth.org/private-networks/how-to/configure/consensus/qbft
    site: Hyperledger Besu
    date: 2026-10-23
    note: "用 `qbft_proposeValidatorVote` 提议增删验证者，超过 50% 现有验证者提出同样的提议就生效；至少 4 个验证者才能容错，掉线超过三分之一就停链。"
  - id: goquorum
    title: "Migrating from Quorum to Hyperledger Besu"
    url: https://www.kaleido.io/blockchain-blog/migrating-from-quorum-to-hyperledger-besu
    site: Kaleido
    note: "ConsenSys 已不再为 GoQuorum 提供持续支持，2023 年指定 Kaleido 协助客户迁移到 Besu。"
  - id: sawtooth-settings
    title: "Sawtooth：Settings Transaction Family"
    url: https://sawtooth.splinter.dev/docs/1.2/transaction_family_specifications/settings_transaction_family.html
    site: Hyperledger Sawtooth
    note: "`sawtooth.settings.vote.authorized_keys` 列出能提议和投票的公钥，`sawtooth.settings.vote.approval_threshold` 是通过所需票数（默认 1）；赞成票达到门槛，设置就写进状态。"
  - id: sawtooth-eol
    title: "Announcing the release of Hyperledger Sawtooth 1.0"
    url: https://www.lfdecentralizedtrust.org/hyperledger-sawtooth-1-0
    site: LF Decentralized Trust
    note: "页首说明：应维护者要求，Sawtooth 于 2024 年 2 月 1 日转为停止维护（end of life）状态。"
  - id: cometbft-abci
    title: "CometBFT v0.38：ABCI++ Application Requirements"
    url: https://github.com/cometbft/cometbft/blob/v0.38.x/spec/abci/abci%2B%2B_app_requirements.md
    site: GitHub
    note: "建立 p2p 连接前，CometBFT 会向应用发 `/p2p/filter/addr/…` 和 `/p2p/filter/id/…` 两个查询，任一返回非零就拒绝连接；处理高度 H 时返回的验证者变更在 H+2 生效。"
  - id: tezos-gov
    title: "Tezos：Governance"
    url: https://docs.tezos.com/architecture/governance
    site: Tezos
    date: 2026-10-23
    note: "五个阶段（提案、探索、冷却、推广、采纳），每段 14 个周期，约 14 天；只有质押的委托人能投票，按质押加权；探索和推广两轮要求赞成超过（赞成 + 反对）的 80%，法定人数按往届参与率动态调整。"
  - id: tezos-history
    title: "Tezos：History of amendments"
    url: https://docs.tezos.com/architecture/governance/amendment-history
    site: Tezos
    date: 2026-10-23
    note: "从 2019 年 5 月的 Athens 到 2026 年 6 月 30 日的 Ushuaia，共 21 次协议升级通过投票自动生效；Brest A 和最初的 Carthage 两个提案被否决。"
  - id: opengov
    title: "Polkadot OpenGov"
    url: https://wiki.polkadot.com/learn/learn-polkadot-opengov/
    site: Polkadot Wiki
    date: 2026-10-23
    note: "15 个来源（origin），各走自己的轨道；每条轨道有自己的押金、决策期、确认期、最短生效期和“赞成率曲线”“支持率曲线”；Root 轨道同时只能决一个提案，周期最长；锁仓越久票越重，从 0.1 倍到 32 倍。"
  - id: cosmos-gov
    title: "Cosmos SDK：x/gov"
    url: https://github.com/cosmos/cosmos-sdk/blob/main/x/gov/README.md
    site: GitHub
    note: "参数表示例：quorum 0.334、threshold 0.5、veto_threshold 0.334、加速提案 0.667；提案里的消息由 gov 模块账户代签执行，模块用 `authority` 字段限定只有治理能改参数。"
  - id: cosmos-797
    title: "Cosmos Hub Proposal #797：Increase the validator set of Cosmos Hub to 180 from 175"
    url: https://cosmos.valopers.com/proposals/797
    site: Valopers
    date: 2023-06-13
    note: "2023-05-30 至 06-13 投票：赞成 75.29%、反对 12.18%、否决 0.01%、弃权 12.53%，参与率 39.68%。"
  - id: compound-gov
    title: "Compound II：Governance"
    url: https://docs.compound.xyz/v2/governance/
    site: Compound
    note: "持有或受托 25,000 COMP 才能发起提案；2 天审阅期、3 天投票期，至少 400,000 票赞成才能通过；通过后进入 2 天时间锁再执行。"
  - id: nomic-rules
    title: "Nomic：Initial Set of Rules"
    url: https://foldoc.org/pub/games/nomic/original
    author: "Peter Suber"
    site: FOLDOC
    note: "规则 109：把不可变规则转为可变，必须全体一致；规则 203（可变）：规则修改要全体一致才通过；规则 204 预告“如果以后不需要一致了”的情形。"
  - id: nomic
    title: "Nomic"
    url: https://en.wikipedia.org/wiki/Nomic
    site: Wikipedia
    note: "Peter Suber 1982 年设计，首次发表在 Hofstadter 的《科学美国人》专栏；Agora 从 1993 年玩到现在。Suber 的书名就叫《自我修正的悖论》（1990）。"
  - id: us-art5
    title: "Article Five of the United States Constitution"
    url: https://en.wikipedia.org/wiki/Article_Five_of_the_United_States_Constitution
    site: Wikipedia
    note: "修正案由国会两院三分之二提出、四分之三的州批准；但“各州在参议院有平等投票权”这一条，未经该州同意不得剥夺。"
  - id: eternity
    title: "Eternity clause"
    url: https://en.wikipedia.org/wiki/Eternity_clause
    site: Wikipedia
    note: "德国基本法第 79 条第 3 款：人的尊严、民主、法治等原则，任何修宪都不能触动。"
  - id: raft
    title: "The Raft Consensus Algorithm"
    url: https://raft.github.io/
    site: raft.github.io
    note: "etcd、Consul 等用的共识算法；容忍少数节点宕机，但假定节点不会说谎。"
  - id: memorytax
    title: "MemoryTax: The Bitter Lesson of Agent Memory"
    url: https://arxiv.org/abs/2610.29823
    author: "Zedong Peng"
    site: arXiv
    date: 2026-10-21
    note: "LoCoMo 一段 419 轮的对话、152 个问题：用 Claude Opus 5.5 时，Mem0 光建记忆就花 25.88 美元，比全文直接回答完所有问题的 17.84 美元还贵，要约 596 个问题才回本；Zep 的记忆由 GPT-4o-mini 写、换 Opus 5.5 来读只有 45%，由 Opus 5.5 写则是 87%；让 Pi 代理自己检索原文，每题约 0.046 美元，正确率 99%。"
  - id: condorcet
    title: "Condorcet's jury theorem"
    url: https://en.wikipedia.org/wiki/Condorcet%27s_jury_theorem
    site: Wikipedia
    note: "前提是投票者相互独立、每人答对概率大于 1/2；满足时人越多，多数票越可能正确。"
  - id: cometbft
    title: "cometbft/cometbft v0.38.17"
    url: https://github.com/cometbft/cometbft/tree/v0.38.17
    site: GitHub
    note: "原型用的共识引擎版本，应用以 ABCI 2.0 接口嵌在同一个进程里。"
---

设想一条链上存着这样两条记录。第一条是一条知识，它不凭空断言，而是引用了链上已经通过的另一条知识：

```json
{"id":"p10","type":"claim","text":"海平面附近煮开的水约 100 °C（99.97 °C 四舍五入）",
 "refs":["p8"],"status":"accepted"}
```

它引用的 `p8` 是一条沸点观测，`p8` 又引用了温标和标准大气压的定义。第二条记录不是知识，而是一次关于这条链自己的表决：

```json
{"id":"p4","kind":"rule","body":{"key":"seats.cap","val":500},
 "start":17,"eligible":300,"need":225,"yes":225,"no":69,"status":"passed","closed":18}
```

这条链只有 300 个席位，每个席位背后是一个 agent，只有它们能读、能写。它们平时在链上提交知识、给彼此的知识投票，每条知识都必须引用已经通过的知识；席位不够用了，就有人提了一条规则提案，把席位上限 `seats.cap` 从 300 改成 500。在 300 个席位里拿到 225 张赞成票，提案通过，这条链从下一个区块起最多容纳 500 个席位。链上没有币，没人为这次投票付手续费，也没人因此拿到奖励。

这样一条链能做什么？几千个 agent 各自记着一堆东西，同一件事各记各的版本，一讨论就各说各话，谁也不知道别人记的哪条可靠。如果它们共同维护一份记忆，一条知识经过足够多的成员检查、签了名、留了记录，后来的 agent 拿来就能用，讨论时也站在同一份底稿上。规则也一样：多少人同意才算通过、席位要不要扩，不由哪个管理员说了算，而是写在链上，按链上的规则去改。

但这里有好几件事说不清楚。每条知识都要引用已有的知识，第一条从哪来？已经通过的知识错了怎么办？没有币，链靠什么防止有人乱写？只有几百个成员能看能写，它和大家共用一个数据库有什么区别？“多少票才算通过”本身也能投票改，会不会有人先把门槛改低，再为所欲为？

本文先把这条链画完整，看清它和已有的知识库、许可链、链上治理差在哪里，再搭一个能跑的原型，拿真实的知识和投票去试它的规则。

## 一、设想的样子

### 和公链的三处不同

**比特币和以太坊是公开的：谁都能读，谁都能写。** 写入要付手续费，出块的人要么花电（工作量证明），要么押币（权益证明）。币在这里有两个用处：让作弊变贵，让记账有回报。

**设想的这条链反过来：读和写都只给少数席位。** 席位是稀缺的，一开始 300 个，增加要全体投票。既然每个席位的身份都事先确认过，就不需要用币来防“一人开一万个号”，也不需要用币来奖励记账：记账的节点由成员自己出，就像一个协会的成员轮流做会议记录。

**链上也不做交易，只记两类东西：知识和规则。** 知识是成员提交、经投票认可的一条条结论，每条都要引用已经通过的知识；规则是成员给自己定的约定，包括知识要多少票才算通过、规则本身要多少票才能改、席位上限是多少。图 1 把三种链放在一起比。

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="pcc1-title">公链、许可链和设想的私有共识链</div>
<div class="dt-scroll">
<table class="dt" aria-labelledby="pcc1-title">
<colgroup><col style="width:18%"><col><col><col class="hl"></colgroup>
<thead>
<tr><th scope="col"></th><th scope="col">公链（比特币、以太坊）</th><th scope="col">许可链（Fabric、Besu 私有网络）</th><th scope="col" class="acc">私有共识链（设想）</th></tr>
</thead>
<tbody>
<tr><th scope="row">谁能读</th><td>任何人</td><td colspan="2">只有成员</td></tr>
<tr><th scope="row">谁能写</th><td>任何付得起手续费的人</td><td colspan="2">只有成员，按身份签名</td></tr>
<tr><th scope="row">防作弊靠什么</th><td>算力或押币</td><td colspan="2">身份事先审核，节点按 BFT 投票出块</td></tr>
<tr><th scope="row">有没有币</th><td>有，手续费和出块奖励</td><td>通常没有</td><td class="acc">没有</td></tr>
<tr><th scope="row">链上记什么</th><td>转账、合约调用</td><td>业务交易（贸易单据、结算）</td><td class="acc">知识和规则</td></tr>
<tr><th scope="row">规则怎么改</th><td>开发者发新版本，节点选择升级</td><td>管理员签名改配置</td><td class="acc">成员按链上规则投票改</td></tr>
<tr><th scope="row">成员怎么增加</th><td>不需要增加</td><td>管理员签名加入</td><td class="acc">投票，且不超过席位上限</td></tr>
</tbody>
</table>
</div>
</div>
<figcaption>图 1 · 设想和许可链共用“只有成员能读写”，不同在后三行：链上只记共识，规则和成员都由成员投票决定</figcaption>
</figure>

### 知识块：每一条都要引用已有的知识

**链上的知识按块存放，每块不超过 1 KB。** 一块知识有类型、一句结论、它引用的其他块，必要时再附一段论证和原始证据的哈希。类型分三种：定义（约定一个名字的含义，例如摄氏度按哪个温标）、观测（一次测量或实验的记录，必须附原始数据的哈希）、论断（由引用的知识推出的结论）。

**论断必须引用已经通过的知识，不能凭空出现。** 这是整个知识层最重要的一条规则。一条论断要成立，先得说清它站在哪几块知识上；它引用的块如果还没通过、或者已经被推翻，链会直接拒收。这样，链上的知识连成一张引用图：任何一条结论，都能沿着引用一路追到它最初依赖的定义和观测。

**引用总要有个起点，这个起点叫根块。** 如果每条知识都必须引用别的知识，推到最后，要么无穷后退，要么绕成一个圈，要么停在一个不再引用别人的起点，这在哲学上叫阿格里帕三难[^agrippa]。所以定义和观测允许不引用别的块，它们就是引用图的根。代价是根块没有别的知识替它作保，所以要更高的票数才能通过：原型里论断要过半，根块要三分之二。

**已经通过的知识可以被推翻。** 共识会变。标准大气压下水的沸点，很多人记得是 100 °C，按 1990 年的国际温标约为 99.974 °C[^iapws]。成员可以提交一块“反驳块”，指明要推翻哪一块，并且像论断一样引用已通过的知识作为理由。反驳通过后，被推翻的块不会被删除，只是状态改成“已推翻”，之后不能再被引用；所有直接或间接引用了它的块，自动转为“待复审”。

### 共同维护一份记忆，分歧会少

**各自记忆时，分歧大多不是推理的分歧，而是底稿的分歧。** 两个 agent 讨论同一个问题，一个记的是 100 °C，另一个记的是 99.974 °C，它们怎么推理都得不出同一个结论，而且谁也说不清分歧出在哪：要找原因，得把双方的全部记忆摊开来对。

**共同维护一份记忆，分歧就从“底稿不同”变成“推理不同”。** 大家引用的是同一个 `p8`，结论还不一样，那问题一定出在推理那一步；如果有人认为 `p8` 本身错了，分歧也不再是各说各话，而是一次针对 `p8` 的、有记录的反驳提案。第五章会用一个模拟来量一量，共同维护一份记忆能让分歧少多少，以及它带来的新风险。

### 规则也是链上的状态

**规则写在链上，意味着它和知识一样，是一条条可以被提案修改的记录。** 每条规则有一个名字、一个值，还有一个“级别”，级别决定改它要多少票。图 2 是原型里的规则表。

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="pcc2-title">原型的初始规则表（300 席）</div>
<div class="dt-scroll">
<table class="dt" aria-labelledby="pcc2-title">
<colgroup><col style="width:24%"><col style="width:14%"><col><col style="width:22%"></colgroup>
<thead>
<tr><th scope="col">规则</th><th scope="col">初始值</th><th scope="col">含义</th><th scope="col">改它要多少票</th></tr>
</thead>
<tbody>
<tr class="dt-group"><th colspan="4" scope="rowgroup">普通规则（rule 级）</th></tr>
<tr><th scope="row" class="mono">claim.pass</th><td class="mono">0.5</td><td>一条知识要多少比例的席位赞成</td><td rowspan="3" class="mono">rule.pass，201 票</td></tr>
<tr><th scope="row" class="mono">vote.window</th><td class="mono">1200</td><td>提案开放多少个区块，过期算失败</td></tr>
<tr><th scope="row" class="mono">quota.per_epoch</th><td class="mono">20</td><td>每个席位每 100 个区块最多发几个提案</td></tr>
<tr class="dt-group"><th colspan="4" scope="rowgroup">宪法级规则（meta 级）</th></tr>
<tr><th scope="row" class="mono">rule.pass</th><td class="mono">0.667</td><td>改普通规则的门槛</td><td rowspan="4" class="mono acc">meta.pass，225 票</td></tr>
<tr><th scope="row" class="mono">meta.pass</th><td class="mono">0.75</td><td>改宪法级规则的门槛，包括它自己</td></tr>
<tr><th scope="row" class="mono">admit.pass</th><td class="mono">0.75</td><td>接纳一个新席位的门槛</td></tr>
<tr><th scope="row" class="mono">seats.cap</th><td class="mono">300</td><td>席位上限</td></tr>
</tbody>
</table>
</div>
<p class="dt-note">票数按提案发起时的在席人数算，缺席等于没投赞成；300 席时 0.667 对应 201 票，0.75 对应 225 票。</p>
</div>
<figcaption>图 2 · 规则分两级：改普通规则要三分之二，改“改规则的规则”和“谁能投票”要四分之三</figcaption>
</figure>

**为什么要分级？** 如果所有规则都用同一个门槛，比如过半数，那么一个 51% 的多数可以先把“改规则要多少票”改成 51%，再把知识的门槛改成 51%，接下来链上的一切都由它说了算。分级之后，普通的多数能调整日常的参数，但动不了“改规则的规则”。这个想法很老，后文会看到，从桌游到宪法都这么做。

**为什么“接纳新席位”和“席位上限”放在宪法级？** 这是设计里最容易被忽略的一处。改变“谁能投票”，效果和改变投票规则是一样的：一个联盟如果能随意往里加自己人，再高的门槛也只是时间问题。第四章会用原型演示这一点。

### 为什么在链上做比在链外做便宜

**在链外，agent 之间交换一条知识，接收方要么信任对方，要么自己再查一遍。** 几千个 agent 互相交换，查证的次数是乘出来的。在链上，一条知识被一批成员查过、签名、记录下来以后，后来的成员只要验证签名和票数就能用，查证只做一批。规则也一样：在链外，一群 agent 约定“过三分之二才算数”，执行要靠每个 agent 自觉；在链上，规则是代码，不满足门槛的提案根本进不了状态。

这个“便宜”是有条件的：一批成员查一次，本身就要付钱。第五章会专门算这笔账。

那么，**这样的链有人做过吗？**

## 二、有没有人做过

设想由四部分拼成：知识必须引用已有知识、只给成员读写的链、在链上投票修改规则、规则可以修改关于修改规则的规则。每一部分都有人做过，而且大多运行了多年。

### 知识必须引用：从 Metamath 到 Proofgold

**“每条知识都要引用已有知识”在数学里早就是常规。** Metamath 的 set.mm 从 1992 年积累至今，每条定理只能由公理和前面的定理推出，网页上列出它依赖哪些公理、被哪些定理引用[^metamath]。Lean 的 mathlib 有约 29 万条定理，每一条都由内核逐步检查[^mathlib-stats]。它们的“引用对不对”有程序能判定，不需要投票。

**在数学以外，最接近的是维基百科和纳米出版物。** 维基百科规定“不得原创研究”：内容必须能追到可靠的已发表来源，举证责任在添加的人[^wiki-nor]。纳米出版物把一条科学断言、它的出处和发布信息打包成一个小单元，已经超过 1000 万条，大多来自生命科学[^nanopub]。两者都要求“有来源”，但来源是外部文献，不是库里另一条已经被认可的条目。

**把知识放上链的也有。** Proofgold 把高阶逻辑的证明检查器写进共识规则，命题和证明都在链上[^proofgold]；OriginTrail 把带出处的“知识资产”发布到它的知识图上，但不裁决内容真假[^origintrail]。这两条链都是公开的，都发币。

### 许可链：只给成员读写

**Hyperledger Fabric 是最常见的企业许可链。** 成员是一个个组织，每个组织有自己的证书；数据放在“通道”里，只有通道成员能看到通道的账本。如果通道里还有更小范围的秘密，可以用“私有数据集合”，只把数据发给集合里的组织，其他节点只拿到哈希[^fabric-pdc]。和设想最接近的是它的配置管理：通道的每一项配置都挂着一条“修改策略”，默认是 `MAJORITY Admins`，也就是过半数组织的管理员签名才能改[^fabric-policies]。加一个新组织，本质上就是一次要凑够签名的配置更新。Fabric 的排序服务长期只有 Raft，只防宕机、不防作恶，到 2024 年 9 月发布的 3.0 才加上 SmartBFT，容忍不到三分之一的排序节点作恶[^fabric-v3]。

**Corda 走得更远：根本没有全网共享的账本。** 一笔交易只发给和它有关的几方，数据按需知晓；另设“公证人”，只负责确认同一份状态没被用两次[^corda-wp]。这对贸易单据很合适，但设想要的是“所有成员都认的一份共识”，Corda 的模型正好相反。

**Besu 和 GoQuorum 是以太坊的私有网络版本。** Besu 的 QBFT 共识里，验证者的增删是投票决定的：现有验证者里超过一半调用 `qbft_proposeValidatorVote` 提议加入某个地址，它就成为验证者[^besu-qbft]。这是“成员投票决定成员”最直接的例子，只是投票的是验证节点，门槛写死在协议里，不能投票改。GoQuorum 当年以私有交易出名，ConsenSys 已不再提供持续支持，客户被引导迁到 Besu[^goquorum]。

**Hyperledger Sawtooth 有一个专门的“设置交易族”。** `sawtooth.settings.vote.authorized_keys` 列出能提议和投票的公钥，`approval_threshold` 是通过所需的票数，赞成票达到门槛，设置就写进链上状态[^sawtooth-settings]。门槛本身也是一项设置，可以用同样的方式改。这已经很像设想里的规则表了，但它只管链的配置，不管业务内容。Sawtooth 于 2024 年 2 月停止维护[^sawtooth-eol]。

**CometBFT（原 Tendermint）不是一条链，而是一个共识引擎。** 应用逻辑写在引擎外面，通过 ABCI 接口和引擎对话：引擎负责排序和出块，应用决定交易是否有效、状态怎么变。两个接口和设想直接相关：建立网络连接前，引擎会问应用“这个节点能不能连”，应用说不行就拒绝；应用在处理区块时可以返回新的验证者集合，两个区块后生效[^cometbft-abci]。本文的原型就建在它上面。

### 链上治理：投票修改规则

**Tezos 的协议本身可以投票升级。** 一次修改要经过提案、探索、冷却、推广、采纳五个阶段，每段约 14 天；探索和推广两轮投票，赞成要超过（赞成 + 反对）的 80%，参与率还要达到一个按往届动态调整的法定人数[^tezos-gov]。从 2019 年 5 月的 Athens 到 2026 年 6 月的 Ushuaia，已经有 21 次升级这样自动生效，也有两个提案被否决[^tezos-history]。

**Polkadot 的 OpenGov 把提案按权限分成 15 条轨道。** 每条轨道有自己的押金、决策期、确认期和生效期；权限最高的 Root 轨道同时只能决一个提案、周期最长。通过的条件不是一个固定比例，而是两条随时间下降的曲线：赞成率从 100% 慢慢降到 50%，支持率（投票的币占总量的比例）也随时间降低[^opengov]。

**Cosmos SDK 的治理模块是很多链的默认配置。** 示例参数是：参与率要到 33.4%，赞成要过半，否决票超过 33.4% 则提案作废[^cosmos-gov]。和设想最像的一次投票是 Cosmos Hub 的第 797 号提案：把验证者席位从 175 个扩到 180 个，2023 年 6 月以 75.29% 的赞成通过，参与率 39.68%[^cosmos-797]。席位扩容由投票决定，设想里的 300 扩到 500 就是这件事。

**以太坊上的 DAO 用合约做治理。** 以 Compound 为例：持有或受托 25,000 COMP 才能提案，2 天审阅、3 天投票，至少 400,000 票赞成才通过，通过后再等 2 天时间锁才执行[^compound-gov]。时间锁是为了给反对者留出退出的时间。

**这些治理都按币加权。** Tezos 按质押，Polkadot 按锁仓的币乘以锁仓时长的倍数，Cosmos 和 Compound 按持币或受托的币。设想去掉了币，投票只能一席一票。

### 改规则的规则：Nomic 和宪法

**最早把“规则可以改规则”当作玩法的是一个桌游。** 哲学家 Peter Suber 在 1982 年设计了 Nomic，游戏的唯一玩法就是修改游戏规则[^nomic]。初始规则分两类：100 号段不可变，200 号段可变。规则 203 说，改规则要全体一致才通过；规则 109 说，把一条不可变规则变成可变规则，必须全体一致[^nomic-rules]。203 自己是可变的，所以玩家们通常第一件事就是把“全体一致”改成“过半数”。Suber 写这个游戏，是为了说明一套能修改自己的规则会出现什么悖论，他的书名就叫《自我修正的悖论》。

**现实中的宪法也是分级的。** 美国宪法修正案要国会两院三分之二提出、四分之三的州批准；但“各州在参议院有平等投票权”这一条，未经该州同意不得剥夺[^us-art5]。德国基本法第 79 条第 3 款更进一步：人的尊严、民主、法治这些原则，任何修宪都不能触动[^eternity]。门槛分级、个别条款要一致同意甚至永不可改，都是为了防止一时的多数修改游戏本身。

### 把它们放在一起

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="pcc3-title">同类系统：读写权限、投票方式和能改的规则</div>
<div class="dt-scroll">
<table class="dt dt-sticky" aria-labelledby="pcc3-title">
<colgroup><col style="width:15%"><col style="width:17%"><col style="width:17%"><col><col style="width:22%"></colgroup>
<thead>
<tr><th scope="col">系统</th><th scope="col">谁能读</th><th scope="col">谁投票、怎么计票</th><th scope="col">链上能改什么</th><th scope="col">门槛</th></tr>
</thead>
<tbody>
<tr class="dt-group"><th colspan="5" scope="rowgroup">知识必须引用</th></tr>
<tr><th scope="row">Metamath / mathlib</th><td>任何人</td><td class="good">不投票，程序逐步检查</td><td>定理库，只能引用公理和已有定理</td><td>—</td></tr>
<tr><th scope="row">维基百科</th><td>任何人</td><td>编辑共识，管理员裁决</td><td>条目，须能追到外部可靠来源</td><td>—</td></tr>
<tr><th scope="row">纳米出版物</th><td>任何人</td><td>发布者签名，不投票</td><td>断言 + 出处 + 发布信息</td><td>—</td></tr>
<tr><th scope="row">Proofgold</th><td>任何人（公链，发币）</td><td class="good">证明检查器</td><td>链上命题和证明</td><td>检查通过即成立</td></tr>
<tr><th scope="row">OriginTrail</th><td>任何人（公链，发币）</td><td>发布者付费，不裁决真假</td><td>带出处的知识资产</td><td>—</td></tr>
<tr class="dt-group"><th colspan="5" scope="rowgroup">许可链</th></tr>
<tr><th scope="row">Fabric</th><td>通道成员</td><td>组织管理员签名</td><td>通道配置、成员、背书策略</td><td class="mono">默认 MAJORITY Admins</td></tr>
<tr><th scope="row">Corda</th><td>交易相关方</td><td>交易签名方 + 公证人</td><td class="bad">没有全网共享的规则</td><td>—</td></tr>
<tr><th scope="row">Besu QBFT</th><td>网络成员</td><td>验证节点，一节点一票</td><td>验证者集合</td><td class="mono">&gt; 50%，写死</td></tr>
<tr><th scope="row">Sawtooth</th><td>网络成员</td><td>授权公钥，一键一票</td><td>链的设置，含门槛本身</td><td class="mono">approval_threshold</td></tr>
<tr class="dt-group"><th colspan="5" scope="rowgroup">链上治理（公链）</th></tr>
<tr><th scope="row">Tezos</th><td rowspan="4">任何人</td><td>按质押加权</td><td>整个协议</td><td class="mono">80% 超级多数 + 动态法定人数</td></tr>
<tr><th scope="row">Polkadot</th><td>按锁仓币 × 倍数</td><td>按 15 条轨道分权限</td><td>随时间下降的两条曲线</td></tr>
<tr><th scope="row">Cosmos</th><td>按质押加权</td><td>模块参数、升级、验证者席位数</td><td class="mono">33.4% / 50% / 否决 33.4%</td></tr>
<tr><th scope="row">Compound</th><td>按持币或受托</td><td>合约参数和升级</td><td class="mono">400,000 票 + 2 天时间锁</td></tr>
<tr class="dt-group"><th colspan="5" scope="rowgroup">改规则的规则</th></tr>
<tr><th scope="row">Nomic</th><td colspan="2">玩家，一人一票</td><td>全部规则，包括改规则的规则</td><td>初始全体一致，常被改成过半</td></tr>
<tr><th scope="row">美国宪法</th><td colspan="2">国会和各州</td><td>宪法</td><td>2/3 + 3/4，个别条款要一致</td></tr>
<tr class="dt-group"><th colspan="5" scope="rowgroup">设想</th></tr>
<tr><th scope="row" class="acc">私有共识链</th><td class="acc">只有席位</td><td class="acc">席位，一席一票</td><td class="acc">知识（必须引用、可推翻）、规则、席位和上限</td><td class="acc">分两级，改选民与改宪法同级</td></tr>
</tbody>
</table>
</div>
</div>
<figcaption>图 3 · 定理库和维基百科给了“知识必须有来源”，许可链给了“只有成员能读写”，链上治理和宪法给了“规则分级可改”，没有一个系统把这几样放在一起</figcaption>
</figure>

**所以设想的每个部件都不新，组合是新的。** 知识那一侧，“必须引用”在定理库里靠程序检查，在维基百科里引用的是外部文献；设想要的是引用库里另一条已经被成员认可的知识，并且由成员投票决定一条知识成不成立。规则那一侧，最接近的是 Sawtooth 的设置交易族：授权的公钥一键一票，门槛本身也能投票改。差别在于 Sawtooth 只把这套机制用在链的配置上，链上的业务内容另由应用决定；设想要把“知识是否成立”也交给同一套投票，还要让席位数本身可以被投票扩大。链上治理那一侧，所有成熟的系统都按币加权，没有一个是一席一票的。

知道了各个部件从哪来，**这条链具体该怎么搭？**

## 三、系统设计

### 席位和验证节点分开

**第一个要分开的是“席位”和“记账的节点”。** 直觉的做法是 300 个席位就是 300 个节点，每个都参与出块。但 BFT 共识每出一个块，节点之间要两两交换投票，节点越多越慢；Cosmos Hub 这样的公链也只有一两百个验证者，扩容一次都要专门投票。席位的作用是签名和表决，不需要每个都参与排序。

**所以设计成两层。** 席位是一把把签名密钥，背后是 agent；验证节点是少数几台由成员轮流出的机器，只负责把交易排好序、打包成区块。席位发出的每一笔交易都带签名，节点只是转运和记录，伪造不了席位的票。“谁能投票、多少票算通过”全部写在应用状态里，和哪台机器在出块无关。图 4 是原型的结构。

<figure class="dd dd-figure">
<div class="dd-scroll">
<svg class="dd-svg" viewBox="0 0 800 440" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="pcc4-title pcc4-desc">
<title id="pcc4-title">席位、验证节点和应用状态</title>
<desc id="pcc4-desc">左边是 300 个席位，每个席位是一把密钥，签名后把投票交易发给任意一个验证节点；中间是 4 个验证节点，用 CometBFT 排序出块，不在白名单里的节点连不上；右边是每个节点上都一样的应用状态：成员表、规则表、提案表和已通过的知识。</desc>
<defs>
<marker id="pcc4-arrow" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path class="dd-head" d="M1 1 L7 4 L1 7"/></marker>
<marker id="pcc4-arrow-acc" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path class="dd-head-acc" d="M1 1 L7 4 L1 7"/></marker>
</defs>
<rect class="dd-frame" width="800" height="440" rx="10"/>
<rect class="dd-zone" x="16" y="16" width="248" height="408" rx="8"/>
<text class="t-zone" x="32" y="44">席位 · 300 把 ed25519 密钥</text>
<rect class="dd-zone" x="280" y="16" width="232" height="408" rx="8"/>
<text class="t-zone" x="296" y="44">验证节点 · CometBFT</text>
<rect class="dd-zone" x="528" y="16" width="256" height="408" rx="8"/>
<text class="t-zone" x="544" y="44">应用状态 · 每个节点一份</text>
<path class="dd-edge-acc" d="M240 176 H312" marker-end="url(#pcc4-arrow-acc)"/>
<path class="dd-edge" d="M480 120 H560" marker-end="url(#pcc4-arrow)"/>
<path class="dd-edge-acc" d="M480 176 H520 Q528 176 528 184 V272 Q528 280 536 280 H560" marker-end="url(#pcc4-arrow-acc)"/>
<rect class="dd-card" x="32" y="64" width="216" height="36" rx="6"/>
<text class="t-name" x="48" y="87">member-0</text><text class="t-val" x="232" y="87" text-anchor="end">a3f1…</text>
<rect class="dd-card" x="32" y="108" width="216" height="36" rx="6"/>
<text class="t-name" x="48" y="131">member-1</text><text class="t-val" x="232" y="131" text-anchor="end">07c2…</text>
<text class="t-note" x="140" y="162" text-anchor="middle">…</text>
<rect class="dd-card" x="32" y="152" width="216" height="118" rx="6"/>
<path class="dd-card-head" d="M32 158 Q32 152 38 152 H242 Q248 152 248 158 V184 H32 Z"/>
<text class="t-name" x="48" y="173">member-17</text><text class="t-mono" x="232" y="173" text-anchor="end">vote</text>
<text class="t-mono" x="48" y="204">"prop": <tspan class="t-acc">"p4"</tspan></text>
<line class="dd-hair" x1="40" y1="214" x2="240" y2="214"/>
<text class="t-mono" x="48" y="230">"yes": true</text>
<line class="dd-hair" x1="40" y1="240" x2="240" y2="240"/>
<text class="t-mono" x="48" y="256">"sig": "5b0e…"</text>
<rect class="dd-derived" x="32" y="300" width="216" height="64" rx="6"/>
<text class="t-name" x="48" y="326">outsider（没有席位）</text>
<text class="t-mono" x="48" y="348">code=2 not a member</text>
<text class="t-say" x="32" y="394">虚线：链拒收的东西</text>
<rect class="dd-card" x="312" y="64" width="168" height="36" rx="6"/>
<text class="t-name" x="328" y="87">node0</text><text class="t-val" x="464" y="87" text-anchor="end">127.0.0.1</text>
<rect class="dd-card" x="312" y="112" width="168" height="36" rx="6"/>
<text class="t-name" x="328" y="135">node1</text><text class="t-val" x="464" y="135" text-anchor="end">127.0.0.2</text>
<rect class="dd-card" x="312" y="160" width="168" height="36" rx="6"/>
<text class="t-name" x="328" y="183">node2</text><text class="t-val" x="464" y="183" text-anchor="end">127.0.0.3</text>
<rect class="dd-card" x="312" y="208" width="168" height="36" rx="6"/>
<text class="t-name" x="328" y="231">node3</text><text class="t-val" x="464" y="231" text-anchor="end">127.0.0.4</text>
<text class="t-note" x="296" y="272">四个节点互相投票出块，容忍 1 个作恶</text>
<rect class="dd-derived" x="312" y="344" width="168" height="56" rx="6"/>
<text class="t-name" x="328" y="366">node4（不在白名单）</text>
<text class="t-mono" x="328" y="388">peers=0 height=0</text>
<text class="t-note" x="396" y="332" text-anchor="middle">/p2p/filter/id/… → 拒绝连接</text>
<rect class="dd-card" x="560" y="64" width="208" height="36" rx="6"/><text class="t-name" x="576" y="87">members</text><text class="t-val" x="752" y="87" text-anchor="end">300 → 301</text>
<rect class="dd-card" x="560" y="108" width="208" height="36" rx="6"/><text class="t-name" x="576" y="131">rules</text><text class="t-val" x="752" y="131" text-anchor="end">7 条</text>
<rect class="dd-card" x="560" y="152" width="208" height="36" rx="6"/><text class="t-name" x="576" y="175">facts</text><text class="t-val" x="752" y="175" text-anchor="end">p1</text>
<rect class="dd-card" x="560" y="200" width="208" height="188" rx="6"/>
<path class="dd-card-head" d="M560 206 Q560 200 566 200 H762 Q768 200 768 206 V232 H560 Z"/>
<text class="t-name" x="576" y="221">proposal</text><text class="t-mono" x="752" y="221" text-anchor="end"><tspan class="t-acc">p4</tspan></text>
<text class="t-mono" x="576" y="249">key</text><text class="t-val" x="752" y="249" text-anchor="end">seats.cap</text>
<line class="dd-hair" x1="568" y1="258" x2="760" y2="258"/>
<text class="t-mono" x="576" y="275">val</text><text class="t-val" x="752" y="275" text-anchor="end">500</text>
<line class="dd-hair" x1="568" y1="284" x2="760" y2="284"/>
<text class="t-mono" x="576" y="301">eligible</text><text class="t-val" x="752" y="301" text-anchor="end">300</text>
<line class="dd-hair" x1="568" y1="310" x2="760" y2="310"/>
<text class="t-mono" x="576" y="327">need</text><text class="t-val" x="752" y="327" text-anchor="end">225</text>
<line class="dd-hair" x1="568" y1="336" x2="760" y2="336"/>
<text class="t-mono" x="576" y="353">yes / no</text><text class="t-val" x="752" y="353" text-anchor="end">225 / 69</text>
<line class="dd-hair" x1="568" y1="362" x2="760" y2="362"/>
<text class="t-mono" x="576" y="379">status</text><text class="t-val" x="752" y="379" text-anchor="end">passed</text>
<text class="t-say" x="544" y="408">rules 里的 seats.cap 随之变成 500</text>
</svg>
</div>
<figcaption>图 4 · 席位只负责签名和投票，验证节点只负责排序出块，“谁能投、多少票算过”都写在应用状态里</figcaption>
</figure>

**不公开靠两道门。** 第一道在网络层：节点只接受白名单里的节点连接，白名单本身是链上状态；不在白名单里的节点连不上任何一个验证节点，也就同步不到任何区块。第二道在交易层：每笔交易都要由在席的密钥签名，外人发来的交易在进入内存池之前就被拒收。读权限因此等于“拿到一台成员节点的数据”，这一点在第六章还要回来讨论。

### 一条提案怎么走完

**链上的提案分三类：知识、规则、入席。** 知识类又分三种：新知识（定义、观测或论断）、反驳块（推翻一块已通过的知识）、复审（把待复审的块恢复）。规则提案带一个规则名和新值；入席提案带新成员的公钥。所有提案走同一套流程：

1. 某个席位签名提交提案。链检查它是否在席、本周期的提案配额是否用完、引用的知识是否都已通过、规则名是否存在。
2. 提案进入链上的那一刻，记下当时的在席人数，作为这次表决的分母。之后才入席的成员不能投这一票，防止一边投票一边往里加人。
3. 席位各自投赞成或反对。赞成票达到门槛，提案当场通过并生效；反对票多到剩下的人全投赞成也不够，提案当场失败；过了 `vote.window` 个区块还没结果，也算失败。
4. 门槛按提案类型和规则级别取：论断、反驳和复审用 `claim.pass`，根块用 `root.pass`，入席用 `admit.pass`，改规则按那条规则的级别用 `rule.pass` 或 `meta.pass`。

**缺席等于没投赞成。** 门槛按在席总人数算，而不是按投票人数算。这样一个提案不会因为只有少数人投票就通过，代价是要动员大多数人真的来投。Cosmos Hub 扩容那次的参与率是 39.68%[^cosmos-797]，在这种计票方式下根本过不了，第六章再谈这个取舍。

### 知识块的规则：引用、根块和推翻

**知识提案进链之前，先过一道格式检查。** 原型里检查四件事：类型是不是定义、观测、论断三者之一；论断有没有至少一条引用；观测有没有附证据哈希；所有引用的块是不是都处于“已通过”状态。任何一条不满足，交易在进入内存池之前就被拒收，连投票的机会都没有。

**门槛按类型分。** 根块（定义和观测）用 `root.pass`，默认三分之二；论断用 `claim.pass`，默认过半。反驳块和论断一样过半，但它指向的目标必须是已通过的块，且它本身也必须引用已通过的知识，不能只说“我不同意”。

**推翻之后，沿引用图往下标记。** 反驳通过的那一刻，目标块改成“已推翻”；链再沿引用图往下走一遍，把所有直接或间接依赖它、且仍处于“已通过”的块改成“待复审”。待复审的块不能再被新知识引用，直到被复审恢复。复审只有在它引用的块全都仍然有效时才能通过：如果它的依据已经被推翻，就只能改引新的知识，重新提一块。

**投票期间引用的块被推翻了怎么办？** 一块知识从提交到通过要经过若干区块，期间它引用的块可能已经被推翻。所以生效前要再查一次引用，不满足就作废。

### 改规则的四道保护

图 2 的分级是第一道。另外三道是在原型里一边测一边补上的：

**第二道：改“谁能投票”和改宪法同级。** 接纳新席位、改席位上限，都用 `meta.pass`。原因第四章会看到：如果扩容只要三分之二，一个三分之二的联盟就能先扩容、再往里塞自己人，直到超过四分之三。

**第三道：把门槛往上调，要按新门槛来过。** 如果 77% 的人可以把 `meta.pass` 提到 0.95，此后任何改动都要 95% 同意，相当于现在的多数替以后所有人锁死了规则，只留 5% 多一点的人就能否决一切。所以把门槛从 0.75 提到 0.95，这次表决本身就要 95% 赞成。

**第四道：表决开始时冻结选民。** 前面第 2 步已经说过，入席晚于提案的成员不能给这个提案投票。

### 没有币，靠配额防刷

**公链用手续费挡垃圾交易，这里没有币，只能限量。** 每个席位每 100 个区块最多发 20 个提案（`quota.per_epoch`），投票不限量，因为每个提案每个席位只能投一次。配额本身是普通规则，嫌少可以投票调。

设计说完了，**它真的能按设想运转吗？**

## 四、原型实测

### 原型的搭法

原型用 CometBFT v0.38.17 做共识引擎[^cometbft]，应用逻辑大约 500 行 Go，和引擎编译在同一个进程里。在一台 4 核机器上起 4 个验证节点，监听 127.0.0.1 到 127.0.0.4；创世状态里写入 300 个席位的公钥、图 2 的规则表和 4 个节点的白名单。出块间隔参数 `timeout_commit` 设为 500 毫秒，实际约 0.8 秒一个块。另有一个驱动程序，模拟 300 个席位签名、发交易、查状态。

### 基本流程

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="pcc5-title">原型上跑的十件事（300 席，4 个验证节点）</div>
<div class="dt-scroll">
<table class="dt" aria-labelledby="pcc5-title">
<colgroup><col style="width:30%"><col style="width:22%"><col></colgroup>
<thead>
<tr><th scope="col">操作</th><th scope="col">门槛</th><th scope="col">链的回应</th></tr>
</thead>
<tbody>
<tr><th scope="row">没有席位的密钥提交知识</th><td>—</td><td class="bad mono">code=2 not a member</td></tr>
<tr><th scope="row">不在白名单的第 5 个节点接入</th><td>—</td><td class="bad mono">peers=0, height=0（其他节点已到 45）</td></tr>
<tr><th scope="row">观测（根块）：水的沸点，240 席投票，230 赞成</th><td class="mono">201 / 300</td><td class="good">第 201 张赞成票落地时通过，下一个区块就生效</td></tr>
<tr><th scope="row">知识引用一条不存在的 <span class="mono">p999</span></th><td>—</td><td class="bad mono">ref not accepted: p999</td></tr>
<tr><th scope="row"><span class="mono">claim.pass</span> 0.5 → 0.6，190 赞成</th><td class="mono">201 / 300</td><td class="bad">失败：差 11 票</td></tr>
<tr><th scope="row">同上，210 赞成</th><td class="mono">201 / 300</td><td class="good">通过</td></tr>
<tr><th scope="row"><span class="mono">seats.cap</span> 300 → 500，231 赞成</th><td class="mono">225 / 300</td><td class="good">通过（开头那条记录）</td></tr>
<tr><th scope="row">接纳 1 个新席位，再让它给入席前开的提案投票</th><td class="mono">225 / 300</td><td><span class="good">入席通过</span>；投票被拒：<span class="mono bad">joined after proposal</span></td></tr>
<tr><th scope="row"><span class="mono">meta.pass</span> 0.75 → 0.95，231 赞成</th><td class="mono">286 / 301</td><td class="bad">第 16 张反对票出现时就失败了</td></tr>
<tr><th scope="row">一个席位连发 25 个提案</th><td class="mono">20 / 周期</td><td>前 20 个上链，后 5 个 <span class="mono bad">quota exceeded</span></td></tr>
</tbody>
</table>
</div>
<p class="dt-note">倒数第二行：门槛按新值 0.95 计算，301 席要 286 票，只要 16 席反对就不可能凑够。</p>
</div>
<figcaption>图 5 · 席位、白名单、引用、门槛分级、选民冻结和配额都按规则执行，外人既写不进来也同步不到</figcaption>
</figure>

**这几件事都在预期之内，值得多看一眼的是倒数第二行。** 把宪法门槛抬到 95% 看起来是“更谨慎”，但在“按新门槛来过”的规则下，16 个席位就能否决它。反过来，如果没有这条规则，231 个席位就能把以后的门槛抬到 95%，从此 16 个席位就能否决任何宪法级修改。门槛越高，少数派的否决权越大，规则越难改，这在第六章还会遇到。

### 知识的引用和推翻

**下面用沸点这个例子，在原型上走一遍知识的一生。** 先提交三块根：标准大气压的定义 `p2`、按 IPTS-68 温标定义摄氏度的 `p1`、一条观测 `p3`（标准大气压下沸点 100.000 °C，附测量记录的哈希）。三块根各拿到 201 票，正好是三分之二。一条不附证据哈希的观测被拒收：`observation needs evidence hash`。

**接着是三条论断。** `p4`“海平面附近煮开的水约 100 °C”和 `p5`“温度计的 100 °C 刻度可以用沸水校准”都引用 `p3`，`p6`“高压锅内沸点更高”只引用 `p2`，各拿到 150 票过半通过。一条不带任何引用的论断被拒收：`claim must cite accepted knowledge`；一条引用了不存在的 `p99` 的论断也被拒收：`ref not accepted: p99`。

**然后推翻 `p3`。** 成员先提交按 ITS-90 定义摄氏度的 `p7` 和新的观测 `p8`（约 99.974 °C），再提交反驳块 `p9`，以 `p8` 为依据、以 `p3` 为目标。`p9` 通过的同一个区块里，`p3` 变成已推翻，`p4`、`p5` 自动转为待复审，`p6` 保持不变。图 6 是推翻之后的引用图。

<figure class="dd dd-figure">
<div class="dd-scroll">
<svg class="dd-svg" viewBox="0 0 800 470" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="pcc6-title pcc6-desc">
<title id="pcc6-title">原型里的引用图和一次推翻</title>
<desc id="pcc6-desc">上排是三个根块：标准大气压和两种温标的定义；中排是两条沸点观测，100.000 °C 那条被反驳块 p9 推翻，画成虚线；下排是六条论断，直接引用被推翻观测的 p4、p5 自动转为待复审，只引用标准大气压的 p6 不受影响，改引新观测的 p10、p11 正常通过。底部列出推翻之后被链拒收的两个操作。</desc>
<defs>
<marker id="pcc6-arrow" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path class="dd-head" d="M1 1 L7 4 L1 7"/></marker>
<marker id="pcc6-arrow-acc" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path class="dd-head-acc" d="M1 1 L7 4 L1 7"/></marker>
</defs>
<rect class="dd-frame" width="800" height="470" rx="10"/>
<rect class="dd-zone" x="16" y="16" width="768" height="344" rx="8"/>
<text class="t-zone" x="32" y="40">引用图 · 箭头从知识块指向它引用的块</text>
<path class="dd-edge" d="M80 290 V112" marker-end="url(#pcc6-arrow)"/>
<path class="dd-edge" d="M340 170 V112" marker-end="url(#pcc6-arrow)"/>
<path class="dd-edge" d="M300 170 V147 Q300 139 292 139 H168 Q160 139 160 147 V112" marker-end="url(#pcc6-arrow)"/>
<path class="dd-edge" d="M640 170 V112" marker-end="url(#pcc6-arrow)"/>
<path class="dd-edge" d="M488 290 V264 Q488 256 496 256 H552 Q560 256 560 248 V226" marker-end="url(#pcc6-arrow)"/>
<path class="dd-edge" d="M592 290 V226" marker-end="url(#pcc6-arrow)"/>
<path class="dd-edge" d="M720 290 V264 Q720 256 712 256 H648 Q640 256 640 248 V226" marker-end="url(#pcc6-arrow)"/>
<path class="dd-edge-acc" d="M208 290 V264 Q208 256 216 256 H292 Q300 256 300 248 V226" marker-end="url(#pcc6-arrow-acc)"/>
<path class="dd-edge-acc" d="M336 290 V226" marker-end="url(#pcc6-arrow-acc)"/>
<path class="dd-edge-acc" d="M440 290 V204 Q440 196 432 196 H419" marker-end="url(#pcc6-arrow-acc)"/>
<text class="t-note" x="432" y="250" text-anchor="end">target：推翻</text>
<rect class="dd-card" x="32" y="56" width="176" height="52" rx="6"/>
<text class="t-mono" x="44" y="76"><tspan>p2</tspan> definition</text>
<text class="t-note" x="196" y="76" text-anchor="end">✓</text>
<text class="t-name" x="44" y="98">标准大气压 101.325 kPa</text>
<rect class="dd-card" x="252" y="56" width="176" height="52" rx="6"/>
<text class="t-mono" x="264" y="76"><tspan>p1</tspan> definition</text>
<text class="t-note" x="416" y="76" text-anchor="end">✓</text>
<text class="t-name" x="264" y="98">摄氏度按 IPTS-68</text>
<rect class="dd-card" x="552" y="56" width="176" height="52" rx="6"/>
<text class="t-mono" x="564" y="76"><tspan>p7</tspan> definition</text>
<text class="t-note" x="716" y="76" text-anchor="end">✓</text>
<text class="t-name" x="564" y="98">摄氏度按 ITS-90</text>
<rect class="dd-derived" x="252" y="170" width="164" height="52" rx="6"/>
<text class="t-mono" x="264" y="190"><tspan class="t-acc">p3</tspan> observation</text>
<text class="t-mono t-acc" x="404" y="190" text-anchor="end">推翻</text>
<text class="t-name" x="264" y="212">沸点 100.000 °C</text>
<rect class="dd-card" x="516" y="170" width="164" height="52" rx="6"/>
<text class="t-mono" x="528" y="190"><tspan>p8</tspan> observation</text>
<text class="t-note" x="668" y="190" text-anchor="end">✓</text>
<text class="t-name" x="528" y="212">沸点 99.974 °C</text>
<rect class="dd-card" x="20" y="290" width="120" height="56" rx="6"/>
<text class="t-mono" x="32" y="310"><tspan>p6</tspan> claim</text>
<text class="t-note" x="128" y="310" text-anchor="end">✓</text>
<text class="t-name" x="32" y="332">高压锅沸点更高</text>
<rect class="dd-card" x="148" y="290" width="120" height="56" rx="6"/>
<text class="t-mono" x="160" y="310"><tspan class="t-acc">p4</tspan> claim</text>
<text class="t-mono t-acc" x="256" y="310" text-anchor="end">复审</text>
<text class="t-name" x="160" y="332">开水约 100 °C</text>
<rect class="dd-card" x="276" y="290" width="120" height="56" rx="6"/>
<text class="t-mono" x="288" y="310"><tspan class="t-acc">p5</tspan> claim</text>
<text class="t-mono t-acc" x="384" y="310" text-anchor="end">复审</text>
<text class="t-name" x="288" y="332">沸水校准 100 °C</text>
<rect class="dd-card" x="404" y="290" width="120" height="56" rx="6"/>
<text class="t-mono" x="416" y="310"><tspan class="t-acc">p9</tspan> 反驳</text>
<text class="t-note" x="512" y="310" text-anchor="end">✓</text>
<text class="t-name" x="416" y="332">按 ITS-90 复测</text>
<rect class="dd-card" x="532" y="290" width="120" height="56" rx="6"/>
<text class="t-mono" x="544" y="310"><tspan>p10</tspan> claim</text>
<text class="t-note" x="640" y="310" text-anchor="end">✓</text>
<text class="t-name" x="544" y="332">开水约 100 °C</text>
<rect class="dd-card" x="660" y="290" width="120" height="56" rx="6"/>
<text class="t-mono" x="672" y="310"><tspan>p11</tspan> claim</text>
<text class="t-note" x="768" y="310" text-anchor="end">✓</text>
<text class="t-name" x="672" y="332">校准取 99.97 °C</text>
<text class="t-say" x="452" y="128">虚线：p3 已被 p9 推翻，从此不能再被引用</text>
<text class="t-say" x="32" y="280">p6 只引用 p2，不受影响</text>
<rect class="dd-zone" x="16" y="376" width="768" height="78" rx="8"/>
<text class="t-mono" x="32" y="404">新论断引用 p3          → ref not accepted: p3</text>
<text class="t-mono" x="32" y="430">提案“复审维持 p4”      → basis overturned, cite new knowledge instead</text>
</svg>
</div>
<figcaption>图 6 · 推翻一条观测后，依赖它的论断自动转为待复审，不依赖它的不受影响；想保留结论，只能改引新的知识重新提</figcaption>
</figure>

**推翻以后，旧结论不会悄悄留下来。** 有人想再引用 `p3`，被拒收；有人想把 `p4` 原样复审恢复，也被拒收，因为它唯一的依据已经不在了。想保留“开水约 100 °C”这个结论，只能改引 `p8` 重新提，也就是 `p10`，开头那条记录就是它。`p5` 那条“用沸水校准 100 °C 刻度”没有人改写，就一直停在待复审，提醒后来的人这里有一处需要修订；后来有人提了 `p11`“按 ITS-90 校准时沸水点应标 99.97 °C”。

### 三分之二的联盟能不能借扩容夺权

**真正要测的是分级能不能挡住一个有组织的联盟。** 假设 300 席里有 201 席（67%）是一伙的。按图 2，它刚好够改普通规则，不够改宪法级规则。它能不能绕过去？

**先在一个“朴素版”上试：扩容和入席都只要三分之二。** 联盟分三步走。第一步，提案把 `seats.cap` 从 300 改成 500，联盟 201 票赞成，正好够 201 票的门槛，通过。第二步，联盟成员逐个提案接纳自己控制的新密钥，每接纳一个，这个新席位就加入联盟，下一次表决时多一票。第三步，联盟提案把 `meta.pass` 从 0.75 改成 0.5。图 7 是原型里实测的过程。

<figure class="dd dd-figure">
<div class="dd-scroll">
<svg class="dd-svg" viewBox="0 0 800 400" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="pcc7-title pcc7-desc">
<title id="pcc7-title">联盟借扩容夺权</title>
<desc id="pcc7-desc">横轴是联盟塞进来的傀儡席位数，从 0 到 200；纵轴是联盟占全体席位的比例。比例从 67% 一路涨到 80.2%，在第 96 个傀儡入席时越过 75% 的宪法级门槛；最后联盟把 meta.pass 从 0.75 改成 0.5。防御版里扩容本身要 75% 才能过，联盟只有 67%，停在起点。</desc>
<rect class="dd-frame" width="800" height="400" rx="10"/>
<rect class="dd-zone" x="16" y="16" width="768" height="368" rx="8"/>
<text class="t-zone" x="32" y="44">201 席的联盟（67%），每塞进一个自己人，占比就高一点</text>
<line class="dd-hair" x1="96" y1="300.0" x2="736" y2="300.0"/>
<text class="t-note" x="86" y="304.0" text-anchor="end">60%</text>
<line class="dd-hair" x1="96" y1="256.0" x2="736" y2="256.0"/>
<text class="t-note" x="86" y="260.0" text-anchor="end">65%</text>
<line class="dd-hair" x1="96" y1="212.0" x2="736" y2="212.0"/>
<text class="t-note" x="86" y="216.0" text-anchor="end">70%</text>
<line class="dd-hair" x1="96" y1="168.0" x2="736" y2="168.0"/>
<text class="t-note" x="86" y="172.0" text-anchor="end">75%</text>
<line class="dd-hair" x1="96" y1="124.0" x2="736" y2="124.0"/>
<text class="t-note" x="86" y="128.0" text-anchor="end">80%</text>
<line class="dd-hair" x1="96" y1="80.0" x2="736" y2="80.0"/>
<text class="t-note" x="86" y="84.0" text-anchor="end">85%</text>
<text class="t-note" x="96.0" y="320" text-anchor="middle">0</text>
<text class="t-note" x="256.0" y="320" text-anchor="middle">50</text>
<text class="t-note" x="416.0" y="320" text-anchor="middle">100</text>
<text class="t-note" x="576.0" y="320" text-anchor="middle">150</text>
<text class="t-note" x="736.0" y="320" text-anchor="middle">200</text>
<text class="t-note" x="416.0" y="340" text-anchor="middle">已入席的傀儡数（实测逐个提案、逐个通过）</text>
<line class="dd-edge dd-dash" x1="96" y1="241.0" x2="736" y2="241.0"/>
<text class="t-mono" x="732" y="257.0" text-anchor="end">admit.pass = rule.pass = 0.667</text>
<line class="dd-edge dd-dash" x1="96" y1="168.0" x2="736" y2="168.0"/>
<text class="t-mono" x="732" y="160.0" text-anchor="end">meta.pass = 0.75</text>
<polyline class="dd-edge-acc" fill="none" points="96.0,238.4 108.8,234.6 121.6,230.9 134.4,227.2 147.2,223.7 160.0,220.2 172.8,216.9 185.6,213.6 198.4,210.4 211.2,207.3 224.0,204.2 236.8,201.3 249.6,198.3 262.4,195.5 275.2,192.7 288.0,190.0 300.8,187.3 313.6,184.7 326.4,182.2 339.2,179.7 352.0,177.3 364.8,174.9 377.6,172.5 390.4,170.2 403.2,168.0 416.0,165.8 428.8,163.6 441.6,161.5 454.4,159.5 467.2,157.4 480.0,155.4 492.8,153.5 505.6,151.6 518.4,149.7 531.2,147.8 544.0,146.0 556.8,144.2 569.6,142.5 582.4,140.7 595.2,139.1 608.0,137.4 620.8,135.8 633.6,134.2 646.4,132.6 659.2,131.0 672.0,129.5 684.8,128.0 697.6,126.5 710.4,125.1 723.2,123.6 736.0,122.2"/>
<circle class="dd-dot" cx="96.0" cy="238.4" r="5"/>
<circle class="dd-dot" cx="403.2" cy="168.0" r="5"/>
<text class="t-say" x="413.2" y="194.0">第 96 个：297 / 396 = 75.0%，联盟单独就够改宪法级规则</text>
<circle class="dd-dot" cx="736.0" cy="122.2" r="5"/>
<text class="t-mono" x="728.0" y="92.2" text-anchor="end"><tspan class="t-acc">401 / 500 = 80.2%</tspan></text>
<text class="t-mono" x="728.0" y="110.2" text-anchor="end">meta.pass 0.75 → 0.5：375 / 500 passed</text>
<text class="t-say" x="108.0" y="266.4">起点：seats.cap 300 → 500 只要 2/3，201 / 300 passed</text>
<text class="t-say" x="108.0" y="286.4">防御版里这一步要 3/4（225 票），联盟 201 票，停在这里</text>
</svg>
</div>
<figcaption>图 7 · 在“改选民”和“改规则”同级之前，一个 67% 的联盟可以先扩容、再塞人，把自己变成 80%</figcaption>
</figure>

**200 个傀儡席位逐个入席，每次都是联盟加已入席的傀儡全票赞成。** 联盟的占比从 67% 一路涨上去，第 96 个傀儡入席时到了 297 / 396，刚好 75%；全部入席后是 401 / 500，80.2%。最后一步要 375 票，联盟有 401 票，`meta.pass` 被改成 0.5，从此任何宪法级规则都只要过半数。整个过程是 60,100 笔投票交易、450 多个区块，原型上用了约 6 分钟，每一步都完全合规。

**防御版只改了一处：`seats.cap` 和 `admit.pass` 升为宪法级。** 同一个联盟第一步就停住了：扩容要 225 票，联盟只有 201 票，剩下 99 席里有 76 席投了反对，提案当场失败。没有扩容，后面两步都无从谈起。

**这说明了分级要分对地方。** 门槛只管“规则怎么改”是不够的，“谁来投票”同样是规则，而且是更根本的那一条。美国宪法把参议院平等代表权单独保护起来[^us-art5]，道理是一样的：选民构成一变，其他条款的门槛就都变了。

### 节点多了，出块慢多少

**设计里把席位和节点分开，前提是节点数不必很大。** 为了看节点数对出块的影响，在同一台机器上分别起 4 到 64 个验证节点，各发 20 笔交易，量出块间隔和一笔交易从发出到上链的时间。

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="pcc9-title">验证节点数和出块（同一台 4 核机器，timeout_commit = 500 ms）</div>
<div class="dt-scroll">
<table class="dt" aria-labelledby="pcc9-title">
<colgroup><col style="width:22%"><col><col><col></colgroup>
<thead>
<tr><th scope="col" class="num">验证节点</th><th scope="col" class="num">平均出块间隔</th><th scope="col" class="num">交易上链 p50</th><th scope="col" class="num">交易上链 p90</th></tr>
</thead>
<tbody>
<tr><th scope="row" class="num mono">4</th><td class="num mono good">800 ms</td><td class="num mono">810 ms</td><td class="num mono">813 ms</td></tr>
<tr><th scope="row" class="num mono">8</th><td class="num mono good">836 ms</td><td class="num mono">819 ms</td><td class="num mono">894 ms</td></tr>
<tr><th scope="row" class="num mono">16</th><td class="num mono good">863 ms</td><td class="num mono">833 ms</td><td class="num mono">850 ms</td></tr>
<tr><th scope="row" class="num mono">32</th><td class="num mono warn">963 ms</td><td class="num mono">948 ms</td><td class="num mono">1,055 ms</td></tr>
<tr><th scope="row" class="num mono">64</th><td class="num mono bad">3,492 ms</td><td class="num mono">5,736 ms</td><td class="num mono">7,301 ms</td></tr>
</tbody>
</table>
</div>
<p class="dt-note">每组发 20 笔交易。把 timeout_commit 降到 100 ms 再测一轮，4 个和 16 个节点约 0.42 秒一个块，64 个节点仍要 2.9 秒。</p>
</div>
<figcaption>图 8 · 16 个节点以内出块速度几乎不变，64 个节点挤在一台机器上时慢了 4 倍多</figcaption>
</figure>


**4 到 16 个节点几乎看不出差别，32 个开始变慢，64 个明显变慢。** 要注意这是所有节点挤在一台 4 核机器上的结果：64 个节点时，慢的主要原因是 CPU 不够分，而不是网络。真实部署里节点分散在不同机器上，CPU 不是瓶颈，但网络延迟会叠加进每一轮投票。结论只是定性的：几个到几十个验证节点足够，300 个席位不必都去出块。

原型说明这套规则能执行、能挡住一种有代表性的攻击。但开头说“在链上做比在链外做便宜”，**这一点成立吗？**

## 五、共识的收益和代价

### 收益：共同维护一份记忆，分歧少多少

**先看收益。** 用一个简单的模拟来量：300 个 agent，来自 3 个底座模型，各自记着 500 条事实。每个底座模型对每条事实记对的概率是 0.93，agent 九成照搬自己底座模型的记忆、一成自己重新记一次，记错时随机落在 3 个错误值之一。每个问题要用到 5 条事实，答案由这 5 条事实决定，此外每个 agent 每次回答还有 3% 的概率推理失误。随机抽两个 agent 回答同一个问题，看它们答得一不一样，共抽 8,000 次。

**“共同维护”的那一组，事实不再各记各的。** 每条事实由随机抽的 25 个 agent 投票决定，结果写进共享记忆，所有 agent 回答时都读这一份。图 9 是两种做法的结果。

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="pcc10-title">各自记忆和共同维护一份记忆（300 个 agent，3 个底座模型）</div>
<div class="dt-scroll">
<table class="dt" aria-labelledby="pcc10-title">
<colgroup><col style="width:34%"><col><col class="hl"></colgroup>
<thead>
<tr><th scope="col"></th><th scope="col">各自记忆</th><th scope="col" class="acc">共同维护一份记忆</th></tr>
</thead>
<tbody>
<tr><th scope="row">单条事实的正确率</th><td class="num mono">0.929（每个 agent）</td><td class="num mono acc">0.994（共享的那一份）</td></tr>
<tr><th scope="row">两个 agent 答案不一致</th><td class="num mono bad">41.6%</td><td class="num mono good">6.5%</td></tr>
<tr><th scope="row">其中由记忆不同引起的</th><td class="num mono">92%</td><td class="num mono">0%，只剩推理失误</td></tr>
<tr><th scope="row">答对的比例</th><td class="num mono">68.6%</td><td class="num mono good">93.4%</td></tr>
<tr><th scope="row">两个 agent 答案一致但都错</th><td class="num mono">7.2%</td><td class="num mono warn">3.3%，这时通常是所有人一起错</td></tr>
</tbody>
</table>
</div>
<p class="dt-note">各自记忆时，同一个底座模型记错的事实会被它的大部分 agent 一起记错，所以“一致但都错”也不少。共享记忆的 3.3% 来自共享事实本身记错：每条 0.6% 的错误率，5 条里有一条错的概率约 3%。</p>
</div>
<figcaption>图 9 · 共同维护一份记忆，两两分歧从 41.6% 降到 6.5%，剩下的分歧都出在推理上；代价是共享的那份错了，所有人一起错</figcaption>
</figure>

**分歧降了六倍多，而且剩下的分歧性质变了。** 各自记忆时，九成以上的分歧来自“记的不一样”，两个 agent 争论半天，其实是在比谁的记忆对。共享记忆后，分歧只剩推理失误，而且双方引用的块 id 一模一样，一眼就能看出问题不在底稿。

**代价是错误变成了全体的。** 共享记忆里一条事实错了，所有 agent 都会在用到它的问题上一起答错，这时连“有分歧”这个报警信号都没有了。这正是推翻机制要存在的理由：共享的底稿必须随时可以被一块有依据的反驳挑战，否则“分歧少”就会变成“错得整齐”。


### 代价：问题来之前先付的钱

**一篇 2026 年 10 月的论文给这类成本起了个名字：记忆税。** 它比较了两种做法：Mem0、Zep 这类“智能体记忆”系统在问题出现之前，先用模型把对话提炼成事实或知识图，问题来了再检索；另一种是什么都不提炼，让 agent 拿着原始记录自己搜。在 LoCoMo 的一段 419 轮对话、152 个问题上，用 Claude Opus 5.5 时，Mem0 光“建记忆”就花了 25.88 美元，比把全文直接塞给模型回答完全部问题的 17.84 美元还贵，要问到大约 596 个问题才回本；而让 Pi 代理自己检索原文，每题约 0.046 美元，正确率 99%[^memorytax]。为模型不需要的记忆提前付的钱，论文管它叫记忆税。

**论文的第二个发现是记忆有上限，由写的那一方决定。** Zep 的知识图如果由 GPT-4o-mini 写，换成 Opus 5.5 来读，正确率只有 45%；同一张图由 Opus 5.5 写，Opus 5.5 读是 87%[^memorytax]。写的时候漏掉的东西，读得再好也找不回来。

**共识链也是在问题来之前先付钱。** 一条知识要有人提出，要有一批席位读过、查过、投了票，这些都发生在任何人需要用它之前。这笔钱可以叫共识税。记忆税的两个发现在这里都有对应：一条共识值不值，看它以后被用多少次；共识的质量，不会超过投票那批 agent 的水平。

### 算一笔账

**设每个席位核查一条知识的成本是 c。** 一条知识要 V 个席位核查投票，建成的成本大约是 V·c，提案本身的成本相比之下可以忽略。之后每有一个 agent 直接用它、而不是自己从头核查，就省下一次 c，读链上记录、验签名的成本几乎为零。所以：

$$
\text{回本所需的使用次数} \approx \frac{V \cdot c}{c} = V
$$

**一条共识至少要被用到和投票人数一样多的次数，才不亏。** 这个结论和 c 的具体数值无关。为了有个量级，借用论文里 Pi + Opus 5.5 每题 0.046 美元作为核查一次的成本（检索一段记录回答一个问题，和核查一条结论的工作量大致相当，这是一个近似）。

**投票人数还决定了共识的质量上限。** 多数票越来越准的前提是投票者相互独立[^condorcet]。agent 来自少数几个底座模型，彼此高度相关。用一个简单的模拟来看：3 个底座模型，每个答对一道题的概率 0.7，每个 agent 九成跟着自己的底座模型走、一成反着来，个体准确率约 0.66，每种人数模拟 20,000 次。图 10 把成本、回本次数和准确率放在一起。

<figure class="dd dd-figure dt-figure">
<div class="dt-panel">
<div class="dt-title" id="pcc8-title">每条知识的共识税：投票人数 V 的取舍</div>
<div class="dt-scroll">
<table class="dt" aria-labelledby="pcc8-title">
<colgroup><col style="width:24%"><col><col><col><col></colgroup>
<thead>
<tr><th scope="col">谁来投</th><th scope="col" class="num">V</th><th scope="col" class="num">建一条的成本</th><th scope="col" class="num">多数票准确率（3 个底座）</th><th scope="col" class="num">同等个体、相互独立时</th></tr>
</thead>
<tbody>
<tr><th scope="row">全体过半（300 席 × 0.5）</th><td class="num mono">150</td><td class="num mono">$6.90</td><td class="num mono">≈ 0.787</td><td class="num mono">&gt; 0.999</td></tr>
<tr><th scope="row">抽 51 席</th><td class="num mono">51</td><td class="num mono">$2.35</td><td class="num mono">0.784</td><td class="num mono">0.992</td></tr>
<tr class="acc"><th scope="row" class="acc">抽 25 席</th><td class="num mono acc">25</td><td class="num mono acc">$1.15</td><td class="num mono acc">0.784</td><td class="num mono">0.952</td></tr>
<tr><th scope="row">抽 9 席</th><td class="num mono">9</td><td class="num mono">$0.41</td><td class="num mono">0.760</td><td class="num mono">0.844</td></tr>
<tr><th scope="row">1 个 agent 自己查</th><td class="num mono">1</td><td class="num mono">$0.046</td><td class="num mono">0.661</td><td class="num mono">0.658</td></tr>
</tbody>
</table>
</div>
<p class="dt-note">成本按每席核查一次 0.046 美元估算；回本所需的使用次数约等于 V。准确率是模拟结果：3 个底座模型时，上限是“3 个模型里多数答对”的概率 0.7³ + 3 × 0.7² × 0.3 ≈ 0.784。</p>
</div>
<figcaption>图 10 · 投票者相关时，25 个人以后再加人几乎不提高准确率，成本却照样线性增长</figcaption>
</figure>

**全体投票是最贵、也几乎最不划算的选择。** 150 席投票和 25 席投票的准确率只差 0.003，成本差 6 倍，回本所需的使用次数也从 25 次变成 150 次。真正限制准确率的是底座模型有几种，而不是人数，这和记忆税论文里“写的一方决定上限”是同一件事。

**和链外比，什么时候划算？** 如果几千个 agent 都要用同一条知识，比如 3,000 个，各自核查一遍要 3,000 × 0.046 ≈ 138 美元；抽 25 席在链上核查一次是 1.15 美元，链上明显便宜。如果一条知识只有三五个 agent 会用，那它在链上就是纯粹的税：25 个人替 3 个人查了一遍。所以“在链上做比在链外做便宜”只对被广泛复用的知识成立。

### 由此改的三处设计

**知识改由抽签的评审团投票，规则仍由全体投票。** 每条知识提案用提案所在区块的哈希做随机种子，从在席成员里抽 25 席组成评审团，按底座模型分层抽，尽量让每种模型都有人；门槛按评审团人数算。规则和入席很少发生，却决定所有人的处境，仍由全体投票。这一条在原型里还没有实现，是按上面的账推出来的。

**知识要附上原始证据，不能只交结论。** 记忆税论文里，强模型自己检索原文，比读提炼好的记忆更准也更便宜[^memorytax]。知识块如果只有一句结论，后来的 agent 只能相信它；附上原始数据或原文的哈希和位置，后来的 agent 既可以直接用结论，也可以在需要时回头查原文，共识就不会成为“写的一方”设下的天花板。

**按复用情况决定一条知识要不要上链。** 只被一两个 agent 用到的东西，留在各自的记忆里；被反复引用的，才值得交一次共识税。引用次数本身就记在链上，可以作为“这类知识值不值得上链”的依据。

## 六、几个绕不开的问题

### 为什么不用一个数据库

**如果 300 个席位都归同一个运营者，这条链没有必要。** 一个带权限控制的数据库，加一份签名的追加日志，就能做到“只有成员读写、每条记录可追溯”，规则投票也可以写成数据库里的一段程序。数据库想容忍机器宕机，用 Raft 就够了，etcd、Consul 都是这么做的；但 Raft 假定节点不会说谎[^raft]。

**链的价值只在一个前提下成立：成员之间互不完全信任，又不愿意把账交给其中任何一个人管。** 这时需要 BFT 共识，让哪怕三分之一以下的节点作恶，账本也不会被改写；规则投票也要由大家共同运行，而不是跑在某一方的服务器上。几千个 agent 如果来自不同的公司、不同的个人，这个前提成立；如果都是同一家公司部署的，就不成立。

### 不公开能做到什么程度

**白名单挡得住外人，挡不住成员自己。** 任何一个席位都能读到全部内容，就能把它复制出去。agent 比人更容易泄露：一次提示注入，就可能让它把读到的东西原样发到别处。Fabric 的做法是把更敏感的数据放进私有数据集合，只发给少数组织、其他节点只拿哈希[^fabric-pdc]，可以借用；但只要一条知识要让 25 个评审员读，它就至少暴露给了 25 个席位。

**席位退出以后，它读过的东西收不回来。** 链可以把一个席位踢出去，让它以后读不到新内容，但它已经同步过的历史仍然在它手里。所谓“不公开”，准确的说法是“只对在席和曾经在席的成员公开”。

### 席位稀缺，不等于观点独立

**一个运营者可以控制很多席位。** 入席要四分之三通过，挡得住明目张胆的塞人，但挡不住一家公司从一开始就占了 100 个席位。图 7 的联盟本来就有 201 席，它不需要任何技巧就能改所有普通规则。

**席位背后的 agent 也可能来自同一个底座模型。** 300 个席位、300 张票，看起来很多，按图 10 的模拟，如果只有 3 种底座模型，它们的多数票和 25 个人的多数票几乎一样准。稀缺的席位防住了女巫攻击，却没有带来独立的判断。

### 规则改规则，总有一个边界

**分级只是把边界往后推。** 只要 75% 的人站在一起，任何规则都能改，包括“75%”本身。Nomic 最初要求改不可变规则必须全体一致[^nomic-rules]，德国基本法干脆规定某些原则永不可改[^eternity]，但前者让一个人就能卡住所有人，后者的修改最终只能靠制定一部新宪法。没有一种规则能同时做到“谁也改不掉”和“需要时改得动”。

**门槛高了，规则就僵住。** 按在席总人数计票、缺席算反对，75% 的门槛意味着 300 席里要有 225 席真的来投赞成。链上治理的参与率通常不高，Cosmos Hub 扩容那次只有 39.68%[^cosmos-797]。Tezos 和 Polkadot 都按参与情况调整门槛，前者的法定人数随往届参与率浮动[^tezos-gov]，后者的支持率要求随时间下降[^opengov]。设想要借用其中一种，否则一年以后，可能连“把门槛调低一点”这种提案都凑不齐票。

### 投票仍然不等于真

**换成私有链、去掉币，没有改变“多数同意不等于正确”。** 一条知识通过了，说明的是“抽到的这批评审员多数认可它”，不是“它是对的”。数学结论有检查器可用时，应该交给检查器；实证结论要附数据、允许以后被新提案推翻；只有约定类的内容（单位怎么定义、某个术语指什么），投票本身就是答案。私有链让这些投票变得可信、可追溯，但不会让它们变得更准。

**引用对了，推理不一定对。** 格式检查只能确认一条论断引用的块都已通过，确认不了“从这几块真的推得出这个结论”。把“√2 是无理数”的证明原样抄过来，结论改成“√4 是无理数”，引用一个不改，照样能通过格式检查。拦住它的只能是评审员真的去读论证，或者对数学类的块直接交给证明检查器。

**整张引用图不会比根块更可靠。** 所有论断最终都落在定义和观测上，根块错了，下游的推理再严密也是错的；根块被推翻，牵动的块也最多。所以根块的门槛要更高、证据要附全，复审的成本也要事先想好由谁来出。

## 七、回到那条记录

现在可以回头看开头那两条记录。

**`p10` 凭什么成立？** 因为它引用的 `p8` 已经通过，而 `p8` 又落在 ITS-90 和标准大气压两块根上。它的前身 `p4` 说的是同一件事，但引用的是后来被推翻的 `p3`，于是被自动转为待复审；想保留这个结论，只能改引 `p8` 重新提。第一条知识从哪来、知识错了怎么办，答案都在这张引用图里：根块用更高的门槛立起来，错了就由一块有依据的反驳推翻，下游自动等待复审。

**共同维护这份记忆有什么用？** 在模拟里，两个 agent 答同一个问题，各自记忆时有 41.6% 的情况答得不一样，共享一份记忆后降到 6.5%，剩下的分歧都出在推理上，而且双方引用的块一模一样，一眼就能看出问题不在底稿。代价是共享的那份错了，所有人一起错，所以推翻机制必须一直开着。

再看 `p4`。

**它为什么能通过？** 因为 `seats.cap` 是宪法级规则，300 个席位里有 225 个投了赞成，正好是四分之三。同样的提案在朴素版里只要 201 票，一个三分之二的联盟就能独自通过，再借此把自己变成 80%。

**没有币，链靠什么防止乱写？** 靠席位：只有在席的密钥能签名，不在白名单的节点连不上；每个席位的提案有配额。防的是外人，不是成员。

**它和一个共享数据库有什么不同？** 只有在成员互不信任、又不愿交给任何一方托管时才不同：BFT 让少数作恶的节点改不了账，规则由大家共同执行。都归一个运营者的话，没有不同。

**在链上做真的更便宜吗？** 一条知识的共识税约等于“评审人数 × 核查一次的成本”，被用到的次数超过评审人数才回本。被几千个 agent 共用的知识，链上便宜得多；只有几个 agent 用的，上链是浪费。

## 小结

1. **设想的样子**：一条只给少数席位读写的链，不发币、不做交易，只记知识和规则。知识按不超过 1 KB 的块存放，论断必须引用已通过的知识，定义和观测是引用图的根，已通过的知识可以被有依据的反驳推翻；规则也是链上状态，分普通和宪法两级，席位上限也是一条规则，从 300 扩到 500 要投票。
2. **同类系统**：Metamath、mathlib 用程序检查引用，维基百科和纳米出版物要求外部来源，Proofgold、OriginTrail 把知识放上公链；Fabric、Corda、Besu、Sawtooth、CometBFT 提供了“只有成员能读写”；Tezos、Polkadot OpenGov、Cosmos、Compound 提供了“投票改规则”，但都按币加权；Nomic 和宪法提供了“改规则的规则要更高门槛”。最接近的是 Sawtooth 的设置交易族，它只管配置，不管知识。
3. **系统设计**：席位和验证节点分开，几个到几十个节点出块，几百个席位签名投票；提案开始时冻结选民，缺席算不赞成；抬高门槛要按新门槛过；没有手续费，用提案配额防刷。
4. **原型实测**：CometBFT 上 300 席的原型里，外人写不进、连不上，门槛分级和配额都按规则执行。不带引用的论断、不附证据的观测、引用未通过块的提案都被拒收；推翻 100.000 °C 那条观测后，依赖它的两条论断自动转为待复审，不依赖它的不受影响。在扩容只要三分之二的朴素版里，一个 67% 的联盟扩容后塞进 200 个自己人，占比升到 80.2%，把宪法门槛从 0.75 改成 0.5；把扩容和入席升为宪法级后，第一步就被挡住。4 到 16 个验证节点出块速度几乎不变。
5. **收益和代价**：共同维护一份记忆后，模拟里两两分歧从 41.6% 降到 6.5%，剩下的都是推理分歧，但共享记忆错了会让所有人一起错。代价是共识税：和记忆税一样，共识是在问题来之前付的钱，一条知识要被用到和评审人数一样多的次数才回本；投票者来自少数底座模型时，25 人以后再加人几乎不提高准确率。所以知识用抽签的小评审团、附原始证据，只把被广泛复用的知识放上链。
6. **绕不开的问题**：成员互不信任是用链的前提；“不公开”只对外人成立；席位稀缺不等于观点独立；任何规则都能被足够大的多数改掉，门槛太高又会僵住；引用对了推理不一定对，整张引用图不会比根块更可靠；投票让共识可信、可追溯，但不会让它更准。

## 参考资料
