Skip to content

Instantly share code, notes, and snippets.

@instagibbs
Created June 3, 2023 12:31
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save instagibbs/ee32be0126ec132213205b25b80fb3e8 to your computer and use it in GitHub Desktop.
Save instagibbs/ee32be0126ec132213205b25b80fb3e8 to your computer and use it in GitHub Desktop.

This was written in response to bitcoin/bitcoin#27578 and any other number of occurrences of the topic.

“Standardness policy” is a term for a transaction that would be consensus-legal, but our node doesn’t want to relay for various reasons. Clearly if it’s consensus valid we want to accept it to not split the network if a miner chooses a “weird” transaction to mine.

There are N motivations for policy that I know of:

  1. Anti-DoS: Only “cheap” things to validate get flooded to the network
  2. Security: Certain types of transactions may mess up certain systems for no good reason
  3. Upgrade hooks: We leave some things “forbidden” such that if we find a use for them later we don’t “confiscate” funds by refusing to relay e.g., a spend or pre-signed transaction
  4. Pro-decentralization: Make it simple/cheap for miners to build blocks that pay well
  5. Paternalism: We want wallet authors to use the least amount of public resources while still accomplishing their end goals(as long as that goal isn’t “attack the network”!).
  6. Safe soft-fork process: Sometimes the only mechanism preventing an unupgraded miner from mining a block that would be considered invalid by upgraded miners (but valid by unupgraded miners) is policy discouragement.
  7. Let people pay fees to make transactions in an acceptable API

All of these motivations obviously have to be weighed against the fact that bitcoiners want to make transactions, and miners want fees from those transactions. Ideally we make a mempool/relay system where both can live in relative harmony.

Let’s dive into the standardness restrictions circa Bitcoin Core 25

Three key places we’ll look if you’re following along at home, though there are a few more scattered about: IsStandardTx AreInputsStandard IsWitnessStandard

All in src/policy/policy.cpp. These checks are turned off in testnet by default, and can be turned off in regtest optionally.

And now here’s the list of logical restrictions, and how I’m classifying them:

IsStandardTx

standard

Only allow transaction nVersions of 1 or 2. Labels: (3) Example future uses: V3 policy bitcoin/bitcoin#25038 Historically it was used to signal opt-in support for relative timelocks.

standard

Don’t allow transactions that are too large Labels: (1), (4) Smaller transactions, especially pre-segwit, are cheaper to validate due to quadratic sighashing issues of legacy script. It also makes block creation easier with respect to the binpacking problem when you have smaller pieces to put in the bin, simplifying mining code/competitiveness.

standard

Legacy scriptSig can’t be bigger than “practical” at 15-of-15 multisig spend, the maximum possible pre-segwit due to P2SH limits. Labels: (1) Avoids signature bombs with quadratic hashing (pre-segwit issue). We’d like to softfork this out but can’t because that’s potentially theft.

standard

scriptSig can’t have opcodes included. Labels: (1), (2) Recall that pre-segwit, all witness data went into the scriptSig, and pushing opcodes here was consensus-legal. Makes Bitcoin script even hard to reason about. We would like to softfork it out, but can’t because that’s potentially theft.

standard

Output scripts should match some “well known” pattern to be relayed. Labels: (1), (2), (3), (4), (5) This is a big one. It basically makes everything in the system easier to reason about. We know, for example, that no one can put a bare script transaction that consists of nothing but 20-of-20 bare multisigs to blow out the sigops limit in a block. It allows us to think about future patterns, like taproot outputs or other segwit versions, without having to make sure people aren’t using said patterns already, therefore risking theft of user’s funds. It’s also a bit of paternalism, in that we think that anything “interesting” can likely be done within these script patterns, and want to encourage people to use those.

standard

Disallow relay of bare multisigs(allowed by default) Labels: (1), (4), (5) Please don’t use bare multisigs. It makes Satoshi sad.

standard

Don’t make outputs that aren’t likely to be spent because they’re so small. Labels: (1), (3), (4), (5) Prior to something like utreexo being standard, every node has to carry every unspent TXO forever to stay in consensus with the network. We want to encourage outputs to be spent eventually. Maybe we can allow dust in near future circumstances provided we make sure they’re swept ala Ephemeral Anchors: bitcoin/bitcoin#26403

standard

Only one OP_RETURN a transaction (and only up to 80 bytes of payload!) Labels: (5) This is one of the rare paternalism-only restrictions in my estimation. I’m for removing it, especially in a post-segwit world where witness data gets a deep discount for publishing random data.

AreInputsStandard

standard

Transaction inputs’ scriptPubKey shouldn’t be non-standard, or future segwit versions Labels: (1), (2), (3) Nonstandard scripts mean potentially scary legacy script behavior. Future segwit versions are left for future softforks, to make deployment easier.

standard

Legacy inputs can only have 15 signatures. Labels: (1), (2), (4) Legacy script sucks.

IsWitnessStandard

Now we’re getting into modern script, which is a bit more interesting in some ways.

standard

Segwitv0 P2WSH script size and stack item size limits. Labels: (3), (5) ? This I’m the most fuzzy on in some ways. These limits replicate some prior policy limits, so perhaps just precautionary principle here? Perhaps larger sizes end up being problematic in analysis, and can just be softforked out?

standard

Taproot annex must be empty Labels: (2), (3), (7) The annex is the most speculative of upgrade hooks in taproot it seems. There are a few ideas on how to use it, and a few issues to work around when it comes to coinjoin like scenarios. For example, did you know that taproot sighash currently doesn’t cover other inputs’ annex fields, allowing other inputs to inflate transaction size? bitcoin-inquisition/bitcoin#22

standard

Tapscript should be BIP342 script Labels: (3) Straight forward upgrade hook, don’t want people using it when it doesn’t have any real consensus meaning yet.

Back to other areas of code

standard

Don’t allow transactions that are “really small” which can break merkle proofs for light clients. Labels: (2), (5) See CVE-2017-12842. The fact that we still disallow <64 bytes is a tiny bit of paternalism, in that there might be other things we have missed still, and the use-case for such isn’t exceedingly strong so discussion was put on hold.


There are a number of things that are standardness or “standardness-like” but I didn’t include but here are some with quick labels:

  • “Virtual transaction size” for transactions with lots of pre-taproot signature operations (1), (4), (5)
    • Don’t disallow relay of things like bare multisigs, but make them cost more to relay...
  • ancestor/descendant package limits (4)
    • Computational limits of package feerate tracking/mining/etc
  • Script interpreter flags e.g., CLEANSTACK, SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_* (2), (3)
  • Sigops limits pre-taproot (1), (4) <--- no need to check sigops in tx when building block
  • and stuff I’ve missed/skipped/forgotten

In my own personal estimation that only thing I can think of as pure paternalism(5) is OP_RETURN limits. Therefore in general I don’t think there are easy answers and “just turn off standardness checks” is unlikely to ever be the right answer.

@LiranCohen
Copy link

Really appreciate this thoughtful write up!

I had one question about #6 in your list.

Safe soft-fork process: Sometimes the only mechanism preventing an unupgraded miner from mining a block that would be considered invalid by upgraded miners (but valid by unupgraded miners) is policy discouragement

Maybe I'm misunderstanding something, but this sounds more like a hard fork if unupgraded miners can mine transactions that are considered invalid by upgraded miners.

@instagibbs
Copy link
Author

instagibbs commented Jun 3, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment