区块能装多大不是节点说了算:CometBFT 链上参数 ConsensusParams 拆解 图 1
区块能装多大不是节点说了算:CometBFT 链上参数 ConsensusParams 拆解 · 图 1

Cosmos 系链的区块不是”能装多大就装多大”,也不是由客户端二进制里的常量拍板。共识层维护一组叫 ConsensusParams 的链上参数,区块体积上限、燃气上限、证据有效期、验证者公钥类型全在里面,改这些参数不需要换软件、不需要硬分叉。本文按 CometBFT 规范文档拆解这组参数的结构、边界与生效方式。

参数分几袋,各管什么

规范里 ConsensusParams 目前分五个部分:block 管区块大小与燃气;evidence 管作弊证据的有效性判定;validator 管验证者能用哪类公钥;version 记录 ABCI 应用版本;synchrony 管区块时间戳的有效性。较老版本中挂在 abci 袋子里的投票扩展开关,从 v1.0 起被挪进了 feature 参数袋,这种挪动本身就是读旧文档时要警惕的兼容性坑。

block 袋子只有两个字段。max_bytes 限制单个区块的字节数,取值必须不小于 -1,且不得超过一个写死在代码里的 100MB 硬上限;填 -1 就等于放开到硬上限。max_gas 限制区块内交易的申请燃气总量,同样允许 -1 表示不设限。这里有个容易误读的细节:规范明说 CometBFT 并不强制区块内申请燃气不超过 max_gas,若某个区块违规,可能是拜占庭提议者塞的,处理责任落在应用侧——应用在执行区块时要自己决定怎么办。

图:链上参数袋——区块体积、燃气与证据有效期参数的分层示意

证据参数为什么和退出期绑在一起

evidence 袋子要求证据不能太旧:max_age_num_blocks 和 max_age_duration 给出双重时效,规范建议时间维度对应应用的解绑期一类机制,目的指向无利害关系攻击——验证者被罚出并退出质押很久之后,它的旧双签证据如果还能生效,惩罚就落不到任何余额上了。规范甚至给出了换算式:块数上限等于时长上限除以平均出块时间。max_bytes 则限制单块能携带的证据体积,防止有人用海量证据挤占区块。

谁来改、何时生效

这组参数不是治理投票直接改写数据库字段,而是随区块流转:应用在处理每个区块时可以返回参数变更建议,共识层收下后在后续高度用”当前参数加变更”的方式滚动更新,新值从约定的高度起生效。这意味着同一份参数在任意历史高度都有一个确定的快照,轻客户端与全节点核对的是同一份数字。version 袋子里的应用版本号也是共识参数的一部分,应用升级换实现时,它是最直观的”链承认哪套逻辑”的标记。

时间戳规则也搬过家

老 Cosmos SDK 时代的读者会记得一个叫 time_iota 的固定最小出块间隔参数,它曾挂在区块袋子里。现行规范里这一袋换成了 synchrony:不再规定”块与块之间至少隔多少”,而是约束区块时间戳的提议与投票两阶段各自允许的漂移上限,把时间合法性从本地时钟假设转向可验证的协议规则。同理,投票扩展的启用高度原先放在 abci 参数袋,v1.0 起归入 feature 袋。这类字段迁移提醒我们:读参数快照时要连同客户端版本一起读,同一个字段名在不同版本规范里的语义并不保证相同。validator 袋子里的公钥类型清单也有一处细节,它采用 ABCI 公钥命名而非钱包生态常用的 Amino 命名,跨工具核对时两边对不上并不罕见。

读参数、改参数的正确姿势

普通用户其实很少直接碰这些数字,但它们解释了不少现象:为什么有的 Cosmos 链区块长期贴着上限跑,为什么拥堵时更大的区块要等参数调整落地,为什么换一种签名算法需要改 validator 参数而不是热修复。排查这类问题时,从区块浏览器或节点 RPC 读当前 ConsensusParams,与链的治理提案记录对时间线,比翻客户端配置更可靠——参数在链上,配置只是节点本地视图。体积参数还连着网络层:区块越大,共识消息传播越慢,超时预算越紧,这也是体积调整往往小步慢走而不是一次放开的原因之一。