p2p: Prefill compact blocks #35558

pull davidgumberg wants to merge 16 commits into bitcoin:master from davidgumberg:2025-11-13-0xB10C-prefill-rebase-binary-limit changing 16 files +706 −142
  1. davidgumberg commented at 6:44 AM on June 18, 2026: contributor

    LLM Disclosure: LLMs were used frequently as a research tool while investigating this topic, but no code or text in this PR was generated with an LLM.

    This is an implementation based on 0xB10C's proposal and implementation of prefilling CMPCTBLOCK messages with what we[^1] needed during CMPCTBLOCK reconstruction in the hopes of providing everything our peers will need to reconstruct without having to ask us for transactions.

    Although full support for receiving prefills is implemented in Bitcoin Core, the only prefills sent presently are coinbases. The goal of prefilling is to improve compact block reconstruction rates, which reduces the number of roundtrips needed to propagate blocks per-hop, which reduces the amount of time needed for blocks to propagate on the network, which mitigates selfish mining attacks by lowering the stale rate and the ratio $γ$ of honest miners a selfish miner is able to recruit in a block race.[^2] The tradeoff of prefilling is that it uses a small amount of extra bandwidth and makes propagation slightly worse when the predictions are bad.

    My primary contribution is limiting the prefill based on the connection's TCP window. Exceeding the boundary of the current TCP window will result in a ~roundtrip at the network layer,[^3] and any time a roundtrip is going to be incurred anyways, it would be better to let our peer tell us exactly what they are missing in a roundtrip instead of hazarding a guess, which risks sending redundant information.[^4]

    Prefill do

    In measurements I took from 2026-02-15 to 2026-03-16, a node receiving prefilled CMPCTBLOCKs limited to the TCP window size was able to reconstruct 89.7% of compact blocks received without a GETBLOCKTXN roundtrip, and a node receiving typical CMPCTBLOCKs with only coinbases prefilled was able to reconstruct 56.9% of blocks received without a GETBLOCKTXN roundtrip.[^5]

    The mean prefill sent was 1,694.64 bytes and the median was 897 bytes. If all the bytes of every prefill were redundant [^6], the cost of prefilling 1,694.64 bytes would be 1.39 MiB per node in wasted bandwidth per day (counting both the sending and the receiving bandwidth for all 3 HB peers).

    Prefill why

    There are changes that are likely more effective at improving propagation times than prefilling, for example:

    The advantage of this approach is that it requires no protocol changes and is entirely backwards compatible with existing node software that has implemented the CMPCTBLOCK protocol. Concretely: An old version of Bitcoin Core that knows nothing about this PR can enjoy faster block reconstructions if it connects to a peer that prefills blocks. I think these benefits are worth the tradeoff of violating the layer cake and taking transport matters into our own hands.

    Prefill what

    • The transactions which we were missing during reconstruction and received in a GETBLOCKTXN->BLOCKTXN round trip with our peer.
    • The transactions which were pulled from our extrapool during reconstruction.[^7]
    • Any transactions that were prefilled to us that we didn't already have in our mempool.

    The reasons to like this heuristic are that it's simple, per-block rather than per-peer, makes sense on paper, and seems to be effective in practice.

    Prefill when

    To avoid having to generate unique CMPCTBLOCK messages for each of our peers, which might be costly[^8], we (lazily[^9]) build and cache 2 CMPCTBLOCK messages: one prefilled and one not prefilled.

    At sending time we check the available bytes in our peer's TCP window, and if the total number of TCP windows occupied by the prefilled block is equal to the total number of windows occupied by the nonprefilled block, then we send the prefilled block.


    TCP Windows

    Discussed in greater detail elsewhere, I'll try to summarize here:

    In RFC 793, TCP was specified with receiver advertised window sizes because receivers allocate some buffer size to a given TCP connection, and this receiver advertised window represents the most unacknowledged data a receiver will process before dropping bytes on the ground or something awful like that. So the sender of a message over a TCP connection will only send up to the last acknowledged byte + the receiver's advertised window size in order to avoid filling up their peer's receive buffer.

    It was later discovered that TCP was susceptible to "congestion collapse", which can probably describe any congestion feedback loop but in TCP is where packets being dropped due to congestion results in retransmissions that cause even more congestion. TCP implementers addressed this with "congestion control" algorithms which decide on the sending side to limit the number of bytes to send dynamically, based on how frequently packets are dropped on a TCP connection. For a more concrete account of various congestion control algorithms see RFC 5681. A user's TCP implementation (typically in their OS kernel) will compute a window size dynamically for each TCP connection usually increasing as packets sent are ACKnowledged and decreasing when packets sent are dropped.

    Computed congestion control window sizes vary:

    • per-connection
    • over connection lifetime
    • with the congestion control algorithm used by the system TCP implementation
    • with user configuration of the TCP implementation.

    There is not likely to be any way to guess or predict what the TCP window will be very effectively, and we must query the TCP implementation in order to learn what our connection window sizes are.

    The usable window size is the smaller of the receiver advertised window and the sender computed congestion control window, but in practice the congestion control window is far smaller. In my observation node, the mean Bitcoin P2P congestion window observed was 17,360.52 bytes and the median was 14,480 bytes.

    [^1]: 'We' refers to the Royal Node. [^2]: (2013) Eyal and Sirer Majority is not Enough (pg. 8) https://arxiv.org/pdf/1311.0243 The claim that lowering block propagation times lowers γ probably needs serious analysis, but my hand-waving argument is that the faster public network-wide block propagation is, the more expensive any proportional propagation time advantage over the public network becomes, and γ is a function of propagation time advantage. [^3]: A network layer roundtrip will be faster than an application layer roundtrip, although probably not by much for most connections. Since at the application layer there will be some time your message spends waiting to be processed by your peer, at least for peers that use single-threaded message processing like Bitcoin Core does presently. [^4]: In practice exceeding the TCP window is ~not quite as bad as I've implied here and in the delving post: because the window is sliding, once the first 1.5 round-trips are completed there is a continuous stream as ACKnowledgements for the oldest segments arrive and the newest segments are fired out. The effect of this more precisely is that if a message exceeds a window boundary, the minimum travel time of the message becomes 1.5 round-trip-time (RTT) instead of 0.5 RTT and the throughput limit of the connection becomes $\text{window size} / \text{RTT}$. I am working on a more complete write-up that takes this more precise cost into consideration, but I think approximating it as a ~round trip is reasonable. [^5]: In reality, not all of the prefill is redundant otherwise prefilling would not be very useful. In my observation node that received prefilled compact blocks, the mean redundant prefill bytes was 865.62 bytes/block. 2 HB announcements will always be redundant so: 1.17 MiB per node in wasted bandwidth per day if one CMPCTBLOCK announcement only has 865.62 redundant bytes. [^6]: I will share a write-up describing my full experimental setup and data soon. It was mostly identical to the set up described here: https://delvingbitcoin.org/t/stats-on-compact-block-reconstructions/1052/34 I had one node running a prefilling branch, and another node set up to only receive CMPCTBLOCK messages from the prefilling node. My infrastructure as code observation set up: https://github.com/davidgumberg/prefill-research and the script I used to analyze the results: https://radicle.network/nodes/iris.radicle.network/rad:z37pH1UAxFvazXnfAMS5qbcUjQaP6/tree/leave/scripts/prefill.py [^7]: The reason to pluck from the extrapool is because it is very likely to differ between nodes. [^8]: But maybe there is some cost here that is worth trading off, it's not something I've explored. [^9]: This is based on andrewtoth's #26755.

  2. DrahtBot commented at 6:45 AM on June 18, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35558.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #35561 (net: move some CNodeState fields to Peer by Crypt-iQ)
    • #35522 (refactor: Extract per-message helpers from SendMessages() (move-only) by pablomartin4btc)
    • #35502 (refactor: extract per-message helpers from ProcessMessage (move-only) by w0xlt)
    • #35368 (tracing: add block header and compact block tracepoints by w0xlt)
    • #34565 (refactor: extract BlockDownloadManager from PeerManagerImpl by w0xlt)
    • #32606 (p2p: Drop unsolicited CMPCTBLOCK from non-HB peer and when blocksonly by davidgumberg)
    • #29418 (rpc: provide per message stats for global traffic via new RPC 'getnetmsgstats' by vasild)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

    LLM Linter (✨ experimental)

    Possible typos and grammar issues:

    • compact block annoucements -> compact block announcements [misspelled word]
    • prefill annoucements -> prefill announcements [misspelled word]
    • recontruct the block -> reconstruct the block [misspelled word]

    <sup>2026-07-03 23:28:54</sup>

  3. davidgumberg renamed this:
    Prefill compact blocks
    p2p: Prefill compact blocks
    on Jun 18, 2026
  4. DrahtBot added the label P2P on Jun 18, 2026
  5. w0xlt commented at 7:55 AM on June 18, 2026: contributor

    Concept ACK

  6. ismaelsadeeq commented at 10:20 AM on June 18, 2026: member

    Concept ACK.

    Curious to see also Prefill Who section.

    The transactions which were pulled from our extrapool during reconstruction.7

    These transactions in the extrapool were sent to us by some peers, no? We can reduce a bit of redundancy by not sending them again to the peers that announced them to us.

  7. josibake commented at 10:28 AM on June 18, 2026: member

    Concept ACK

    Based on prior discussions we've had about this, very excited to see it come to life. I have not looked at the code yet, but after reading the PR description (very well done, btw), I strongly agree that the simplicity and backwards compatibility of the approach make this a very strong proposal.

  8. edilmedeiros commented at 12:50 PM on June 18, 2026: contributor

    Concept ACK

  9. murchandamus commented at 3:49 PM on June 18, 2026: member

    Concept ACK

    Very excited to see this PR.

  10. in src/net_processing.cpp:2273 in f610cdd2a6
    2274 | +                    prefilled_windows,
    2275 | +                    not_prefilled_size,
    2276 | +                    not_prefilled_windows,
    2277 | +                    window_total,
    2278 | +                    window_avail);
    2279 | +            }
    


    0xB10C commented at 6:58 AM on June 19, 2026:

    Running this PR and observing this in the logs should give us information about how often we can prefill.

  11. in src/blockencodings.cpp:253 in f610cdd2a6
     253 | -        if (vtx_missing.size() < 5) {
     254 | -            for (const auto& tx : vtx_missing) {
     255 | -                LogDebug(BCLog::CMPCTBLOCK, "Reconstructed block %s required tx %s\n", hash.ToString(), tx->GetHash().ToString());
     256 | -            }
     257 | +        for (const auto& tx : vtx_missing) {
     258 | +            LogDebug(BCLog::CMPCTBLOCK, "Reconstructed block %s required tx %s\n", hash.ToString(), tx->GetHash().ToString());
    


    0xB10C commented at 7:02 AM on June 19, 2026:

    I'm not too sure about logging this for all required transactions in a non-test setting (which might be a few thousands). Could this cause log rate-limiting? Maybe a good use for the trace log level?


    davidgumberg commented at 6:25 PM on June 30, 2026:

    Maybe a good use for the trace log level?

    Ah! Great idea! Pushing an update that does this...

    I'm not too sure about logging this for all required transactions,

    Yeah I kind of agree, to me it just didn't make sense to log only if there are 5 or fewer, it seems either all of them should be logged or none.

    Could this cause log rate-limiting?

    Trace and Debug level logs are not rate limited:

    https://github.com/bitcoin/bitcoin/blob/dc282ff31d1cc97507530a541d9cec8a8f6a6ef4/src/util/log.h#L132-L140

  12. 0xB10C commented at 7:06 AM on June 19, 2026: contributor

    Concept ACK.

    Again, thanks for picking this idea up and moving it closer to the finish line.

    An idea mentioned in the delving post was to log information about wasted prefill bandwidth on the receiving side. How many transactions were received that we didn't use? How many extra bytes did we receive? This doesn't have to happen in this PR, but would probably good to have before this is reaches broader deployment on mainnet.

    Once merged: I've been thinking about how I could test the effect on mainnet once this is deployed. One idea would be to run a node that's patched to specifically NOT use anything prefilled besides the coinbase and compare it's reconstruction performance to the other mainnet nodes. Additionally, keeping track of what share of blocks come with more than a coinbase prefilled and measuring their reconstruction performance would be interesting.

  13. edilmedeiros commented at 1:56 PM on June 19, 2026: contributor

    Once merged: I've been thinking about how I could test the effect on mainnet once this is deployed. One idea would be to run a node that's patched to specifically NOT use anything prefilled besides the coinbase and compare it's reconstruction performance to the other mainnet nodes. Additionally, keeping track of what share of blocks come with more than a coinbase prefilled and measuring their reconstruction performance would be interesting.

    This is probably a good idea even before merging this, maybe there is some fine tuning we can find.

    cc @m4ycon

  14. in src/net.cpp:930 in f610cdd2a6
     925 | +    return msg.data.size() + GetMessageHeaderSize(msg.m_type);
     926 | +}
     927 | +
     928 | +size_t V1Transport::GetSendMessageSize() const noexcept
     929 | +{
     930 | +    AssertLockNotHeld(m_send_mutex);
    


    johnnyasantoss commented at 11:56 PM on June 26, 2026:

    nit: this assert is not needed here and elsewhere in this file (feel free to ignore) https://github.com/bitcoin/bitcoin/blob/e1290ce7f74b50f99932e7b83e414dec2732a8b9/doc/developer-notes.md?plain=1#L976-L979


    davidgumberg commented at 12:37 AM on July 3, 2026:

    I didn't know that! thanks, taken.

  15. in src/net.cpp:1610 in f610cdd2a6
    1603 | @@ -1583,6 +1604,38 @@ size_t V2Transport::GetSendMemoryUsage() const noexcept
    1604 |      return sizeof(m_send_buffer) + memusage::DynamicUsage(m_send_buffer);
    1605 |  }
    1606 |  
    1607 | +size_t V2Transport::GetMessageHeaderSize(const std::string& m_type) const noexcept
    1608 | +{
    1609 | +    AssertLockNotHeld(m_send_mutex);
    1610 | +    LOCK(m_send_mutex);
    


    johnnyasantoss commented at 12:21 AM on June 27, 2026:
        auto send_state = WITH_LOCK(m_send_mutex, return m_send_state);
    

    Since we are just reading the send_state why not prefer WITH_LOCK?


    davidgumberg commented at 12:38 AM on July 3, 2026:

    Good catch, fixed, thank you.

  16. johnnyasantoss commented at 1:53 AM on June 27, 2026: none

    f610cdd2a6d3aa6de8de8cc20af3664277bba07d utACK

    will test it locally and gather debug logs.

    Context: 1) I'm not cpp programmer. 2) we (@vinteumorg folks and I) did a deepdive on compact block relay BIP and other resources and then reviewed this PR together.

    PS: add context

  17. in src/net_processing.cpp:2230 in f610cdd2a6
    2230 | +        }
    2231 |  
    2232 | -            const CSerializedNetMsg& ser_cmpctblock{lazy_ser.get()};
    2233 | -            PushMessage(*pnode, ser_cmpctblock.Copy());
    2234 | -            state.pindexBestHeaderSent = pindex;
    2235 | +        const auto& cb_fut = m_most_recent_pow_block.cmpctblock_msg_fut;
    


    andrewtoth commented at 6:05 PM on June 27, 2026:

    I think we can hoist cb_fut and prefilled_cb_fut out and copy the shared futures while m_most_recent_block_mutex is held, then release the lock for the rest of this method. The only other thing we need is m_most_recent_pow_block.hash below, but we can get that via pindex->GetBlockHash() instead.


    davidgumberg commented at 12:38 AM on July 3, 2026:

    Nice! Much better to not hold a lock that prevents block updates while doing syscalls!!

  18. in src/net_processing.cpp:2221 in f610cdd2a6 outdated
    2212 | @@ -2169,17 +2213,85 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha
    2213 |          // If the peer has, or we announced to them the previous block already,
    2214 |          // but we don't think they have this one, go ahead and announce it
    2215 |          if (state.m_requested_hb_cmpctblocks && !PeerHasHeader(&state, pindex) && PeerHasHeader(&state, pindex->pprev)) {
    2216 | +            SendCompactBlock(*pnode, pindex);
    2217 | +        }
    2218 | +    });
    2219 | +}
    2220 | +
    2221 | +bool PeerManagerImpl::SendCompactBlock(CNode& pnode, const CBlockIndex* pindex)
    


    andrewtoth commented at 7:23 PM on June 27, 2026:

    style nit: no hungarian notation. Also, please be consistent in declaration and implementation of parameters. Some places are putting the ref or pointer marker next to the variable name, but they should all be next to the type (CNode& node instead of CNode &node).

    bool PeerManagerImpl::SendCompactBlock(CNode& node, const CBlockIndex* block_index)
    

    davidgumberg commented at 11:28 PM on July 3, 2026:

    Fixed, thank you.

  19. davidgumberg force-pushed on Jul 3, 2026
  20. davidgumberg commented at 12:39 AM on July 3, 2026: contributor

    Thanks to reviewers for feedback, I've pushed to address.


    These transactions in the extrapool were sent to us by some peers, no? We can reduce a bit of redundancy by not sending them again to the peers that announced them to us.

    Even if a peer has sent us a transaction that ends up in our extrapool, they may not have it in their mempool now since:

    1. It might have been RBF'ed. (good chance this is how it ends up in your extra pool)
    2. It might have been evicted.

    The other problem with this that I see would be the cost in implementation complexity and in node resources of tracking per-peer, and potentially creating new CMPCTBLOCK's per-peer. The current branch is very conservative in only generating two candidate CMPCTBLOCK messages, one prefilled, and one not prefilled, as the working assumption is that it would be bad for performance to have to generate unique CMPCTBLOCK messages for each peer, and because of the way CMPCTBLOCK serialization works, adding a single prefilled transaction unfortunately means having to reserialize the whole thing, since the short-txid has to be removed, and the differential index for the next prefill would have to be changed.

    The assumption that per-peer prefills would be too expensive might be wrong, but needs to be investigated. Empirically in my observations, I should point out that of the redundant prefill data received by the prefill-receiving node, 85% was stuff that was already in the prefill-receiving node's extra-pool.


    An idea mentioned in the delving post was to log information about wasted prefill bandwidth on the receiving side. How many transactions were received that we didn't use? How many extra bytes did we receive? This doesn't have to happen in this PR, but would probably good to have before this is reaches broader deployment on mainnet.

    That's a great point, I had logic for this in my observation nodes, but I've incorporated the changes into this PR.


  21. in src/net_processing.cpp:2166 in 63757da199 outdated
    2161 | @@ -2141,25 +2162,48 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha
    2162 |  
    2163 |      if (!DeploymentActiveAt(*pindex, m_chainman, Consensus::DEPLOYMENT_SEGWIT)) return;
    2164 |  
    2165 | -    uint256 hashBlock(pblock->GetHash());
    2166 | -    const std::shared_future<CSerializedNetMsg> lazy_ser{
    2167 | -        std::async(std::launch::deferred, [&] { return NetMsg::Make(NetMsgType::CMPCTBLOCK, *pcmpctblock); })};
    2168 | +    std::shared_future<CSerializedNetMsg> cb_msg_fut{
    2169 | +        std::async(std::launch::async, [pblock = pblock]  {
    


    andrewtoth commented at 4:57 PM on July 3, 2026:

    I don't think we should be switching the serialization from std::launch::deferred to std::launch::async. The latter spawns a new thread and serializes message eagerly, while the former just defers the serialization lazily until something calls get() on the future.

    Spawning threads is harder to reason about here as well. There can be lifetime issues introduced.

    Edit: Hmm I see from the commit message this is intentional. I suppose it doesn't introduce any lifetime issues since we're just copying shared_ptrs. But, I think the main benefit was that we serialize the message once for all our peers, instead of having to reserialize for each. With prefilling it might make sense to also do that eagerly in a background thread.

  22. in src/net_processing.cpp:887 in 63757da199 outdated
     886 | +        std::unique_ptr<const std::map<GenTxid, CTransactionRef>> txs;
     887 | +        /** A pair of block hash and prefill candidates for our compact block
     888 | +         * annoucements. If a transaction index is in the set, it indicates that
     889 | +         * the transaction is likely a good candidate to prefill in a
     890 | +         * compact block annoucements related to the block hash. */
     891 | +        std::pair<uint256, std::set<uint32_t>> prefill_candidates;
    


    andrewtoth commented at 4:59 PM on July 3, 2026:

    When will the block hash in prefill_candidates differ from hash above? Can these be merged?

  23. in src/net.cpp:4204 in 63757da199 outdated
    4199 | +    auto bytes_used = (bytes_inflight + bytes_inqueue) % window_size;
    4200 | +
    4201 | +    // How many bytes we can use before reaching the next window boundary.
    4202 | +    bytes_available = window_size - bytes_used;
    4203 | +
    4204 | +    LogDebug(BCLog::NET,
    


    andrewtoth commented at 5:02 PM on July 3, 2026:

    We log window_size and bytes_available here, but we also log them on the call side. Can we remove one of the logs?

  24. in src/blockencodings.h:156 in 63757da199 outdated
     151 | +    // predictively prefill transactions in our compact block annoucements.
     152 | +    // This includes transactions that:
     153 | +    // - were prefilled by the cmpctblock announcer and were not in our mempool
     154 | +    // - transactions we found in our extra_pool (but not mempool)
     155 | +    // - transactions we had to request from the announcer
     156 | +    std::set<uint32_t> prefill_candidates{ /*coinbase=*/0 };
    


    andrewtoth commented at 5:17 PM on July 3, 2026:

    I don't think we should seed with the coinbase here. In that case, the check in net_processing for prefill_candidates.size() > 0 is always true, so we will always go through the prefill path and do all the syscalls even for the current behavior of always prefilling only the coinbase. We should only bother with that logic if we have at least one non-coinbase prefill tx.

  25. in src/net.cpp:1632 in 63757da199 outdated
    1627 | +{
    1628 | +    auto send_state = WITH_LOCK(m_send_mutex, return m_send_state);
    1629 | +
    1630 | +    if (send_state == SendState::V1) return m_v1_fallback.GetSendMessageSize();
    1631 | +
    1632 | +    return WITH_LOCK(m_send_mutex, return m_send_buffer.size() - m_send_pos);
    


    andrewtoth commented at 9:06 PM on July 3, 2026:

    Here and in GetMessageSize above, we should take m_send_mutex lock and return the value if send_state != SendState::v1, and then return the fallback after releasing the lock. That way we don't take and release the lock multiple times.

  26. in src/blockencodings.cpp:182 in 63757da199 outdated
     181 | -                    txn_available[idit->second].reset();
     182 | -                    mempool_count--;
     183 | +                txn_available[idit->second].reset();
     184 | +                mempool_count--;
     185 | +                if (debug_log) {
     186 | +                    mempool_size -= txn_available[idit->second]->ComputeTotalSize();
    


    andrewtoth commented at 9:22 PM on July 3, 2026:

    This is a use-after-free. We need to get the size before we reset it 3 lines above.


    davidgumberg commented at 10:33 PM on July 3, 2026:

    Thanks for catching, sorry the quality of this logging commit was low when I pushed it.


    davidgumberg commented at 10:43 PM on July 3, 2026:

    Also this probably should've been caught by a sanitizer during testing, I'll investigate.

  27. in src/blockencodings.cpp:116 in 63757da199 outdated
     110 | @@ -94,14 +111,26 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
     111 |              }
     112 |              txn_available[lastprefilledindex] = cmpctblock.prefilledtxn[i].tx;
     113 |  
     114 | +            size_t tx_size = 0;
     115 | +            if (debug_log) {
     116 | +                tx_size = cmpctblock.prefilledtxn[i].tx->ComputeTotalSize();
    


    andrewtoth commented at 9:31 PM on July 3, 2026:

    Also need prefilled_size += tx_size; We don't increment/decrement extra_size either. Seems like an oversight?


    davidgumberg commented at 10:39 PM on July 3, 2026:

    Thanks for catching, sorry this went out broken.

  28. cmpctblock: log: TXID's of all missing cmpctblock tx'es. dd7aec4403
  29. build: Bump minimum Windows to >= Windows 1703
    This is needed for the use of the `SIO_TCP_INFO` API.
    
    https://learn.microsoft.com/en-us/windows/win32/api/mstcpip/ns-mstcpip-tcp_info_v0#requirements
    38d1d67aa0
  30. sock: Add TCPInfo wrapper for getting socket info. cc7cf3bb7e
  31. sock: TCPInfo::GetTCPWindowSize() a5f5bf00f2
  32. sock: Add GetOSBytesQueued 8338dea0d7
  33. net: Add Transport::GetMessageSize() for serialized msg sizes
    This is unused here, but will be useful for estimating the serialized
    bytes in the application send queue.
    269a5a55b1
  34. net: Add GetSendQueueSize()
    Not used yet, but will be useful for deciding whether or not prefilling
    a CMPCTBLOCK will cause the current message queue to overflow a TCP
    window boundary.
    fbb933bf31
  35. net: Add CNode::WindowBytesTotalAndAvailable() d9f4c1c10b
  36. p2p: refactor: Stuff m_most_recent* into a struct 9f41a1d4a7
  37. p2p: Cache cmpct_block_msg for low bandwidth relay.
    This commit is drawn from the closed #26755.
    (https://github.com/bitcoin/bitcoin/pull/26755)
    
    This also changes `std::launch::deferred` to `std::launch::async` since
    we are likely going to use this result very soon if someone has
    requested HB blocks from us, and if no one has, then performance here is
    not that critical.
    
    Co-authored-by: Andrew Toth <andrewstoth@gmail.com
    bba4f0c75e
  38. net: refactor: Move common logic into SendCompactBlock
    Also one non-refactor change which is setting the `pIndexBestHeaderSent`
    on the `SendMessages` CMPCTBLOCK announcement fallback.
    6d92a81e3e
  39. net: Protect PeerHasHeader from nullptr 8ccff94020
  40. p2p: keep track of cmpctblock prefill candidates
    Keep track of the block position of transactions that we didn't have in
    our mempool while reconstructing this compact block. We can use these to
    predictively prefill transactions in our compact block annoucements.
    This includes transactions that:
    - were prefilled by the cmpctblock announcer and were not in our mempool
    - transactions we found in our extra_pool (but not mempool)
    - transactions we had to request from the announcer
    89b3c16892
  41. p2p: prefill our compact blocks with candidates
    Upon receving a compact block, we keep a set of prefill candidates
    (transactions we didn't have in our mempool) for this block. When
    constructing a compact block, we try to use these candiates to prefill
    our compact block annocement of this block.
    0297276291
  42. cmpctblock: initdata: Log extrapool separately from mempool b622e109a5
  43. cmpctblock: log: Log sizes of all tx types and prefill redundancies 9c3a0a5666
  44. davidgumberg force-pushed on Jul 3, 2026
  45. DrahtBot added the label CI failed on Jul 4, 2026
  46. DrahtBot added the label Needs rebase on Jul 6, 2026
  47. DrahtBot commented at 10:57 PM on July 6, 2026: contributor

    <!--cf906140f33d8803c4a75a2196329ecb-->

    🐙 This pull request conflicts with the target branch and needs rebase.


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-07-09 06:47 UTC