{
 "number": 36313,
 "input_hash": "b79f918a9a4189be",
 "model": "ledger",
 "prompt_hash": null,
 "created": "2026-10-05T01:16:20+00:00",
 "result": {
  "summary": "Updates `CWallet::LoadLockedCoin` to set `it->second |= persistent` when an entry already exists in `m_locked_coins`. This ensures that upgrading a non-persistent lock to a persistent lock updates the in-memory flag while preventing subsequent temporary locks from downgrading a persistent lock.",
  "problem": "When a coin with an existing non-persistent lock (such as from `fundrawtransaction`) is upgraded to a persistent lock, `m_locked_coins.emplace()` leaves the in-memory persistence flag set to `false`. When the coin is subsequently spent, `UnlockCoin()` skips deleting the persistent `LOCKED_UTXO` database record, causing the spent coin to reappear as locked whenever the wallet is restarted or reloaded.",
  "card": "Updates LoadLockedCoin to set the persistence flag if an entry is already present in m_locked_coins instead of ignoring updates via emplace. Upgrading a temporary coin lock to persistent previously left the in-memory entry marked non-persistent; spending the coin then skipped deleting the persistent database record and left a phantom lock on reload. It also ensures non-persistent locking attempts cannot downgrade an existing persistent lock. Fixes issue #36304 with accompanying functional tests.",
  "evidence": [
   "Fixes issue #36304: 'wallet: upgrading a non-persistent coin lock to persistent leaves a stale lock on the spent output after restart'",
   "PR author description confirms `m_locked_coins.emplace()` did not update the value, preventing `UnlockCoin()` from erasing the database record upon spending"
  ],
  "scope_notes": "",
  "changed_since_previous": "Switched from replacing entries with `insert_or_assign` to `it->second |= persistent` on existing entries, preventing temporary locks like `fundrawtransaction` from downgrading an existing persistent lock, and added a test case for downgrade prevention.",
  "thread": {
   "last_event_at": "2026-10-04T01:42:19Z",
   "events": 8,
   "head_sha": "23dbc1fe5cc02bb3afa681b530f8ebdecdd9a51a",
   "schema_floor": 2,
   "schema": 2
  },
  "waiting_on": [
   {
    "at": "2026-10-04",
    "id": "c:5975483009",
    "on": "nothing",
    "url": "https://github.com/bitcoin/bitcoin/pull/36313#issuecomment-5975483009",
    "what": "nothing pending; objection resolved and PR has tested ACK"
   }
  ],
  "risk": {
   "level": "low",
   "touches": [
    "wallet",
    "wallet_storage",
    "tests"
   ],
   "why": "Flaws in wallet coin lock state tracking could lead to spent coins remaining locked or unspent coins failing to unlock properly across restarts."
  },
  "discussion": {
   "author_status": "last statement processed 2026-10-04",
   "open_concerns": [],
   "resolved_concerns": [
    "achow101: Use insert_or_assign rather than setting the fields afterwards on failed emplacement (fixed by ArvinFarrelP 2026-09-30)",
    "jcastros: A non-persistent lock overwrites an existing persistent lock in memory without removing the db record, causing spent outputs to be restored as locked on reload (accepted by jcastros 2026-10-04)"
   ]
  },
  "reviewability": {
   "state": "Ready",
   "label": "Ready",
   "reason": "Nothing known that would invalidate a review now."
  },
  "agreement": {
   "state": "Strong",
   "summary": "Strong: substantive support, no open objection (vicjuma, vicjuma, jcastros, jcastros)",
   "reason": "Author pushed a fix preventing non-persistent locks from downgrading persistent ones along with a regression test; jcastros verified the fix and gave a Tested ACK.",
   "evidence": [
    "vicjuma: Concept ACK \u2014 offers good UX and existing RPC validation already supports upgrading from non-persistent to persistent in a single call",
    "vicjuma: support \u2014 tested solution and confirmed before/after behavior works as expected",
    "jcastros: Concept ACK \u2014 Concept ACK on fixing #36304",
    "jcastros: Tested ACK \u2014 verified persistent lock is not downgraded when spent with lockUnspents=true across unload/load wallet, and regression test catches insert_or_assign behavior"
   ],
   "objections": [
    {
     "reviewer": "achow101",
     "association": "MEMBER",
     "type": "suggestion",
     "kind": "approach",
     "harm": "",
     "request": "Use insert_or_assign rather than setting the fields afterwards on failed emplacement",
     "question": "",
     "text": "Use insert_or_assign rather than setting the fields afterwards on failed emplacement",
     "clears_with": "answer",
     "blocking": false,
     "status": "fixed",
     "status_note": "author updated the code to use insert_or_assign",
     "cleared": true,
     "author_replied": true,
     "others_replied": false,
     "fix_pushed": true,
     "replies": [
      "rc:4141254523"
     ],
     "evidence": "2026-09-29: 'This can use `insert_or_assign` rather than setting the fields afterwards on failed emplacement.'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36313#discussion_r4138795110",
     "id": "rc:4138795110",
     "at": "2026-09-29",
     "status_at": "2026-09-30",
     "status_by": "ArvinFarrelP",
     "resolution_evidence": "2026-09-30: ArvinFarrelP: 'I've updated the code to use `insert_or_assign` as suggested.'",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "jcastros",
     "association": "NONE",
     "type": "objection",
     "kind": "correctness",
     "harm": "A non-persistent lock overwrites an existing persistent lock in memory without removing the db record, causing spent outputs to be restored as locked on reload",
     "request": "",
     "question": "",
     "text": "A non-persistent lock overwrites an existing persistent lock in memory without removing the db record, causing spent outputs to be restored as locked on reload",
     "clears_with": "change",
     "blocking": true,
     "status": "accepted",
     "status_note": "author fixed downgrade and added test; reviewer confirmed and Tested ACKed",
     "cleared": true,
     "author_replied": true,
     "others_replied": false,
     "fix_pushed": true,
     "replies": [
      "c:5975240001"
     ],
     "evidence": "2026-10-03: 'The other direction looks broken. Lock the coin with `lockunspent` persistent, then spend that same coin. On the base, `listlockunspent` is empty before and after a reload. On this commit it is empty '",
     "url": "https://github.com/bitcoin/bitcoin/pull/36313#issuecomment-5970820999",
     "id": "c:5970820999",
     "at": "2026-10-03",
     "status_at": "2026-10-04",
     "status_by": "jcastros",
     "resolution_evidence": "2026-10-04: jcastros: 'Tested ACK 23dbc1fe5c. The downgrade is gone.'",
     "pin": null,
     "from_schema": 2
    }
   ],
   "support": [
    {
     "reviewer": "vicjuma",
     "reason": "offers good UX and existing RPC validation already supports upgrading from non-persistent to persistent in a single call",
     "substantive": true,
     "verdict": "Concept ACK",
     "id": "r:5291418009",
     "url": "https://github.com/bitcoin/bitcoin/pull/36313#pullrequestreview-5291418009",
     "at": "2026-09-23",
     "association": "CONTRIBUTOR",
     "evidence": "read",
     "areas": []
    },
    {
     "reviewer": "vicjuma",
     "reason": "tested solution and confirmed before/after behavior works as expected",
     "substantive": true,
     "verdict": "",
     "id": "rc:4082789218",
     "url": "https://github.com/bitcoin/bitcoin/pull/36313#discussion_r4082789218",
     "at": "2026-09-23",
     "association": "CONTRIBUTOR",
     "evidence": "tested",
     "areas": []
    },
    {
     "reviewer": "jcastros",
     "reason": "Concept ACK on fixing #36304",
     "substantive": true,
     "verdict": "Concept ACK",
     "id": "c:5970820999",
     "url": "https://github.com/bitcoin/bitcoin/pull/36313#issuecomment-5970820999",
     "at": "2026-10-03",
     "association": "NONE",
     "evidence": "none",
     "areas": []
    },
    {
     "reviewer": "jcastros",
     "reason": "verified persistent lock is not downgraded when spent with lockUnspents=true across unload/load wallet, and regression test catches insert_or_assign behavior",
     "substantive": true,
     "verdict": "Tested ACK",
     "id": "c:5975483009",
     "url": "https://github.com/bitcoin/bitcoin/pull/36313#issuecomment-5975483009",
     "at": "2026-10-04",
     "association": "NONE",
     "evidence": "both",
     "areas": [
      "test/functional/wallet_basic.py"
     ]
    }
   ],
   "participants": [
    {
     "login": "vicjuma",
     "stance": "support",
     "note": "Concept ACK and manual testing confirmation",
     "association": "CONTRIBUTOR",
     "comments": 2,
     "first": "2026-09-23",
     "last": "2026-09-23"
    },
    {
     "login": "achow101",
     "stance": "neutral",
     "note": "suggested using insert_or_assign",
     "association": "MEMBER",
     "comments": 1,
     "first": "2026-09-29",
     "last": "2026-09-29"
    },
    {
     "login": "jcastros",
     "stance": "objection",
     "note": "objected to persistent lock downgrade regression, then Tested ACK after fix",
     "association": "NONE",
     "comments": 2,
     "first": "2026-10-03",
     "last": "2026-10-04"
    }
   ],
   "derivation": "substantive support, no open objection (vicjuma, vicjuma, jcastros, jcastros)",
   "model_state": null,
   "corrections": [],
   "notes": "Author pushed a fix preventing non-persistent locks from downgrading persistent ones along with a regression test; jcastros verified the fix and gave a Tested ACK."
  },
  "dependencies": {
   "depends_on": [],
   "enables": []
  },
  "categories": [
   {
    "name": "wallet",
    "member": true,
    "evidence": "Matches the Wallet label and modifies coin locking logic in `src/wallet/wallet.cpp`.",
    "band": "P3",
    "reason_tag": "bug fix",
    "score": 0.35,
    "factors": {
     "bug_severity": 1,
     "leverage": 0,
     "performance": 0,
     "security_stability": 1,
     "user_value": 1
    },
    "rationale": "Fixes a bug where upgrading an existing non-persistent coin lock to persistent leaves stale `LOCKED_UTXO` records in the database if the coin is spent, causing spent coins to reappear as locked upon wallet reload (#36304). While an annoying state inconsistency, it is an edge-case locking bug that does not risk funds or wallet corruption, making it reasonably deferrable."
   }
  ],
  "confidence": "high",
  "uncertainties": [],
  "needs": []
 },
 "cost_usd": 0.0,
 "source": {
  "record": "2026-10-05T01:16:20+00:00",
  "code": "2026-10-05T01:18:40+00:00",
  "judgments": 1
 }
}