{
 "number": 36542,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/36542",
 "title": "AssumeUTXO: allow retrying loadtxoutset after an interrupted load",
 "author": "l0rinc",
 "author_association": "MEMBER",
 "created_at": "2026-10-15T11:35:04Z",
 "updated_at": "2026-10-30T23:32:13Z",
 "description_hash": "9d45f828dfb7e117",
 "age_days": 17,
 "draft": false,
 "labels": [
  "Validation"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "15a891d4021e0cf8c009127721ee1f1702dd9471",
 "head_ref": "l0rinc/assumeutxo-recover-cleanup",
 "head_repo": "l0rinc/bitcoin",
 "head_history": [
  {
   "t": "2026-10-20T22:04:30Z",
   "sha": "6cd9fd01beb00377252bf162bdf9d702c93a8c90"
  },
  {
   "t": "2026-10-21T09:04:37Z",
   "sha": "15a891d4021e0cf8c009127721ee1f1702dd9471"
  }
 ],
 "additions": 7,
 "deletions": 3,
 "changed_files": 3,
 "commit_count": 2,
 "size_bucket": "S",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "ack": [
     {
      "login": "cyb3ralbert",
      "url": "https://github.com/bitcoin/bitcoin/pull/36542#issuecomment-6497227759"
     }
    ]
   },
   "conflicts": []
  }
 },
 "acks_parsed": {},
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 0,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "cyb3ralbert"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-10-21T09:05:47Z",
  "last_reviewer_activity": "2026-10-29T12:54:17Z",
  "last_reviewer": "cyb3ralbert",
  "author_silent_days": 11,
  "waiting_on_author_days": 3,
  "days_since_update": 2
 },
 "refs": {
  "mentioned": [],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [],
  "conflicts": []
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [],
 "body": "**Problem:** An interrupted `loadtxoutset` can leave an incomplete `chainstate_snapshot` database without its required `base_blockhash` marker. A later call can fail to open that database, requiring the operator to remove it manually before retrying.\n\n**Fix:** Wipe the snapshot database before opening it so a later call can replace incomplete data. LevelDB acquires the database lock before deleting files, so a database held open by another load cannot be wiped. Also correct the startup warning to identify the missing marker and explain that retrying replaces the directory.",
 "commits": [
  {
   "sha": "00b1aa6116c66e7c5164ded8f53a3b394a462b79",
   "date": "2026-10-21T08:48:39Z",
   "message": "test: characterize incomplete snapshot database retry\n\nRecord that an incomplete snapshot database prevents loadtxoutset until the operator removes its directory."
  },
  {
   "sha": "15a891d4021e0cf8c009127721ee1f1702dd9471",
   "date": "2026-10-21T08:48:39Z",
   "message": "validation: replace incomplete snapshot databases when loading\n\nAn interrupted snapshot load can leave a database without its base-block marker, preventing later loadtxoutset attempts.\nWipe the snapshot database before opening it so callers can retry without removing the directory manually.\nCorrect the startup warning to point at the missing marker and say that a retry replaces the directory."
  }
 ],
 "timeline": [
  {
   "t": "2026-10-20T22:04:30Z",
   "kind": "force_push",
   "who": "l0rinc",
   "commit": "6cd9fd01beb00377252bf162bdf9d702c93a8c90",
   "id": "push:6cd9fd01beb00377252bf162bdf9d702c93a8c90"
  },
  {
   "t": "2026-10-21T09:04:37Z",
   "kind": "force_push",
   "who": "l0rinc",
   "commit": "15a891d4021e0cf8c009127721ee1f1702dd9471",
   "id": "push:15a891d4021e0cf8c009127721ee1f1702dd9471"
  },
  {
   "t": "2026-10-21T09:05:47Z",
   "kind": "comment",
   "who": "l0rinc",
   "assoc": "MEMBER",
   "text": "Found a simpler fix using the existing database wipe option, which lets interrupted loads be retried.",
   "id": "c:6312238071",
   "url": "https://github.com/bitcoin/bitcoin/pull/36542#issuecomment-6312238071",
   "hash": "f86367a0f4b41f99",
   "edited": null
  },
  {
   "t": "2026-10-29T12:54:17Z",
   "kind": "comment",
   "who": "cyb3ralbert",
   "assoc": "CONTRIBUTOR",
   "text": "Should the regression test also cover a snapshot database whose LOCK is held by another process?\n\ntACK 15a891d4021e0cf8c009127721ee1f1702dd9471\n\nTested on Linux aarch64 (Debian 13, GCC 14.2.0):\n- `restart-retry-pruned`, `restart-retry-default`, `readable-leftover-retry`, and `locked-leftover-retry` passed. The locked case returned RPC error `-1`, left the database files unchanged, and the retry succeeded after the lock was released.\n- `feature_assumeutxo.py` passed in a direct slot run on the same head.",
   "id": "c:6497227759",
   "url": "https://github.com/bitcoin/bitcoin/pull/36542#issuecomment-6497227759",
   "hash": "5e5e28bfcce7308e",
   "edited": null
  }
 ],
 "labels_log": [
  {
   "t": "2026-10-15T11:35:08Z",
   "action": "labeled",
   "label": "Validation",
   "who": "DrahtBot"
  },
  {
   "t": "2026-10-20T22:49:24Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-10-21T09:42:59Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2026-10-20T11:25:15Z",
   "kind": "renamed",
   "who": "l0rinc",
   "from": "validation: remove leftover AssumeUTXO cleanup data",
   "to": "validation: clean up failed AssumeUTXO databases"
  },
  {
   "t": "2026-10-21T09:02:56Z",
   "kind": "renamed",
   "who": "l0rinc",
   "from": "validation: clean up failed AssumeUTXO databases",
   "to": "AssumeUTXO: allow retrying loadtxoutset after an interrupted load"
  }
 ],
 "text_chars": 1816,
 "text_tokens_estimate": 454,
 "changed_paths": [
  "src/node/utxo_snapshot.cpp",
  "src/validation.cpp",
  "test/functional/feature_assumeutxo.py"
 ],
 "files": [
  {
   "path": "src/node/utxo_snapshot.cpp",
   "add": 2,
   "del": 2
  },
  {
   "path": "src/validation.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "test/functional/feature_assumeutxo.py",
   "add": 4,
   "del": 0
  }
 ],
 "test_lines": 4,
 "git": {
  "head": "15a891d4021e0cf8c009127721ee1f1702dd9471",
  "head_matches_backup": true,
  "base": "4303f3b7f0775cdbbe77faddf142e1e44fa590ca",
  "patch_id": "9b613a7c94b2e63d",
  "commits": [
   {
    "sha": "00b1aa6116",
    "subject": "test: characterize incomplete snapshot database retry",
    "files": 1,
    "add": 5,
    "del": 2
   },
   {
    "sha": "15a891d402",
    "subject": "validation: replace incomplete snapshot databases when loading",
    "files": 3,
    "add": 6,
    "del": 5
   }
  ],
  "patch_truncated": false
 },
 "patch_id": "9b613a7c94b2e63d",
 "input_hash": "0cf5268437443ff7",
 "extracted_at": "2026-11-02T01:09:49+00:00"
}