{
 "number": 36157,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/36157",
 "title": "contrib: fix dead null-byte check in linearize-data.py",
 "author": "aman21-droid",
 "author_association": "FIRST_TIME_CONTRIBUTOR",
 "created_at": "2026-09-03T06:56:06Z",
 "updated_at": "2026-09-03T06:56:19Z",
 "age_days": 14,
 "draft": false,
 "labels": [
  "Scripts and tools"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "ea4fed5aaa533d783094b4adf780b50dda3784b7",
 "head_ref": "fix/linearize-null-byte-check",
 "head_repo": "aman21-droid/bitcoin",
 "head_history": [],
 "additions": 1,
 "deletions": 1,
 "changed_files": 1,
 "commit_count": 1,
 "size_bucket": "S",
 "mergeable_state": "unstable",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {},
   "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": []
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "unstable",
  "last_author_activity": "2026-09-03T05:28:20Z",
  "last_reviewer_activity": null,
  "last_reviewer": null,
  "author_silent_days": 14,
  "waiting_on_author_days": 0,
  "days_since_update": 14
 },
 "refs": {
  "mentioned": [
   32978
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 32978,
    "type": "pull",
    "state": "closed",
    "merged": false,
    "merged_at": null,
    "title": "fix: Python 3 bytes comparison in linearize-data.py"
   }
  ],
  "conflicts": []
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [],
 "body": "`linearize-data.py` hangs on any block file that ends in zero padding.\n\nReproduce:\n\n```\nmkdir -p /tmp/lin/blocks && cd /tmp/lin\npython3 -c \"open('blocks/blk00000.dat','wb').write(bytes(4096))\"\nprintf '%064d\\n' 0 > hashlist.txt\nprintf 'input=blocks\\nhashlist=hashlist.txt\\noutput_file=bootstrap.dat\\ngenesis=%064d\\n' 0 > linearize.cfg\npython3 /path/to/bitcoin/contrib/linearize/linearize-data.py linearize.cfg\n```\n\nBefore, it never returns:\n\n```\nRead 1 hashes\nInput file blocks/blk00000.dat\n<hangs>\n```\n\nAfter:\n\n```\nRead 1 hashes\nInput file blocks/blk00000.dat\nInput file blocks/blk00001.dat\nPremature end of block data\n```\n\nIndexing a bytes object returns an int in Python 3, so `inhdr[0] == \"\\0\"` is always false and the zero-padding check never fires. The script instead falls through to the magic-bytes search, which advances one byte per iteration; at the end of the file `read(8)` returns 7 bytes and `seek(-7)` moves back to the same offset, so it loops there forever and the `Premature end of block data` path is never reached.\n\nBlock files are preallocated in `BLOCKFILE_CHUNK_SIZE` (16 MiB) chunks and only truncated once finalized, so the most recent blk*.dat normally ends in padding.\n\nThis is reached whenever the hashlist references blocks that are not in the blocks directory. The most common case is a pruned datadir, which the script explicitly supports - `getFirstBlockFileId()` starts at the first surviving blk file for exactly that reason. The intended response is \"Premature end of block data\", but that path is never reached.\n\nThis is the same one-line change as #32978, which was closed because no reproduction was provided. Happy to add a test to `test/functional/feature_loadblock.py` instead if that is preferred.",
 "commits": [
  {
   "sha": "ea4fed5aaa533d783094b4adf780b50dda3784b7",
   "date": "2026-09-03T05:28:20Z",
   "message": "contrib: fix dead null-byte check in linearize-data.py\n\nIndexing a bytes object returns an int in Python 3, so `inhdr[0] == \"\\0\"`\nis always false and the check for zero padding at the end of a block file\nnever fires.\n\nBlock files are preallocated in 16 MiB chunks and are only truncated once\nfinalized, so the most recent blk*.dat normally ends in zero padding. On\nreaching it the script scans forward one byte at a time and then loops\nforever at the end of the file, rather than moving to the next file and\nreporting \"Premature end of block data\"."
  }
 ],
 "timeline": [],
 "labels_log": [
  {
   "t": "2026-09-03T06:56:09Z",
   "action": "labeled",
   "label": "Scripts and tools",
   "who": "DrahtBot"
  }
 ],
 "state_log": [],
 "text_chars": 2342,
 "text_tokens_estimate": 585,
 "changed_paths": [
  "contrib/linearize/linearize-data.py"
 ],
 "files": [
  {
   "path": "contrib/linearize/linearize-data.py",
   "add": 1,
   "del": 1
  }
 ],
 "test_lines": 2,
 "git": {
  "head": "ea4fed5aaa533d783094b4adf780b50dda3784b7",
  "head_matches_backup": true,
  "base": "dc0395c5858a1d55239b82a834e5075cf2069219",
  "commits": [
   {
    "sha": "ea4fed5aaa",
    "subject": "contrib: fix dead null-byte check in linearize-data.py",
    "files": 1,
    "add": 1,
    "del": 1
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "91ab488ad1f63c61",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}