比特币 v31 把内存池的限额单位从”链”换成了”簇”。跟着一起换掉的还有一个新的拒绝代号:too-large-cluster。它在源码里出现在四个位置,返回的类别却不只一种,弄清这个差别,比记住默认值更能省时间。
先对一下参数账
v31.0 的启动参数帮助文本里,老的祖先条数限制与后代条数限制都被明确标注为已弃用:它们被簇限制取代,现在只有钱包在做选币时还会用到。同时新增了两个调试类参数,一个限制簇内交易条数,一个限制簇内虚拟体积合算出的千字节数。簇条数的默认值是六十四,且源码里给它设了一个硬上限,同样也是六十四——也就是说这个参数只能往小调,往大调会被钳回。
另外两个老参数如果还在配置文件里,节点启动会直接给一条警告,说祖先体积限制与后代体积限制已经被簇体积限制取代,所填的这两项不起作用。这是排查”改了参数怎么没反应”时最容易撞上的一条:参数名写的是老名字,改动其实没有生效。
簇的口径和祖先链不一样。它算的是内存池里通过父子关系直接或间接连通的一整团未确认交易,包含链的两侧。同一条资金链上,往上追加子交易和往下补父交易都会让簇变大,这在旧口径下是分开计数的。
四处触发的区别在返回类别
源码里能看到四处返回这个代号,它们都叫 too-large-cluster,但挂在两种结果类别上。
- 单交易准入路径上的一处:交易已经过了费用与冲突处理,节点把要被替换掉的交易登记进变更集之后,再对变更集做一次簇体积校验。这里返回的是交易级策略结果
TX_MEMPOOL_POLICY。走这条路的常见情形是带替换的交易:因为替换会先删掉一批在池交易再收新的,删完之后的簇形态才是要检查的对象。 - 另一处同样返回
TX_MEMPOOL_POLICY,位置在逐笔处理结果收敛的地方,返回的是一个失败结果,附带这笔交易自己的状态对象。 - 还有两处返回的是包级结果
PCKG_POLICY:一处出现在包内替换的费用判定之后,另一处出现在整包准入流程末尾,返回的是整包失败并带上每笔交易的逐笔结果。
这个类别差异有实际后果。包级失败意味着调用方拿到的是”这一包不行”,需要按包重排——比如把过大的簇拆开分批提交;交易级失败则意味着是其中某一笔被拒,包本身还有救。日志里同样一行代号,处理方式完全不同。
为什么检查点要放在替换之后
一个直觉的问题是:为什么不早点检查簇尺寸,非等交易处理完再回头量一次。
原因和变更集的构造方式有关。v31 的准入流程用一套”变更集”来记录这次操作会往内存池里加什么、删什么,替换掉的交易也是先登记再统一校验。簇尺寸是对最终形态的判断,只有把该删的删掉、该加的加上,量出来的数字才是真实的。提前量会出现假阳性:原本超限的簇,可能因为这笔交易会顺手替换掉几笔而变得合规。
代价是检查被推到了流水线后段,前面的脚本验证、费用比较都白做了。这也是为什么在替换频繁的小额支付通道场景里,能看到一批交易反复在同一处碰壁。
运维上怎么应对
先确认你的客户端到底在按哪个口径算。老参数写簇限制的位置、或者写了已经失效的祖先体积参数,都属于配置没生效但看起来生效了的状态,启动日志里那条警告是唯一线索。
其次,遇到 too-large-cluster 时不要一味提高手续费,簇尺寸与费率无关。可行的动作只有三种:拆小包分批提交;把已经堆在池里的那一簇先让出去(等它被打包或者主动替换掉);以及在自己的部署里把簇条数上限往小调,让节点更早拒绝,避免下游客户端在临界值附近反复试探。
第三,簇条数上限往大调是调不动的,因为源码里的默认值就等于硬上限。想放宽只能改代码重新编译,配置文件做不到。
第四,如果这个代号出现在你自己的批量提交脚本里,值得顺手检查脚本是否在同时做替换。带替换的批量提交是簇超限最容易成形的场景:一次替换登记的删除项与新增项会同时改变簇形态,任何一侧估错都会撞上这一条。
风险提示:本文依据比特币核心 v31.0 源码与帮助文本撰写,参数名与默认值可能随版本调整;涉及费用与交易处理,请以实际节点行为为准,本文不构成任何投资建议。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。