WEB3核心技术的一种实现:时间长河共识算法(TRC, Time-River Consensus)

WEB3核心技术的一种实现:时间长河共识算法(TRC, Time-River Consensus)

副题 抽签分权 · 焊接定史 · 信用担保 · 追偿平复

版本 落地版 v4.2 状态 完成落地评审

结构 第一部分为讲解稿;第二部分为白皮书稿。节点规模交由部署决定,协议不再推算。


第一部分 讲解稿

0 它是什么

一条单父哈希链。每一环由一个人焊上去。

谁焊,不靠商量,靠抽签。

焊坏了怎么办,不靠投票否掉,靠举证、罚没、追偿。

整条链上没有一处需要"多数人点头":判定靠规则,收场靠顺延,处罚靠证据。

这是它和现有共识最根本的差别。


0.5 为什么叫时间长河

这个名字来自一个关于时间的猜测,不是修辞。

时间的特性,不是"在流",而是"改不动"。

我们感觉时间在流逝,其实是因为回不去。真正让人确认"过去存在"的,不是钟表的滴答,而是昨天做过的事,今天改不了。假如历史可以随意改写,"昨天"和"今天"就没有区别,时间也就不成立了。

所以让时间成其为时间的,是不可逆。

这条算法就是把这句话做成结构:

时间的特性 链上的实现
历史极难改变 焊接:改一环,后面每一环都得重焊
时间只向前 刻度只增,闭合过的不可回退
时间由事件显现 没有闭合,就没有下一格
静止期无公共时间 没有事件,就没有共同可见的刻度

四条特性,四条结构,一一对应。它叫时间长河,因为它要仿的就是时间的这四条性质,不是别的什么。

反过来说:如果为了活性和方便,允许历史被悄悄改写,那它就不再是一条时间长河,只是一本可以修改的账。

(说明:这是动机,不是论证。白皮书部分不依赖这段话成立;它只解释这套设计为什么长成这样。)


1 起点:出块人不能靠投票选

如果出块人靠投票选,就要先通信,再计票,再公布。通信需要时间,计票需要时间------而"时间"恰恰是这条链要解释的东西,不能先借来用。

所以出块人必须满足一个更强的条件:每个人各自在家里就能算出同一个答案,一句话都不用说。

这不是效率考虑,是逻辑顺序考虑。先有"共同",才有"时间";不能先有"时间",再造"共同"。


2 抽签名册:一本谁都改不了的书

有一本早已写定的书,翻到第几页就是第几页。所有人翻到同一页,看到同一个数。

它为什么合适?三个原因:

一、它没有作者。 没有人能说"这本书是我写的",也就没有人能偷偷改一页。这是它比"某个机构发布的随机表"强的地方------后者的中立性要靠信任,前者不靠。

二、它不用通信。 每个人手上都有同一本,翻页不需要问别人。出块人的身份因此是零消息确定的。

三、它是无限的。 链要走多久,书就有多长。

这一层的目的必须说准 :不是为了"让人猜不到下一个是谁",而是为了让人无法把自己封闭起来。

抽签是均匀的。一个占了几分之一的集团,无论占多少位置,被抽中的那一格仍有确定的概率落在外面的人身上。资源买得来概率,买不来确定。

所以这一层保证的不是"不能作弊",而是:

作弊无法成为稳定状态。

因为要稳定作弊,就得永远抽中自己人;而只要还有一个外人在名单上,这件事就做不到。


3 翻到哪一页,由交易量决定

如果按轮次翻页,节点可以挑时机------想让自己被翻到,就在那一页之前凑上去。

所以要换成一个已经长在历史里的量。交易量就是这样的量:它只能一笔一笔堆出来,而且堆在已经焊死的环里。想改它,就得改写历史,而历史改不动。

于是翻页的手不在任何人手里,在历史自己的累积里。人可以往里加交易,但加了之后翻到哪一页,他控制不了。

这就是"随机因子是交易量"的意思:交易量不是权重,是翻页的依据。

一个必须补的细节:读到的不能只是"一位数字"。一位数字只有十个取值,取模之后,永远只有十个位置有机会------这会把"人人有机会"变成"只有十个人有机会"。所以要从那一页起连续读若干位,凑成一个大数,再折进人数里。这一步不难,但漏了就把整个第一层废掉了。

还有一处要防 :翻页用的必须是过去的交易量,不能包含当轮正在打包的交易。否则出块人自己就能决定下一页翻到哪里,等于自己给自己抽签。


4 焊接:让历史无法被偷偷替换

新块头里写进上一环的哈希,再签上自己的名。

这动作叫焊接。焊上之后,谁想抹掉这一环,就得把后面每一环重焊一遍。

所以使一个人成为历史一部分的,不是同意,是遮挡------他在前面挡住了所有后来者。

这一步没有替代方案。它不是选择,是定义。换成"只写高度"或者"只写序号",遮挡关系就断了,历史立刻变成可以偷偷替换的东西。


5 时间:只在闭合处产生

这里要慢一点,因为它是整套东西的枢纽。

只有焊死之后,下一页才能翻开------因为翻页要用这一环的交易量,而这一环的交易量在它焊死之前并不存在。

所以在焊死之前,"下一环是谁"在物理上没有答案。不是没人知道,是那个数还不存在。

于是:

每一环的闭合,就是"下一刻"的诞生。

这跟我们的习惯是反的。习惯说时间先流过去,事件在里面发生。这里反过来:先有事件闭合,然后时间才有了下一格。

没有闭合,就没有下一格。静止期不是"时间在走但账本没动",是没有公共时间------因为没有任何东西被共同看见。


6 为什么不要投票:否决权与追责权是两种东西

投票在共识里干的事,说到底只有一件:否决。多数人说"我不接受这一块",这一块就作废。

但还有另一种办法:不否决,只追责。谁作弊,谁拿证据出来,谁挨罚。

否决需要多数,追责只需要证据。

证据如果能自证------比如同一个人在同一高度对两个不同区块签了名,两段签名摆出来,谁都能验------那就不需要任何人点头。规则即判决,即刻生效。

这就是"符合天道即刻判赢"的字面含义:合规就是赢,不合规就是不存在。 中间没有一段等待多数表态的时间。

撤掉投票,还顺带带来一个意外的好处:能罚的罪只剩一种。没有见证签名,整个系统只剩"焊接签名"和"报名签名"两种。而"同高双签"是其中唯一无歧义的罪------没有解释空间,也不可能栽赃。

签名面越小,冤案越少。而永久除名是不可逆的刑罚,这一点很要紧。

有人会问:抓到双签,谁来收场?

这里也不需要投票。

因为出块人是推导出来的,每个槽位后面跟着谁也推导得出来。双签一旦成立,那个槽位就在本高度作废,顺延到下一个下标------下一个是谁,人人算得出,不需要商量。

所以收场的人和出块的人一样,都是算出来的:

  • 作废的槽位不重来;
  • 顺延者补上这一块,块里必须处理作弊:查封、补平、除名;
  • 不处理,就是共犯,按 §9 第四条办;
  • 处理完,下一格恢复抽签。

所以整条链上没有一处需要多数人点头。判定靠规则,收场靠顺延,处罚靠证据。


7 作弊长什么样:一个账户变成负数

这是整套设计里最省力的一步。

如果作弊表现为"两条都声称自己是正统的历史",就必须有人来裁断哪条是真的。裁断一旦交给多数,多数就成了权力------这正是要躲开的东西。

(双签确实会造出两条分支,但它的收场不靠裁断,靠顺延:作废、跳到下一个下标、由下一个人处理。见 §4.9。)

而如果作弊表现为一个账户余额变成负数,就完全不需要裁断。它就是一笔算错的加法,任何人本地一算就能看见。

所以账本分两层处理:正常的超花在块内就被挡下 (余额不足,交易失败,谁也不用赔);绕过检查、把负数写进账本的,才叫作弊------那个负数就是痕迹。

这不是纵容,是分清两件事:失败是规则内的结果,负数才是规则被破坏的证据。前者不需要处理,后者一旦出现,就必须被记录、被追偿。


8 质押不是保险,是押金

每一笔交易由发起人指定一个守护者背书,守护者的质押就是它为这笔交易押上的钱。

它不担保"这笔钱一定付得出"------余额不足时交易直接失败,谁也不用赔。它担保的是自己不会配合做假:若它放一笔付不出的转账进块、把余额写成负数,那个负余额就是证据,质押要被全额查封去补。

所以质押量不是声望,是作恶成本的上限:押多少,最多就赔进去多少,一分不多。额度规则(0.9 × 质押)因此不是"信用额度",是"一次能造成的最大破坏"。

这两件事的区别很要紧:保险赔意外,押金罚作弊。 前者要收款方事后索赔,后者只要收款方做一件事------等块。块封了、交易在块里没标失败,钱就是真的;标了失败,就是没付。


9 四条硬规则,一条都不能省

一、足额背书才有效。

交易入块时必须校验:这个守护者当前还没结清的背书总额,加上本笔金额,不超过它的可用额度(0.9 × 质押 减去 已用敞口,§7.2)。

为什么必须有:额度就是作恶成本的上限。没有它,一个守护者可以配合把任意金额写成负数,破坏规模不再由质押锁死,"作弊不划算"这句话当场失效。

二、敞口上限。

一个守护者可以同时背书很多笔,质押必须覆盖全部未结清的背书,不是单笔。

为什么必须有:否则一个守护者给一百笔背书,一次罚没就把九十九笔悬在空中。那不是保险,是放大杠杆。

三、收款方要能验收。

付款方选守护者,收款方就该有权拒绝背书不足的款项。

为什么必须有:收款方的安全来自"等块"------块封了、交易没标失败,钱才真的到;标了失败,就是没付。验收的意义是把"注定失败"挡在交付之前:背书不足的款项,失败的概率更高,收款方有权不收。

四、查验即担保:不查等于共谋。

守护者在交易上签字,签的就是"我验过"。若这个块里出现了作弊------负余额、双签、状态根对不上------而签字放行,那就不是"疏忽",是共同作弊。

处罚一样重:全部罚没 。缺口先赔,赔完剩下的全部归举证者。

为什么这条能成立,而"不作为不可罚"在这里不成立:因为查验是一件做出来的事 ------你签字了。签字就是作为。"没查验"不是沉默,是签了一个假字,有签名可对照。

这一条把最大的口子补上了:审查、放水、装看不见,都得落笔;落笔就留证。


10 一个干净的结果

把这四条写进去,会看到一个巧合:

额度规则既是作恶成本的上限,也是破坏规模的上限。

因为能写进块的最大负数就是质押。作弊者能造成的破坏,不超过他被冻结的钱,所以净损益永远是负的。

同一条规则,两头都管。这种"一条规则顶两条"的地方,通常是设计对了的信号。


11 永久除名:一种不需要人执行的刑罚

这里必须先把两种事情分开,否则会把好人吓跑:

失职 欺诈
没来、没出块、断网 双签、负余额、放过没查验的块
只丢位置,不罚钱 全部罚没,余额归举证者
观察期 → 重复才除名 一次即除名

理由很实在:机房断电不该等同于作弊。若一次断电就永久除名,等于要求守护者做到百分之百可用------那会把准入抬到没人愿意进,最后名单里只剩大机构,反而更中心化。

钱归钱,位归位。

欺诈者被举证成立后,除了罚没,还永久失去被抽中的资格。

这一点比罚没更彻底,而且有个漂亮的特性:它不需要执行。

罚没要有人写进链,要按规则分配这笔钱。除名不用------身份表上把那个位置标死,抽签是规则,规则自己会绕开他。

不需要执法者,不需要投票,不需要任何人记住这件事。

而且它是结构性的:罚钱是一次性的,除名是永久的收入剥夺。天道不罚款,天道只是不再给他位置。


12 追偿:账会自己平

顺序是固定的:

  1. 作弊被记进历史:账上出现负数,成为一个缺口;
  2. 罚没的质押先进赔偿池,优先补那个变负的账户;
  3. 经济重新平衡;
  4. 结余用来奖励举证者;
  5. 缺口归零,事件关闭。

只有作弊才走这条流水线。失职不产生缺口,也就没有可赔的东西------它只丢位置;失败的交易也不产生缺口,它就是没付。

期间每一笔赔偿都是链上的事件,也就都是刻度。

这一步不是慈善,是让作弊从"一次性犯罪"变成"一笔长期负债"。

而且它承认了一件现实:负数一旦写进账本,就是既成事实。系统不能假装没发生,只能记账、追偿、平复。


13 两个市场,互不干扰

到这里,会有两个不同的分配机制同时存在:

  • 出块权:抽签。 为了公平,防止资源垄断,保证不可封闭。而且出块不给报酬------维持网络是守护者的义务,不是一笔生意。
  • 背书权:按额度。 谁质押多,谁的担保能力就大。费率固定,不竞价;客户端先筛掉"网络状态差"和"额度不够"的,再在剩下的里面等概率抽一个。

一个决定"谁有权力",一个决定"谁敢担保"。

权力靠抽,责任按额度,价格不动。 三件事分开,系统的性格就清楚了。

出块不发钱,这一点值得多说一句:一旦出块有奖励,抽签就会被经济动机污染------被抽中的人想多出,没被抽中的人想抢。抽签的公平性恰恰依赖"被抽中不划算、没被抽中也不亏"。把出块做成义务,抽签才真的只是抽签。

13.1 守护者靠什么赚钱

背书收手续费,费率固定,所以收入跟它背书的金额走。金额越大,收入越高。

而能背多少,受质押限制(见上节第一、二条)。所以:

想多赚,就得多押。

质押不是门槛,是产能 。押得越多,能承接的背书越多,收入越高。这是一条不需要任何人督促的加杠杆路径------只不过在这里,加的是责任。

于是"质押量代表可背书额度"这句话同时是经济激励:守护者有动力把额度做到最厚,因为那直接等于它的收入上限。


14 它不做什么

必须写在前面,否则会被误读:

  1. 不表达时长。 没有定时转账、没有计息、没有 T+1 结算。静止期没有公共时间,所以"过了多久"不可说。
  2. 不做分片。 整体性要求所有区块共享同一条历史。
  3. 不消灭作弊。 它让作弊不划算,并且可以被追平。这是比"不可能作弊"弱、但真正能做到的目标。
  4. 单笔支付的上限由质押决定,不由算法决定。 链能承载的单笔上限,就是守护者们锁在里面的钱。这是押金制度的本来面貌,不是缺陷。
  5. 不给做出块奖励。 出块是义务,不是生意。想靠出块赚钱的设计,会在抽签里长出竞价与抢槽。
  6. 分区后不自动合并。 协议只会挂起等待,合并与双花处置交给人。

15 故障与边界

15.1 节点不提供服务:这是常态,不是异常

先纠正一个看法:抽中的人没来,不是罕见事故,是常态。

一条均匀的时间河需要足够大的体量。节点越多,单点故障对全局的扰动越小;体量不够时,任何一次故障都像往浅水里扔石头。

所以这一条不是漏洞,是运行条件。它靠两道机制兜底。

第一道:准入。

时间守护节点不是想进就进。准入条件之一是网络稳定 ,而"稳定"不是自述,是由现存节点共同考验出来的:负载能力、抗 DDoS 能力、长期在线记录。过不了这一关,连名单都进不去。

这一道把"开一千个号"的成本抬到实打实的运维水平------原先担心的多开问题,在这里被堵住了。

第二道:顺延。

不可抗力真的发生了:机房断电、链路被切、整片区域断网。这时必须有办法把这一格让过去,否则整条河跟着停。

谁有权宣告故障:邻居,五个里三个。

邻居不是"网络上的邻居",是标识哈希最近的五个节点。按哈希距离取而不按索引邻接取,是为了打散地理位置:批量入网、索引连号的节点往往同机房,若互为邻居,一次断电就连作证的人一起消失。

门槛定在五取三:

  • 一个,等于给它单方面抢槽位的权力,而且不留痕迹;
  • 两个,合谋成本几乎为零;
  • 三个,必须动员一个真实的小联盟,而三份签名会永久留在链上。

为什么还留两个缺席的余量:失败处置本来就发生在节点陆续掉线的时刻。若要求最近的三个必须都到场,第二个节点一挂,顺延就永远启动不了------系统反而更脆。

处置流程。

  1. 邻居中的三个共同签名,宣告"这一刻该槽位没有服务";
  2. 该刻所有登记的交易标记为失败------不转移、不继承,直接作废;
  3. 交易退回发起方,重选守护者,重走一遍;
  4. 该节点进入观察期(失职,不是欺诈,见 §11);
  5. 反复失职或明显故意,才永久拉黑准入资格。

这条指控的边界:只对空槽位有效。

不需要时间,只需要因果------如果那个槽位已经有块,任何人一查便知,指控自动无效。于是"诬告一个已经出了块的人"在结构上做不到;能诬告的,只剩"他还没出块",而那正是要处置的状态本身。

顺延者拿到的是什么。

拿的是出块的机会 ,不是那些交易的处置权。交易已经作废,退回发起方重发,吞不下去。

而出块本来就没有报酬,所以抢一个槽位的直接收益为零;能捞到的只有"让对手的一批交易失败"这种破坏,而每次破坏都要留下三份永久签名。

规矩写死:故障处置不产生任何财产转移,只产生"作废与重来"。

15.2 不查验就是共犯

块里出现了没被查验的作弊,放它过去的查验者与作弊者同罪,共同罚没,而且是全部罚没。

这一条看起来重,其实最省事:它把"装看不见"从一种追究不了的消极行为,变成了一种留了签名的积极行为。你不签,它进不了块;你签了,你跑不掉。

(细则见 §9 第四条。)

15.3 三条曾悬着的,现在都落了

一、双签之后谁来收场。 曾经想过"由下一任裁定",现在不需要裁定:槽位作废,顺延到下一个下标,由顺延者处理,处置必须写进块里。见 §4.9。

二、出块人和担保人是不是同一批人。 是同一批。出块权与质押绑定,不押钱不能出块------因为出块人唯一的罪是双签,而双签的罚则是全额罚没,没押钱就罚不出东西来。见 §4.10。

三、罚没与奖励怎么分。 已定:欺诈全部罚没,缺口先赔,余额全部归举证者;失职不罚钱,只丢位置。见 §7.6。

真正还悬着的只剩一处:小额市场里质押赚不到钱,安全预算可能随业务缩水。靠最低质押自动上调兜底,但阈值要实测(§7.5、§8.2)。

15.4 一句话

这套东西不消灭故障,也不消灭作弊。它做的是:让故障有处置流程,让作弊有价格,让价格能被追平。


16 概念自检清单

给审阅者:下面每条都是本稿的承重假设,任一条不成立,上层结论跟着塌。

编号 假设 若不成立
A1 抽签均匀且不可被登记表操纵 资源可以买到确定,第一层失效
A2 抽签结果零通信可算 必须先通信才能定人,退回投票结构
A3 随机因子只来自已焊死的历史 出块人可操纵继任者
A4 签字即担保:焊接与背书都要落笔 不作为无法追究,共犯无人可指
A5 覆盖规则被严格执行 超花上限失控,损失外部化
A6 罚没足以覆盖超花 缺口永久挂账,第三层失效
A7 位置钉死、只滑不排 登记表浮动可被用来挤位
A8 准入考验真实有效 多开节点无成本,抽签被稀释
A9 邻居按哈希距离打散 同机房节点互为作证人,一次断电全灭
A10 顺延门槛五取三 一或二则合谋冒充故障,故障处置被滥用
A11 双签能被节点看见 网络被切成不相交两半时检测不到,退化为分区问题

(本表 A1--A11 是假设编号;§12 决策记录里的 A1--A5 是决策编号。两套并存,引用决策时一律写"§12 Ax"。)


第二部分 白皮书(Time-River Consensus)

本部分为实现级规范。第一部分是动机与讲解,不作为论证依据;凡论证均以本部分为准。

1 问题陈述

给定一个不允许外部时钟的对抗环境,构造一条单父哈希链,使其满足:

  • C1 唯一性:每个高度至多存在一个合法区块,且任何人独立计算可得同一结果;
  • C2 不可回退:已封闭的区块不能被任何合法扩展排除;
  • C3 无通信定人:出块人由已固化历史唯一导出,不需任何协商或随机数广播;
  • C4 结果判据可本地化:合规即成立;收场的人由顺延算出,也不需要多数表决;
  • C5 欺诈有界且可追偿:任何资产缺口在有限步内被清偿,且作弊的期望收益为负。

C1--C3 决定"谁焊",C4 决定"何时算数",C5 决定"焊坏了怎么办"。

2 系统模型与假设

2.1 参与者

角色 职责 是否需质押
发起方 构造交易,指定背书守护者 否
中继 转发与预校验,无出块权 否
守护者 背书交易、查验、可被抽中出块 是
举证者 任意主体,提交自证材料 否

出块权与背书权是同一批人:只有质押中的守护者能被抽中,出块是它的义务,背书是它的生意(§4.10)。守护者集合即身份表。

2.2 网络

异步、可丢弃、可重放、可分区。不假设任何时间上界。节点间以 gossip 传播,连通性由准入条件保证(§7.4)。

2.3 故障

拜占庭节点可任意偏航,但签名不可伪造 、哈希抗第二原像。

本设计不假设任何"多数决定":判定靠规则,收场靠顺延。只保留一条较弱的假设------诚实验证者在名单中占多数,以便证据最终能被写进链;否则作弊永远罚不了,不是因为判不出来,而是因为没人愿意记。

2.4 密码学

Ed25519 或 secp256k1 签名;SHA-256 或 BLAKE3 哈希;Merkle 累加器用于状态根与证据集。

已定,不再二选一:签名 secp256k1(65 字节,必须 low-s),哈希 SHA-256,Merkle 树用于状态根与证据集(§3.7.1、§3.9)。混用两种曲线或两种哈希会让规范序列化分叉。

2.5 关键假设(承重)

编号 假设 若不成立
H1 抽签输入只取 ≤ h−K 的已固化数据 出块人可操纵继任者
H2 身份表在窗口内不可被单方改动 资源可买到确定
H3 邻居按哈希距离选取且地理打散 同机房节点互为证人
H4 准入考验真实有效 抽签被稀释
H5 举证材料自证 举证退化为权力

2.6 术语:事件、刻度、高度

三个词指同一个量:一个区块 = 一个事件 = 一个刻度 = 一个高度单位。

词 用法
高度 h 区块在链上的序号,创世为 0
tick 区块头字段,恒等于 height。独立保留,只为将来可能的分化留位
事件 / 刻度 高度增量。说"100 个事件"就是"100 个块",两者等量换算

为什么必须先定死。 §4.10 的解冻、§8.4 的暂停上限、§4.4 的观察期都按"事件数"计时。若允许各实现自行理解 tick 怎么推进,同一份状态会算出不同的解冻高度,链当场分裂。这也解释了本链"没有时钟"却还能计时:计的是区块,不是秒------所以计时器在静止期不走,这是特性,不是缺陷。

3 数据结构

3.1 身份表

复制代码
Entry = { slot, pubkey, stake, status, admitted_at, strikes, resume_height, probation_until }
status ∈ { active, paused, probation, banned, unbonding }
  • 表为追加式,slot 单调分配,永不复用、永不重排;
  • banned 槽位保留,抽签时跳过;
  • 表的根 registry_root 提交在区块头,取 h−K 处快照参与抽签。

3.2 区块头

复制代码
Header = { version, chain_id, height, parent_hash, tick,
           tx_root, state_root, registry_root, checkin_root,
           gas_used, proposer_slot, round }

Block  = { header, sig, tx_envelopes[] }        // 签名在头之外
  • block_hash = SHA256(canonical(Header));签名单独存放,签的是 block_hash(§3.9)。
  • 签名不进 header:否则"先算哈希、再签名"的顺序会因签名长度而改变哈希,且哈希覆盖签名自身,闭环不了。
  • version 起始为 1;round 只用于诊断,不参与任何校验。

约束:tx 集非空(无空块);tick = height(§2.6);gas_used ≤ 30,000,000(§9)。

3.3 交易

复制代码
Tx = { version, chain_id, nonce, from, to, amount,
       gas_limit, gas_price, data_len, data }

TxEnvelope = { tx, sig, guardian_slot, guardian_sig }

txid = SHA256(canonical(Tx))        // 不含任何签名
  • 签名字段一律在 Tx 之外 (TxEnvelope)。理由有两条:签名可变(可塑性),算进 txid 就会让同一笔交易有两个 id;更要紧的是背书签名要签 txid,而 txid 若含背书签名,就成了"必须先知道自己的签名,才能算出要签的东西"的循环。
  • data_len 显式前置长度;不设"省略默认值"的编码(§3.8)。
  • amount = 0 的交易用于系统事件(报名补录、举证、账单、参数触发、升级指令);
  • to 决定交易类型,四类互斥,没有"既像转账又像调用"的编码:
    • to = 0²⁰:系统交易,data 承载事件本体(§3.6);
    • to ≠ 0 且该地址已有代码:合约调用,gas_limit 必填;
    • to ≠ 0、该地址尚无代码、且 to = H(from ‖ nonce):合约部署,data 为字节码,部署成功后代码哈希写进该账户(§4.11);
    • 其余:普通转账,data 必须为空。
  • gas_price 是发送方接受的最大系数 :打包高度上的当前系数必须 ≤ gas_price,否则该交易无效;实收按当前系数算,差额随未用完的 gas_limit 一起退回。字段保留,是为了让系数调整期间旧交易仍可验证;
  • 手续费只有一个来源:gas。没有按金额的比例费------金额只决定敞口(§7.2),不决定价格。这是为了让"占一块状态"有明确标价:转 1 个单位和转 100 万个单位,占的区块空间与状态位是一样的。
  • guardian_sig 是强制字段:无背书签名的交易无效;把无背书交易放进块,是共谋证据(§4.8)。

3.4 背书

复制代码
Endorse = { txid, amount, expiry_height, sig }

expiry_height 是保留字段 ,当前不参与任何校验(与 §3.2 的 round 同类)。启用它等于改规则,须硬分叉。不要拿它做"过期即退出敞口"------那等于给背书者一条跑路通道:只要拖到过期,赔付责任就没了。

状态中为每个守护者维护:

复制代码
exposure(g) = Σ 未结清背书金额
可用额度(g) = 0.9 × stake(g) − exposure(g)

3.5 报名

复制代码
CheckIn = { tick, slot, sig }
  • 每刻度签名一次,由任意节点打包进 checkin_root;

  • 允许在后续 W 个刻度内补录(防提议者漏收);

  • 补录不回写过去:记录只追加在未来块里,过去的状态根永不改变(§12 A4)。

  • 缺席判定是一个纯函数。 按"连续 W 个刻度没有报名"算,且只取已经封口的刻度:

    复制代码
    已封刻度 t* := h − W − 1            // 刻度 t 的补录最晚在 t+W 上链
    缺席(slot) := 报名树中 [t*−W+1, t*] 没有任何该 slot 的叶
                  且该 slot 在 B_{h−K} 的 registry 快照中为 active 或 probation

    其余状态(paused / unbonding / banned)不参与判定,也不会因"连续 W 刻度未报名"被标记离线------暂停本来就不报名(§4.12),两层规则不叠加。

    右端取 h−W−1 而不是 h−1:刻度 t 的补录最晚在 t+W 上链,取到这个边界时整段窗口都已封口,判定不会因消息先后而不同。代价是判定滞后约 W 个块------可以接受,顺延与剔除都不要求即时。

3.5.1 受理确认(账单)与到块回执

复制代码
Bill = { height, slot, txids[], sig }        // txids 可以为空
Ack  = { height, block_hash, slot, sig }    // "我收到了这一块"
  • 每个守护者在每个高度交一份,内容是该高度它受理(背书)的交易清单;一笔都没有,也要交空账单。
  • 提交方式是零额系统交易(to = 0²⁰),不收 gas 费------守护行为是义务,不是生意。它仍占区块空间,所以不能无限塞。
  • 出块人必须打包账单。 块内账单覆盖的槽位数少于 ⌈2N/3⌉ 时(N 取 B_{h−K} 的活跃槽位数),该块仍然有效,但出块人按下面的表降权。
  • 账单里的 txid 必须入块,或在该块的失败清单里。 否则这份账单不计入覆盖------这条把"少打包"和"留账单"两条路一起堵死:想少打,就得丢覆盖;丢了覆盖,就得降权。
  • 没交账单的槽位,下一高度不能参与抽签。 账单允许在后续 W 个高度内补录(与报名同窗口),补录只追加在未来块里,不回溯;缺席判定沿用 §3.5 的窗口函数,把"报名"换成"账单"。
  • 收到块就回执,回执上链。 邻居收到某高度的块后,发一笔零额系统交易 Ack { height, block_hash, slot, sig }。它和账单一样走链上:可查、可核对。回执只证明"我收到了",不代表认可它。
  • 回执可以指向任何块哈希,包括没被采纳的块。 它是"我收到了"的签名陈述,不是"我认可它"------被顺延掉的迟到块同样值得回执,因为那份回执就是矛盾的证据(§4.5)。任何人可以代为打包:举证人手里有那份签名,就能把它送进块。
  • 缺回执记一次失职,同一段缺失只记一次。 连续多个高度都没回执、直到重新回执为止,算一段,只记一次------否则一次断网就等于除名,那正是本设计要避开的。失职进观察期 30 刻度(§4.12),观察期内再犯即除名(§7.6)。缺回执的槽位,下一高度不参与抽签,与没交账单同等对待。
  • 回执与故障声明互斥 :回过执的槽位,不能再宣告该块"没服务"(§4.5)。回执由下一高度打包,与账单同一个窗口,补录规则也相同。
  • 状态里按 (slot, height) 记一个标记与账单哈希,叶类型 0x07。

为什么要有账单。 出块是义务、没有报酬,"少打包"本来零成本:被抽中的节点可以每块只放 1 笔,合法地把吞吐压到 1 笔/块,也可以定向丢弃某个地址的交易,全程不留证据。账单把"我收到了什么、愿意为谁背书"变成一份签名清单------少打包就与账单对不上,不交账单就直接失去下一次抽签资格。打包从"没人管"变成"两边都要留痕"。

2/3 是门槛,不是分片。 缺三分之一以内的账单可以容忍(掉线、延迟),超过就说明出块人没有真的在收集,或者在有选择地收集。所以处罚落在出块人身上,不落在被漏掉的守护者身上------后者可以用补录窗口自证。

降权处罚。 记在身份表里,按累计次数 k 停权:

第几次 停权高度数 恢复方式
1 1 停满后自动回到 active,计数保留
2 2 同上
k k 同上

停权期间该槽位不参与抽签,也不接受新背书。连续 10⁴ 个事件没有再次触发,计数清零。停权不是第六种状态 :status 仍是 active,靠身份表里的 resume_height 屏蔽抽签,这样五态表不用改,实现也少一个分支。为什么按次递增而不是一次重罚:漏收账单通常是网络问题,一次重罚会把偶发故障变成除名;但反复发生就是能力或意图问题,停权期一次比一次长,成本随次数上升。

3.6 证据

复制代码
Evidence::DoubleSign  = { h, blockA, blockB }        同一 slot 同高两块
Evidence::Overdraft   = { h, txid, path }            账户在 h 后为负
Evidence::Complicity  = { h, txid }                  块内含无背书交易
Evidence::FalseFault  = { h, block, acks[], fault_proof }   // 回了执又宣告"没服务"

三者均自证:不含任何需要被信任的陈述。

3.7 状态

复制代码
State = { balances, exposure, stakes, registry, deficits, insurance,
          codes, code_hash → bytes,        // 合约代码,按哈希存
          storage, contract → (key → value) // 合约存储,独立前缀
        }

3.7.1 叶类型与树形(冻结)

叶子键 = SHA256(tag ‖ key_bytes)。四类叶进状态树 (根 = state_root):

tag 类型 key value
0x01 账户 地址 20 balance u64 ‖ nonce u64 ‖ code_hash 32
0x02 合约存储 地址 20 ‖ slot 32 value 32
0x03 质押 / 敞口 slot_id u32 stake u64 ‖ exposure u64 ‖ status u8
0x04 系统 名称哈希 32 任意字节

两类叶各进独立树 ,根分别提交在 registry_root 与 checkin_root:

tag 树 key value
0x05 身份表 slot u32 pubkey 33 ‖ stake u64 ‖ status u8 ‖ admitted_at u64 ‖ strikes u16 ‖ resume_height u64 ‖ probation_until u64
0x06 报名 slot u32 ‖ tick u64 签名 65(该刻度未报名则无此叶)
0x07 账单 slot u32 ‖ height u64 账单哈希 32(该高度未交账单则无此叶)

为什么现在就把 tag 写死。 §3.8 规定叶前缀是冻结项,改动等于换链。身份表与报名在 M0 里恒为空树,但 M1 一上来就要写它们;若那时才定 tag,等于在每条节点的状态根上做一次硬分叉。

树形约定,四条都不能由实现自选:

  • 深度 256,二进制;每层取键的一位,大端、从最高位开始(第 0 层取首字节最高位);

  • 叶哈希 = SHA256(0x00 ‖ 键 ‖ SHA256(value));内部节点 = SHA256(0x01 ‖ left ‖ right);

  • 空子树不用裸零,而是一条递推链:

    复制代码
    EMPTY[0]   = 32 个零字节
    EMPTY[i+1] = SHA256(0x01 ‖ EMPTY[i] ‖ EMPTY[i])
    空树根      = EMPTY[256]
  • 三棵稀疏树(状态 / 身份表 / 报名)的空根一律是 EMPTY256,写成 32 个零是错的。

位序若两边相反,算出来的根一样是"合法哈希",值却完全不同,而且极难从结果反推原因------这类错误只能靠两套实现互相对照才抓得到。

tx_root 不在这三棵树里:它是一棵 2 的幂补零树,叶子是 txid,内部节点 = SHA256(0x02 ‖ left ‖ right),空位补 32 个零,空集根就是 32 个零(§4.2)。两套"空"不得混用:稀疏树用 EMPTY256,交易树用零。

证明格式(冻结)。 包含证明是从叶到根的 256 个兄弟哈希,按深度 0 → 255 排列,每项 32 字节,共 8192 字节。压缩版利用"第 d 层的空兄弟恒等于 EMPTY256−d−1"这一点,只传 32 字节位图(第 d 位为 1 表示该层兄弟非空)加逐项非空兄弟;压缩不改变根,因为根始终在完整的 256 层树上算,压缩只影响传输。非包含证明同理:把叶值当作空,走同一条路径,终点必须落在空位------"账户不存在"必须能被证明,否则无法拒绝伪造的余额。M0 只实现完整版,压缩版留到 M5。

3.8 规范序列化(冻结项)

两个实现必须算出同一个 state_root,因此编码不能有自由度:

项 规定
字段顺序 按本文档结构体声明顺序,不得重排
整数 大端、定长(u64 占 8 字节)
变长 前置 u32 长度,再放字节
可选字段 前置 1 字节标记(0 = 无,1 = 有)
Merkle 叶 前缀单字节区分类型,取值与键值格式见 §3.7.1;已分配 0x01--0x06,新增只能追加
状态树 稀疏 Merkle 树,键为哈希,深度固定
哈希 单一算法,写死;不得在中途更换

以上七条是冻结项:改动等于换链。新增字段只能追加在末尾,且必须升版本号。

3.9 地址、签名与签名域

  • 地址 = SHA256(压缩公钥)[-20:]。全链只用一把哈希、一条曲线。

  • 签名 = secp256k1,编码 r ‖ s ‖ v(65 字节),v ∈ {27,28},且必须 s ≤ n/2(low-s)。非 low-s 的签名一律无效------否则同一笔交易有两个合法签名编码,§11.3 的签名索引就不唯一。

  • 签名对象不是裸哈希,一律加域前缀,防跨语境重放:

    复制代码
    sig_payload = SHA256("TRC:TX:"    ‖ canonical(Tx))
    sig_payload = SHA256("TRC:BLK:"   ‖ block_hash)
    sig_payload = SHA256("TRC:ENDR:"  ‖ txid ‖ amount ‖ guardian_slot)
    sig_payload = SHA256("TRC:CHK:"   ‖ slot ‖ tick)
    sig_payload = SHA256("TRC:PAUSE:" ‖ canonical(PauseSelf))
    sig_payload = SHA256("TRC:UPGR:"  ‖ canonical(Upgrade))
  • 合约里有一处必须提前知道 :Solidity 的 ecrecover 用 keccak256 派生地址,与本链的 SHA256 派生不一致。所以合约不能靠 ecrecover 还原链上地址;需要鉴权的合约应接收公钥、自行算一次 SHA256 再比对。这是"全链一把哈希"换来的代价,写在这里,免得 M4 才发现。

3.10 创世块

创世块是唯一允许 tx 集为空的块(§3.2 的"无空块"从 h ≥ 1 起生效),字段固定:

复制代码
Genesis = { version = 1, chain_id, height = 0, parent_hash = 0^32,
            tick = 0, tx_root = 0^32, gas_used = 0,
            proposer_slot = 0, round = 0 }

它的三个根不由"空"决定,而由创世表算出:

  • state_root:alloc(地址 → 余额)建出的状态树;
  • registry_root:validators(地址、slot、质押、身份哈希)建出的身份表树------创世就有验证者,所以它不是空根;
  • checkin_root:创世无报名,故为 EMPTY256。

创世表以 JSON 描述、由生成器转成规范编码:alloc、validators、params(fee_rate_bp、gas_price、block_gas_limit、registry_lag_k、checkin_window_w、min_stake)。三条硬要求:JSON 只用于生成、不用于运行;生成器必须确定性(键排序、数字用字符串、无浮点);genesis_hash 一经发布不得修改,改了就是新链。

为什么创世的 registry_root 必须现在就算清楚。 它是 §4.1 抽签第一次要读的字段。若让它为空,前 K 个块的抽签就没有名单可读,M1 的第一次出块会直接落空。


4 协议

4.1 抽签(零通信)

复制代码
S_h      = Σ txcount(B_i),  i ≤ h − K
registry = load( H_{h−K}.registry_root )        ← 取 h−K 块头那个字段,不回溯状态树
ω        = digits_8( π, (S_h + H(registry)) mod 10^6 )
idx0     = rejection(ω, N)                       ← 严格均匀
idx      = 从 idx0 起,跳过 {状态不是 active 或 probation} ∪ {按 §3.5 判为缺席(报名)}
           ∪ {按 §3.5.1 判为缺席(账单)} ∪ {按 §3.5.1 判为缺席(回执)} ∪ {resume_height > h}
proposer = registry[idx]

h < K 的边界。 h−K 为负时一律取 0:抽签读创世表,S_h = 0。于是前 K 个块由同一个 proposer 产出------这是推导的结果,不是特例,也不需要额外规则。冷启动阶段没有传播抖动要覆盖,K 的缓冲用不上,正好。

拒绝采样:若 ω ≥ N·⌊10^8/N⌋,则取下一窗口 digits_8(π, p+8),直至落入;期望迭代 < 1.05,最坏界由 8 位窗口与 N ≤ 10^3 保证。

π 表就是圆周率的小数位。 取 π 的前 10⁶ 位十进制小数,每 8 位一窗。它没有作者、任何人可用任意精度库自行复算------所以"这张表从哪来、有没有被做过手脚"不是需要信任的问题,是算术问题。

发行版仍内嵌这张表(约 1 MB),只为省掉每次启动算一百万位小数的时间;附 SHA-256 校验和,启动时自检,不依赖任何在线源。

表的哈希在创世块里承诺(§8.1)。节点启动时拿本机表的哈希与创世块比对,不一致就拒绝启动;想自己算一遍再比也可以。这样"我的表对不对"不靠发布方声明,靠一条已经焊死的历史,加一次谁都能做的计算。

取位与越界。 位置 p = (S_h + H(registry)) mod 10⁶;拒绝采样每次后移 8 位,越过表尾则回卷到 0。窗口固定 8 位十进制(0 -- 99,999,999),足够覆盖 N ≤ 10³ 的取模。

4.2 出块

被抽中者取与 sh(B_{h−1}) 相容的交易(≥1 笔),收齐 §3.5.1 的账单(覆盖 ⌈2N/3⌉ 以上的槽位),计算状态根,焊接 parent_hash,广播。

余额不足的也要收进来,标成 failed。 块记录的是"收到过什么",不是"成功过什么":把付不出的交易也写进块、注明失败原因,出块人就无法悄悄丢掉背书人交来的东西;账单把这条约束钉死在 2/3 覆盖上(§3.5.1)。

没有任何一轮通信用于定人:所有节点在 B_{h−1} 落地后各自算出同一 proposer。

块内顺序:from 升序 → nonce 升序 → txid 升序。 这一条是强制的,不是约定------状态根必须只由交易集合决定,不由提议者的排列决定。否则提议者可以靠调换顺序吃掉价差(前跑),而且两个实现会算出不同的 state_root。

为什么不是单纯按 txid 排。 同一账户的 nonce 0 与 1,按 txid 排可能让 nonce 1 先执行;它因 nonce 不匹配被判无效,于是一笔本来合法的交易被排序规则弄死。先保证账户内 nonce 单调,跨账户再用 txid 定位,既不让提议者挑顺序,也不误杀合法交易。排序仍是交易集合的纯函数,所以"状态根只由集合决定"依然成立。

4.3 校验(合规即终局)

任一节点独立校验六项:父哈希连续、tx 逐笔有效、背书足额、state_root 可重放、抽签结果与自身计算一致、缺口处置义务已履行 (若 B_{h−1} 结束时存在缺口,本块必须含对应的清偿记录,§4.8)。六项通过即接受,不等任何确认。

4.4 报名与剔除

每刻度签名;连续 W 刻度无记录 → 从活跃集剔除(不拉黑,可随时恢复);banned 永久剔除。

4.5 顺延

块缺失且满足下列条件时,该槽位判为故障:

  1. 邻居集 N(i) = 与 slot_i 的标识哈希距离 最近的 5 个活跃槽位。三个量的取法写死:
    • 标识哈希 = SHA256(压缩公钥)(32 字节);
    • 距离 = 两个标识按 256 位无符号整数做 XOR,小者更近;并列时按 slot 升序取满 5 个;
    • 活跃集取 B_{h−K} 块头 registry_root 的那个快照(与 §4.1 抽签同一张表,不得另取)。
  2. N(i) 中任意 3 个签名宣告"该槽位无服务";
  3. 目标槽位在该高度上还没有被封的块:块已在链上,指控无效;块只是迟到、尚未入链,按下面的裁决规则处理。

处置:该刻度交易全部标记 failed 并退回;槽位记一次 miss;进入观察期。不发生任何财产转移。

同高两块的裁决。 若被判定故障的槽位后来又广播了它的块,同一高度就出现两块。规则:

携带三邻居故障证明的块优先,另一块作废,但不罚------它可能是网络问题,不是恶意。

这个优先是终局的,不因事后收到迟到块而翻转。 迟到块到达时,同一高度已经被封;回滚它就等于否定"合规即终局"(§4.3),而这条链的全部活性都建立在"看到合规块就接受、不等确认"上。所以这里只能二选一,选的是证明优先:宁可作废一个迟到块,也不让任何一块在被接受后还能被换掉。

迟到块是证据,但只罚矛盾,不罚迟到。 判据不在"块有没有出现",在"签名者有没有回过执":

  • 回了执,又宣告"没服务"------自相矛盾,三签者按共谋罚没(§4.6);
  • 没回执,宣告"没服务"------不算矛盾。它确实没收到,罚它等于罚网络抖动。

回执就是这条线的证据。 收到块的邻居回一份签名 Ack(§3.5.1);出块人手里于是有三样东西:自己签的块、三份故障签名、以及对方那份回执。三样凑齐就是矛盾,离线可验,不需要任何人的陈述。

不回执的代价落在链上。 缺回执记一次失职、进观察期,观察期内再犯即除名(§7.6);连续缺失只记一次。刻意不回执的人,每用一次假故障就得赔上一段观察期,用得多了就出局------成本从"没有"变成"信用"。

顺延块不罚。 它只是执行别人给的证明,自己无从判断真假;连它一起罚,真出故障时就没人敢接顺延。

谁举证,谁拿钱。 矛盾由原槽位节点举证,罚没全额归它------它的块已经作废,这笔钱是补偿。

顺延是单步接力,不跳级。 一个块只能证明"按抽签顺序排在它前面的那一个活跃槽位"无服务。前驱唯一,所以同一高度上不可能同时存在两个各带合法证明的块:若出现第二个,它声称的前驱此时必然已经出块,按上面第 3 条(有块则指控无效)当场作废。顺延者自己也不出块时,由再下一个活跃槽位接同一高度------接力的每一步只走一格,同一高度仍然只有一个接力者。

作废那块里的交易全部退回重发;出块权已经花掉,不回补。这条规则也适用 §4.9 的双签收场。

4.6 举证与罚没

证据可被任一交易携带。校验通过即执行:

复制代码
slash(offender) = stake 全额
缺口优先由 slash 清偿;余额归举证者
FalseFault 没有缺口,罚没全额归举证者

同一证据被多人提交时,只认链序第一份,其余作废、不重复发奖(与"首次出现生效"一致)。这样既避免重复支付,也避免为了抢奖励而塞满区块。

4.7 追偿瀑布

复制代码
deficit → ① 作弊者质押 → ② 全体验证者按质押比例分摊(单次不超过质押的 5%)
        → ③ 剩余缺口转为链上债券(不可转让),由后续罚没余额摊销

② 的上限按次算,不按年算。 这条链没有时钟,"一年"不是一个可计算的量;写成年上限,等于把一条无法执行的规则留在规范里。单次分摊封顶 5%,既限制单次冲击,又不需要任何时间单位。

债券只由罚没余额偿还,不从手续费里抽。 债券是受损账户名下的一笔只能收、不能转的余额。此后每次罚没,先补当次缺口,再按未偿余额比例偿还历史债券,全部清零后剩余才归举证者。没有专门的池子------赔付款只从作弊者身上出,不从日常交易里预扣。

4.8 失败与作弊:两件不同的事

余额不足的交易直接失败,不入账。 逐笔执行时先扣手续费:够付 gas 才进块;够 gas 但不够金额的,扣费、转账不发生、标记 failed。

失败不罚。 一笔支付没成,可能是付款方在别处先花了钱,也可能是一次没得手的攻击------两种情况都在规则之内,协议不做任何处置。协议只对破坏规则的行为动手。

负余额是作弊的痕迹,不是账本的一种状态。 它只有一个来源:有人跳过了余额检查,把一笔付不出的转账写进了块。它同时证明两件事:这一块违了规,签名者看到了却放过去了。所以它不是经济模型的一部分,是回击的起点。

失败的交易照样入块、照样付 gas、照样消耗 nonce。 三条都不能省:不入块,出块人就能悄悄丢掉背书人交来的交易;不付 gas,失败交易可以免费塞满块;不消耗 nonce,同一笔可以被无限重放。

处理义务在负余额出现时触发。 若 B_h 结束时存在缺口,则 B_{h+1} 必须包含处理该缺口的系统交易------查封签名者质押、清偿缺口账户、标记除名。三者由状态确定性推出,不含裁量。

为什么这不需要时钟。 块是一个封闭对象:里面有没有清偿记录,一查便知。所以"没处理"是一个可证的缺席------不需要多数声明,也不需要计时器。

这是全设计里唯一一处"缺席可证"的地方,原因是:缺席发生在块的内部,而不是网络之中。 网络里的沉默无法证明,块里的空白可以。

不处理的后果。 该块不合规,任何节点直接拒收;同时,这份被签名的块本身就是共谋证据------它证明签名者看到了缺口,却放过去了。口径与 §9 第四条一致:不查验即共犯,全部罚没。

分叉的处置。 若作弊者私下提交另一条分支以掩盖缺口,该分支一律判无效,判据是它没有处理缺口。处理了缺口的那条分支即正史;在正史上按规则处理的节点,不承担任何责任。

(边界:若两条分支都处理了缺口,则回到"同一高度两个合规块"的情形,由 §4.9 的顺延规则接管。)


4.9 双签的发现与处置(不投票)

见证。 每个节点收到一块后,向邻居互报一条极小的摘要:(height, proposer_slot, block_hash, sig)。这不是共识消息,只是互相看一眼。

检测。 若某节点在同一个 (height, proposer_slot) 上看到两个不同的 block_hash,且两份签名都属于该槽位,则双签成立。

证据自证:两个块、两段签名,凑在一起就够,不需要任何人的陈述,也不需要任何人被信任。

因为出块人是推导出来的(§4.1),只有被抽中的那一个能造成这种冲突,别人做不到。所以检测面极窄:每个高度,只有一个可能作弊的人。

前提。 检测成立要求两块的信息在网络上相遇------至少有一个节点同时看到两块,或者两个看到不同块的节点互相通信。

若攻击者把网络切成完全不相交的两半,任何一方都看不到另一方的块,此时检测不到,退化为 §6.4 的分区问题。这是假设,不是结论。

处置:作废并顺延。

  1. 双签成立 ⇒ 该槽位在本高度作废,两个块都不进入正史;
  2. 顺延到下一个活跃下标------跳过规则与 §4.1 完全一致(banned、未报名者跳过);
  3. 顺延者在该高度出块,块内必须 包含处置:查封双签者质押、补平缺口、标记除名;若该高度没有缺口,则只查封与除名,"补平"一项记为零额------字段照填、值为 0,不留"到底有没有缺口"的解释空间;
  4. 顺延者出了块却不处置 ⇒ 该块不合规,节点直接拒收;而这份签名本身即共谋证据,按 §9 第四条全部罚没;
  5. 顺延者不出块 ⇒ 走 §15.1 的故障流程(五取三邻居宣告),继续顺延;
  6. 处置完成,下一高度恢复抽签。

为什么这里不需要投票。

收场者是谁,是推导 的结果,不是选择的结果:槽位有序,下一个就是下一个,人人算得出。

投票唯一能多给的是"合法性感",代价是把多数裁决重新引进来------而那是这条链最不该有的东西。既然顺延已经给出唯一的答案,就没有再问一遍的必要。

边界。 顺延者仍须决定保留哪一支的普通交易;被舍弃那一支里的支付会变成债权,由 §4.7 的瀑布理赔。可审计,不可申诉。

与 §4.8 的关系。 §4.8 管"缺口必须被处理",§4.9 管"处理不了时谁来接手"。前者是义务,后者是接力。

4.10 质押、自交易上限与退出

绑定。 出块权与质押绑定:只有质押中的守护者才能被抽中。不存在"不押钱也能出块"的位置。

自交易上限。 同一账户既是付款方又是背书人时(自己给自己背书),其未结清交易总额不得超过自身质押的 2/3,超出部分无效。

为什么是 2/3 而不是 0.9:给自己背书时没有第二双眼睛,"查验"退化为自证。留出 1/3 的质押,等于强制它始终有一部分额度在为别人承担风险------自己不能把全部身家押在自己身上。

退出。 解除质押不能直接从链上抽走,必须三步:

  1. 发布暂停服务声明(一笔系统交易,签名即生效);
  2. 自声明生效起,该节点退出抽签、停止承接新背书,质押继续冻结;它原有的出块义务由后续槽位顺延承担;
  3. 100 个事件之后,若无未结清缺口或争议,质押解冻可取。

为什么必须留这 100 个事件:缺口是事后才被发现的------负余额要在下一块暴露,双签的证据要等两块相遇。若允许立刻取走质押,作弊者可以在事发前抽身,整套罚没就成了摆设。

100 个事件与 §4.8 的"下一块必须处理"是两层保护:前者保证退出者仍可被追责 ,后者保证在位者必须及时处理。


4.11 智能合约层

合约是本链的扩展,但它不能破坏会计模型。三条边界写死:

一、合约调用同样需要背书。 每一笔用户交易都要一个守护者签字,合约调用不例外------否则它就成了唯一不需要担责的入口。

二、合约内部转账不产生负余额。 合约执行是原子的,余额不足即 revert,不留痕迹。所以 §4.8 的"负余额 = 背书者失职"只适用于普通转账,不被合约污染。

三、合约不能作为背书者。 背书人必须是质押中的守护者;合约没有质押,也就没有可被罚没的东西。

费用只有一层:gas。 按金额收的比例费已经取消,理由见 §7.5:

复制代码
手续费 = gas_used × 系数     (全部归背书者;系数见 §7.9)

背书者是唯一必须在签字前先执行一遍的人------不跑 VM 就算不出会不会 revert,也就签不了字。这是实打实的算力,手续费全归它。其他节点执行是在验证区块时重算,那是身为节点的义务,不另收。

单价写死为系数 69,000 个最小单位 / gas(暂定),不拍卖、不浮动;只有创世地址能调,约束见 §7.9.5。合约调用须预付上限,未用完退还。

确定性红线:禁用浮点、随机源、外部 I/O、依赖实现细节的 gas 计量。违反任一条,两个实现会算出不同 state_root,链当场分裂。

合约里的钱没有担保人。 额度规则管的是转账金额;合约账户里的余额不受任何质押约束------一笔 amount = 0 的调用可以把合约里的钱全部转走,协议不赔。这一点必须写在用户看得见的地方,不能只藏在白皮书里。

合约地址由哈希派生:H(部署者地址 ‖ nonce),不需要治理分配,也不需要抢注。可读名称交给链外的域名服务。


4.12 节点生命周期

五种状态,一张表定死,避免各实现各写一套:

状态 能否被抽中 能否背书 质押 是否继续报名 进入条件 离开条件
active 是 是 可动(受额度约束) 是 入网考验通过 自暂停 / 除名 / 退出
paused 否 否 冻结 否 自暂停声明上链 满 100 事件且无缺口
probation 是 是 冻结 是 一次失职被顺延认定,或缺回执 满 30 刻度无再犯
banned 否 否 全额罚没 否 欺诈举证成立 永不恢复
unbonding 否 否 锁定待释放 否 自暂停满 100 事件 释放完成

三条容易搞错的细节:

  1. paused 期间不报名,所以也不会因"连续 W 刻度未报名"被标记离线------两层规则不叠加。
  2. probation 仍可被抽中,否则一次抖动就等于停业,惩罚过重。
  3. unbonding 不是独立状态,是 paused 的最后一段;文档里单列,只是为了让实现者知道"质押什么时候真的能取走"。

5 安全性

5.1 命题 1(唯一后继)

给定 B_{h−1} 与已固化状态,proposer(h) 唯一。因 S_h、registry、N 均取 h−K 处快照,与 B_h 的内容无关。

推论:同一高度不存在两个"合规但不同"的合法区块,除非出块人自身双签(可举证)。

5.2 命题 2(抽签均匀)

拒绝采样后 Pridx0 = i = 1/N 严格成立,误差为零(非近似)。故任一活跃槽位获得出块权的概率相同,与质押、年龄、位置无关。

5.3 命题 3(不可回退)

区块头含 parent_hash 且后继唯一 ⇒ 改动 B_i 需从 i 起重算全部哈希并重新取得全部后继的派生权,而派生权由不可改的 S 与 registry 决定。故回退代价为全链重算,且新分支在抽签上无任何优势。

5.4 命题 4(超花在块内被挡住,突破规则必留痕)

正常执行下,超花到不了账本:余额不足的交易在块内就被标成 failed,余额不会为负(§4.8)。所以作弊没有"卷走一笔钱"的常规路径。

它必须先突破执行规则------让一笔付不出的转账真的入账。一旦这么做,B_h 结束时账户为负,B_{h+1} 必须清偿(§4.8):查封质押、补平、除名。

因背书额度上限为 0.9·s,必有 A ≤ 0.9·s < s。所以突破的结果不是"卷走 A",而是"质押清零、位置永久剥夺"。

净收益为负,且缺口不会挂账。 这条命题保护的不是"不会失败",是"失败也不丢钱":正常交易失败只是没付成,突破规则才产生缺口,而缺口必有清偿。

5.5 命题 5(追偿收敛)

瀑布三级各有上界:质押封顶单人损失,分摊封顶单次冲击,债券只由后续罚没偿还 ⇒ 缺口单调递减至零。收敛速度取决于未来罚没的规模,与出块速度无关。

5.6 抽签研磨:为什么它买不到东西

出块人可以通过调整块内交易数来移动 S,从而移动下一次抽签的位置。这条通道存在,本节不假装它不存在。它是一条按次收费的通道,而它买到的东西价值为负。

"少打"这条路先被堵死。 账单(§3.5.1)要求出块人交齐 ≥2/3 守护者的受理清单,且账单里列的 txid 必须入块、或记为 failed;漏掉就丢覆盖,覆盖不足 ⌈2N/3⌉ 即降权(第 k 次停 k 个事件)。所以"只打一笔"不是免费选项,是拿自己的出块资格换的。

"多打"这条路明码标价。 位置 p = (S + H(registry)) mod 10⁶,多打一笔就移一位。要把偏置覆盖到任意目标,得把整块打满:30,000,000 ÷ 1,450 ≈ 20,688 笔,按当前系数约 20,700 TRC,是当前最低质押的二十倍。这不是顺手微调,是批发采购------而且整块的真实交易会被自己的 dust 挤掉,行为在链上极其显眼。

买到的又是什么。 出块是义务、没有奖励(§7.1),执行费归背书者、不归出块人。所以"偏到自己"不是抢收益,是给自己加活。剩下两个动机都不划算:

  • 让对手多出块:他出一块的成本是带宽和 CPU,收益为零------花两万 TRC 让对方忙一下;
  • 让对手漏块:漏块只进观察期,不罚钱(§7.6)------花两万 TRC 换对方一次观察期,而且你无法预知他何时离线。

反复做还要另一笔本钱。 要一次次拿到出块权,得长期握住大量槽位:准入考验、足额质押、每次被抽中都要打包。欺诈一旦举证成立,罚没全额、除名永久(§4.6)。收益上限被质押锁死,损失下限是全部质押。

所以这里不给概率上界,不是因为没有上界,而是因为上界不重要 :偏置的价格线性、公开、可复算,而它买到的东西价值为负。攻击的动机不是被规则消灭,是被成本结构消灭------这是设计选择,不是数学疏漏。

这条防线有一个价格锚:系数。 以上数字全部按 69,000 计。若系数被执行到下限 1,一个满块只要 0.3 TRC,整套论证当场失效。所以 §7.9.5 的下界不是防手滑,是这条防线的地基。


6 活性

6.1 单点故障

若 N(i) 中 ≥ 3 个在线,顺延在 1 个块周期内完成。N = 21 时,邻居全灭需 ≥ 3 个同机房节点相邻,由 H3 排除。

6.2 抽签遍历

设失职节点比例 p,连续 W 次抽中失职节点的概率 ≤ p^W;W = 10 时对 p ≤ 1/3 已降至 1.7×10^−5。

6.3 节点规模

节点数不是协议常数,由部署方按实际规模决定。协议不设下限、不做推算:抽签所用的 N 在运行时从已提交的登记表读取,N 变则结果变,机制不变。

落地优先,所以本文不再给出"需要多少节点"的推导------那是部署决策,交给部署方。

6.4 分区:挂起,交给人

网络断成两半时,测得出的事实只有一件:顺延要三个邻居,而邻居未必在同一片网络里。

于是每一侧都面临同一个选择------继续跑,还是停。继续跑就有作弊嫌疑(你不知道对侧出了什么块),停则全线冻结。

规则定为:停。

  1. 当前事件的守护者挂出一条「等待网络融合」的特殊事件,写明预计恢复时间;
  2. 该片区内的节点一律挂同一条事件(这是一次广播,不是一次投票);
  3. 挂着事件的这一片强制暂停出块与背书;
  4. 另一片保持出块,同时接收并暂存对侧的融合数据;
  5. 融合完成后,由人类技术委员会会议处置双花------追根源、处罚与补偿,或者把受害者一侧先行搁置。

这是本设计唯一需要人类介入的地方,而且必须极少发生。 它不是漏洞补丁,是设计者对"协议不该处理的事"划下的线:没有时钟,就没有办法判断两片网络谁更正统,与其让协议猜,不如让它停。

若两片都挂出了等待事件,则全链暂停,直到人恢复。这是可接受的:它比两条历史都自称正统要好。

7 经济

这一章讲的是作弊的价格,不是保险产品。质押、罚没、追偿瀑布存在的唯一目的,是让破坏规则的成本高于收益。正常的交易失败不在其中------失败了就是没付,没有赔付,也没有罚。

7.0 总量、单位与发行

总量 1 × 10^9 TRC(十亿),精度 10^-8,恒定,不增发。 最小单位 10^17,可安全落在 u64 之内。

没有出块奖励,也没有通胀:出块与背书的全部收入来自交易手续费。因此总量在创世那一刻就固定,此后只发生转移 ,不发生创造。罚没的钱也不会被销毁------先补缺口,余额给举证者,一分不烧。

为什么是十亿。

单笔支付的上限由单个守护者的质押决定,与总量之间只隔一个比例:

复制代码
可背书额度 = 0.9 × 质押

押总量的千分之一(100 万),就能承接 90 万的支付;押千分之二,就是 180 万。所以总量决定的是货币单位的大小,不是单笔上限本身。

十亿的好处是整数好算:千分之一恰好 100 万,千分之二 200 万,不产生小数尾。落地阶段最怕参数带小数尾巴,十亿是能整除的最整齐的一档。

想要更大的单笔,只有两条路:某个守护者押更大份额,或发起方自行拆分(§7.8)。

创世分配的三条硬约束。

  1. 初始质押 ≥ 总量的 30%。 低于此,安全预算不足以覆盖目标支付额,链一开始就是纸糊的。
  2. 剩余部分不得集中在少数地址。 集中会立刻抬高 h,使"抽签均匀"在账面上变成"质押均匀"的假象------公平是抽签给的,不是分配给的。

7.1 唯一的收入:背书服务费

来源 比例 归属
手续费(gas_used × 系数) 100% 背书者(预执行的服务费,非租金)
出块 无报酬 守护义务
罚没余额 缺口清偿后的剩余 100% 举证者

费用只由 gas 决定,不由发起方声明。 交易里没有手续费字段:扣多少完全由 gas_used 与系数算出,不存在"自报费用"或"两种取整"的空间。普通转账按 §7.9 的模型是 1,450 gas,合约调用与系统交易按各自的操作序列累加,上限由 gas_limit 预付、未用完退还。

扣费时点。 入块校验时先扣,扣不动即整笔无效------手续费永远不能把余额扣成负数,否则 §4.8 的"负余额 = 双花痕迹"就被污染了。

失败的交易照扣。 余额够付 gas、不够付金额的:gas 照扣、转账不发生、标 failed,gas 不退------算力已经花掉。余额连 gas 都不够的:整笔无效,不进块。

守护行为不收费。 报名、账单、回执、举证、自暂停声明、升级指令都是零额系统交易,一律不收手续费------它们是守护者的义务,不是生意,让义务自己掏钱等于给每个节点加一笔固定税。它们仍占区块空间、仍算进块 gas 上限,所以出块人有权按空间取舍,免费不等于无限。

执行失败不退费。 revert 或 out of gas,手续费照收:算力已经花掉,退款等于让全网为失败付费。

出块不发钱。 这是本设计与几乎所有主流链最不同的一点:出块不产生任何收益,它只是保护网络的义务。守护者的收入来自背书,来自它承担的风险,而不是来自它占据的位置。

理由:一旦出块有奖励,抽签就会被经济动机污染------被抽中的人想多出块,没被抽中的人想抢。抽签的公平性依赖"被抽中不划算、没被抽中也不亏"。把出块做成义务,抽签才真的只是抽签。

没有池子。 赔付的钱只从作弊者的质押里出,不够就由全体按质押比例分摊------不从日常手续费里预扣一分。

7.2 质押决定产能,也决定上限

复制代码
第三方背书额度 = 0.9 × 质押 − 未结清
自交易总额     ≤ 2/3 × 质押

第二条单列,因为它最容易被绕开:一个人给自己背书时,背书人与付款人是同一个人,查验形同虚设。把自交易压在 2/3 以内,等于强制它留出三分之一质押去承担别人的风险。

7.3 客户端怎么挑节点

两段式:

  1. 筛选:网络状态达标(延迟与可达性在阈值内),且额度足够(可用额度 ≥ 本笔金额)。
  2. 均匀随机:在通过筛选的候选池里等概率抽一个。

筛选是阈值,不是排名。 这一点很要紧:若按"最快"或"额度最大"排序,所有客户端会涌向同几个节点,负载迅速集中,分散性当场作废。阈值加均匀,才能既筛掉不合格的,又把负载摊平。

这一层只是降低失败率,不是安全边界。入块时仍会按 §9 第一条重新校验额度,不合格的交易直接无效------客户端筛错了,损失的是它自己的时间,不是别人的钱。

7.4 单价为什么固定

手续费单价由协议固定,不随行情浮动,不由市场撮合。

竞价会把"可信"翻译成"便宜",而这套系统的信用来自质押,不来自价格。一旦允许竞价,低价者会挤走高额度者,而低价的背后通常是薄质押。

7.5 质押的回报从哪来

收入按笔计,不按金额计。 一笔 50 万的支付与一笔 50 的支付,背书者拿到的是同一笔 gas 费(1,450 × 69,000 = 100,050,000 个最小单位 ≈ 1 TRC)。这是取消比例费的直接结果。

它不禁止任何接单方式。 额度是唯一的稀缺资源:一笔 50 万占掉 0.9 × 质押 的全部额度,收益固定;同样额度接几百笔小额,收益高几个数量级。于是节点会优先接小单、把大单留给还有余量的节点,或者由付款方拆成多笔(§7.8)。这是自由市场行为------协议只管额度与单价,谁接什么单由节点自己判断;用接单策略去挤占别人的份额,也不禁止。

代价落在区块空间,而区块空间已经被定价。 一笔 50 万拆成 1000 笔 500,手续费合计 0.84 TRC(约占金额的 0.00017%),但要吃掉约 2100 万 gas,接近一个整块。所以拆单不是免费的市场行为:它用区块空间换额度效率,而 gas 正是给区块空间定价的东西。

真正会被费率挡住的是极小额的支付。 单笔手续费固定 84,000 个最小单位,一笔 0.001 TRC 的支付要付 84% 的费用。这类支付不适合上链------它占的区块空间与一笔大额支付完全一样。

残余风险(无法用参数消除)。 若业务以小额为主,额度不起分层作用,押多不赚多,理性节点会把质押压到下限。只能靠一条硬下限兜底:最低质押随全网交易额的移动平均自动上调(见 §8.2 的自动参数)。

7.6 失职与欺诈分离

失职 欺诈
判据 顺延成立 三类自证证据
财产 无 全额罚没
资格 观察期 30 刻度,再犯除名 一次除名

若失职即除名,则要求守护者 100% 可用,准入将只剩机构,反而中心化。

7.7 激励相容

  • 发起方:选背书不足者,交易被收款方拒收 ⇒ 被迫选足额者;
  • 收款方:可拒收,故有动力查额度;
  • 背书者:签名即表示查验过。正常失败(余额不足)只是没付成,不罚;一旦负余额出现------也就是有人跳过了余额检查------签名者按共犯全额罚没(§4.8),所以它有动力在签字前真的看一眼;
  • 举证者:奖励为罚没余额,故有动力举证;
  • 出块者:出块无收益,但漏出块会被顺延并记 miss,故有动力维持在线;双签则全部罚没,故有动力不双签。

五方各自的最优策略与系统目标一致。出块者这一方的激励是负向的(怕罚、怕除名),不是正向的(赚钱)------这是刻意的:出块权不该是生意。

7.8 大额支付:拆分,不叠加背书

单笔上限就是单守护者的可用额度(0.9 × 质押),协议不提供多签叠加,也不提供任何超额通道。

超过上限的支付由发起方自行拆分成若干笔,各自选背书、各自计费、各自生效。

这样定的理由:多签叠加需要一套跨守护者的责任划分(谁先赔、赔多少、如何追偿),而每多一条这样的规则,就多一处可以被钻的缝。单签单责,责任边界永远是一条直线。

代价要写清楚:拆分不保证原子性。 拆成三笔的付款,可能成功两笔、失败一笔,中间没有回滚。业务层需要自己处理这个缺口(分次确认、或者先付定金)。

7.9 gas 从哪来:一个锚,两张表,一个系数

先立锚。 1 gas ≡ 一次 SHA-256 压缩(64 字节块)。所有成本都换算成它的倍数,全链只此一个单位。

选它当锚:跨平台确定、可计数,而且是这套系统里出现最多的原语------写一个叶要 256 次哈希。

一条前提:gas 只能是"计数",不能是"计时"。 验证者要重放你的块,必须用同一套数;墙钟时间在别人机器上不一样,链会当场分裂。所以"真实计算量"指协议规定的操作次数,不指你的实现跑多快。哪天有人把树路径优化到快一半,gas 也不能跟着降------否则同一笔交易在优化版和普通版上扣不同的钱。

7.9.1 计算量表(可校准)
原语 gas 依据
SHA-256 / 64 字节 1 锚
secp256k1 验签 400 参考机实测约 45--55 µs,约 350--450 个哈希
序列化 / 32 字节 1
内存 32 字节读写 1
树路径 256 层 256 每层一次节点哈希

这张表靠参考机标定,只随算法改动而改,不随行情改。下表是暂定标定值:实测后只改这张表的数字,不动公式,也不动操作的价格构成。

7.9.2 存储定价表(政策,不是测量)
项 gas 理由
已有叶更新 256 只付路径重算
新叶写入 +2,000 永久占用磁盘

两张表必须分开写。 混在一起,下一个人会问"为什么新叶比旧叶多两千倍的计算量"------它没有多,那是政策:写一个新叶和更新一个旧叶,计算量几乎一样(都是 256 次哈希),差别全在它永久占了一块地方。

7.9.3 操作的价格由模型算出,不按类型定额
操作 gas 组成
转账 1,450 验签 400 + 读 2 叶 512 + 写 2 叶 512 + 编码 26
报名 / 账单 / 回执 0(免费) 仍占块 gas,用于容量核算,不计费
合约写一个新存储槽 3,170 验签 400 + 账户 256 + 新叶 2,256 + 回写 256
双签举证 3,600 2 验签 800 + 查封 256 + 赔付 256 + 证据去重新叶 2,256
合约部署(1 KB 代码) 64,000 验签 400 + 新账户 2,256 + 代码 64,000(2,000 / 32 字节,与新叶同价)

比值 1 : 2 : 2.2 : 2.5 (转账 : 报名/账单 : 合约写槽 : 双签举证)。差这么小,是因为它们都由同样两件事构成:一次验签加一两个叶。真实成本结构里没有"操作类型"这一维,所以按类型定额从方法上就是错的。

7.9.4 系数
复制代码
手续费 = gas_used × 系数

系数只有一个,全链统一。暂定 69,000 个最小单位 / gas:

复制代码
转账 1,450 × 69,000 = 100,050,000 个最小单位 ≈ 1.0005 TRC

一次转账约 1 个 TRC。取这个起点不是为了赚手续费,是为了让金额有直觉:一笔 1 TRC,一百笔 100 TRC,账算得清。

7.9.5 系数谁调、怎么调

系数由创世地址签署调整指令,走正常的零额系统交易上链:

复制代码
GasPrice = { chain_id, new_coefficient, activation_height, genesis_sig }

四条约束,缺一条这套权限就会从"保险"变成"后门":

  1. 生效高度必须大于当前高度加冷却期(建议 100 个事件),让钱包与节点有时间换价;
  2. 上下界写死:不得低于 1,不得高于当前的 100 倍,越界即无效;
  3. 两次调整之间至少隔 1,000 个事件,防止高频调价把链变成事实上的拍卖场;
  4. 永久留痕:指令与生效高度进链,任何人可离线验证。

为什么偏偏这个参数可以调。 系数不是规则,是汇率:TRC 的对外价值会变,手续费必须跟着变,否则同一笔交易的实际成本会随时间漂移。把它放在 §8.1 的不可变清单之外,是刻意的例外------规则的稳定性与价格的灵活性是两件事。

7.9.6 暂定值的后果
  • 按 1,450 gas 一笔,30,000,000 的块能装 ≈20,000 笔,不是旧模型下的 1,428 笔。块容量、满块收入、年吞吐这些推算,都要按这个模型重算。
  • 一个满块的手续费 ≈ 30,000,000 × 69,000 = 2.07 × 10^12 个最小单位(约 20,700 TRC)。这个费率是高是低,取决于真实业务量,系数可调的意义正在这里。
  • 最低质押必须跟系数成比例 :目标值是 1,000 笔转账的手续费(当前 ≈1,000 TRC),并随系数自动缩放。押 10^4 个最小单位去接 1 TRC 的单,是量纲错了,不是参数偏了。

8 治理

8.1 不可变

chain_id、π 表、抽签算法、哈希与签名算法、瀑布顺序。写入创世块,变更即硬分叉。

唯一的例外是手续费系数:它是汇率,不是规则,随 TRC 的对外价值调整,由创世地址签令改(§7.9.5)。除此之外,这一节没有任何东西可以改。

8.2 唯一会自动变的参数

只有一条参数会自己动,触发条件完全链上可算,无需任何表决:

  1. 最低质押。 设 a_h 为最近 10⁴ 个块内普通转账的单笔平均金额(没有转账时取 0),G₀ 为最低质押的基准值------1,000 笔转账的手续费,随系数同步缩放。目标值 = max(G₀, 10·a_h),即覆盖典型单笔支付一个数量级以上。实际值按迟滞留动:目标值高于当前值 10% 才上调,低于 10% 才下调。理由是 §7.5 的残余风险------业务以小额度为主时额度不分层,押多不赚多,理性节点会把质押压到下限,安全预算随之变薄,而这条参数是唯一能不靠竞价、不靠表决把它撑住的杠杆。

这条按上面的阈值留了缓冲,避免在临界点上来回抖动。

8.3 其余变更

协议内不提供参数表决通道。任何非自动参数变更只能通过硬分叉。理由:表决通道一旦存在,就会成为新的权力中心,与"无多数裁决"的立身之本冲突。

8.4 暂停只有两种,都不是链级

单节点暂停。 守护者要退出或停机维护,自己签一份声明:

复制代码
PauseSelf = { chain_id, slot, reason, expect_blocks, sig }

自声明上链即生效:退出抽签、停止承接新背书、质押冻结;100 个事件后无未结清缺口则解冻(§4.10)。

签名者是它自己的密钥------所谓"需要验签",在这里就是自证身份,没有第三方授权。解冻以事件数计(高度差),不能用本地时间,否则各节点判断不一。

片区暂停。 分区时该片区的节点各自停手(§6.4)。它带签名,但不是投票:这是同一片区的节点分别声明"我这一侧停",不是多数通过后集体执行。

挂起是本地策略,链上不留事件。 因为要写事件就得先出块,出了块就不算暂停。恢复后由该片区补一条融合记录。

暂停有上限:1000 个事件,但只能由"对面"来数。 挂起不留链上事件(见上),所以计时不能靠被暂停的那一侧------它没有块,也就没有事件。规则是:该片区最后一次出块的高度之后,对侧每出一个块记一个事件;满 1000 个仍未融合,对侧在其块内打「暂停放弃」标记,全网可见。 没有上限的暂停,等于没有结束。

双侧同时挂起时,这条上限失效。 两侧都不出块,就没有事件可数,链处于静止,不存在"超时"这个量。此时只能由人介入(§6.4)。写清楚这一条,比假装协议能在静止中计时要好------一个没有时钟的系统,本来就不该声称自己能数清静止了多久。

本链没有链级暂停按钮。 一个能一键关停全网的设计,等于把整条链押在一把钥匙上。

两种暂停都不产生"维护块"。单节点暂停后链由别人继续,片区暂停后另一片区继续------不存在"全世界只剩我一个还得凑个块"的场景,所以 §4.2 的"无交易不出块"一个字都不用改。

8.5 升级:创世者签发,节点自行应用

升级指令是一条零额系统交易,由创世区块生成者签名:

复制代码
Upgrade = { chain_id, from_version, to_version, code_hash,
            activation_height, migration_script, rollback_hash,
            genesis_sig }

它搭正常区块上链,因此不产生空块、不破坏"无交易不出块"。三条约束:

  1. activation_height 必须大于当前高度加冷却期(建议 100 个事件);
  2. migration_script 必须是可重放的确定性脚本,不能是任意代码;
  3. 必须附带 rollback_hash。

节点在自己的暂停窗口 里应用:先发自暂停声明退出抽签,停机换版本,重启后重新报名。先离开,再换装,再回来。 若允许在线热切换,同一高度会出现两个版本的 state_root,那是双签之外最难查的一种分叉。

8.6 拒绝升级:协议不罚,现实来罚

节点可以拒绝。协议不做任何惩罚------它没有能力判断"拒绝"是恶意还是谨慎。

后果全在链外,但后果是真实的:

  1. 被抛弃:跑旧版本的节点 state_root 与新链不一致,无法同步、无法被抽中,实际退出网络;
  2. 司法后果:这类升级主要发生在处置分区作弊的场景,拒绝方可能被视为妨碍调查,承担法律责任;
  3. 商业后果:托管方、交易所、支付方会切断往来。

怎么识别"拒绝":不看节点自报的版本,看 state_root。 同一高度算出不同状态根,就是没升级------这是客观比对,节点无法谎报。

所以这不是"协议内的权力",而是协议留了一个钩子,现实把绳子拴上去。

写清楚这一点的意义:它承认了这套系统的真相------最后一道防线不是算法,是人。算法负责把作弊变成不划算,把分区变成可识别;当这两件事都失效时,能用的只剩法律。

8.7 三条约束与密钥分工

对权力的约束:

  1. 范围 :升级指令只能改代码与迁移状态,不能凭空转移资产。这一条不是链上检查,是委员会裁定------见下;
  2. 时限:冷却期后未生效即作废,不追溯;
  3. 留痕:所有声明与指令永久上链,可离线验证。

三条缺一条,这套权力就会从"保险"变成"后门"。

范围这一条靠人守,不靠代码守。 要让链上自动判定"这次迁移没碰余额",就得先有一套能读懂任意迁移脚本语义的机制------那等于在共识层再实现一遍形式化验证,成本高于收益,而且判定逻辑本身一旦有洞,洞就在最底层。所以这里刻意留一个口子:

由委员会裁定。 委员会认定越界,该指令即无效;节点可以拒绝跟随,链就此分叉。

裁定以委员会签名的声明发布,链外传播,不进共识------它不改变任何状态,只改变人跟不跟。分叉不是事故,是这套设计给人类组织留的出口。 技术有边界,人的组织没有;就像物理法则不是由技术决定的。只要升级碰不到余额,它最坏也只能让链停下,不能让人丢钱------但这条边界靠人守,不靠代码守。

为什么不是漏洞。 漏洞是"说好要做却没做到"。这里说好的是"留给人裁定",做到的也是"留给人裁定"。真正的风险不是这条规则,而是人不裁、或裁了没人跟------那是组织问题,写不进白皮书。

密钥分工:

密钥 用途 归属
创世密钥 签署升级指令 离线、分片、多人共管
节点密钥 出块、背书、自暂停声明 节点自身,加密落盘
委员会密钥 分区处置、升级范围的裁定、证据包的链外签署 硬件模块,多签;不能停链

委员会密钥不能停链,是因为"能一键关停全网"的能力,无论交给谁,都会成为比作弊更难防的风险。

9 参数表

参数 取值 依据
总量 1 × 10^9 TRC 十亿,千分位无尾数(§7.0);精度 10^-8,最小单位 10^17
增发 0 无出块奖励;收入全部来自手续费
初始质押占比 ≥ 30% 低于此安全预算不足(§7.0)
验证者规模 N 由部署决定 非协议常数;运行时从登记表读取(§6.3)
π 表 π 的前 10⁶ 位十进制小数 无作者、谁都能复算;内嵌只为省算力,哈希进创世(§4.1)
取位宽度 d 8 位 10^8 ≥ 10^3·N,拒绝期望 < 1.05
滞后 K 8 块 覆盖传播抖动,且使 S 与表根均落在已焊死区
报名窗口 W 10 刻度 容忍连续十次抖动;对应遍历概率 1.7×10^−5
补录追溯 W 刻度 防提议者漏收导致误判缺席
事件 / 刻度 1 个区块 = 1 个事件 = 1 个高度 计时的唯一单位;静止期不推进(§2.6)
顺延邻居 k 5 门槛 3 时容忍 2 个同时离线
顺延门槛 m 3 一人可独断、二人可偶然合谋,三人须真实联盟
最低质押 1,000 笔转账的手续费(当前 ≈1,000 TRC),随系数缩放,并随全网交易额自动调整 覆盖典型单笔支付一个数量级以上(§8.2)
敞口系数 α 0.9 留 10% 缓冲吸收结算抖动
手续费 100% 归背书者 见 §7.1;只有转账与合约执行付费,守护行为免费
分成 100% 归背书者 出块无报酬;不设保险池,赔付只从罚没出(§7.1)
欺诈罚没 100% 使命题 4 成立的最小值
观察期 30 刻度 约两类故障间隔的一个量级
解绑期 先挂暂停服务声明,100 个事件后生效 覆盖事后发现缺口的窗口(§4.10)
自交易上限 2/3 × 质押 自背书无第二双眼睛(§4.10)
单块上限 30,000,000 gas / 4096 笔 / 2 MB,三者同时生效 一次转账 1,450 gas,故 gas 是唯一瓶颈(≈20,689 笔);4096 笔与 2 MB 是结构与传播上限,正常转账触不到
负余额 不设上限,须在下一块内清偿 负余额 = 双花痕迹 = 背书者失职证据(§4.8)
多签背书 不支持 单签单责,责任边界不弯;超出即拆分(§7.8)
升级签发者 创世区块生成者 零额系统交易,搭正常区块上链(§8.5)
升级冷却期 100 个事件 给节点留出反应与准备时间(§8.5)
节点暂停 自签声明,100 个事件后解冻 先离场再换装,避免热切换分叉(§8.4、§4.10)
手续费系数 暂定 69,000 个最小单位 / gas(一次转账 ≈ 1.0005 TRC) 创世地址可调:冷却 100 事件、间隔 ≥1,000 事件、上下界 1--100 倍(§7.9.5)
地址派生 SHA256(压缩公钥)-20: 全链一把哈希(§3.9);代价是合约内不能用 ecrecover
签名规范化 secp256k1,65 字节,必须 low-s(s ≤ n/2) 否则同一签名有两种合法编码,签名索引不唯一(§3.9)

10 已知限制

五条限制无法用参数消除,留给部署、运营与社区,不留给实现:

  1. 小额市场里质押不赚多(§7.5)。额度分层只在大额单上起作用;业务以小额为主时押多不赚多,只能靠最低质押自动上调兜底,而阈值要实测。
  2. 分区两侧都出块时不自动合并。协议只挂起,合并与双花处置靠人(§6.4)。
  3. 顺延会误判"慢但活着"的节点。没有时钟就无法证伪"它只是慢",只能靠准入与声誉约束(§4.5)。
  4. 宣告故障押的是回执(§4.5)。回过执又宣告"没服务",即自相矛盾,三签罚没;没回执的宣告不算矛盾、不罚,但它拿不到那一块的状态,下一高度的账单做不出来,等于自动让位一次。想用假故障压块,三个身份得一起放弃下一轮。
  5. 冷启动没有协议内补贴。守护者早期收入只来自手续费,激活市场、把交易量拉起来是社区的责任------协议不承诺早期收益,也不为拉量而增发(§7.0)。

另有两处是刻意的取舍,不是遗留:大额支付不做多签、超出即拆分(§7.8);抽签偏置不设概率上界,靠成本结构压制,不靠对称博弈(§5.6)。


11 对外接口

11.1 三个面

面 用途 是否可写
浏览器 块、交易、账户、合约、守护者、事件 只读
检索 按数据 hash / 账户 / 签名反查 只读
运维 API 暂停、升级、恢复 写,须验签

11.2 索引不是真相

浏览器与检索都建立在索引库上,而索引库是派生数据:它必须能由全节点数据完整重建。

三条硬要求:构建脚本开源;关键字段可用 Merkle 证明回验;任何聚合数都能点进去看原始交易。缺任何一条,浏览器就从"窗口"变成"喉舌"。

证明从哪里拿:向全节点要,不要向索引器要。 索引器只提供"去哪个块、哪个位置找",前端拿到定位后向全节点索取 Merkle 路径并本地验证。若证明也由索引器给,名义上验了,实际还是信任它。

11.3 签名索引

按签名反查交易,把"谁签过什么"变成可检索的事实。取证价值极高:拿到一段签名,可直接定位到具体交易与背书者。

代价是存储------65 字节乘交易数,一亿笔约 6.5 GB 原始数据,索引再加一倍。必须预先规划冷热分层。

11.4 运维 API 的验签

自暂停声明由节点自签 ,只需验"是不是它本人";升级指令由创世者签发,节点应用前独立验签,验不过就拒绝应用并记录。

两者都要带:签名、理由文本、生效高度(升级还要带回滚版本)。

拒绝应用不算违规------但会与主网分叉,后果见 §8.5。


12 决策记录

以下二十六条已定案。实施以本节为准;正文已按本节修正。若仍发现出入,是正文漏改,应回改正文,不得另立一套。

形状(决定块格式与状态布局)

编号 决定 落点
A1 交易加 gas_limit / gas_price / data;块头加 gas_used;状态树加合约代码与合约存储两棵前缀;序列化七条冻结 §3.2、§3.3、§3.7、§3.8
A2 registry_root 取第 h−K 块头的显式字段,不回溯状态树 §4.1
A3 同高两块:带三邻居故障证明者优先,另一块作废不罚 §4.5
A4 补录只追加在未来块;缺席判定向前看 W 块,过去不改写 §3.5
A5 节点五态表 active / paused / probation / banned / unbonding §4.12
A6 每个守护者每高度交一份受理确认(账单),可为空;未交者下一高度不参与抽签;出块人账单覆盖不足 ⌈2N/3⌉ 即按次降权 §3.5.1
A7 同高两块:带三邻居证明者优先、不因迟到块翻转;回执与故障声明互斥,回过执再宣告即矛盾------三签罚没、顺延块不罚、罚没归举证人(Evidence::FalseFault) §4.5、§3.5.1、§3.6
A8 账单所列 txid 必须入块或记为 failed,否则该账单不计入 2/3 覆盖 §3.5.1

行为

编号 决定 落点
B1 入块校验时先扣费,扣不动即整笔无效;手续费永不产生负余额 §7.1
B2 合约执行失败不退手续费 §7.1
B3 片区暂停是纯本地策略,链上不留事件;恢复后补一条融合记录 §8.4
B4 合约账户余额不受任何质押担保,风险自担,须显著声明 §4.11
B5 债券当作一种余额记账,不可转让 §4.7
B6 同一证据只认链序第一份,其余作废不重复发奖 §4.6
B7 手续费只有 gas 一个来源,取消按金额的比例费;交易结构里没有手续费字段 §3.3、§7.1
B8 手续费 = gas × 系数;系数由创世地址签令调整(冷却 100、间隔 ≥1,000、上下界 1--100 倍),暂定 69,000,使一次转账 ≈1 TRC §7.9.4、§7.9.5
B9 余额不足的交易直接失败、不入账;失败的交易照样入块、扣 gas、消耗 nonce;负余额只在规则被击穿时出现,是回痕与回击依据 §4.2、§4.8、§7.1
B10 守护行为(报名、账单、回执、举证、自暂停、升级)不收手续费,只占块 gas;只有转账与合约执行付费 §3.5.1、§7.1、§7.9
B11 取消保险池:手续费 100% 归背书者;赔付只从罚没出------先质押、再全体分摊(单次 ≤5%)、余额转债券由后续罚没偿还 §4.7、§7.1、§8.2

常量与交付

编号 决定 落点
C1 π 表内嵌发行版,附 SHA-256 校验和,启动自检 §4.1
C2 Merkle 证明向全节点索取,索引器只提供定位 §11.2
C3 合约地址由 H(部署者 ‖ nonce) 派生,无治理分配 §4.11
C4 π 表取圆周率前 10⁶ 位小数,任何人可复算;内嵌 + 创世哈希校验,越界回卷 §4.1

运维

编号 决定 落点
D1 暂停上限 1000 个事件,由对侧计数;满额由对侧打「升级放弃」标记;双侧同时挂起时上限失效,交人 §8.4
D2 拒绝升级以 state_root 不一致为准,不看自报版本 §8.6
D3 升级指令的"不能碰余额"由委员会裁定、不进共识;裁定不成即硬分叉。这是刻意留给人组织的口子,不是链上检查 §8.7

规范主体与实施前置闭合。 余下三类不影响开工:实现细节(gas 表逐条 cost、索引库选型)、需实测才能定的数值(最低质押自动上调的阈值)、本质不可证伪的残余(顺延对"慢但活着"节点的误判)。

相关推荐
OxYGC21 小时前
[Web3] 基础第5篇: 共识算法与 P2P 通信协议
web3·区块链·以太坊·比特币
Bczheng16 天前
四十六.创建一笔交易(9)--第三个区块 添加tx到钱包
区块链
2301_776045237 天前
理解Layer 1区块链协议
区块链
幻智星科技7 天前
零知识证明三大核心特性解析
区块链·零知识证明
木西8 天前
AI 驱动的去中心化资产管理:QuantixAI 核心金库与智能风控架构解析
web3·智能合约·solidity
2301_776045238 天前
山寨币与比特币之间的关系
大数据·人工智能·区块链
JF_Ma9 天前
1000个量化策略第29例:经典红利低波策略
区块链
AlanAshley9 天前
实时湖仓与区块链:数据架构的信任革命
架构·区块链
m0_547486669 天前
《Web开发技术基础》全套PPT课件2026
web3·web开发