{
 "number": 35522,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/35522",
 "title": "refactor: Extract per-message helpers from SendMessages() (move-only)",
 "author": "pablomartin4btc",
 "author_association": "MEMBER",
 "created_at": "2026-06-12T23:48:32Z",
 "updated_at": "2026-09-15T09:07:23Z",
 "age_days": 96,
 "draft": false,
 "labels": [
  "Refactoring",
  "Needs rebase"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "03c5b2ba6d59ba63751bbc26cb7574ab7a041df4",
 "head_ref": "refactor/extract-sendmessages-helpers",
 "head_repo": "pablomartin4btc/bitcoin",
 "head_history": [
  {
   "t": "2026-06-15T14:23:46Z",
   "sha": "06741a6f9da38d15d288847659724806075984a3"
  },
  {
   "t": "2026-08-12T23:40:12Z",
   "sha": "03c5b2ba6d59ba63751bbc26cb7574ab7a041df4"
  }
 ],
 "additions": 661,
 "deletions": 424,
 "changed_files": 1,
 "commit_count": 17,
 "size_bucket": "XL",
 "mergeable_state": "unknown",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "hodlinator",
      "url": "https://github.com/bitcoin/bitcoin/pull/35522#pullrequestreview-5207925196"
     }
    ],
    "approach_ack": [
     {
      "login": "w0xlt",
      "url": "https://github.com/bitcoin/bitcoin/pull/35522#pullrequestreview-4492597174"
     }
    ]
   },
   "conflicts": [
    {
     "number": 36080,
     "title": "p2p: Suspend ping timeout while downloading blocks from a peer",
     "author": "mzumsande"
    },
    {
     "number": 35591,
     "title": "[DO NOT MERGE] Erlay: bandwidth-efficient transaction relay protocol (Full implementation)",
     "author": "sr-gi"
    },
    {
     "number": 35561,
     "title": "net: move some CNodeState fields to Peer",
     "author": "Crypt-iQ"
    },
    {
     "number": 35558,
     "title": "p2p: Prefill compact blocks",
     "author": "davidgumberg"
    },
    {
     "number": 35229,
     "title": "refactor: Use CBlockIndex parameters as reference",
     "author": "optout21"
    },
    {
     "number": 34743,
     "title": "p2p: don't disconnect manual peers for block stalling",
     "author": "willcl-ark"
    },
    {
     "number": 33854,
     "title": "fix assumevalid is ignored during reindex",
     "author": "Eunovo"
    }
   ]
  }
 },
 "acks_parsed": {
  "w0xlt": {
   "kind": "approach_ack",
   "hash": null,
   "t": "2026-06-14T07:48:55Z",
   "stale": false
  },
  "hodlinator": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-09-15T09:07:20Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 1,
  "approach_ack": 1,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "hodlinator",
   "w0xlt"
  ]
 },
 "signals": {
  "needs_rebase": true,
  "ci_failed": false,
  "mergeable_state": "unknown",
  "last_author_activity": "2026-08-13T01:14:12Z",
  "last_reviewer_activity": "2026-09-15T09:07:20Z",
  "last_reviewer": "hodlinator",
  "author_silent_days": 35,
  "waiting_on_author_days": 2,
  "days_since_update": 2
 },
 "refs": {
  "mentioned": [
   9579,
   34059,
   34824,
   35148,
   35502,
   35535
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 34824,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "net: encapsulate TxRelay state and replace recursive mutexes"
   },
   {
    "number": 35502,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "refactor: extract per-message helpers from ProcessMessage (move-only)"
   },
   {
    "number": 35148,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-04-25",
    "title": "refactor: Remove confusing DataStream::in_avail() alias"
   },
   {
    "number": 34059,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-03-20",
    "title": "refactor: Use NodeClock::time_point for m_addr_token_timestamp"
   },
   {
    "number": 9579,
    "type": "pull",
    "state": "closed",
    "merged": false,
    "merged_at": null,
    "title": "Net: Trivial-review: Make SendMessages easier to review"
   },
   {
    "number": 35535,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-06-15",
    "title": "iwyu: Fix warning in `bench/pool.cpp`"
   }
  ],
  "conflicts": [
   36080,
   35591,
   35561,
   35558,
   35229,
   34743,
   33854
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "src/net_processing.cpp"
 ],
 "body": "`PeerManagerImpl::SendMessages()` is a ~500-line function handling every p2p conditional send message type inline, which makes it hard to navigate and review. This was reduced to less than 90 lines.\n\nI've [identified](https://github.com/bitcoin/bitcoin/pull/34824#pullrequestreview-4445529843) this issue/ possible improvement while reviewing #34824.\n\nThis follows the pattern of similar PRs (#35502, and some commits fa5ab02 - from #35148 -, and fa55723 from #34059 ) and there was also a previous attempt in #9579 mentioned in some related PR's refactoring [comment](https://github.com/bitcoin/bitcoin/pull/9608#issuecomment-283545547).\n\n-<ins>_**Notes**_</ins>:\n\nEach of the 17 commits represents a helper function extraction so it can be easily reviewed, it's only a pure code move, the only new lines are the declaration (with thread-safety annotations), the function signature, and the one-line call site, and they can be reviewed with the git options:\n`--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space`.",
 "commits": [
  {
   "sha": "4994f71dc955dc8a222cb72a068e71bff6dc970a",
   "date": "2026-08-12T23:12:10Z",
   "message": "move-only: Extract ScheduleTxRelayTrickle() helper\n\nExtracts the periodic relay scheduling logic from the tx-relay section\nof SendMessages() into a self-contained helper. The helper determines\nwhether it is time to trickle inventory to a peer and clears the\npending inventory set if the peer has requested no transaction relay.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "852d4414c43989e908995e2148cda7e922be400f",
   "date": "2026-08-12T23:14:45Z",
   "message": "move-only: Extract MaybeSendMempoolResponse() helper\n\nExtracts the BIP35 mempool-response block from the tx-relay section of\nSendMessages() into a self-contained helper. The m_send_mempool guard\nmoves inside as an early return, keeping the call site a single line.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "5bc8bc93e76abfcdd51ef6f37870c86a98d3af2c",
   "date": "2026-08-12T23:32:53Z",
   "message": "move-only: Extract MaybeSendTxInventory() helper\n\nExtracts the regular tx-inventory relay selection block from the\ntx-relay section of SendMessages() into a self-contained helper.\nThe helper covers candidate collection, heap-based fee/topology\nsorting, bloom/feerate filtering, and the m_last_inv_sequence update.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "1ebdde981521669e7ffb91939a652799830ae778",
   "date": "2026-08-12T23:32:53Z",
   "message": "move-only: Extract MaybeSendInitialGetheaders() helper\n\nExtracts the initial headers-sync kick-off block from SendMessages()\ninto a self-contained helper. The helper handles the fSyncStarted\nguard, the single-peer-or-close-to-tip condition, the getheaders\nlocator construction, and the timeout initialisation.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "47d622a0f1d1c0b713480710ced514b562c7cba6",
   "date": "2026-08-12T23:32:53Z",
   "message": "move-only: Extract MaybeSendBlockAnnouncements() helper\n\nExtracts the block-announcement section from SendMessages() into a\nself-contained helper. The helper covers header-relay candidate\nselection, compact-block sending (with cached-message optimisation),\nmulti-header relay, and the inv fallback path.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "9d24eee37c7e9af03fec68b1c2838ee69b2a17f4",
   "date": "2026-08-12T23:33:43Z",
   "message": "move-only: Extract MaybeSendBlockInv() helper\n\nExtracts the block-inv drain loop from SendMessages() into a\nself-contained helper. The helper flushes m_blocks_for_inv_relay\ninto the caller-provided vInv vector so downstream tx-relay\nlogic can continue appending to the same batch.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "5c603dd3cc04303588b065fd18624ccd0d19edd9",
   "date": "2026-08-12T23:33:43Z",
   "message": "move-only: Extract CheckBlockSyncTimeouts() helper\n\nExtracts the three timeout/stall checks from SendMessages() into a\nself-contained helper: block-download stall detection (with adaptive\ntimeout backoff), per-block in-flight timeout, and headers-sync\ntimeout. Returns true when a disconnect was triggered so the caller\ncan early-return, preserving identical semantics.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "1c93ec4c8de87b6102d63e4225ef28bc809291e0",
   "date": "2026-08-12T23:33:43Z",
   "message": "move-only: Extract MaybeSendGetData() helper\n\nExtracts the getdata section from SendMessages() into a self-contained\nhelper. The helper covers block requests (FindNextBlocksToDownload and\nhistorical-block ranges), transaction download requests, and the final\ngetdata flush. vGetData is local to the helper; the m_tx_download_mutex\nacquisition moves inside.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "88e1d0ef52661d7e559ce5ae9a1cb6dfeae76f2a",
   "date": "2026-08-12T23:33:43Z",
   "message": "move-only: Extract SendCompactBlockOrHeaders() helper\n\nExtracts the compact-block/headers send path from\nMaybeSendBlockAnnouncements() into a self-contained helper. The helper\nchooses between a compact-block (with cached-message optimisation),\na headers message, or sets fRevertToInv when neither format applies.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "e02e05c198115f4274dd5bac47a298d80301f847",
   "date": "2026-08-12T23:33:43Z",
   "message": "move-only: Extract SendBlockInvFallback() helper\n\nExtracts the inv-fallback path from MaybeSendBlockAnnouncements() into\na self-contained helper. The helper inv-announces the chain tip when\nneither a headers nor a compact-block relay was possible.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "6c47f463b290a8c797585d0a521d503898e73fb0",
   "date": "2026-08-12T23:33:43Z",
   "message": "move-only: Extract CheckBlockDownloadStall() helper\n\nExtracts the stall-detection block from CheckBlockSyncTimeouts() into a\nself-contained helper. The helper detects when the block-download window\nhas stalled and disconnects the peer, applying an adaptive timeout backoff\nto avoid disconnecting multiple peers when local bandwidth is insufficient.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "714ece749a96f8a8590dcbc5aef67b6879c40399",
   "date": "2026-08-12T23:33:43Z",
   "message": "move-only: Extract CheckBlockFlightTimeout() helper\n\nExtracts the per-block in-flight timeout check from CheckBlockSyncTimeouts()\ninto a self-contained helper. The helper disconnects a peer when a requested\nblock has been in flight longer than the threshold, compensating for the\nnumber of peers with validated downloads.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "d9caa959e7ad8f8f87d3021beafc1e7a44ba9769",
   "date": "2026-08-12T23:33:43Z",
   "message": "move-only: Extract CheckHeadersSyncTimeout() helper\n\nExtracts the initial headers-sync timeout check from CheckBlockSyncTimeouts()\ninto a self-contained helper. The helper disconnects (or resets sync state for\nNoBan peers) when initial headers sync has stalled, and resets the timeout\nonce the chain has caught up.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "7f39d84c06e0e23f5f12b1187e1578edf04f5d6c",
   "date": "2026-08-12T23:33:43Z",
   "message": "move-only: Extract QueueBlocksGetData() helper\n\nExtracts the block getdata request queuing logic from MaybeSendGetData() into\na self-contained helper. The helper queues blocks via FindNextBlocksToDownload\nand TryDownloadingHistoricalBlocks, and marks a stalling peer when the\nin-flight queue runs empty.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "fc962d9281a689d106f85c23d927becd492a0da2",
   "date": "2026-08-12T23:33:43Z",
   "message": "move-only: Extract QueueTxGetData() helper\n\nExtracts the transaction getdata request queuing logic from MaybeSendGetData()\ninto a self-contained helper. The helper acquires m_tx_download_mutex, iterates\npending tx requests from m_txdownloadman, and flushes intermediate batches when\nthe getdata size limit is reached.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "7350a15e5ba5db5ce786f662f1cca4902f4e14b7",
   "date": "2026-08-12T23:33:43Z",
   "message": "move-only: Extract ComputeSyncBlocksAndHeaders() helper\n\nExtracts the sync-peer eligibility computation from the SendMessages() cs_main\nblock into a self-contained helper. The helper initialises m_best_header if\nneeded and returns whether blocks and headers should be synced from this peer\nbased on preferred-download status and current in-flight state.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  },
  {
   "sha": "03c5b2ba6d59ba63751bbc26cb7574ab7a041df4",
   "date": "2026-08-12T23:33:43Z",
   "message": "move-only: Extract MaybeSendTxMessages() helper\n\nExtracts the tx-relay trickle and inventory dispatch block from the\nSendMessages() cs_main block into a self-contained helper. The helper acquires\nthe per-peer tx_inventory_mutex, schedules the trickle interval, and\nconditionally sends the mempool response and tx inventory.\n\nThis commit can be reviewed with the git options:\n--color-moved=dimmed-zebra --color-moved-ws=ignore-all-space"
  }
 ],
 "timeline": [
  {
   "t": "2026-06-12T23:52:31Z",
   "kind": "comment",
   "who": "pablomartin4btc",
   "assoc": "MEMBER",
   "text": "@w0xlt, my first impulse is to put it into draft till your both PRs #34824 and #35502 land and get merged before but perhaps you find this useful and easier to work on those changes on top of this one?"
  },
  {
   "t": "2026-06-14T07:48:52Z",
   "kind": "review_comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "path": "src/net_processing.cpp",
   "commit": "f69c587028b2b280467b98ee252e55f2defa6534",
   "in_reply_to": null,
   "text": "`MaybeSendTxMessages` acquires tx_relay lock internally.\nIt only requires `cs_main` and `g_msgproc_mutex` held.\n\n```suggestion\n    /** Schedule trickle and send tx inventory messages. */\n```"
  },
  {
   "t": "2026-06-14T07:48:55Z",
   "kind": "review",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "f69c587028b2b280467b98ee252e55f2defa6534",
   "text": "Approach ACK, same pattern as https://github.com/bitcoin/bitcoin/pull/35502."
  },
  {
   "t": "2026-06-14T07:52:28Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "[quoted text omitted]\n\nI don\u2019t think this PR needs to be draft. Keeping it open is useful for review.\n\nIf this, #34824, or #35502 lands first, rebasing should be straightforward."
  },
  {
   "t": "2026-06-15T14:23:46Z",
   "kind": "force_push",
   "who": "pablomartin4btc",
   "commit": "06741a6f9da38d15d288847659724806075984a3"
  },
  {
   "t": "2026-06-15T14:25:13Z",
   "kind": "review_comment",
   "who": "pablomartin4btc",
   "assoc": "MEMBER",
   "path": "src/net_processing.cpp",
   "commit": "f69c587028b2b280467b98ee252e55f2defa6534",
   "in_reply_to": 3409208307,
   "text": "Done. Thanks!"
  },
  {
   "t": "2026-06-15T15:05:11Z",
   "kind": "comment",
   "who": "pablomartin4btc",
   "assoc": "MEMBER",
   "text": "-<ins>_**Updates**_</ins>:\n  - Corrected misleading comment on `MaybeSendTxMessages()`, [observed](https://github.com/bitcoin/bitcoin/pull/35522#discussion_r3409208307) by @w0xlt.\n\n(iwyu CI failure is not related and I think it's being fixed in #35535)"
  },
  {
   "t": "2026-08-12T23:40:12Z",
   "kind": "force_push",
   "who": "pablomartin4btc",
   "commit": "03c5b2ba6d59ba63751bbc26cb7574ab7a041df4"
  },
  {
   "t": "2026-08-13T01:14:12Z",
   "kind": "comment",
   "who": "pablomartin4btc",
   "assoc": "MEMBER",
   "text": "-<ins>_**Updates**_</ins>:\n  - Rebased."
  },
  {
   "t": "2026-09-15T09:07:20Z",
   "kind": "review",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "03c5b2ba6d59ba63751bbc26cb7574ab7a041df4",
   "text": "Concept ACK\n\nWas recently reviewing some code here and felt it would have been nice to be able to refer to smaller parts of `SendMessages()` by name."
  }
 ],
 "labels_log": [
  {
   "t": "2026-06-12T23:48:36Z",
   "action": "labeled",
   "label": "Refactoring",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-15T15:48:48Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-16T18:25:49Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-25T12:11:55Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-13T01:00:32Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-14T15:51:46Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [],
 "text_chars": 9479,
 "text_tokens_estimate": 2369,
 "changed_paths": [
  "src/net_processing.cpp"
 ],
 "files": [
  {
   "path": "src/net_processing.cpp",
   "add": 661,
   "del": 424
  }
 ],
 "test_lines": 0,
 "git": {
  "head": "03c5b2ba6d59ba63751bbc26cb7574ab7a041df4",
  "head_matches_backup": true,
  "base": "b2c45888fde06429e86913fab5e7b7a075f091c3",
  "commits": [
   {
    "sha": "4994f71dc9",
    "subject": "move-only: Extract ScheduleTxRelayTrickle() helper",
    "files": 1,
    "add": 31,
    "del": 16
   },
   {
    "sha": "852d4414c4",
    "subject": "move-only: Extract MaybeSendMempoolResponse() helper",
    "files": 1,
    "add": 48,
    "del": 36
   },
   {
    "sha": "5bc8bc93e7",
    "subject": "move-only: Extract MaybeSendTxInventory() helper",
    "files": 1,
    "add": 61,
    "del": 51
   },
   {
    "sha": "1ebdde9815",
    "subject": "move-only: Extract MaybeSendInitialGetheaders() helper",
    "files": 1,
    "add": 44,
    "del": 28
   },
   {
    "sha": "47d622a0f1",
    "subject": "move-only: Extract MaybeSendBlockAnnouncements() helper",
    "files": 1,
    "add": 140,
    "del": 129
   },
   {
    "sha": "9d24eee37c",
    "subject": "move-only: Extract MaybeSendBlockInv() helper",
    "files": 1,
    "add": 24,
    "del": 14
   },
   {
    "sha": "5c603dd3cc",
    "subject": "move-only: Extract CheckBlockSyncTimeouts() helper",
    "files": 1,
    "add": 80,
    "del": 62
   },
   {
    "sha": "1c93ec4c8d",
    "subject": "move-only: Extract MaybeSendGetData() helper",
    "files": 1,
    "add": 71,
    "del": 56
   },
   {
    "sha": "88e1d0ef52",
    "subject": "move-only: Extract SendCompactBlockOrHeaders() helper",
    "files": 1,
    "add": 55,
    "del": 37
   },
   {
    "sha": "e02e05c198",
    "subject": "move-only: Extract SendBlockInvFallback() helper",
    "files": 1,
    "add": 36,
    "del": 25
   },
   {
    "sha": "6c47f463b2",
    "subject": "move-only: Extract CheckBlockDownloadStall() helper",
    "files": 1,
    "add": 27,
    "del": 3
   },
   {
    "sha": "714ece749a",
    "subject": "move-only: Extract CheckBlockFlightTimeout() helper",
    "files": 1,
    "add": 14,
    "del": 4
   },
   {
    "sha": "d9caa959e7",
    "subject": "move-only: Extract CheckHeadersSyncTimeout() helper",
    "files": 1,
    "add": 11,
    "del": 0
   },
   {
    "sha": "7f39d84c06",
    "subject": "move-only: Extract QueueBlocksGetData() helper",
    "files": 1,
    "add": 27,
    "del": 7
   },
   {
    "sha": "fc962d9281",
    "subject": "move-only: Extract QueueTxGetData() helper",
    "files": 1,
    "add": 20,
    "del": 11
   },
   {
    "sha": "7350a15e5b",
    "subject": "move-only: Extract ComputeSyncBlocksAndHeaders() helper",
    "files": 1,
    "add": 43,
    "del": 25
   },
   {
    "sha": "03c5b2ba6d",
    "subject": "move-only: Extract MaybeSendTxMessages() helper",
    "files": 1,
    "add": 20,
    "del": 11
   }
  ],
  "patch_truncated": true
 },
 "input_hash": "9e4aebf544321a14",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}