{
 "number": 35151,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/35151",
 "title": "wallet, follow-up: Refactor IsSpent to use HowSpent",
 "author": "musaHaruna",
 "author_association": "CONTRIBUTOR",
 "created_at": "2026-04-24T12:53:10Z",
 "updated_at": "2026-09-17T02:35:00Z",
 "age_days": 146,
 "draft": false,
 "labels": [],
 "milestone": null,
 "base": "master",
 "head_sha": "ac774b318440c7cc4804516b1f811005e25e8d45",
 "head_ref": "wallet-use-howspent-for-isspent",
 "head_repo": "musaHaruna/bitcoin",
 "head_history": [
  {
   "t": "2026-04-24T13:01:08Z",
   "sha": "ba4f82874e72eb26bc6a0d857fddc9d8c9d7c146"
  },
  {
   "t": "2026-04-24T15:05:29Z",
   "sha": "8722fad4619ccfd3e3bd5036725ac2176dafadc4"
  },
  {
   "t": "2026-04-24T15:55:55Z",
   "sha": "ccb9caff215cead7125b852e1233bdd60cc9e3e9"
  },
  {
   "t": "2026-04-25T09:03:01Z",
   "sha": "e24b33364c5f2336b5491fa2164b40cc59e032bf"
  },
  {
   "t": "2026-04-25T09:03:52Z",
   "sha": "97753185199163037effe7056ea09d968301bcaa"
  },
  {
   "t": "2026-04-30T15:40:11Z",
   "sha": "775964ef02e8e8c85ea2caf01b76e41a454212f6"
  },
  {
   "t": "2026-05-05T08:35:21Z",
   "sha": "ac774b318440c7cc4804516b1f811005e25e8d45"
  }
 ],
 "additions": 8,
 "deletions": 24,
 "changed_files": 2,
 "commit_count": 1,
 "size_bucket": "S",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "ack": [
     {
      "login": "polespinasa",
      "url": "https://github.com/bitcoin/bitcoin/pull/35151#pullrequestreview-4904988743"
     }
    ],
    "concept_nack": [
     {
      "login": "luke-jr",
      "url": "https://github.com/bitcoin/bitcoin/pull/35151#issuecomment-4320329483"
     }
    ]
   },
   "conflicts": [
    {
     "number": 35716,
     "title": "wallet: Replace mapWallet and wtxOrdered with a boost::multi_index",
     "author": "achow101"
    },
    {
     "number": 27865,
     "title": "wallet: Track no-longer-spendable TXOs separately",
     "author": "achow101"
    }
   ]
  }
 },
 "acks_parsed": {
  "polespinasa": {
   "kind": "ack",
   "hash": "ac774b318440c7cc4804516b1f811005e25e8d45",
   "t": "2026-08-11T09:59:35Z",
   "stale": false
  },
  "luke-jr": {
   "kind": "concept_nack",
   "hash": null,
   "t": "2026-04-25T18:54:51Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 1,
  "stale_ack": 0,
  "concept_ack": 0,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 1,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "luke-jr",
   "polespinasa"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-05-05T09:37:37Z",
  "last_reviewer_activity": "2026-08-11T09:59:35Z",
  "last_reviewer": "polespinasa",
  "author_silent_days": 135,
  "waiting_on_author_days": 37,
  "days_since_update": 0
 },
 "refs": {
  "mentioned": [
   33671
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 33671,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-04-22",
    "title": "wallet: Add separate balance info for non-mempool wallet txs"
   }
  ],
  "conflicts": [
   35716,
   27865
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "src/wallet/wallet.cpp",
  "src/wallet/wallet.h"
 ],
 "body": "Follow-up to [#33671](https://github.com/bitcoin/bitcoin/pull/33671#discussion_r2920222467)\n\nThis PR refactors `CWallet::IsSpent` to reuse the logic already implemented in `CWallet::HowSpent`.\n\nInstead of manually iterating over mapTxSpends and checking transaction states, IsSpent now simply returns:\n\n`return HowSpent(outpoint) != SpendType::UNSPENT;`\n\nAlso move `CWallet::IsSpent` from wallet.cpp to wallet.h as a small inline helper, since it is a one-line wrapper around HowSpent.",
 "commits": [
  {
   "sha": "ac774b318440c7cc4804516b1f811005e25e8d45",
   "date": "2026-05-05T08:26:32Z",
   "message": "wallet: Refactor IsSpent to use HowSpent\n\nSimplify CWallet::IsSpent by delegating to CWallet::HowSpent.\n\nPreviously, IsSpent manually iterated over mapTxSpends and applied\nlogic to determine whether an output was spent. This logic is now\ncentralized in HowSpent, which classifies spends into CONFIRMED,\nMEMPOOL, NONMEMPOOL, or UNSPENT.\n\nIntroduce an optional `isSpent` flag to HowSpent to allow early\nexit when only checking whether an outpoint is spent.\n\nMove CWallet::IsSpent from wallet.cpp to wallet.h as a small inline helper,\nsince it is a one-line wrapper around HowSpent.\n\nCo-authored-by: w0xlt <94266259+w0xlt@users.noreply.github.com>"
  }
 ],
 "timeline": [
  {
   "t": "2026-04-24T13:01:08Z",
   "kind": "force_push",
   "who": "musaHaruna",
   "commit": "ba4f82874e72eb26bc6a0d857fddc9d8c9d7c146"
  },
  {
   "t": "2026-04-24T13:46:16Z",
   "kind": "review_comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "path": "src/wallet/wallet.cpp",
   "commit": "ba4f82874e72eb26bc6a0d857fddc9d8c9d7c146",
   "in_reply_to": null,
   "text": "Given that it is a one-line function I think is fine to remove it from wallet.cpp and add the logic in wallet.h"
  },
  {
   "t": "2026-04-24T13:50:02Z",
   "kind": "review",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "ba4f82874e72eb26bc6a0d857fddc9d8c9d7c146",
   "text": "concept ACK\n\nThe refactor is nice and clean.\n\nI think it is worth adding in the commit message that this refactor has a super super small performance downgrade, but we can take it as it is negligible. Now we don't early exit if we found any condition that tells us that a coin is spent."
  },
  {
   "t": "2026-04-24T13:57:56Z",
   "kind": "review_comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "path": "src/wallet/wallet.cpp",
   "commit": "ba4f82874e72eb26bc6a0d857fddc9d8c9d7c146",
   "in_reply_to": null,
   "text": "I don't think the changes inside HowSpent are necessary. It can distract from what is really being changed."
  },
  {
   "t": "2026-04-24T14:00:06Z",
   "kind": "review_comment",
   "who": "musaHaruna",
   "assoc": "CONTRIBUTOR",
   "path": "src/wallet/wallet.cpp",
   "commit": "ba4f82874e72eb26bc6a0d857fddc9d8c9d7c146",
   "in_reply_to": 3138169932,
   "text": "What if I move the change to a separate commit and update everything appropriately?\nWould that work?"
  },
  {
   "t": "2026-04-24T14:04:24Z",
   "kind": "review_comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "path": "src/wallet/wallet.cpp",
   "commit": "ba4f82874e72eb26bc6a0d857fddc9d8c9d7c146",
   "in_reply_to": 3138169932,
   "text": "It's just the changes are not necessary for the PR. To simplify `IsSpent()` you don't need to touch `HowSpent()`.\n\nI don't agree with them anyway. I am not a super fan of using `auto` it makes code less readable as you don't know what you are using. But that's a personal opinion."
  },
  {
   "t": "2026-04-24T14:08:40Z",
   "kind": "review_comment",
   "who": "musaHaruna",
   "assoc": "CONTRIBUTOR",
   "path": "src/wallet/wallet.cpp",
   "commit": "ba4f82874e72eb26bc6a0d857fddc9d8c9d7c146",
   "in_reply_to": 3138169932,
   "text": "Yeah. Also not a big fan of using `auto`.\nI will address all the suggestion in the next push.\nThank you for the review."
  },
  {
   "t": "2026-04-24T15:05:29Z",
   "kind": "force_push",
   "who": "musaHaruna",
   "commit": "8722fad4619ccfd3e3bd5036725ac2176dafadc4"
  },
  {
   "t": "2026-04-24T15:09:54Z",
   "kind": "comment",
   "who": "musaHaruna",
   "assoc": "CONTRIBUTOR",
   "text": "Force pushed [8722fad](https://github.com/bitcoin/bitcoin/pull/35151/commits/8722fad4619ccfd3e3bd5036725ac2176dafadc4)\n[quoted text omitted]\n\nUpdated the commit message as suggested.\n\n[quoted text omitted]\nMove `CWallet::IsSpent` from wallet.cpp to wallet.h"
  },
  {
   "t": "2026-04-24T15:42:48Z",
   "kind": "review_comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "path": "src/wallet/wallet.h",
   "commit": "8722fad4619ccfd3e3bd5036725ac2176dafadc4",
   "in_reply_to": null,
   "text": "There's an extra space here, that breaks the lint.\nI think you can do a one line to occupy less space, similar to `SteadyClock::duration ScanningDuration()`:\n\n```c++\n    /** Outpoint is spent if any non-conflicted transaction spends it */\n    bool IsSpent(const COutPoint& outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { return HowSpent(outpoint) != SpendType::UNSPENT; }\n```"
  },
  {
   "t": "2026-04-24T15:55:55Z",
   "kind": "force_push",
   "who": "musaHaruna",
   "commit": "ccb9caff215cead7125b852e1233bdd60cc9e3e9"
  },
  {
   "t": "2026-04-25T09:03:01Z",
   "kind": "force_push",
   "who": "musaHaruna",
   "commit": "e24b33364c5f2336b5491fa2164b40cc59e032bf"
  },
  {
   "t": "2026-04-25T09:03:52Z",
   "kind": "force_push",
   "who": "musaHaruna",
   "commit": "97753185199163037effe7056ea09d968301bcaa"
  },
  {
   "t": "2026-04-25T10:00:21Z",
   "kind": "review_comment",
   "who": "musaHaruna",
   "assoc": "CONTRIBUTOR",
   "path": "src/wallet/wallet.h",
   "commit": "8722fad4619ccfd3e3bd5036725ac2176dafadc4",
   "in_reply_to": 3138775000,
   "text": "Fixed. Thank you!"
  },
  {
   "t": "2026-04-25T18:54:51Z",
   "kind": "comment",
   "who": "luke-jr",
   "assoc": "CONTRIBUTOR",
   "text": "Concept NACK. You've made it much less efficient. Not only does it perform more checks, it also doesn't exit the loop early."
  },
  {
   "t": "2026-04-27T09:45:52Z",
   "kind": "comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nI don't think the extra checks is a performance decrease. If I am not mistaken `isConfirmed()` and `InMempool()` only read a value already loaded in `CWalletTx`.\n\n[quoted text omitted]\nI am not sure how bad it would be to ignore the early exit. But anyway it's easily solvable by adding a bool arg saying if we are checking for the exact `HowSpent` or only if `IsSpent`.\n\n```c++\n    SpendType HowSpent(const COutPoint& outpoint, const bool isSpent = false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);\n\n    /** Outpoint is spent if any non-conflicted transaction spends it */\n    bool IsSpent(const COutPoint& outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { return HowSpent(outpoint, /*isSpent=*/true) != SpendType::UNSPENT; }\n```\n\n```c++\nCWallet::SpendType CWallet::HowSpent(const COutPoint& outpoint, bool isSpent) const\n{\n    SpendType st{SpendType::UNSPENT};\n\n    std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;\n    range = mapTxSpends.equal_range(outpoint);\n\n    for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {\n        const Txid& txid = it->second;\n        const auto mit = mapWallet.find(txid);\n        if (mit != mapWallet.end()) {\n            const auto& wtx = mit->second;\n            if (wtx.isConfirmed()) return SpendType::CONFIRMED;\n            if (wtx.InMempool()) {\n                st = SpendType::MEMPOOL;\n            } else if (!wtx.isAbandoned() && !wtx.isBlockConflicted() && !wtx.isMempoolConflicted()) {\n                if (st == SpendType::UNSPENT) st = SpendType::NONMEMPOOL;\n            }\n            // If we are only checking for spent condition and not how the coin is spent\n            // early exit as fast as we know if it is spent.\n            if (isSpent && st != SpendType::UNSPENT) return st;\n        }\n    }\n    return st;\n}\n```"
  },
  {
   "t": "2026-04-30T15:40:11Z",
   "kind": "force_push",
   "who": "musaHaruna",
   "commit": "775964ef02e8e8c85ea2caf01b76e41a454212f6"
  },
  {
   "t": "2026-04-30T17:15:37Z",
   "kind": "review",
   "who": "musaHaruna",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "775964ef02e8e8c85ea2caf01b76e41a454212f6",
   "text": "Added commit [775964e](https://github.com/bitcoin/bitcoin/pull/35151/commits/775964ef02e8e8c85ea2caf01b76e41a454212f6) as suggested by @polespinasa to address the early-exit concern raised in review.\n\n`HowSpent` now takes an optional `isSpent` flag, allowing it to return early when used by IsSpent, restoring the previous early-exit behavior while still keeping the refactor.\n\nThank you so much @polespinasa for the reviews and suggestions.\nI will keep the changes like this to see what other reviewers thinks about it."
  },
  {
   "t": "2026-04-30T18:15:09Z",
   "kind": "comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "text": "Great!\n\nThe commits can be squashed into one single commit. Each commit should be good for himself and the first one is a behavior change so it needs the changes in the second :)"
  },
  {
   "t": "2026-05-05T08:35:21Z",
   "kind": "force_push",
   "who": "musaHaruna",
   "commit": "ac774b318440c7cc4804516b1f811005e25e8d45"
  },
  {
   "t": "2026-05-05T09:37:37Z",
   "kind": "review",
   "who": "musaHaruna",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "ac774b318440c7cc4804516b1f811005e25e8d45",
   "text": "[quoted text omitted]\n\nSquashed. Thanks."
  },
  {
   "t": "2026-08-11T09:59:35Z",
   "kind": "review",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "ac774b318440c7cc4804516b1f811005e25e8d45",
   "text": "ACK ac774b318440c7cc4804516b1f811005e25e8d45\n\nI am not sure about the bool variable name `isSpent`. It does not self-explain what it does. But anything like `only_check_if_spent` might be too much.\n\nThe comment later in the code makes it clear and because the code function is not large I think this is not a big problem."
  }
 ],
 "labels_log": [
  {
   "t": "2026-04-24T13:02:21Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-24T13:53:23Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-24T15:56:27Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-25T09:56:58Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-30T15:41:23Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-30T17:03:49Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  }
 ],
 "state_log": [],
 "text_chars": 5884,
 "text_tokens_estimate": 1471,
 "changed_paths": [
  "src/wallet/wallet.cpp",
  "src/wallet/wallet.h"
 ],
 "files": [
  {
   "path": "src/wallet/wallet.cpp",
   "add": 4,
   "del": 22
  },
  {
   "path": "src/wallet/wallet.h",
   "add": 4,
   "del": 2
  }
 ],
 "test_lines": 0,
 "git": {
  "head": "ac774b318440c7cc4804516b1f811005e25e8d45",
  "head_matches_backup": true,
  "base": "2d5ab09f0dca4bfec0b365f5f431def2c0c9d70f",
  "commits": [
   {
    "sha": "ac774b3184",
    "subject": "wallet: Refactor IsSpent to use HowSpent",
    "files": 2,
    "add": 8,
    "del": 24
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "d786967a386cc707",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}