BIP draft: Consensus ScriptPubKey Length Limit #2039

pull billymcbip wants to merge 4 commits into bitcoin:master from billymcbip:master changing 1 files +97 −0
  1. billymcbip commented at 4:47 pm on November 19, 2025: none

    This BIP adds a length limit for new scriptPubKeys in transactions at or above the activation height.

    #2017 (“Reduced Data Temporary Softfork”) includes a similar mechanism among many other, more complex, and, in my opinion, more risky changes. It would be valuable to consider a scriptPubKey length limit in isolation. This BIP would be a permanent change, and the same limit would apply to OP_RETURN and non-OP_RETURN outputs.

    Thank you in advance for your feedback.

    Edits:

    • The length limit applies to all blocks except those with a height that’s a multiple of 256. In other words, one out of every 256 blocks is exempt. This allows pre-signed transactions containing large scriptPubKeys to be mined, just at a throttled rate, which should fully eliminate any “confiscation” concerns.
  2. Add BIP: Consensus ScriptPubKey Length Limit 676d78fdd8
  3. billymcbip renamed this:
    BIP draft: Consensus ScriptPubKey Length Limit (includes OP_RETURN outputs)
    BIP draft: Consensus ScriptPubKey Length Limit
    on Nov 19, 2025
  4. moonsettler commented at 11:49 pm on November 19, 2025: none

    The implementation is fairly straightforward: example

    If you want to avoid the confiscatory accusations, you can do something like this:

     0    if (DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_260)) {
     1        int violations = 0;
     2        for (const auto& tx : block.vtx) {
     3            for (unsigned int i = 0; i < tx->vout.size(); i++) {
     4                if (tx->vout[i].scriptPubKey.size() > MAX_SCRIPT_SIZE_260) {
     5                    if (++violations > 1) {
     6                        return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-invalid-block-???", "invalid-output transaction");
     7                    } else {
     8                        break;  // skip the other outputs of the same transaction!
     9                    }
    10                }
    11            }
    12        }
    13    }
    

    This would let a single transaction per block to have the pre-fork limits applied to it.

  5. portlandhodl commented at 1:46 am on November 20, 2025: contributor
    There should be some mention about the effects of this change on OP_CHECKSIG / OP_CHECKMULTISIG DoS vulnerabilities. A limit this low (bytes) would likely reduce the worst case substantially.
  6. in bip-????.mediawiki:45 in 676d78fdd8
    40+* P2SH: 23 bytes
    41+* P2WPKH: 22 bytes
    42+* P2WSH: 34 bytes
    43+* P2TR: 34 bytes
    44+
    45+Even x-of-3 bare multisig scriptPubKeys are smaller than 260 bytes.
    


    portlandhodl commented at 1:51 am on November 20, 2025:
    There is no consensus rule that OP_CHECKMULTISIG is limited to 3 pubkeys. Consensus is 20 pubkeys max. BIP11 did make (n)/3 standard though.

    billymcbip commented at 11:51 am on November 20, 2025:
    Yes, I know. The reason I added that is because IsStandard includes x-of-3 bare multisigs (as you have indicated in your other comment). My point is that the rule would not affect any standard spendable outputs.
  7. in bip-????.mediawiki:38 in 676d78fdd8 outdated
    33+
    34+However, OP_RETURN should only be ''marginally'' more attractive for data embedding than methods leading to arbitrary data in the UTXO set.
    35+
    36+'''Why 260 bytes?'''
    37+
    38+The length of ScriptPubKeys for all standard outputs is well below 260 bytes:
    


    portlandhodl commented at 2:12 am on November 20, 2025:

    P2PK should be mentioned as it is Standard (66 bytes max) 1x 65 Byte pubkey P2MS should be mentioned as it is Standard (198 bytes max) 3x 65 Byte pubkeys

    (WITNESS_UNKNOWN) outpoints are standard and allow up to (42 bytes) https://github.com/bitcoin/bitcoin/blob/1af46cff947802828ee15dccc0ea1d603074cde7/src/script/script.cpp#L250


    billymcbip commented at 2:52 pm on November 20, 2025:
    Done
  8. in bip-????.mediawiki:47 in 676d78fdd8 outdated
    42+* P2WSH: 34 bytes
    43+* P2TR: 34 bytes
    44+
    45+Even x-of-3 bare multisig scriptPubKeys are smaller than 260 bytes.
    46+
    47+A 260 byte limit allows 256 bytes of data in OP_RETURN outputs:
    


    portlandhodl commented at 2:15 am on November 20, 2025:

    This is true, though this is only the limit on UTXO set excluded outpoints (unspendable)

    One could literally just use all 260 bytes for data if they didn’t care about the execution of the script that resulted.


    billymcbip commented at 11:48 am on November 20, 2025:
    Correct, but a ~11 byte overhead per chunk would remain (see my other comment).
  9. in bip-????.mediawiki:24 in 676d78fdd8 outdated
    19+
    20+==Motivation==
    21+
    22+Bitcoin is money. Transactions embedding arbitrary data compete with financial transactions for block space, and many node operators clearly do not want to process, relay or store arbitrary data.
    23+
    24+The motivation of this BIP is to reduce the amount of arbitrary data that can be embedded in transactions and in the UTXO set.
    


    portlandhodl commented at 2:23 am on November 20, 2025:

    This BIP only has a marginal effect on the total amount of data that could be stored as it only forces segmentation of the data into .size()/260 + .size()%260 ? 1 : 0 chunks.

    There is a reduction in the total usable space for arbitrary data by 5.625% with 9 bytes of overhead against 160 bytes of payload.


    billymcbip commented at 11:37 am on November 20, 2025:

    @portlandhodl I mostly agree - the effect is marginal. I think the ROI of this BIP is attractive because it can be implemented in very few LOC that are easy to reason about.

    Nit: It might make more sense to split data into .size()/255 + .size()%255 ? 1 : 0 chunks to avoid having to use OP_PUSHDATA2 (2 length bytes).

    There is a reduction in the total usable space for arbitrary data by 5.625% with 9 bytes of overhead against 160 bytes of payload.

    Not following the numbers 9 and 160 here. I think the overhead is 14 bytes per chunk:

    • value: 8 bytes
    • scriptSize: 3 bytes
    • in-script overhead: 3 bytes (OP_RETURN, OP_PUSHDATA1, 0xff)
  10. billymcbip commented at 12:12 pm on November 20, 2025: none

    @moonsettler: Agree that your approach would work, but not sure what kind of “confiscation” you have in mind. The only case I can see is where a previously signed transaction becomes invalid because it contains a long scriptPubKey output. In that situation users are only affected if they’re unable to re-sign a modified version with shorter outputs. Is that edge case worth introducing more state? Let me know if I am missing anything.

    Edit: Excepting even one tx per block would defeat the purpose of this BIP almost entirely. Edit: Added block height exception to address this concern.

  11. moonsettler commented at 12:27 pm on November 20, 2025: none

    @moonsettler: Agree that your approach would work, but not sure what kind of “confiscation” you have in mind. The only case I can see is where a previously signed transaction becomes invalid because it contains a long scriptPubKey output. In that situation users are only affected if they’re unable to resign a modified version with shorter outputs. Is that edge case worth introducing more state? Let me know if I am missing anything.

    More state is an integer in a local context. If you read the ML on the topic, a lot of people declared possibly “confiscatory” changes a non-starter. Since Bitcoin lacks proper covenants pre-signed, deleted key transactions are the only way to do certain relative time-lock spends. I have no idea why they would also use an absolute time-lock in such a security solution.

    PS: It’s also trivially possible to limit the total number of bytes new outputs in violation of the new rule can take up.

  12. billymcbip commented at 12:45 pm on November 20, 2025: none
    @moonsettler: If even a single long scriptPubKey per block remains allowed, it undermines the purpose of this BIP almost entirely. I’d love to know which concrete cases people are worried about, as this concern seems quite contrived. Of course, this soft fork would be deployed with many months of notice.
  13. Updated BIP: Consensus ScriptPubKey Length Limit In Most Blocks 38798f884e
  14. billymcbip commented at 2:39 pm on November 20, 2025: none

    @moonsettler: I’ve added an exception for one in 256 blocks (block_height % 256 == 0). For those blocks, the limit does not apply at all.

    This way there is no confiscation at all, just throttling. And 255/256 blocks will not contain any large ScriptPubKeys.

  15. Updated BIP: Consensus ScriptPubKey Length Limit In Most Blocks 54883a00dd
  16. Updated BIP: Consensus ScriptPubKey Length Limit In Most Blocks bfee3c5bdc
  17. moonsettler commented at 3:31 pm on November 20, 2025: none

    If even a single long scriptPubKey per block remains allowed, it undermines the purpose of this BIP almost entirely

    It makes such transactions very unreliable to get included in the next block. Later on could be restricted further if abused, but I’m not insisting on this, just an idea. Every nth block is also a possibility. There is always a potential for degens to place a huge premium on such rare space tho.

  18. jonatack commented at 3:33 pm on November 20, 2025: member

    This PR appears to have been opened prematurely, to not be original work by the author, and appears to be a gamification or shortcut of the BIPs process:

    • No dedicated ML post to present this specific draft proposal and have prior discussion of concept, technical merit, or soundness
    • LLM-generated (“95% – Extremely likely LLM-generated”)
    • Author’s GitHub was just created (https://github.com/billymcbip) with no previous proof of work in this space and its sole action has been to open this PR. It would be best to propose a branch of your original (not LLM-generated) work on your own fork of this repository via a dedicated ML post.
  19. jonatack closed this on Nov 20, 2025

  20. portlandhodl commented at 4:19 pm on November 20, 2025: contributor
    • No dedicated ML post to present this specific draft proposal and have prior discussion of concept, technical merit, or soundness

    This was my statement on Twitter (X) from a week ago, I welcomed a new champion. This draft reads very close to my original intent other than cutting the size in half.

  21. billymcbip commented at 4:31 pm on November 20, 2025: none

    @jonatack I am disappointed that you closed my PR.

    I’ve not claimed that I am the first person to have this idea - I credited BOTH the RDTS and @portlandhodl’s mailing list thread (AFAIK he never made a BIP PR, so this is not a duplicate). And allowing every n-th block to circumvent the limit to prevent the confiscation “FUD” (for lack of a better term) is my original idea! Again, Portland specifically asked for someone else to continue iterating on his idea!

    The RDTS (#2017) combines a ScriptPubKey length limit with highly controversial changes to Taproot and it has a deactivation block height. I really think it’s valuable to consider a (higher) ScriptPubKey length limit separately from the rest of the RDTS.

    The fact that my account is new is undeniable. Yes, this is my first contribution to Bitcoin.

    It’s just a PR for a BIP - I don’t see why we cannot openly discuss it.

  22. jonatack commented at 4:48 pm on November 20, 2025: member
    Per my feedback: it would be best to propose a branch of your original (not LLM-generated) work on your own fork of this repository via a dedicated ML post.
  23. bitcoin locked this on Nov 20, 2025

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bips. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-12-10 00:10 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me