{
 "number": 34872,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/34872",
 "title": "wallet: fix mixed-input transaction accounting in history RPCs",
 "author": "w0xlt",
 "author_association": "CONTRIBUTOR",
 "created_at": "2026-03-19T22:47:16Z",
 "updated_at": "2026-09-09T09:49:39Z",
 "age_days": 181,
 "draft": false,
 "labels": [
  "Wallet",
  "Needs rebase"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "eba63bfe77c148a447f44ba0703cb211c7a3213d",
 "head_ref": "wallet-mixed-input-history-only",
 "head_repo": "w0xlt/bitcoin",
 "head_history": [
  {
   "t": "2026-05-20T13:35:06Z",
   "sha": "a3028465652d30e492e0967aca947cdfe6c99b43"
  },
  {
   "t": "2026-06-15T05:13:32Z",
   "sha": "6aee1680f1257ff1909128285522512543271a14"
  },
  {
   "t": "2026-06-15T05:30:01Z",
   "sha": "096910ca827a05df61c1d05bbf41842befa50b48"
  },
  {
   "t": "2026-06-18T23:56:13Z",
   "sha": "898bd00196c6439cbb7afa4286fe1e7ff5f7b2d2"
  },
  {
   "t": "2026-06-22T08:02:35Z",
   "sha": "daabbba2313924c6df1b1db4b425d183d6d87654"
  },
  {
   "t": "2026-06-22T09:00:42Z",
   "sha": "f971f356ce763405aabe5c36f920870a3821d3cc"
  },
  {
   "t": "2026-06-23T07:43:55Z",
   "sha": "42044ec295540781fffb6e4b4a83c61119a350c5"
  },
  {
   "t": "2026-07-07T20:05:54Z",
   "sha": "1626331131a1e497f853c48b0e29b3d87b532a14"
  },
  {
   "t": "2026-07-07T22:08:46Z",
   "sha": "92a5b26e0c0deb5ad29e97ef7d227f51797474ec"
  },
  {
   "t": "2026-07-08T08:31:35Z",
   "sha": "eba63bfe77c148a447f44ba0703cb211c7a3213d"
  }
 ],
 "additions": 993,
 "deletions": 59,
 "changed_files": 11,
 "commit_count": 13,
 "size_bucket": "XL",
 "mergeable_state": "dirty",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_nack": [
     {
      "login": "achow101",
      "url": "https://github.com/bitcoin/bitcoin/pull/34872#issuecomment-4491965088"
     }
    ],
    "concept_ack": [
     {
      "login": "rkrux",
      "url": "https://github.com/bitcoin/bitcoin/pull/34872#issuecomment-4509144362"
     }
    ]
   },
   "conflicts": [
    {
     "number": 35786,
     "title": "wallet: drop spent parents redundant cache invalidation and notification",
     "author": "furszy"
    },
    {
     "number": 35716,
     "title": "wallet: Replace mapWallet and wtxOrdered with a boost::multi_index",
     "author": "achow101"
    },
    {
     "number": 35501,
     "title": "wallet: store all witness variants of a transaction",
     "author": "achow101"
    },
    {
     "number": 27865,
     "title": "wallet: Track no-longer-spendable TXOs separately",
     "author": "achow101"
    }
   ]
  }
 },
 "acks_parsed": {
  "achow101": {
   "kind": "nack",
   "hash": null,
   "t": "2026-05-19T20:55:14Z",
   "stale": false
  },
  "rkrux": {
   "kind": "concept_ack",
   "hash": "29fcb54dac4a8f4b45573ba20b97874eec81be9d",
   "t": "2026-05-21T14:16:30Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 1,
  "approach_ack": 0,
  "nack": 1,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "achow101",
   "luke-jr",
   "maflcko",
   "murchandamus",
   "rkrux",
   "sedited"
  ]
 },
 "signals": {
  "needs_rebase": true,
  "ci_failed": false,
  "mergeable_state": "dirty",
  "last_author_activity": "2026-07-08T08:33:44Z",
  "last_reviewer_activity": "2026-09-09T09:49:39Z",
  "last_reviewer": "sedited",
  "author_silent_days": 71,
  "waiting_on_author_days": 8,
  "days_since_update": 8
 },
 "refs": {
  "mentioned": [
   14136,
   25991
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 14136,
    "type": "issue",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "rpc: Wrong `gettransaction` info for a coinjoin"
   },
   {
    "number": 25991,
    "type": "pull",
    "state": "closed",
    "merged": false,
    "merged_at": null,
    "title": "Wallet: Add foreign_outputs metadata to support CoinJoin transactions"
   }
  ],
  "conflicts": [
   35786,
   35716,
   35501,
   27865
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "doc/release-notes-34872.md",
  "src/wallet/receive.cpp",
  "src/wallet/rpc/transactions.cpp",
  "src/wallet/test/wallet_tests.cpp",
  "test/functional/wallet_gettransaction_mixed_inputs.py"
 ],
 "body": "When a wallet owns only some inputs of a transaction, such as in CoinJoins, payjoins, or other collaborative transactions, wallet history RPCs currently apply normal send accounting.\n\nThat works when all inputs are wallet-owned, but breaks for mixed-input transactions.\n\nExample:\n\nInputs:\n```\n1.00 BTC wallet-owned\n2.00 BTC foreign\n```\n\nOutputs:\n```\n0.80 BTC wallet-owned\n2.19 BTC non-wallet\n```\n\nThe wallet can safely know:\n\n```\nwallet_debit  = 1.00\nwallet_credit = 0.80\nwallet_net    = -0.20\n```\n\nBut it cannot reliably know, from wallet history alone, the foreign input value, the total fee, the wallet's fee share, or which non-wallet output should be attributed as the user's payment. This is especially important after restore, rescan, or descriptor import, where any local transaction-intent metadata may be missing.\n\nThis PR adds a conservative fallback for that no-metadata case:\n\n- classify wallet transactions as having no wallet inputs, partial wallet inputs, or all wallet inputs\n- keep existing send/fee accounting when all inputs are wallet-owned\n- also keep normal per-output send/fee accounting for mixed-input transactions when every non-wallet input has a known zero value\n- otherwise report a single unattributed aggregate `send` entry with no address, no `vout`, and no fee, carrying the negative total of wallet-owned inputs spent\n- report wallet-owned outputs as `receive` entries, so the transaction's entries sum to the wallet's net change\n- expose `involves_mixed_inputs`, `wallet_debit`, and `wallet_credit`\n- document that `vout` and `fee` are optional when attribution is unavailable\n\nThis does not try to fully solve collaborative transaction attribution. A richer layer with foreign-output / fee-share / intent metadata would still be useful for wallet-created transactions. This PR only makes the fallback honest when that metadata is unavailable.\n\nAddresses #14136",
 "commits": [
  {
   "sha": "3d1134d11fbcbbe4e62a00be06f04648e1bf5e90",
   "date": "2026-06-30T23:46:17Z",
   "message": "wallet: cache transaction input ownership\n\nAdd a cached helper that classifies wallet transaction inputs as all,\npartial, or none owned by the wallet. This lets history code distinguish\nmixed-input transactions without repeating input ownership scans."
  },
  {
   "sha": "2d5e4ee60276074b89645279fa22afd7c18027a3",
   "date": "2026-06-30T23:47:04Z",
   "message": "wallet: add history accounting helper\n\nAdd a cached history accounting helper that returns input ownership,\nwallet debit, wallet credit, and fee information in one place before\nthe RPC code consumes it."
  },
  {
   "sha": "7eab5306be1df90183d10fba6941ce4b35751fe6",
   "date": "2026-06-30T23:47:49Z",
   "message": "wallet: invalidate child input caches on parent insertion\n\nInvalidate cached input ownership for wallet transactions that spend\noutputs from a newly inserted parent, so later imports can refresh child\naccounting."
  },
  {
   "sha": "40d2e72f16c099a15688fa0cc26b7f0bf258636c",
   "date": "2026-06-30T23:48:04Z",
   "message": "wallet,rpc: rename transaction entry helper"
  },
  {
   "sha": "0d3f1141ef76ef3cbd527f5f1a96518a252f2aed",
   "date": "2026-06-30T23:48:46Z",
   "message": "wallet,rpc: report unattributable mixed-input history conservatively\n\nUse aggregate wallet debit for mixed-input transaction history when\noutputs and fees cannot be attributed to specific inputs. Expose wallet\ndebit and credit fields so callers can identify the conservative\naccounting."
  },
  {
   "sha": "46f70e01eddb03a3165477e6a2aa9901b97ceae3",
   "date": "2026-07-08T08:24:53Z",
   "message": "test: cover conservative mixed-input history accounting\n\nAdd functional coverage for conservative mixed-input history entries in\ngettransaction, listtransactions, and listsinceblock, including filtered\nhistory and removed entries."
  },
  {
   "sha": "e04e0906bd63503ac62a86cb04e91eddbc3425ad",
   "date": "2026-07-08T08:24:53Z",
   "message": "wallet: cache zero-value foreign input state\n\nTrack whether every non-wallet input of a mixed-input wallet\ntransaction is known to spend a zero-value output.\n\nThis is not used for attribution yet. It lets later history accounting\ndifferentiate unknown or nonzero foreign contributions from foreign\ninputs that provably cannot fund outputs or fees."
  },
  {
   "sha": "056ccd7bab93110d65b5c028f1502238c3a587b9",
   "date": "2026-07-08T08:24:53Z",
   "message": "wallet,rpc: attribute zero-value foreign mixed inputs\n\nUse normal per-output send and fee accounting for mixed-input\ntransactions when every non-wallet input is known to have zero value.\n\nUnknown or positive-value foreign inputs remain conservative because\nthe wallet cannot attribute recipient outputs or its fee share from the\ntransaction alone."
  },
  {
   "sha": "9b422a2237b7d7e856145c04fa487cdb29c74205",
   "date": "2026-07-08T08:24:53Z",
   "message": "test: cover zero-value foreign input accounting\n\nAdd functional coverage for a mixed-input transaction that spends a\nwallet-owned input together with a zero-value pay-to-anchor input.\n\nThe test asserts that the wallet keeps normal send and fee entries,\nwhile still marking the transaction as involving mixed inputs."
  },
  {
   "sha": "a4193188c5300d4b968b01a38d39a012a476a23d",
   "date": "2026-07-08T08:24:53Z",
   "message": "test: cover late mixed-input parent import\n\nExercise the case where a wallet first sees a mixed-input child\ntransaction before seeing the parent that creates a zero-value foreign\ninput.\n\nAfter the parent is imported, the child history accounting must be\nrecomputed and switch from conservative aggregate accounting to normal\nsend and fee attribution."
  },
  {
   "sha": "242acb8af8bccd4ee21ae3b77a1a7839272d1e27",
   "date": "2026-07-08T08:24:53Z",
   "message": "test: cover known nonzero foreign inputs\n\nAdd coverage showing that a mixed-input transaction remains\nconservatively reported when the wallet knows a foreign input has\nnonzero value but still cannot attribute the fee share."
  },
  {
   "sha": "cf1b676c3ddb1e5ff27d1c4cbbff8b540d1ff528",
   "date": "2026-07-08T08:24:53Z",
   "message": "test: cover zero-value wallet inputs\n\nAdd coverage for mixed-input transactions where the wallet-owned input\nhas zero value, ensuring history still reports the wallet credit with a\nzero aggregate debit."
  },
  {
   "sha": "eba63bfe77c148a447f44ba0703cb211c7a3213d",
   "date": "2026-07-08T08:24:53Z",
   "message": "doc: add mixed-input history RPC release note\n\nDocument how wallet history RPCs report transactions that spend both\nwallet-owned and non-wallet inputs.\n\nMention the normal attribution allowed for known zero-value foreign\ninputs, the conservative aggregate fallback, and the new mixed-input\nmetadata fields."
  }
 ],
 "timeline": [
  {
   "t": "2026-03-20T14:56:51Z",
   "kind": "comment",
   "who": "luke-jr",
   "assoc": "CONTRIBUTOR",
   "text": "This won't show even the true send anymore... not sure that's a good idea.\n\nSee #25991 for what is needed to fix this properly."
  },
  {
   "t": "2026-03-22T05:40:35Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "The goal here, in this PR, is a smaller immediate fix: for mixed-input transactions, the history RPCs should stop reporting send entries and full fees when the wallet cannot attribute them objectively.\n\n#25991 is an interesting direction, but as written it depends on manually providing additional wallet-local per-output metadata.\nWithout that metadata, we still need a safe fallback, and that is what this PR provides."
  },
  {
   "t": "2026-03-23T12:24:37Z",
   "kind": "review",
   "who": "rkrux",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "5c5176ec4c5e0eada830668b8480e8a0665223d7",
   "text": "As I read the related issue #14136, it's unfortunate that the RPC shows incorrect information in the result - glad that this PR tries to address it.\n\nHowever, I'm leaning towards a NACK because this PR removes the `send` category details of such transactions altogether, which is not correct. The wallet does participate (though partially) in sending funds within these transactions and not showing those can be problematic as well.\n\nFrom https://github.com/bitcoin/bitcoin/pull/34872#issue-4104631274\n[quoted text omitted]\n\nI am also not in favour of having two different views of CachedTxIsFromMe - one without accounting and one with. Having two views is also a sign that there is mismatch between what the wallet shows to the user and what the wallet does for the user.\n\nFrom https://github.com/bitcoin/bitcoin/pull/34872#issuecomment-4105597428:\n[quoted text omitted]\n\nDue to the above reasons, I don't believe this is a safe fallback, and it only replaces one issue by another.\n\nFrom https://github.com/bitcoin/bitcoin/pull/34872#issue-4104631274\n[quoted text omitted]\n\nIt appears that this assumption made by the wallet doesn't hold true anymore and maybe it needs to be reworked for this issue to be completely fixed."
  },
  {
   "t": "2026-03-23T20:15:23Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "@rkrux  Thanks for the review. I agree this isn\u2019t a complete solution for mixed-input accounting.\n\nThe goal here is narrower: to prevent history RPCs from reporting send entries and full fees that the wallet cannot objectively attribute from the transaction alone.\n\nSo I see this as an improvement over the current behavior.\n\nA complete solution likely requires additional attribution metadata. However, that\u2019s tricky - even if we add something like #25991, or a more automated way to set it, the metadata would not survive an `importdescriptors` restore, since there\u2019s currently no way to import it.\n\nIn those cases, we would still need a conservative fallback for history RPCs when attribution is unavailable.\n\nDo you see another way to address this without relying on additional metadata?"
  },
  {
   "t": "2026-05-19T20:55:14Z",
   "kind": "comment",
   "who": "achow101",
   "assoc": "MEMBER",
   "text": "NACK\n\nI think it's even more misleading to not show any send entries at all for transactions where we participate in the inputs."
  },
  {
   "t": "2026-05-19T21:56:54Z",
   "kind": "comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "text": "At first glance, I would expect our wallet to be able to recognize which inputs are ours, and I\u2019m astonished that it would just assume that all of the inputs must be ours when it recognizes one. Would it perhaps be possible to recognize such transactions as \u201cmulti user transactions\u201d and only apply the inputs that came from our wallet as debits? If our wallet\u2019s balance is decreased by the transaction, we might recognize any outputs from the transaction to our wallet as change output, whereas if the wallet\u2019s balance is increased by the transaction (e.g., a Payjoin that paid us), we would treat the output as an incoming payment. The transaction should then be labeled as having us paid the amount that our wallet balance increased."
  },
  {
   "t": "2026-05-19T22:23:28Z",
   "kind": "comment",
   "who": "achow101",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nThat's not really what it is doing. It is correctly treating transactions that have any inputs belonging to the wallet as that transaction belonging to the wallet. The \"assumption\" comes from `CachedTxGetDebit` only retrieving the total amount of our inputs, which only works when all of the inputs of the transaction belong to the wallet.\n\nBut without storing more information, there is nothing that we can do to fix that. It shouldn't be astonishing that we are unable to calculate fees when the wallet does not know how much value the inputs that it doesn't know about are providing to the transaction.\n\n[quoted text omitted]\nThis isn't about annotating Bitcoin transactions, it's about annotating logical financial transactions and trying to determine what they are from a single Bitcoin transaction. Because a Bitcoin transaction can have multiple outputs, it can have multiple logical transactions, and the wallet tries to display these as such. For example, a multi party transaction could conceivably contain an output created by someone else in that transaction which pays us, while the same transaction simultaneously has an output that we create paying someone else. These should show as two entries in `listtransactions` - one showing a receive and one showing the send. The issue is with annotating the rest of the outputs (we don't store the logical transactions, so how do we know that the remaining outputs are not sends initiated by the user), and showing the correct amount for the fee (we don't know about the inputs that aren't ours, thus we cannot accurately calculate the fees).\n\nThe solution presented in this PR is to omit all of that logical transaction information entirely for multi party transactions, which I disagree with."
  },
  {
   "t": "2026-05-20T13:35:06Z",
   "kind": "force_push",
   "who": "w0xlt",
   "commit": "a3028465652d30e492e0967aca947cdfe6c99b43"
  },
  {
   "t": "2026-05-20T13:41:34Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "@achow101  @murchandamus Thanks for the feedback.\n\nI pushed a new proposal that addresses it.\n\nAs I understand it, a complete solution has two layers:\n\n1. A conservative fallback for mixed-input transactions when the wallet has no extra attribution metadata.\n\n\u20282. A richer metadata layer, e.g. foreign-output / ownership / fee-share marks, for wallet-created collaborative transactions.\n\nThe idea here to solve the layer 1 only.\nLayer 2 is still useful, but it cannot replace the fallback. If a wallet is restored from descriptors, rescanned, or imported without the original local metadata, the wallet still needs a reliable way to report history without inventing send outputs or fees."
  },
  {
   "t": "2026-05-20T13:47:34Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "The new proposal:\n\nIn master, wallet history accounting effectively does this when any input is ours:\n\n```\nwallet_debit = sum(wallet-owned inputs)\nfee = wallet_debit - total_outputs\nsend entries = all non-change outputs\n```\n\nThat works only when all inputs are wallet-owned.\n\nExample:\n\nInputs:\n```\n    1.00 BTC mine\n    2.00 BTC foreign\n```\n\nOutputs:\n```\n    0.80 BTC mine\n    2.19 BTC foreign\n ```\n\nMaster can calculate `wallet_debit = 1.00`, but it does not know/store the foreign input value reliably in wallet history. So subtracting all outputs from only wallet-owned inputs gives wrong accounting:\n\n`fee = 1.00 - 2.99 = -1.99`\n\nIt can also report foreign outputs as wallet send entries, even though the wallet cannot know from the transaction alone whether those outputs are wallet's payment, another participant\u2019s change, or something else.\n\nThis new push changes the previous fallback model to:\n\n```\nwallet_debit  = sum(wallet-owned inputs)\nwallet_credit = sum(wallet-owned outputs)\namount        = wallet_credit - wallet_debit\n```\n\nFor the same example:\n\n```\nwallet_debit  = 1.00\nwallet_credit = 0.80\namount        = -0.20\nfee_known     = false\ncategory      = mixed\n```\nSo the wallet reports the part it can prove: \u201cthe wallet balance went down by 0.20 BTC.\u201d It does not guess the fee share or recipient attribution."
  },
  {
   "t": "2026-05-20T13:49:28Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "Moving this to draft for further discussion."
  },
  {
   "t": "2026-05-20T14:02:12Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "PR description updated."
  },
  {
   "t": "2026-05-20T14:50:28Z",
   "kind": "comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nSorry, I had forgotten about this PR. I would prefer a basic conservative solution first without relying on additional metadata by letting the wallet return correct information (as much as it can) while not showing incorrect responses based on any missing transaction data.\n\nBased on a cursory glance, the new proposal seems to be in this^ direction, will review."
  },
  {
   "t": "2026-05-20T17:13:30Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "CI error unrelated"
  },
  {
   "t": "2026-05-21T14:16:30Z",
   "kind": "comment",
   "who": "rkrux",
   "assoc": "MEMBER",
   "text": "Concept ACK 29fcb54dac4a8f4b45573ba20b97874eec81be9d\n\nThe new approach lgtm, will review when taken out of draft."
  },
  {
   "t": "2026-05-21T17:07:05Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "Done."
  },
  {
   "t": "2026-06-15T05:13:32Z",
   "kind": "force_push",
   "who": "w0xlt",
   "commit": "6aee1680f1257ff1909128285522512543271a14"
  },
  {
   "t": "2026-06-15T05:30:01Z",
   "kind": "force_push",
   "who": "w0xlt",
   "commit": "096910ca827a05df61c1d05bbf41842befa50b48"
  },
  {
   "t": "2026-06-18T23:56:13Z",
   "kind": "force_push",
   "who": "w0xlt",
   "commit": "898bd00196c6439cbb7afa4286fe1e7ff5f7b2d2"
  },
  {
   "t": "2026-06-19T00:27:53Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "PR description updated."
  },
  {
   "t": "2026-06-22T08:02:35Z",
   "kind": "force_push",
   "who": "w0xlt",
   "commit": "daabbba2313924c6df1b1db4b425d183d6d87654"
  },
  {
   "t": "2026-06-22T09:00:42Z",
   "kind": "force_push",
   "who": "w0xlt",
   "commit": "f971f356ce763405aabe5c36f920870a3821d3cc"
  },
  {
   "t": "2026-06-23T07:43:55Z",
   "kind": "force_push",
   "who": "w0xlt",
   "commit": "42044ec295540781fffb6e4b4a83c61119a350c5"
  },
  {
   "t": "2026-06-23T21:15:25Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/receive.cpp",
   "commit": "cde6efd3d2a6484a7e6ea02f4b302bc2115567fd",
   "in_reply_to": null,
   "text": "How would this resolve if there were a P2A input?"
  },
  {
   "t": "2026-06-30T20:13:27Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "doc/release-notes-34872.md",
   "commit": "eba63bfe77c148a447f44ba0703cb211c7a3213d",
   "in_reply_to": null,
   "text": "In \"doc: add mixed-input history RPC release note\" (eba63bfe77c148a447f44ba0703cb211c7a3213d):\nI\u2019m not sure how safety is an issue here. How about \"reported correctly\", \"with improved attribution\", \"in more detail\", or similar?\n```suggestion\n  broken down in more detail by the `gettransaction`, `listtransactions`, and\n```"
  },
  {
   "t": "2026-07-07T20:05:54Z",
   "kind": "force_push",
   "who": "w0xlt",
   "commit": "1626331131a1e497f853c48b0e29b3d87b532a14"
  },
  {
   "t": "2026-07-07T20:07:29Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "Split the PR into more commits based on offline feedback"
  },
  {
   "t": "2026-07-07T22:08:46Z",
   "kind": "force_push",
   "who": "w0xlt",
   "commit": "92a5b26e0c0deb5ad29e97ef7d227f51797474ec"
  },
  {
   "t": "2026-07-08T05:38:22Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "test/functional/wallet_gettransaction_mixed_inputs.py",
   "commit": "92a5b26e0c0deb5ad29e97ef7d227f51797474ec",
   "in_reply_to": null,
   "text": "What is this sync needed for on block events? Also, the `called_by_framework` in the prior line doesn't make sense?"
  },
  {
   "t": "2026-07-08T08:31:35Z",
   "kind": "force_push",
   "who": "w0xlt",
   "commit": "eba63bfe77c148a447f44ba0703cb211c7a3213d"
  },
  {
   "t": "2026-07-08T08:33:44Z",
   "kind": "review_comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "path": "test/functional/wallet_gettransaction_mixed_inputs.py",
   "commit": "92a5b26e0c0deb5ad29e97ef7d227f51797474ec",
   "in_reply_to": 3541463153,
   "text": "Fixed. Thanks."
  },
  {
   "t": "2026-07-15T21:13:21Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/test/wallet_tests.cpp",
   "commit": "3d1134d11fbcbbe4e62a00be06f04648e1bf5e90",
   "in_reply_to": null,
   "text": "In \"wallet: cache transaction input ownership\" (3d1134d11fbcbbe4e62a00be06f04648e1bf5e90):\n\nI\u2019d be curious how an anyone-can-spend output such as a P2A output is categorized by `InputIsMine(\u2026)`, and it might also be a good addition to this test."
  },
  {
   "t": "2026-07-15T21:18:34Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/transactions.cpp",
   "commit": "40d2e72f16c099a15688fa0cc26b7f0bf258636c",
   "in_reply_to": null,
   "text": "In \"wallet,rpc: rename transaction entry helper\" (40d2e72f16c099a15688fa0cc26b7f0bf258636c):\nI\u2019m not sure I understand the motivation for this rename. This RPC would print transactions to the terminal based on the given criteria, right? What is it appending to?\n\nCould you please add a short explanation to the commit message why this RPC was renamed?"
  },
  {
   "t": "2026-07-15T21:21:32Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/transactions.cpp",
   "commit": "0d3f1141ef76ef3cbd527f5f1a96518a252f2aed",
   "in_reply_to": null,
   "text": "In \"wallet,rpc: report unattributable mixed-input history conservatively\" (0d3f1141ef76ef3cbd527f5f1a96518a252f2aed):\nWhat do you mean with \"unattributable outputs\"? Do you perhaps mean that no outputs go to our wallet, i.e., that `credit` is zero?"
  },
  {
   "t": "2026-07-15T21:25:53Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/transactions.cpp",
   "commit": "0d3f1141ef76ef3cbd527f5f1a96518a252f2aed",
   "in_reply_to": null,
   "text": "In \"wallet,rpc: report unattributable mixed-input history conservatively\" (0d3f1141ef76ef3cbd527f5f1a96518a252f2aed):\nEven if there are mixed inputs, either the `debit` or `credit` could have a greater magnitude. Could you perhaps add an explanation in the commit message why a transaction that overall reduces the balance in the wallet would not be categorized as a _send_, and a transaction that overall increases the balance in the wallet as a _receive_?\nI assume it is because it would be hard to distinguish e.g., a Payjoin in which we get paid and the sender gets a change output from a Payjoin transaction in which we get paid by a sender and also pay another receiver, but it would be good to document the rationale somewhere."
  },
  {
   "t": "2026-07-15T21:27:03Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/transactions.cpp",
   "commit": "0d3f1141ef76ef3cbd527f5f1a96518a252f2aed",
   "in_reply_to": 3590840079,
   "text": "I still think that there might be a special case here, in which there are mixed inputs, but all outputs go to our wallet, in which we might want to categorize it as a _receive_?"
  },
  {
   "t": "2026-07-15T21:33:21Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/transactions.cpp",
   "commit": "0d3f1141ef76ef3cbd527f5f1a96518a252f2aed",
   "in_reply_to": null,
   "text": "In \"wallet,rpc: report unattributable mixed-input history conservatively\" (0d3f1141ef76ef3cbd527f5f1a96518a252f2aed):\nI find this description confusing. What is \"unattributed\" about the \"aggregate send entry\"?\n\nPerhaps: \"\n```diff\n-                so it reports a single unattributed aggregate send entry (marked with involves_mixed_inputs and \\n\"\n-                \"without address, vout, or fee) carrying the negative total of wallet-owned inputs spent. Wallet-owned outputs \\n\"\n+                so it reports the sum of the wallet-owned inputs as a single aggregate send entry (marked with involves_mixed_inputs and \\n\"\n+                \"without address, vout, or fee). Wallet-owned outputs \\n\"\n```"
  },
  {
   "t": "2026-07-15T21:35:52Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/transactions.cpp",
   "commit": "0d3f1141ef76ef3cbd527f5f1a96518a252f2aed",
   "in_reply_to": null,
   "text": "In \"wallet,rpc: report unattributable mixed-input history conservatively\" (0d3f1141ef76ef3cbd527f5f1a96518a252f2aed):\n\nThe \"cannot be attributed\" here also confuses me. FWIU at this point in the review, when no outputs go to ourselves, or all outputs go ourselves, we consider it \"attributable\", but if there are both foreign-owned inputs and foreign-owned outputs, we call it \"not attributable\". If that\u2019s the correct understanding, perhaps we can find a more speaking description of that?"
  },
  {
   "t": "2026-07-15T21:38:00Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/transactions.cpp",
   "commit": "0d3f1141ef76ef3cbd527f5f1a96518a252f2aed",
   "in_reply_to": null,
   "text": "In \"wallet,rpc: report unattributable mixed-input history conservatively\" (0d3f1141ef76ef3cbd527f5f1a96518a252f2aed):\nAlso here: \"cannot attribute\" needs more context."
  },
  {
   "t": "2026-07-15T21:40:24Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/transactions.cpp",
   "commit": "0d3f1141ef76ef3cbd527f5f1a96518a252f2aed",
   "in_reply_to": null,
   "text": "In \"wallet,rpc: report unattributable mixed-input history conservatively\" (0d3f1141ef76ef3cbd527f5f1a96518a252f2aed):\nI\u2019m confused by this line. If all of `credit`, `debit`, and `fee` are stored as positive numbers, then surely it should be `credit - debit - fee`. If `fee` and `debit` are stored as negative numbers, it should be `credit + debit + fee`. If `fee` is stored as a negative number and `debit` is stored as a positive number, what are we even doing here? \ud83d\ude05"
  },
  {
   "t": "2026-07-15T21:49:39Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/transactions.cpp",
   "commit": "056ccd7bab93110d65b5c028f1502238c3a587b9",
   "in_reply_to": null,
   "text": "In \"wallet,rpc: attribute zero-value foreign mixed inputs\" (056ccd7bab93110d65b5c028f1502238c3a587b9):\n\nThe \"known\" seems obsolete, as we always know the value of spent TXOs.\n\n```diff\n-\"all non-wallet inputs have known zero value. Otherwise the wallet cannot attribute the foreign outputs or its \\n\"\n+\"all non-wallet inputs have zero value. Otherwise the wallet cannot attribute the foreign outputs or its \\n\""
  },
  {
   "t": "2026-07-15T21:49:55Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/transactions.cpp",
   "commit": "056ccd7bab93110d65b5c028f1502238c3a587b9",
   "in_reply_to": null,
   "text": "In \"wallet,rpc: attribute zero-value foreign mixed inputs\" (056ccd7bab93110d65b5c028f1502238c3a587b9):\n\n\"known\" seems to be extraneous as above."
  },
  {
   "t": "2026-07-15T21:54:39Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/rpc/transactions.cpp",
   "commit": "056ccd7bab93110d65b5c028f1502238c3a587b9",
   "in_reply_to": null,
   "text": "In \"wallet,rpc: attribute zero-value foreign mixed inputs\" (056ccd7bab93110d65b5c028f1502238c3a587b9):\nIf someone only saw this RPC description, \"only available when known\" would be confusing. How about something along the lines of:\n\n```diff\n-{RPCResult::Type::STR_AMOUNT, \"fee\", /*optional=*/true, \"The amount of the wallet-attributable fee in \" + CURRENCY_UNIT + \". This is negative and only available when known.\"},\n+{RPCResult::Type::STR_AMOUNT, \"fee\", /*optional=*/true, \"The amount of the wallet-attributable fee in \" + CURRENCY_UNIT + \". The fee is negative and will only be reported for the 'send' category. The fee cannot be calculated for transactions with multiple senders.\"},\n```"
  },
  {
   "t": "2026-07-15T21:56:25Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/receive.cpp",
   "commit": "056ccd7bab93110d65b5c028f1502238c3a587b9",
   "in_reply_to": null,
   "text": "In \"wallet,rpc: attribute zero-value foreign mixed inputs\" (056ccd7bab93110d65b5c028f1502238c3a587b9):\nThis explanation is excellent. \"not computable\" might be a better expression for the above cases where I found \"attributable\" to be insufficiently clear."
  },
  {
   "t": "2026-07-15T21:57:21Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "src/wallet/receive.cpp",
   "commit": "056ccd7bab93110d65b5c028f1502238c3a587b9",
   "in_reply_to": null,
   "text": "In \"wallet,rpc: attribute zero-value foreign mixed inputs\" (056ccd7bab93110d65b5c028f1502238c3a587b9):\nDo you mean \"every spent input **with nonzero** value\"? Or perhaps \"the total input value was contributed by our wallet\"?"
  },
  {
   "t": "2026-07-15T22:01:42Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "doc/release-notes-34872.md",
   "commit": "eba63bfe77c148a447f44ba0703cb211c7a3213d",
   "in_reply_to": null,
   "text": "In \"doc: add mixed-input history RPC release note\" (eba63bfe77c148a447f44ba0703cb211c7a3213d):\n\n```suggestion\n  and considered all non-wallet outputs to be wallet sends (see issue #14136).\n```"
  },
  {
   "t": "2026-07-15T22:06:31Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "doc/release-notes-34872.md",
   "commit": "eba63bfe77c148a447f44ba0703cb211c7a3213d",
   "in_reply_to": null,
   "text": "In \"doc: add mixed-input history RPC release note\" (eba63bfe77c148a447f44ba0703cb211c7a3213d):\n\nThe \"**known** zero value\" keeps throwing me for a loop. Transactions can only spend TXOs that are in our UTXO set when we first see them. Therefore, we should always know every spent TXO\u2019s value when we first validate a transaction. Shouldn\u2019t it therefore also be available when we store a transaction in the wallet? If not, the wallet should learn it at the time a block is processed, and the value should be in the revert data?"
  },
  {
   "t": "2026-07-15T22:08:51Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "doc/release-notes-34872.md",
   "commit": "eba63bfe77c148a447f44ba0703cb211c7a3213d",
   "in_reply_to": null,
   "text": "In \"doc: add mixed-input history RPC release note\" (eba63bfe77c148a447f44ba0703cb211c7a3213d):\n\nI think my issue with \"attribute\" might be that the verb always needs a target for the attribution that I was missing. Maybe it makes sense when we describe it as the wallet being able to attribute it **to itself**?\n\n```suggestion\n  pay-to-anchor output), the wallet can still attribute the full fee and all\n  sent outputs to itself, so these transactions continue to be reported with the usual\n```"
  },
  {
   "t": "2026-07-15T22:09:47Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "doc/release-notes-34872.md",
   "commit": "eba63bfe77c148a447f44ba0703cb211c7a3213d",
   "in_reply_to": null,
   "text": "In \"doc: add mixed-input history RPC release note\" (eba63bfe77c148a447f44ba0703cb211c7a3213d):\n\n```suggestion\n  per-output `send`/`receive` entries. Otherwise the wallet cannot compute its share of the\n  foreign outputs and the fee, so it reports a single unattributed\n```"
  },
  {
   "t": "2026-07-15T22:10:52Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "doc/release-notes-34872.md",
   "commit": "eba63bfe77c148a447f44ba0703cb211c7a3213d",
   "in_reply_to": null,
   "text": "In \"doc: add mixed-input history RPC release note\" (eba63bfe77c148a447f44ba0703cb211c7a3213d):\n\nMaybe:\n\n```suggestion\n  foreign outputs or its fee share, so it reports the negative total of the wallet-owned inputs\n  as the `send` amount\n```"
  },
  {
   "t": "2026-07-15T22:16:46Z",
   "kind": "review_comment",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "path": "doc/release-notes-34872.md",
   "commit": "eba63bfe77c148a447f44ba0703cb211c7a3213d",
   "in_reply_to": null,
   "text": "In \"doc: add mixed-input history RPC release note\" (eba63bfe77c148a447f44ba0703cb211c7a3213d):\n\nThe fee can always be determined per `\u03a3(inputs)\u2212\u03a3(outputs)`, rather we cannot determine our share of the fee.\n\n```suggestion\n  output. The `fee` field is likewise omitted when the wallet cannot determine its share of\n  the fee. (#34872)\n```"
  },
  {
   "t": "2026-07-15T22:19:51Z",
   "kind": "review",
   "who": "murchandamus",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "eba63bfe77c148a447f44ba0703cb211c7a3213d",
   "text": "Thanks for working on this. This sounds like a great improvement regarding multi-user transaction accounting. I have a few questions and I especially found the use of \"attributable\" somewhat confusing at times."
  },
  {
   "t": "2026-09-09T09:49:39Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "@w0xlt can you rebase and respond to murch's review comments?"
  }
 ],
 "labels_log": [
  {
   "t": "2026-03-19T22:47:21Z",
   "action": "labeled",
   "label": "Wallet",
   "who": "DrahtBot"
  },
  {
   "t": "2026-05-20T15:36:57Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-05-21T07:25:05Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-15T05:30:39Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-15T06:34:07Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-19T23:14:01Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-22T09:01:15Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-22T09:25:34Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-22T10:14:19Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-07T21:06:46Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-07T23:11:25Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-04T22:57:36Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2026-05-20T13:49:41Z",
   "kind": "convert_to_draft",
   "who": "w0xlt"
  },
  {
   "t": "2026-05-21T17:05:07Z",
   "kind": "ready_for_review",
   "who": "w0xlt"
  }
 ],
 "text_chars": 21358,
 "text_tokens_estimate": 5339,
 "changed_paths": [
  "doc/release-notes-34872.md",
  "src/wallet/receive.cpp",
  "src/wallet/receive.h",
  "src/wallet/rpc/transactions.cpp",
  "src/wallet/test/wallet_tests.cpp",
  "src/wallet/transaction.h",
  "src/wallet/wallet.cpp",
  "src/wallet/wallet.h",
  "test/functional/test_runner.py",
  "test/functional/wallet_gettransaction_mixed_inputs.py",
  "test/functional/wallet_listtransactions.py"
 ],
 "files": [
  {
   "path": "doc/release-notes-34872.md",
   "add": 26,
   "del": 0
  },
  {
   "path": "src/wallet/receive.cpp",
   "add": 89,
   "del": 12
  },
  {
   "path": "src/wallet/receive.h",
   "add": 14,
   "del": 1
  },
  {
   "path": "src/wallet/rpc/transactions.cpp",
   "add": 97,
   "del": 34
  },
  {
   "path": "src/wallet/test/wallet_tests.cpp",
   "add": 45,
   "del": 0
  },
  {
   "path": "src/wallet/transaction.h",
   "add": 12,
   "del": 0
  },
  {
   "path": "src/wallet/wallet.cpp",
   "add": 19,
   "del": 0
  },
  {
   "path": "src/wallet/wallet.h",
   "add": 4,
   "del": 0
  },
  {
   "path": "test/functional/test_runner.py",
   "add": 1,
   "del": 0
  },
  {
   "path": "test/functional/wallet_gettransaction_mixed_inputs.py",
   "add": 617,
   "del": 0
  },
  {
   "path": "test/functional/wallet_listtransactions.py",
   "add": 69,
   "del": 12
  }
 ],
 "test_lines": 744,
 "git": {
  "head": "eba63bfe77c148a447f44ba0703cb211c7a3213d",
  "head_matches_backup": true,
  "base": "ea626c268add060c207809c5b22c0e11f284f232",
  "commits": [
   {
    "sha": "3d1134d11f",
    "subject": "wallet: cache transaction input ownership",
    "files": 4,
    "add": 73,
    "del": 0
   },
   {
    "sha": "2d5e4ee602",
    "subject": "wallet: add history accounting helper",
    "files": 2,
    "add": 23,
    "del": 0
   },
   {
    "sha": "7eab5306be",
    "subject": "wallet: invalidate child input caches on parent insertion",
    "files": 2,
    "add": 23,
    "del": 0
   },
   {
    "sha": "40d2e72f16",
    "subject": "wallet,rpc: rename transaction entry helper",
    "files": 1,
    "add": 8,
    "del": 8
   },
   {
    "sha": "0d3f1141ef",
    "subject": "wallet,rpc: report unattributable mixed-input history conservatively",
    "files": 4,
    "add": 161,
    "del": 50
   },
   {
    "sha": "46f70e01ed",
    "subject": "test: cover conservative mixed-input history accounting",
    "files": 2,
    "add": 256,
    "del": 0
   },
   {
    "sha": "e04e0906bd",
    "subject": "wallet: cache zero-value foreign input state",
    "files": 3,
    "add": 42,
    "del": 0
   },
   {
    "sha": "056ccd7bab",
    "subject": "wallet,rpc: attribute zero-value foreign mixed inputs",
    "files": 2,
    "add": 30,
    "del": 12
   },
   {
    "sha": "9b422a2237",
    "subject": "test: cover zero-value foreign input accounting",
    "files": 1,
    "add": 96,
    "del": 2
   },
   {
    "sha": "a4193188c5",
    "subject": "test: cover late mixed-input parent import",
    "files": 1,
    "add": 119,
    "del": 1
   },
   {
    "sha": "242acb8af8",
    "subject": "test: cover known nonzero foreign inputs",
    "files": 1,
    "add": 70,
    "del": 0
   },
   {
    "sha": "cf1b676c3d",
    "subject": "test: cover zero-value wallet inputs",
    "files": 1,
    "add": 80,
    "del": 0
   },
   {
    "sha": "eba63bfe77",
    "subject": "doc: add mixed-input history RPC release note",
    "files": 1,
    "add": 26,
    "del": 0
   }
  ],
  "patch_truncated": true
 },
 "input_hash": "a72bca589ed9f040",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}