{
 "number": 36482,
 "input_hash": "e344ba8ef02b3050",
 "model": "ledger",
 "prompt_hash": null,
 "created": "2026-10-26T01:22:21+00:00",
 "result": {
  "summary": "Adds a new broadcast mode, MEMPOOL_AND_BROADCAST_ADDED, to node transaction broadcast handling and switches periodic wallet rebroadcasts to use it. Transactions already present in the local mempool are retained without being rebroadcast to peers, while transactions that had dropped out and were re-added to the mempool are broadcast. The wallet resend functional test suite is refactored into isolated test methods and expanded to cover mempool-present rebroadcast suppression and wallet-load resubmission.",
  "problem": "Periodic wallet rebroadcasts unconditionally announce unconfirmed transactions to any connected peers that have not yet received an inventory for them, even if the transaction has resided continuously in the node's mempool. This redundant relay signals to peers that the node has a special interest in the transaction, leaking the user's IP and wallet ownership.",
  "card": "Restricts periodic wallet transaction rebroadcasting to only announce transactions to peers if they were missing from the mempool and successfully re-added. Previously, unconfirmed transactions were unconditionally rebroadcast to peers that had not yet seen an inv, even when already present in the local mempool, leaking transaction ownership and node IP. Addresses privacy leak concerns raised in issue #36403.",
  "evidence": [
   "PR description references issue #36403 ('Rethinking Transaction Rebroadcasting') and #3828: 'one of the issues with current rebroadcast behavior is that the rebroadcast begins an unconditional relay of a transaction to peers... there is still a privacy leak in this double relay of a transaction, especially so for transactions that are still in nodes' mempools.'"
  ],
  "scope_notes": "Most of the diff (+141/-63) is in `test/functional/wallet_resendwallettransactions.py`, refactoring a single procedural test into isolated helper methods and adding test coverage for load-time resubmissions and rebroadcast suppression.",
  "changed_since_previous": "",
  "thread": {
   "last_event_at": "2026-10-25T07:43:22Z",
   "events": 4,
   "head_sha": "4dbd27f37b52e49a8d392bd2ee6713ae7dcf23df",
   "schema_floor": 2,
   "schema": 2
  },
  "waiting_on": [
   {
    "at": "2026-10-09",
    "id": "rc:4231801500",
    "on": "author",
    "url": "https://github.com/bitcoin/bitcoin/pull/36482#discussion_r4231801500",
    "what": "response to mzumsande's objection regarding address probing"
   },
   {
    "at": "2026-10-25",
    "id": "c:6395009208",
    "on": "author",
    "url": "https://github.com/bitcoin/bitcoin/pull/36482#issuecomment-6395009208",
    "what": "response to fametrano's testing results and suggestions"
   }
  ],
  "risk": {
   "level": "medium",
   "touches": [
    "wallet",
    "p2p"
   ],
   "why": "A flaw in mempool detection or broadcast mode handling could prevent dropped wallet transactions from rebroadcasting to peers, leaving them unconfirmed until manual user intervention."
  },
  "discussion": {
   "author_status": "last statement processed 2026-10-25",
   "open_concerns": [
    "mzumsande: An attacker can use the replacement pattern to probe which nodes an address belongs to, leaving the receiver privacy issue from #3828 unresolved.",
    "fametrano: Extend test_resubmit_on_load past the first periodic resubmission to pin the intended rebroadcast behaviour",
    "fametrano: Update the comment above ResubmitWalletTransactions referencing MEMPOOL_AND_BROADCAST_TO_ALL and adjust the log message counting unconfirmed transactions"
   ],
   "resolved_concerns": [
    "murchandamus: Whether the combination of MEMPOOL_NO_BROADCAST on wallet loading and MEMPOOL_AND_BROADCAST_ADDED on rebroadcast could prevent a transaction from being resubmitted if the node was offline during a mempool spike that purged the transaction from the network (answered by fametrano 2026-10-25)"
   ]
  },
  "reviewability": {
   "state": "Paused",
   "label": "Waiting on author",
   "reason": "Open objections from fametrano, mzumsande with no author reply for 7 days; review would repeat what has been asked."
  },
  "agreement": {
   "state": "Mild",
   "summary": "Mild: objection that needs an answer has none yet (mzumsande)",
   "reason": "fametrano answered murchandamus's question by testing on regtest, confirming that transactions kept in the mempool are not rebroadcast after restart, and suggested test extensions and updating comments and log strings.",
   "evidence": [
    "mzumsande (objection, safety, must be answered, open): An attacker can use the replacement pattern to probe which nodes an address belongs to, leaving the receiver privacy issue from #3828 unresolved.",
    "fametrano (suggestion, maintenance, must be answered, open): Extend test_resubmit_on_load past the first periodic resubmission to pin the intended rebroadcast behaviour",
    "fametrano (suggestion, maintenance, must be answered, open): Update the comment above ResubmitWalletTransactions referencing MEMPOOL_AND_BROADCAST_TO_ALL and adjust the log message counting unconfirmed transactions",
    "polespinasa: Concept ACK",
    "murchandamus: support \u2014 This is an obvious privacy improvement."
   ],
   "objections": [
    {
     "reviewer": "mzumsande",
     "association": "MEMBER",
     "type": "objection",
     "kind": "safety",
     "harm": "An attacker can use the replacement pattern to probe which nodes an address belongs to, leaving the receiver privacy issue from #3828 unresolved.",
     "request": "",
     "question": "",
     "text": "An attacker can use the replacement pattern to probe which nodes an address belongs to, leaving the receiver privacy issue from #3828 unresolved.",
     "clears_with": "answer",
     "blocking": false,
     "status": "open",
     "status_note": "",
     "cleared": false,
     "author_replied": false,
     "others_replied": false,
     "fix_pushed": false,
     "replies": [],
     "evidence": "2026-10-09: 'This replacement pattern with `indep_utxo` is just the mechanism that an attacker could do to probe for which nodes a given address belong to, so this doesn't appear to completely solve the receiver i'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36482#discussion_r4231801500",
     "id": "rc:4231801500",
     "at": "2026-10-09",
     "status_at": null,
     "status_by": null,
     "resolution_evidence": "",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "murchandamus",
     "association": "MEMBER",
     "type": "question",
     "kind": "correctness",
     "harm": "",
     "request": "",
     "question": "Whether the combination of MEMPOOL_NO_BROADCAST on wallet loading and MEMPOOL_AND_BROADCAST_ADDED on rebroadcast could prevent a transaction from being resubmitted if the node was offline during a mempool spike that purged the transaction from the network",
     "text": "Whether the combination of MEMPOOL_NO_BROADCAST on wallet loading and MEMPOOL_AND_BROADCAST_ADDED on rebroadcast could prevent a transaction from being resubmitted if the node was offline during a mempool spike that purged the transaction from the network",
     "clears_with": "answer",
     "blocking": false,
     "status": "answered",
     "status_note": "fametrano confirmed with regtest tests that transactions retained in the local mempool are not reannounced after restart",
     "cleared": true,
     "author_replied": false,
     "others_replied": true,
     "fix_pushed": false,
     "replies": [
      "c:6395009208"
     ],
     "evidence": "2026-10-21: 'The only open question I have at the moment is whether the combination of using `MEMPOOL_NO_BROADCAST` on wallet loading and then `MEMPOOL_AND_BROADCAST_ADDED` on the wallet\u2019s rebroadcast could preven'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36482#pullrequestreview-5604335981",
     "id": "r:5604335981",
     "at": "2026-10-21",
     "status_at": "2026-10-25",
     "status_by": "fametrano",
     "resolution_evidence": "2026-10-25: fametrano: 'After a restart, this branch does not announce a wallet transaction that peers already received while our own mempool keeps it, so the answer to murch's question is yes.'",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "fametrano",
     "association": "CONTRIBUTOR",
     "type": "suggestion",
     "kind": "maintenance",
     "harm": "",
     "request": "Extend test_resubmit_on_load past the first periodic resubmission to pin the intended rebroadcast behaviour",
     "question": "",
     "text": "Extend test_resubmit_on_load past the first periodic resubmission to pin the intended rebroadcast behaviour",
     "clears_with": "answer",
     "blocking": false,
     "status": "open",
     "status_note": "",
     "cleared": false,
     "author_replied": false,
     "others_replied": false,
     "fix_pushed": false,
     "replies": [],
     "evidence": "2026-10-25: 'test_resubmit_on_load stops before the first periodic resubmission; extending it would pin whichever behaviour is intended.'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36482#issuecomment-6395009208",
     "id": "c:6395009208",
     "at": "2026-10-25",
     "status_at": null,
     "status_by": null,
     "resolution_evidence": "",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "fametrano",
     "association": "CONTRIBUTOR",
     "type": "suggestion",
     "kind": "maintenance",
     "harm": "",
     "request": "Update the comment above ResubmitWalletTransactions referencing MEMPOOL_AND_BROADCAST_TO_ALL and adjust the log message counting unconfirmed transactions",
     "question": "",
     "text": "Update the comment above ResubmitWalletTransactions referencing MEMPOOL_AND_BROADCAST_TO_ALL and adjust the log message counting unconfirmed transactions",
     "clears_with": "answer",
     "blocking": false,
     "status": "open",
     "status_note": "",
     "cleared": false,
     "author_replied": false,
     "others_replied": false,
     "fix_pushed": false,
     "replies": [],
     "evidence": "2026-10-25: 'Smaller: the comment above ResubmitWalletTransactions still names MEMPOOL_AND_BROADCAST_TO_ALL for the periodic path, and \"resubmit N unconfirmed transactions\" now counts transactions not relayed.'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36482#issuecomment-6395009208",
     "id": "c:6395009208#2",
     "at": "2026-10-25",
     "status_at": null,
     "status_by": null,
     "resolution_evidence": "",
     "pin": null,
     "from_schema": 2
    }
   ],
   "support": [
    {
     "reviewer": "polespinasa",
     "reason": "",
     "substantive": false,
     "verdict": "Concept ACK",
     "id": "c:6070254413",
     "url": "https://github.com/bitcoin/bitcoin/pull/36482#issuecomment-6070254413",
     "at": "2026-10-08",
     "association": "MEMBER",
     "evidence": "none",
     "areas": []
    },
    {
     "reviewer": "murchandamus",
     "reason": "This is an obvious privacy improvement.",
     "substantive": true,
     "verdict": "",
     "id": "r:5604335981",
     "url": "https://github.com/bitcoin/bitcoin/pull/36482#pullrequestreview-5604335981",
     "at": "2026-10-21",
     "association": "MEMBER",
     "evidence": "read",
     "areas": []
    }
   ],
   "participants": [
    {
     "login": "polespinasa",
     "stance": "support",
     "note": "Concept ACK with no rationale",
     "association": "MEMBER",
     "comments": 1,
     "first": "2026-10-08",
     "last": "2026-10-08"
    },
    {
     "login": "mzumsande",
     "stance": "objection",
     "note": "points out an attacker can use this replacement pattern to probe node addresses, leaving the receiver issue open",
     "association": "MEMBER",
     "comments": 1,
     "first": "2026-10-09",
     "last": "2026-10-09"
    },
    {
     "login": "murchandamus",
     "stance": "support",
     "note": "praises the privacy improvement while asking whether transactions could fail to rebroadcast after being offline",
     "association": "MEMBER",
     "comments": 1,
     "first": "2026-10-21",
     "last": "2026-10-21"
    },
    {
     "login": "fametrano",
     "stance": "neutral",
     "note": "tested rebroadcast behavior, answered murchandamus's question, and suggested test and comment updates",
     "association": "CONTRIBUTOR",
     "comments": 1,
     "first": "2026-10-25",
     "last": "2026-10-25"
    }
   ],
   "derivation": "objection that needs an answer has none yet (mzumsande)",
   "model_state": null,
   "corrections": [],
   "notes": "fametrano answered murchandamus's question by testing on regtest, confirming that transactions kept in the mempool are not rebroadcast after restart, and suggested test extensions and updating comments and log strings."
  },
  "dependencies": {
   "depends_on": [],
   "enables": []
  },
  "categories": [
   {
    "name": "tests",
    "member": false,
    "evidence": "Touches test/functional/test_framework/p2p.py (+7/-0) only as a minor helper to support wallet functional test coverage.",
    "band": "Unranked",
    "reason_tag": "test coverage",
    "score": 0.0,
    "factors": {
     "bug_severity": 1,
     "leverage": 0,
     "performance": 0,
     "security_stability": 1,
     "user_value": 2
    },
    "rationale": "The test changes are dedicated to verifying wallet rebroadcast suppression rather than general test harness or runner infrastructure."
   },
   {
    "name": "wallet",
    "member": true,
    "evidence": "Has the Wallet label, modifies wallet rebroadcast logic in src/wallet/wallet.cpp, and updates wallet_resendwallettransactions.py.",
    "band": "P2",
    "reason_tag": "bug fix",
    "score": 0.65,
    "factors": {
     "bug_severity": 1,
     "leverage": 0,
     "performance": 0,
     "security_stability": 1,
     "user_value": 2
    },
    "rationale": "Fixes a wallet privacy leak where periodic transaction rebroadcasts unconditionally relay transactions already resident in the local mempool. As noted in the description citing issue #36403, redundant rebroadcasts leak user IP and transaction ownership by signaling to peers that the node has special interest in those transactions."
   }
  ],
  "confidence": "high",
  "uncertainties": [],
  "needs": []
 },
 "cost_usd": 0.0,
 "source": {
  "record": "2026-10-26T01:22:21+00:00",
  "code": "2026-10-10T01:25:51+00:00",
  "judgments": 2
 }
}