Merge bitcoin/bitcoin#33671: wallet: Add separate balance info for non-mempool wallet txs

32325d1777 tests: Add test for mempool-invalid wallet tx (Anthony Towns)
25e063d950 wallet: Add separate balance info for non-mempool wallet txs (Anthony Towns)
81e763f1e5 wallet: Have GetBalance report used amount directly without two calls (Anthony Towns)

Pull request description:

  Changes `getbalances` to report the sum of txos spent by transactions that aren't confirmed nor in the mempool (eg due to being part of too long a mempool chain, or spending non-standard outputs, or having a datacarrier output that exceeds `-datacarriersize`, etc). Those values are added to the trusted/untrusted_pending/immature/used fields as appropriate (where previously they were skipped), and subtracted from the new nonmempool field, so that the sum of all fields remains the same.

  For example:

  ```
  $ bitcoin-cli -regtest getbalances
  {
    "mine": {
      "trusted": 6049.99999220,
      "untrusted_pending": 0.00000000,
      "immature": 3200.00000780,
      "nonmempool": -100.00000000
    },
    "lastprocessedblock": {
      "hash": "3ab4582226d5e8ad76438db48d76e822c31bce2cdbc7ba82a5d974a277515d0d",
      "height": 221
    }
  }
  ```

  Closes #11887

ACKs for top commit:
  achow101:
    ACK 32325d1777
  w0xlt:
    lgtm ACK 32325d1777
  musaHaruna:
    Code Review ACK [32325d1](32325d1777)

Tree-SHA512: 142581944d1b3213067e219e3b8205f27b89007e545149c01b801bad38fe730c5b2bfdfe6a2064c3649889f66ec48ec7616982564d00e3d83837249e925d8f16
This commit is contained in:
Ava Chow
2026-04-22 16:19:55 -07:00
14 changed files with 121 additions and 46 deletions

View File

@@ -32,8 +32,8 @@ class WalletSendTest(BitcoinTestFramework):
self.noban_tx_relay = True
self.supports_cli = False
self.extra_args = [
["-walletrbf=1"],
["-walletrbf=1"]
["-walletrbf=1", "-datacarriersize=16"],
["-walletrbf=1", "-datacarriersize=16"]
]
getcontext().prec = 8 # Satoshi precision for Decimal
@@ -45,7 +45,7 @@ class WalletSendTest(BitcoinTestFramework):
conf_target=None, estimate_mode=None, fee_rate=None, add_to_wallet=None, psbt=None,
inputs=None, add_inputs=None, include_unsafe=None, change_address=None, change_position=None, change_type=None,
locktime=None, lock_unspents=None, replaceable=None, subtract_fee_from_outputs=None,
expect_error=None, solving_data=None, minconf=None):
expect_error=None, solving_data=None, minconf=None, nonmempool=False):
assert_not_equal((amount is None), (data is None))
from_balance_before = from_wallet.getbalances()["mine"]["trusted"]
@@ -171,16 +171,20 @@ class WalletSendTest(BitcoinTestFramework):
tx = from_wallet.gettransaction(res["txid"])
assert tx
assert_equal(tx["bip125-replaceable"], "yes" if replaceable else "no")
# Ensure transaction exists in the mempool:
tx = from_wallet.getrawtransaction(res["txid"], True)
assert tx
if amount:
if subtract_fee_from_outputs:
assert_equal(from_balance_before - from_balance, amount)
else:
assert_greater_than(from_balance_before - from_balance, amount)
if nonmempool:
assert_raises_rpc_error(-5, "No such mempool transaction", from_wallet.getrawtransaction, res["txid"])
assert from_wallet.getbalances()["mine"]["nonmempool"] < 0
else:
assert next((out for out in tx["vout"] if out["scriptPubKey"]["asm"] == "OP_RETURN 35"), None)
# Ensure transaction exists in the mempool:
tx = from_wallet.getrawtransaction(res["txid"], True)
assert tx
if amount:
if subtract_fee_from_outputs:
assert_equal(from_balance_before - from_balance, amount)
else:
assert_greater_than(from_balance_before - from_balance, amount)
else:
assert next((out for out in tx["vout"] if out["scriptPubKey"]["asm"] == "OP_RETURN 35"), None)
else:
assert_equal(from_balance_before, from_balance)
@@ -280,6 +284,9 @@ class WalletSendTest(BitcoinTestFramework):
res = w2.walletprocesspsbt(res["psbt"])
assert res["complete"]
self.log.info("Create mempool-invalid tx (due to large OP_RETURN)...")
self.test_send(from_wallet=w0, data=b"The quick brown fox jumps over the lazy dog".hex(), nonmempool=True)
self.log.info("Test setting explicit fee rate")
res1 = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, arg_fee_rate="1", add_to_wallet=False)
res2 = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, fee_rate="1", add_to_wallet=False)