UTXO 集合统计从哪来:gettxoutsetinfo 快慢差异与 coinstatsindex 图 1
UTXO 集合统计从哪来:gettxoutsetinfo 快慢差异与 coinstatsindex · 图 1

一个回答“现在全网有多少未花费”的按钮

比特币没有“总账合计”这张表——全网余额是几十 GB 的未花费输出集合(UTXO 集合),要数清楚,要么逐块重放记账,要么翻记账数据库。gettxoutsetinfo 是比特币核心提供的官方接口,回答三件统计问题:未花费输出有多少笔、它们的聪值总和是多少、当前集合的承诺哈希是什么。链上供应分析里“交易所钱包数变化”“长期持有者余额”这类口径,很多都建立在周期性调用它做的快照差分上。

为什么同一句命令,有时几秒有时几十分钟

同一句 RPC 的耗时差异来自两条截然不同的执行路径。默认路径是把链状态数据库整个扫一遍,现场累加每一笔未花费输出——机器好坏、缓存大小(-dbcache)直接决定快慢,冷缓存下全扫可能需要很久。另一条路径依赖一个可选索引:用 -coinstatsindex 启动的节点会在处理每个区块时顺手维护一份累计统计,查询变成一次索引读取,耗时降到秒级,而且能按历史区块哈希或高度直接取任意时点的快照(可选参数 hash_or_height 仅在此索引可用时生效)。该索引自 22.0 版引入,默认关闭,代价是索引本身占用磁盘、并轻微拉长每个区块的处理时间。

三种哈希口径

gettxoutsetinfohash_type 参数可选三种算法:沿用历史序列化规则的 hash_serialized_3、抗长度扩展更强的 muhash,以及 none(只统计不算哈希)。跨节点比对数字前先对字段:不同版本的默认值有过调整(早期默认 muhash,后来默认回归序列化哈希),不同实现之间的序列化哈希定义也不保证一致。把接口返回的 muhash 与某个第三方网站宣称的“UTXO 集合哈希”直接划等号,是数据核对里的经典乌龙。

用它做分析的正确姿势

第一,同步完成前不要记录任何快照:未追平的节点给出的是一个“历史某刻”的世界,数字会误导整条分析链,先查同步状态再谈统计。第二,把哈希值当版本敏感的指纹而不是通用常数:它是取证与两节点一致性核对的工具,跨环境比较前确认版本与算法。第三,索引不是必需品:偶尔查询直接用默认路径即可,只有做高频快照的分析型节点才值得为 coinstatsindex 付出磁盘与首建时间。最后提醒口径常识:该统计是“未花费输出的面值总和”,不含尚未成熟的矿块奖励、不计入任何链下余额,任何把它与“流通供应量”划等号的表述都丢了一个机制细节。本文为链上数据方法说明,不构成投资建议。

索引的启用代价与不可逆之处

-coinstatsindex 是启动参数,意味着改动它往往伴随一次重启与一段较长的索引构建期:它需要从头把历史区块逐个套用一遍累计统计,节点状态栏里会单独出现这个索引的合成进度。它与 txindex、blockfilterindex 一样属于可选索引,共享同一个前提——不能与修剪模式共存,因为统计要能追溯到任意历史高度,而修剪后的节点已经丢掉了旧区块数据。想验证索引是否真的在干活,看 gettxoutsetinfo 的响应时间最有说服力:索引就位时同一句查询应从“数十秒起步”掉到秒级,配合 use_index 参数还能现场对比两条路径算出的数字是否一致,这是自检配置是否生效最省事的办法。数字对不上通常是版本或算法差异,而不是索引坏了。

三个容易踩坑的统计口径

第一,别把不同版本的哈希值当同一指标比较:hash_serialized 系列算法在版本演进中调整过序列化细节,muhash 也曾在不同版本里担任过不同默认值,跨来源做“月度快照连续性检查”时,先固定来源再谈趋势。第二,注意未成熟币base 输出:挖矿奖励输出要等一百个区块才能花,这段窗口里的输出在集合里的存在方式会影响“某一时点总额”的读法,做供应类叙述时应说明用的是哪种口径。第三,索引给的是账本快照,不是经济体量:交易所余额、长期持有者规模这类分析结论都建立在“给输出贴地址标签”这一步上,而这一步属于第三方启发式,与 RPC 返回的数字无关。数字与结论之间隔着一整层方法论,任何跳过这层的引用都要多问一句来源。