这枚 UTXO 被谁动了:gettxspendingprevout 与它背后的专用索引 图 1
这枚 UTXO 被谁动了:gettxspendingprevout 与它背后的专用索引 · 图 1

钱包对账时有一类问题很别扭:你手里有一批 txid + vout 的输出清单,想知道”最近有没有哪笔在途交易想花掉它们”——比如怀疑某个地址被人从另一台设备双花,或者想确认某笔替换交易的输入到底撞了谁。UTXO 集合本身回答不了这个问题:它只记录”还没被花”,不记录”谁正在试图花”。v24.0 起的 gettxspendingprevout 专门补这个方向。

基本用法:批量问输入归属

参数是一个数组,每个元素形如 {"txid": "...", "vout": 3},一次可以塞很多个;传空数组会直接报 Invalid parameter, outputs are missing。返回是逐条对应的数组:

  • txid、vout:回显你问的那个输出。
  • spendingtxid:内存池里有交易正在花它时给出的花费交易 ID;没人花就整个字段省略。
  • spendingtx:只有开了 return_spending_tx 选项才出现,直接给花费交易的完整十六进制。
  • blockhash:花费交易已确认时给出的区块哈希(需要索引,见下文)。

注意它的语义:这不是”这个输出还剩不剩”的查询——那是 gettxout 和 UTXO 扫描的活——而是”有没有冲突花费在途或已发生”。两者配起来用才完整。

v31.0 的两个选项

老版本的实现只扫内存池。v31.0 给这个 RPC 加了两个命名参数:

  • mempool_only:只查内存池。默认值很有意思:没开 txospenderindex 时默认 true,开了索引则默认 false。
  • return_spending_tx:返回花费交易的完整原文,省一次按 txid 再取的往返。

配套的 -txospenderindex

v31.0 同时新增 -txospenderindex 启动选项(默认关)。它的实现是一个写进 LevelDB 的映射:对每个区块里每笔交易的每个输入,记录”被花的 outpoint 指向哪笔花费交易、在哪个块”。于是当内存池里查不到花费者时,gettxspendingprevout 会转去问这个索引,把历史确认的花费也翻出来——此时返回里才会带上 blockhash,配合 return_spending_tx 还能直接取回那笔早已确认的花费交易原文。

代价也明确:

  • 默认关闭,要显式开;
  • 与修剪模式互斥,开了 -prune 再开它会以 Prune mode is incompatible with -txospenderindex. 拒绝启动;
  • 和所有可选索引一样从头回放,追平进度可以用 getindexinfo 里的 txospenderindex 条目看。

两个易混淆的邻居

gettxout 查的是”当前这个输出在不在 UTXO 集合”,未确认花费对它没有影响;scantxoutset 按脚本扫全集合,回答”现在有多少这类输出”。只有 gettxspendingprevout 站在花费方向反查。做双花监控的常见组合是:scantxoutset 或钱包自维护的清单给出目标集合,gettxspendingprevout 盯在途冲突,spendingtx 拿回来后再解码看费率——确认前的一切都可能被替换,日志里最好把每次快照都留下来。

用脚本搭一个双花盯梢器

把零件组装成典型形态:钱包侧定期用 listunspent 导出自己的 UTXO 清单,分批打包进 gettxspendingprevout 的 outputs 数组;某条返回出现 spendingtxid 就说明有人在抢花,立刻用返回的 spendingtx(记得带 return_spending_tx 选项)取原文解码,看费率和脚本模式,区分是自家设备重发还是外人扫地址。没出现冲突也要把时间戳落盘——确认之前,任何一次没查到都不构成永远安全,下一轮轮询才是新证据。

工程细节三条:输出数组别一口气塞几千条,按账户分批,响应体积和节点耗时都更可控;vout 传负数会被直接拒绝,报 Invalid parameter, vout cannot be negative;把每轮结果写成表格做差分,比人眼盯 JSON 可靠。这套主动拉冲突的结构,正是 v0.20 之后 P2P 层沉默时代的对位补件。

索引之外的两条纪律

一是把索引当辅助而不是事实源:权威永远是链上 UTXO 集合与内存池本身,txospenderindex 只是把反查做成常数时间的加速读法。它坏了、歪了,关掉选项重启重建即可,共识数据一根毫毛都不会少。二是查询节奏:轮询间隔要显著大于出块节奏(全网平均约十分钟一个块),秒级打满不会带来新信息,只会给你的节点添堵。把每轮结果做差分、只在变化出现时告警,比每轮都全量比对省心得多。

风险提示:涉及在途交易的核对与处置只涉及技术判断,不构成买卖或投资建议;开启索引会显著增加磁盘占用,请在节点容量规划中计入。