BIP-110

Response

Why OP_PLENTY is not OP_RETURN

OP_RETURN is Bitcoin's explicit data outlet and contains the payload bytes directly. OP_PLENTY repurposes executable opcodes that custom software must decode to recover the payload.

BIP110.orgSource: OP_PLENTY by stevenrabinow-hash

The difference is simple. OP_RETURN is a defined, recognizable place for arbitrary data, so software can copy its payload bytes straight from the output script. OP_PLENTY instead turns executable script into a covert channel: every payload byte is replaced by two opcode bytes. The original payload is not directly readable until separate software recognizes the scheme and decodes those opcodes.

What holds up

The published encoder looks consensus-valid under BIP-110, and the decoder does pull arbitrary payload bytes back out of the opcode stream.

Where the argument slips

Treating executable script repurposed as a coded channel like it is the same thing as Bitcoin's explicit data outlet. OP_PLENTY only yields the payload after a protocol-specific decoding step.

How OP_PLENTY encodes data

OP_PLENTY splits every payload byte into two nibbles, then picks a Tapscript opcode for each nibble so that the opcode number modulo 22 gives the value back. A small state machine keeps the scratch stack valid while those opcodes execute.

Every payload byte ends up costing two script bytes. Optional v2 framing adds seven OP_5 opcodes as a searchable marker plus eight more for the encoded length. Skip the framing and the receiver has to learn the script boundary or raw-transaction offset some other way.

Published worked example: b"Hi"View source
0x48 -> nibbles (4, 8)0x69 -> nibbles (6, 9)encoded body: 9e 60 a0 61
The separate payload decoderView source
payload_hex = "".join(    f"{op % 22:x}" for op in payload)

Bitcoin validates the Tapscript and stops. Getting the payload back means external software running the modulo-22 decoder.

What OP_RETURN is for

OP_RETURN is the place Bitcoin already leaves for small amounts of arbitrary metadata. BIP-110 keeps that outlet and caps the whole output script at 83 bytes. Once an OP_RETURN output is identified, its payload bytes can be read directly from the script. No OP_PLENTY mapping or modulo-22 transformation is needed. The cap is about how much explicit data Bitcoin supports. Nobody serious thinks it plugs every covert channel; a programmable ledger cannot do that.

Raise or remove the OP_RETURN limit and you expand a defined, recognizable, relayable interface for arbitrary data. Software that accepts a larger standardized carrier is supporting more of that use. Whether someone can hide bits in opcode choices does not tell you where that explicit boundary should sit.

Same idea as inscriptions

Inscriptions take a Tapscript envelope and its data pushes and use them as a file carrier. OP_PLENTY takes the choice of executed opcodes and does the same job with different symbols. Either way you are turning spend-path machinery into a payload channel that has nothing to do with the spending condition.

Signatures, public keys, input ordering, and scripts all have spare degrees of freedom that can carry outside bits. Steganography is always going to be available. Jumping from “someone can still hide data” to “so leave the explicit data carrier unlimited” is the bad leap.

What a node stores on disk

A full node stores the serialized transaction, Tapleaf script included. With an ordinary inscription, the payload bytes sit plain inside script pushes. Push framing can break up a long file, but things like the PNG magic still show up in the block data.

With OP_PLENTY, what hits the disk is the selected opcodes. The PNG signature itself never appears. Getting the file back means knowing OP_PLENTY's mapping and running its decoder on purpose.

PNG signature
89 50 4e 47 0d 0a 1a 0a
OP_PLENTY payload opcodes for the same eight bytes
a2 61 5d 9a 5c 92 9e 5f 9a 91 58 a4 59 a4 58 a4

The second block is the payload body only, without the optional v2 framing.

Bitcoin stops at script validation

A BIP-110 node knows what each Tapscript opcode does. That is the end of its job. The payload only shows up once an outside protocol maps opcode % 22 to a nibble. If “stored on the node” means anything some imaginable decoder could derive, the phrase stops meaning anything useful.

Cost and recovery

All three put bytes in transactions. After that, the interface, how easy the file is to find, and the cost diverge hard.

Explicit carriers and steganographic workarounds
MethodRoleBytes on diskRecoveryPayload floorUnder BIP-110
OP_RETURNSupported metadata outletOriginal payload bytesCopy the bytes from the output script; no custom decoding≈4 WU/byteValid within an 83-byte script cap
Inscription envelopeData stuffed into the spend pathPayload bytes plain in pushes; framing can split chunksParse the envelope and pushes; file signatures still readable≈1 WU/byteLarge pushes capped; Tapscript OP_IF/OP_NOTIF rejected
OP_PLENTYEncode data in which opcodes runEncoded opcodes, not the original payload bytesKnow OP_PLENTY and run its modulo-22 decoder≈2 WU/bytePublished construction looks valid

Weight figures are payload-byte floors before transaction, framing, commitment, reveal, authorization, and other fixed overhead. OP_RETURN lives in non-witness transaction data; inscription and OP_PLENTY script bytes get witness weighting.

Optional OP_PLENTY v2 makes the tradeoff plain. The seven-OP_5 marker makes the payload easy to find; drop it and the recipient has to learn where the script lives some other way.

If the bar is “no encoding left”

Demand that BIP-110 block every possible encoding and every limit fails by construction. No general-purpose programmable ledger clears that bar. A test everything fails does not tell you whether a limit actually cuts the arbitrary data Bitcoin supports.

BIP-110 keeps the explicit data outlet bounded, shuts the cheapest standardized bulk paths, and pushes workarounds toward harder, less readable, more expensive encodings. The site's steganography answer already says this.

Bottom line

OP_PLENTY is what you get when the cheap carrier is gone: a custom 2:1 cipher in executed script. Every file byte costs two script bytes, and anyone who wants the file has to run a protocol-specific decoder. That is the limit doing work, not proof the limit failed.