I have completed my evaluations of the various proposals that are being publicly evaluated by the Bitcoin development community. The proposals themselves and the endorsement grid can be found here
Before I embark on a discussion as to my specific thoughts on each of the proposals in that grid. I want to talk about my general philosophy on what makes a good addition to the Bitcoin Script VM environment.
The purpose of the Bitcoin Script VM is to be able to determine whether or not a transaction should be valid. At the end of the day the output of the Bitcoin Script VM is a simple "Yes" or "No" to whether this input should be considered spendable by this transaction.
To that end I consider an ideal Bitcoin Script VM to be one that allows us to define any function (predicate) in the set defined by the following type:
script :: Transaction -> Bool
Further, to keep the system secure all of these functions need to terminate in finite time that can be estimated effectively without simply running the script. This essentially means that we want it to not be Turing Complete but rather Finitarily Complete.
To accomplish this we have a number of different choices. We could, in theory, just enumerate every possible function we would want in this set, give it its own distinct opcode and then, soft fork that opcode into Bitcoin. Hopefully this should seem absurd to most of you. For one, the idea of having purpose built opcodes for every function in this set should be intuitively impossible, or at the very least, intractable.
However, the hallmark of a good programming environment is "composability": the ability to take different building blocks, assemble them in different configurations, to build the function you want. To this end, we should be favoring opcodes that are simpler and do less, rather than ones that byte-efficiently do more. This is equivalent to wanting basis unit vectors to cover a given coordinate system as opposed to awkward differently-sized non-orthogonal vectors to specify coordinates in a plane.
This is desirable for two reasons: First, from general mathematical point of view we can effectively "cover more space" with fewer opcodes if we choose to do things this way. Given that soft-forks are expensive to coordinate even under the best of circumstances, we can minimize the number of deployments that need to happen to get to the point where we can completely cover the space of predicates over transactions. Secondly, from an economic coordination point of view, shipping purpose built opcodes that are optimized for specific use cases is tantamount to central planning. If we choose to do this, we, the architects of Bitcoin's consensus ruleset would be presupposing the types of economic activity that people wish to engage in and building custom tools for those things that exclude the possibility of reusing those opcodes towards other interesting ends.
Some people argue that we "don't want to enable behavior that we don't understand". My main counterargument to this is that
by limiting the space of allowable operations to predicates over transactions -- p : Transaction -> Bool
-- we are already
excluding behaviors that would introduce nonlinearities that could be dangerous to Bitcoin. However, it is desirable to cover
this predicate space completely, so we can all move on with our lives.
The best primitives we can get towards that end are a generalized (finite) computation environment, and the ability to introspect the entirety of the transaction.
With all of that out of the way we can actually talk about the different proposals before us:
CTV is the godfather of all of the covenant opcodes. It was first, and does a decent enough job of giving us predicate access to things we previously didn't have, namely, the ability to specify certain requirements for the outputs. If we get CTV we could probably do most of what we want to do in a not-exceedingly-painful manner. For this reason I'm OK with shipping it. However, I find it to be inferior to other choices. I do not believe including it (even alongside the superior alternatives) represents any harm to Bitcoin.
CSFS is not really a covenant opcode, it is a generalization of the signature checking mechanism that allows us to verify signatures of messages that aren't simply the overall transaction. If we could go back and design Bitcoin from scratch, I think most developers would agree that this would be the preferred way to do signature evaluation in Bitcoin Script.
PAIRCOMMIT is a rather silly opcode imo because it can be entirely recovered using PUSH, CAT, DUP and HASH256. At present we do not have CAT but we have the rest of them and as we will discuss in a bit, I fully support the inclusion of CAT. This means that the inclusion of PAIRCOMMIT does nothing to further the goal of pushing greater completeness over the predicate space, but simply optimizes a potentially common use case. We may wish to do such a thing in Bitcoin's future, but I think it is a non-priority while we still have not solved predicate space completeness.
In line with my previous commentary, the purpose of INTERNALKEY is to push the taproot internal key into the script environment. This is a form of introspection and as such I think it is a great candidate for inclusion. The reason I list it as Acceptable instead of Prefer is that I don't personally understand the use cases that this specific introspection enables but I wholeheartedly support introspection and this furthers that goal.
This is probably the most dead obvious Yes in the entire list. CAT is the most basic opcode we could possibly want and allows us to do incremental computation on values. The fact that we don't have it is more of a historical mistake due to its danger when naively combined with DUP. By simply placing an upper bound on the resulting size of a stack element, we completely mitigate any concerns.
This was probably the hardest opcode of the set to evaluate. While it seems to be an exciting construction that would allow for a lot of interesting possibilities, I believe the specific opcode that is being proposed for it is more complicated and purpose-built (for the MATT smart contracting system) than is necessary or ideal for the next phase of Bitcoin's development. I'm generally wary of opcodes that have too many distinct arguments as CCV does as it indicates a lack of composability. I also suspect (but do not assert here) that you can recover MATT functionality if all of the opcodes listed as "Prefer" in this document are shipped.
This one has a pretty straightforward explanation. While I sympathize with the goals of increasing the robustness of self-custody and improving people's security posture against meatspace attacks, we should not be surgically soft-forking Bitcoin to enable hyper-specific use cases, regardless of how they appeal. It's not a good way to design a future-proof programming environment.
This is the third most important thing we can enable behind CAT and CSFS. This is because it fully generalizes CTV, allowing us to get introspection-like capabilities on any subset of the transaction that we deem relevant to our use case. Similarly this in combination with CSFS allows us to drop the somewhat annoying to use sighash system because we now reify the entire sighash computation process inside the Bitcoin Script VM, making it much easier to work with. This isn't the same as being able to directly introspect the entire transaction data, but it allows us to commit to the transaction data we wish to introspect and we can simply push the data itself onto the stack in the witness.
The only real purpose of APO has been to enable LN_Symmetry which can be enabled with a combination of CSFS, CAT, and TXHASH. As a result, since this is an extension of the SIGHASH system instead of an actual addition to the Script VM, I consider it to be strictly inferior to the other options we have available. I don't think it'll be harmful and so if there's overwhelming support for it I wouldn't try and contradict that, but I cannot be bothered to devote mental effort to that type of construction when we have known methods of doing it inside the Script VM.
Ship CAT, CSFS, TXHASH. Optionally ship CTV, INTERNALKEY. We are aiming for completeness of the predicate space over transactions. Optimizations should wait until we see actual usage. If we have completeness, then no use case is impossible, it just may be pricey. The stuff that gets used frequently can be optimized when that usage data makes it evident that such a use case has durable demand.
Finally, I want to note that I really don't wish for any of this to be taken as an attack on the quality of work that went into each of these proposals. The developers that have worked on them have done a great job defining and championing their ideas and their arguments are not without merit. However, I think that from a philosophical point of view, some of these things just don't seem like effective uses of effort.