The Script That Wants to Know Where Its Coins Are Going

You lock some bitcoin into an address. The script fires. It checks your signature, checks the timelock, maybe counts the multisig quorum. Then it stops, because there is one thing it cannot do: look at the transaction spending it and ask where, exactly, those coins are going next.

That single gap is the root of the entire covenant debate.

A covenant is a spending condition that constrains not just who can move coins, but where they can move next. Think of it less like a lock and more like a deed restriction baked into the title itself: the property can change hands, but only to buyers who inherit the same encumbrance. The technical fight isn't really about whether Bitcoin should have covenants. It's about the mechanism, and that question has fractured the developer community into two recognizable camps for several years now.

Two Philosophies Wearing the Same Label

The introspection camp wants opcodes that let a script examine the spending transaction field by field. The template camp wants a single, tightly scoped opcode that checks whether the transaction matches a pre-committed hash. Same destination. Completely different machinery.

Start with introspection. Proposals like `OP_TXHASH` and the older `OP_CHECKTEMPLATEVERIFY` variant sometimes blur the line, but the purest introspection proposals (think `OP_CAT` combined with `OP_CHECKSIGFROMSTACK`, or the `OP_TX` family floated in various BIPs) let a script pull individual fields out of the spending transaction and reason about them directly. Output value at index 0? Readable. The scriptPubKey of the second output? Readable. You can write logic like: this input may only be spent if the first output sends at least 0.5 BTC to address X, and the fee does not exceed 1,000 satoshis.

That's powerful. It's also expressive in ways that make a certain kind of Bitcoin developer reach for the fire extinguisher.

The template approach, best represented by `OP_CHECKTEMPLATEVERIFY` (CTV, BIP-119 as proposed by Jeremy Rubin), works differently. Instead of reading transaction fields at runtime, you commit to a hash of the transaction template at the time you create the output. When someone later tries to spend it, the opcode checks one thing: does the spending transaction hash to that committed value? Yes, spend permitted. No, rejected.

No field reading. No arithmetic over outputs. One hash comparison.

A Worked Example Worth Actually Following

Two developers, Priya and Marcus, both want to build a vault: coins that can't be stolen in a single transaction because any withdrawal must pass through a 24-hour delay address first.

Priya uses the template approach. She pre-commits a CTV hash encoding exactly one valid spending transaction, one that sends all funds to a specific delay script. The vault output will only ever move coins to that delay script, full stop. She can't change it later without creating a new address, and nobody can redirect the coins mid-flight. The template is the constraint.

Marcus builds with an introspection opcode. His script reads the first output's scriptPubKey at spend time and verifies it matches the delay script hash. Same functional result, but his script is doing live arithmetic and field parsing at validation time.

For this use case, both vaults behave identically. The difference surfaces when you ask what else each mechanism can be used for. Marcus's introspection opcode can be recombined with other opcodes to express conditions Priya's template hash cannot, because the hash is fixed at creation. That flexibility is either a feature or a threat, depending on which camp you're in.

What Each Camp Is Actually Worried About

CTV advocates argue that the template approach's restrictiveness is the point. A hash is a hash. There's no emergent complexity, no novel execution paths, no possibility of accidentally enabling Turing-complete-adjacent behavior through opcode composition. The validation cost is constant and bounded. Formal analysis is tractable.

Introspection advocates counter that templates are too rigid for real applications. A vault is a clean example, but production use cases often need to inspect amounts, not just destinations. Payment pools, congestion control outputs (where a single UTXO fans out to hundreds of recipients without touching the chain until necessary), and more sophisticated constructions on Bitcoin all require amount introspection. CTV in its pure form doesn't provide that. You commit to exact byte sequences, which means exact amounts, which means the template breaks if fees or amounts shift by even one satoshi.

That brittleness is real. Not theoretical.

On the other side, introspection proposals carry a different kind of risk: the interaction surface with future opcodes is genuinely hard to predict. Bitcoin Script is not evaluated in isolation; opcodes compose. `OP_CAT` alone seems harmless, but `OP_CAT` plus `OP_CHECKSIGFROMSTACK` plus a transaction introspection opcode can reconstruct covenants far more expressive than any single proposal advertises. Reviewers have to think about the combinatorial space, not just the opcode sitting in front of them.

This is where the debate gets genuinely hard. Both concerns are legitimate. I don't think either camp is being paranoid.

What People Get Wrong About This Debate

The most common misreading is treating this as conservative versus progressive, ossification versus innovation. It isn't, and that framing does real damage to the conversation. Several researchers who support introspection opcodes are among the most careful, technically rigorous contributors in the space. Several CTV supporters are genuinely interested in expanding Bitcoin's expressiveness.

The real disagreement is about where you place the complexity budget, and I think that's actually the more interesting argument. Template approaches front-load complexity into the tooling: wallet software must pre-compute and commit to templates, keeping the consensus layer simple. Introspection approaches push complexity into the consensus layer, giving developers more runtime flexibility in exchange for richer script execution on every full node.

Neither choice is free. Bitcoin's script execution runs on every full node, forever, for every block. A validation cost that seems trivial today compounds across millions of nodes and decades of blocks, and anyone who waves that away hasn't done the arithmetic.

There's also a quieter disagreement about auditability. A template commitment is visible and static; you can inspect it before the coins are locked. An introspection-based covenant's behavior depends on the full script logic, which may be harder to reason about for less technical users who inherit a UTXO.

So before you commit to a covenant design you like: do you need amount flexibility, or just destination constraints? That single question will tell you which approach actually fits your use case.

The debate won't resolve cleanly because it stopped being a purely technical argument some time ago. It's an argument about what kind of complexity Bitcoin should absorb, and at which layer. Those arguments don't close. They accumulate, proposal by proposal, until one approach earns enough consensus to activate or gets quietly shelved while the next one queues up behind it.