)
Bitcoin Core 钱包 RPC 变更解析getbalances 新增 nonmempool 余额字段PR #33671【免费下载链接】bitcoinBitcoin Core integration/staging tree项目地址: https://gitcode.com/GitHub_Trending/bi/bitcoin本文解析 Bitcoin Core 最近一次钱包 RPC 变更getbalances命令在mine对象下新增nonmempool字段。读完后你将理解该字段的准确语义何时出现、为何恒为负、为何是高估能在运维与排查场景中用它定位钱包资金看似消失的问题并从SpendType分类与GetBalance实现层面理解其底层计算链路。背景钱包余额中凭空消失的资金钱包通过getbalances报告余额时一个长期存在的困惑是钱包里的 UTXO 明明被钱包自己创建的交易花费了但那笔交易并没有进入内存池mempool——例如手续费率太低被拒、未确认祖先交易过多package 限制、或包含超大OP_RETURN输出而被节点策略拒绝。此时这些 UTXO 在trusted等字段中已被视为已花费而扣减但它们又不在 mempool 里无法出现在untrusted_pending等任何字段中结果是这些资金在getbalances的所有字段中无处可寻从钱包余额的角度看如同消失。变更的发布说明记录于 doc/release-notes-33671.mdgetbalancesnow includes anonmempoolfield undermine, reporting the net balance of wallet transactions that are not in the mempool (e.g. due to too low a feerate, too many unconfirmed ancestors, or a too-largeOP_RETURNoutput). This value is always negative, and is typically an over-estimate since it accounts for coins being spent but not for change outputs returning to the wallet (which are also outside the mempool). Without this field, funds involved in non-mempool transactions could appear to go missing from the wallet balance.也就是说本次变更的核心目标是给未入池钱包交易花费的资金一个可见的、可核算的落点让用户能验证trusted untrusted_pending immature nonmempool的勾稽关系而不是面对余额对不上却无从查起。getbalances 的完整返回结构变更后getbalances无参数返回的mine对象包含以下字段RPC 文档中RPCResult声明见 src/wallet/rpc/coins.cpp#L402-L455字段含义trusted可信余额钱包自己创建的输出或已确认输出untrusted_pending不可信待确认余额他人创建、当前在 mempool 中的输出immature未成熟 coinbase 输出的余额nonmempool本次新增被不在 mempool 中的交易花费的代币总额。通常是一个高估值因为只计算了被花费的币而未计算同样不在 mempool 中的找零返回以及互相冲突的花费used仅当设置了avoid_reuse钱包标志时存在发送到曾经被花过的地址的余额可能涉及隐私泄露除mine外返回值还带有last_processed_block等公共字段见AppendLastProcessedBlock。字段语义的 RPC 文档原文为nonmempool: sum of coins that are spent by transactions not in the the mempool (usually an over-estimate due to not accounting for change or spends that conflict with each other)三个关键性质恒为负或为零该字段统计的是支出方向的净余额因此非零时永远是负数。通常是高估计算时只扣减了被非入池交易花费的 UTXO而没有加回这些交易产生、且同样不在 mempool 中的找零输出如果多笔非入池交易互相冲突双花同一批 UTXO冲突的部分也会被重复计入。不改变其它字段trusted、untrusted_pending、immature的计算逻辑保持不变nonmempool是纯粹的增量视图。源码实现SpendType 四分类nonmempool的判定基础是钱包对每个 outpoint 花费状态的分类。在 src/wallet/wallet.h#L556-L562 中定义了四种花费类型enum class SpendType { UNSPENT, // 未花费 CONFIRMED, // 已被链上确认交易花费 MEMPOOL, // 已被 mempool 中的交易花费 NONMEMPOOL, // 已被一笔既未确认也不在 mempool的钱包交易花费 }; SpendType HowSpent(const COutPoint outpoint) const;HowSpent的实现在 src/wallet/wallet.cpp#L799-L819它遍历记录花费该 outpoint 的钱包交易mapTxSpends逐笔判断该交易是否isConfirmed()返回CONFIRMED、是否InMempool()标记MEMPOOL否则若该交易既未被放弃abandoned、未链上冲突、未 mempool 冲突则标记为NONMEMPOOL。这个排除已放弃/已冲突交易的细节很重要只有那些钱包认为还活着但就是进不了 mempool的交易其花费才计入nonmempool。余额计算GetBalance 的 new 路径getbalances的 handler 调用GetBalance并首次将include_nonmempool传为true见 src/wallet/rpc/coins.cpp#L437-L445const auto bal GetBalance(wallet, /*min_depth*/0, /*avoid_reuse*/true, /*include_nonmempool*/true); ... balances_mine.pushKV(nonmempool, ValueFromAmount(bal.m_mine_nonmempool));GetBalance的核心逻辑在 src/wallet/receive.cpp#L245-L295。对钱包持有的每个 outpoint用HowSpent(outpoint)分类。CONFIRMED与MEMPOOL直接跳过视为已花NONMEMPOOL时若调用方未要求包含 nonmempoolinclude_nonmempool false则同样跳过否则置nonmempool_spent true并fallthrough到UNSPENT分支——即该 UTXO 仍会先按其可信/未确认属性计入trusted或untrusted_pending等正向桶计入正向桶之后再执行ret.m_mine_nonmempool - credit_mine把同一笔金额从m_mine_nonmempool中扣掉。m_mine_nonmempool在Balance结构体中声明于 src/wallet/receive.h#L51注释为 Coins spent by wallet txs that are not in the mempool。这段实现恰好解释了发布说明中的两个性质恒为负代码中只有m_mine_nonmempool - credit_mine这一条写入路径没有任何操作高估被非入池交易产生的找零输出本身也是不在 mempool 的钱包交易输出但该代码路径没有为它们做回加find change → add back且多笔互相冲突的非入池交易会各自扣减同一批 UTXO。另一个值得注意的联动点在 src/interfaces/wallet.h#L369-L375 与 src/wallet/interfaces.cpp#L383钱包接口层供 GUI/bitcoin-wallet等消费者使用的Balances结构也同步新增了nonmempool_balance并在变更判断中参与比较——也就是说这次 RPC 变更同时打通到了非 RPC 的钱包接口。功能测试中的行为验证仓库中的功能测试套件对nonmempool有多处断言可以作为该字段行为的可验证依据test/functional/wallet_balance.py在正常场景下断言nonmempool为0.0验证没有非入池交易时该字段不产生噪声test/functional/wallet_abandonconflict.py在放弃冲突交易后验证untrusted_pending trusted nonmempool 新余额的勾稽关系test/functional/wallet_conflicts.py验证冲突交易场景下untrusted_pending -nonmempool的对应关系test/functional/wallet_send.py构造带超大OP_RETURN类数据输出的场景nonmempoolTrue用例断言发送后getbalances()[mine][nonmempool] 0——直接对应发布说明中too-largeOP_RETURNoutput这一动机test/functional/wallet_migration.py、test/functional/wallet_v3_txs.py、test/functional/wallet_orphanedreward.py在钱包迁移、新交易格式等流程中把nonmempool纳入mine字段的完整性断言。实战使用建议结合源码与测试可以给出以下排查范式对账当getbalances的trusted等字段对不上预期时先读mine.nonmempool。若其为负数说明有等值量级上的资金被卡在 mempool 之外的钱包交易里。归因从发布说明列举的三类原因入手——手续费率过低estimatesmartfee/-minrelaytxfee相关策略拒绝、未确认祖先过多、超大OP_RETURN。可用listtransactions找到未确认且未入池的交易再核对。修正对卡住的交易执行abandontransaction放弃或重新sendrawtransaction更高费率版本nonmempool应归零、资金回到trusted/untrusted_pending。注意源码中已放弃/已冲突的交易不计入NONMEMPOOL见HowSpent中的isAbandoned()、isBlockConflicted()、isMempoolConflicted()判断这与修正后字段归零的行为一致。解释偏差向用户展示该字段时务必说明它是高估的负值未计找零回退、未去重冲突交易不要把它当成精确金额。小结PR #33671 是一次小而精确的钱包 RPC 可见性改进getbalances的mine对象新增nonmempool字段把被非入池钱包交易花费、从而从余额各桶中蒸发的资金显式暴露出来。其语义由 src/wallet/wallet.cpp 中HowSpent的NONMEMPOOL分类排除已放弃/冲突交易与 src/wallet/receive.cpp 中GetBalance的先入正向桶、再负扣逻辑共同决定功能测试在 test/functional 的多个钱包测试中对其取值和勾稽关系做了系统断言。对依赖getbalances做余额监控、对账或 GUI 展示的下游工具而言升级后应把该字段纳入mine的字段解析并把它作为资金消失排查的第一检查项。【免费下载链接】bitcoinBitcoin Core integration/staging tree项目地址: https://gitcode.com/GitHub_Trending/bi/bitcoin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考