{
 "number": 36156,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/36156",
 "title": "mining: include chunks that exactly fill block limits",
 "author": "l0rinc",
 "author_association": "MEMBER",
 "created_at": "2026-09-03T04:28:22Z",
 "updated_at": "2026-09-15T04:50:22Z",
 "age_days": 14,
 "draft": true,
 "labels": [
  "Mining"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "dc73908d7f3a0db4e8fc0badb42ad1774a28cc70",
 "head_ref": "l0rinc/mine-exact-limit-chunks",
 "head_repo": "l0rinc/bitcoin",
 "head_history": [],
 "additions": 16,
 "deletions": 8,
 "changed_files": 2,
 "commit_count": 2,
 "size_bucket": "S",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "ismaelsadeeq",
      "url": "https://github.com/bitcoin/bitcoin/pull/36156#issuecomment-5527080808"
     }
    ]
   },
   "conflicts": [
    {
     "number": 35581,
     "title": "node: add block template manager and track waitNext fee inflow",
     "author": "ismaelsadeeq"
    }
   ]
  }
 },
 "acks_parsed": {
  "ismaelsadeeq": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-09-03T14:12:20Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 1,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "ajtowns",
   "ismaelsadeeq"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-09-03T02:37:06Z",
  "last_reviewer_activity": "2026-09-03T17:44:41Z",
  "last_reviewer": "ajtowns",
  "author_silent_days": 14,
  "waiting_on_author_days": 13,
  "days_since_update": 2
 },
 "refs": {
  "mentioned": [
   35596
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 35596,
    "type": "issue",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "`BlockAssembler` underfill  blocks and mixes reserve weights"
   }
  ],
  "conflicts": [
   35581
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [],
 "body": "Draft to get conceptual reviews first.\n\n----\n\n**Problem:** `BlockAssembler` fills block templates with mempool chunks that fit the configured weight and sigops limits, but currently rejects a chunk when it makes either total equal to its limit.\nEquality is valid: [`block_max_weight` is the maximum block weight](https://github.com/bitcoin/bitcoin/blob/b811aeabad94ef48cd0f0fb1d2fcc456594aeedb/src/node/mining_types.h#L59-L65), and [BIP 141 defines both consensus limits using `\u2264`](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#block-size).\nThe `>=` checks can therefore leave valid capacity unused and omit a fee-paying chunk.\n\n**Fix:** Use strict greater-than comparisons so exact-limit chunks are included. Extend the existing chunk-limit test to cover equality for both weight and sigops.\n\nThis addresses issue 1 in #35596.",
 "commits": [
  {
   "sha": "96ee80f7ebba4a2ecb8f582a851f2d33194377db",
   "date": "2026-09-03T02:37:06Z",
   "message": "test: characterize exact-limit chunk underfill\n\nRecord that `BlockAssembler` omits a one-transaction chunk that brings the block exactly to `block_max_weight` or `MAX_BLOCK_SIGOPS_COST`."
  },
  {
   "sha": "dc73908d7f3a0db4e8fc0badb42ad1774a28cc70",
   "date": "2026-09-03T02:37:06Z",
   "message": "mining: include exact-limit chunks\n\n`BlockAssembler` rejects a chunk that brings the block exactly to `block_max_weight` or `MAX_BLOCK_SIGOPS_COST`,\nalthough consensus accepts a block that reaches its limits exactly, so a valid fee-paying chunk is left out of the template.\n\nCompare both limits with strict greater-than so block assembly accepts equality like consensus does."
  }
 ],
 "timeline": [
  {
   "t": "2026-09-03T13:41:45Z",
   "kind": "comment",
   "who": "ajtowns",
   "assoc": "MEMBER",
   "text": "This seems backwards to me: the risk of a mistake here is that the block becomes invalid losing all possible reward from mining it, while the benefit of success is perhaps a single larger / additional transaction at the bottom of the block. Currently the bottom transaction in a block seems to pay less than 1000sats in total fees, so generously, that's less than 80c per block, as compared to the subsidy of around $240k per block."
  },
  {
   "t": "2026-09-03T14:12:20Z",
   "kind": "comment",
   "who": "ismaelsadeeq",
   "assoc": "MEMBER",
   "text": "Concept ACK\n\nLooks correct to me.\n\n[quoted text omitted]\nThis fix seems straightforward and correct, with good tests. Will the mistake come from the individual chunks sigops or  weight accounting error? If indeed we do have that error, we still could end up creating an invalid block even without this fix.\n\nIf we are confident that our accounting of weight and sigops is correct without this PR, and that the block assembler will not create an invalid block, then fixing this issue is okay.\n\n[quoted text omitted]\nI think it's less about the revenue but more about making the block assembler code correct and reflect consensus allowed limits, and making it explicit that filled blocks may be created, are valid and will be accepted as part of the blockchain.\n\nFor me the more risky part is when we allow this minor bugs in the code, it incentivise pool companies to [patch the code themselves](https://github.com/bitcoin/bitcoin/pull/31384#issuecomment-2593329870) to fix it, fwiw F2Pool did fix these bugs and have their custom binaries which create [filled blocks.](https://mempool.space/block/00000000000000000001eac8304428ea2fc5fc56e9ffefec848efde3c5a4f279)"
  },
  {
   "t": "2026-09-03T17:44:41Z",
   "kind": "comment",
   "who": "ajtowns",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nThe issue you're referencing was in regards to 500vb of wasted space, versus this PR which is a delta of 1vb of space. The block you're referring to has a 2127 WU unused:\n\n```\n$ bitcoin-cli getblock 00000000000000000001eac8304428ea2fc5fc56e9ffefec848efde3c5a4f279 | jq 4e6-.weight\n2127\n```\n\nIt's certainly bad if mining pools introduce bugs in their software that invalidate blocks while trying to get to the very edge of valid behaviour, but at least it only impacts a single pool that way. I don't see why we would want to play the same stupid game and risk winning the same stupid prize. Off by one errors are common; removing a defensive buffer against that might be appropriate if there was a significant win to be had, but there isn't here.\n\nAnyway, I've said my piece, I'll unsubscribe."
  }
 ],
 "labels_log": [
  {
   "t": "2026-09-03T04:28:26Z",
   "action": "labeled",
   "label": "Mining",
   "who": "DrahtBot"
  }
 ],
 "state_log": [],
 "text_chars": 3873,
 "text_tokens_estimate": 968,
 "changed_paths": [
  "src/node/miner.cpp",
  "src/test/miner_tests.cpp"
 ],
 "files": [
  {
   "path": "src/node/miner.cpp",
   "add": 2,
   "del": 2
  },
  {
   "path": "src/test/miner_tests.cpp",
   "add": 14,
   "del": 6
  }
 ],
 "test_lines": 20,
 "git": {
  "head": "dc73908d7f3a0db4e8fc0badb42ad1774a28cc70",
  "head_matches_backup": true,
  "base": "b811aeabad94ef48cd0f0fb1d2fcc456594aeedb",
  "commits": [
   {
    "sha": "96ee80f7eb",
    "subject": "test: characterize exact-limit chunk underfill",
    "files": 1,
    "add": 14,
    "del": 6
   },
   {
    "sha": "dc73908d7f",
    "subject": "mining: include exact-limit chunks",
    "files": 2,
    "add": 4,
    "del": 4
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "b57885cc6069e5cb",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}