CTV, APO, CAT activity on signet

BIP 118 (SIGHASH_ANYPREVOUT, APO) and BIP 119 (OP_CHECKTEMPLATEVERIFY, CTV) have been enabled on signet for about two years now, since late 2022. More recently, BIP 347 (OP_CAT) was also activated – it’s been available for about six months now.

Here’s a brief investigation into how they’ve been used:

APO

That’s the extent of APO-based usage on signet to date to the best of my knowledge. It’s possible that further ln-symmetry tests will be possible soon, with all the progress in tx relay that’s been made recently.

CTV

And that’s it. I didn’t see any indication of exploration of kanzure’s CTV-vaults which uses OP_ROLL with OP_CTV, or the simple-ctv-spacechain, which uses bare CTV and creates a chain of CTV’s ending in an OP_RETURN.

CAT

There are substantially more transactions on chain (74k) that use it than either APO (1k) or CTV (16) due to the PoW faucet, which adds three spends per block, so it’s a bit harder to analyse. Linking to addresses rather than txids, I think they sum up as:

Addendum

I tracked these by hacking up a signet node that tries to validate block transactions with all of CTV/APO/CAT discouraged, and on failure retries with CTV and APO individually enabled, logging a message hinting at what features txs use. Could be interesting to turn that into an index that could track txs that use particular features a bit more reliably.

patch
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2663,13 +2663,22 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
             std::vector<CScriptCheck> vChecks;
             bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
             TxValidationState tx_state;
-            if (fScriptChecks && !CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], m_chainman.m_validation_cache, parallel_script_checks ? &vChecks : nullptr)) {
-                // Any transaction validation failure in ConnectBlock is a block consensus failure
-                state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,
-                              tx_state.GetRejectReason(), tx_state.GetDebugMessage());
-                LogError("ConnectBlock(): CheckInputScripts on %s failed with %s\n",
-                    tx.GetHash().ToString(), state.ToString());
-                return false;
+            auto xflags = flags | SCRIPT_VERIFY_DISCOURAGE_CHECK_TEMPLATE_VERIFY_HASH | SCRIPT_VERIFY_DISCOURAGE_ANYPREVOUT | SCRIPT_VERIFY_DISCOURAGE_OP_CAT;
+            if (fScriptChecks && !CheckInputScripts(tx, tx_state, view, xflags, false, false, txsdata[i], m_chainman.m_validation_cache, nullptr)) {
+                if (CheckInputScripts(tx, tx_state, view, (xflags ^ SCRIPT_VERIFY_DISCOURAGE_CHECK_TEMPLATE_VERIFY_HASH), false, false, txsdata[i], m_chainman.m_validation_cache, nullptr)) {
+                    LogInfo("CTV using transaction %s\n", tx.GetHash().ToString());
+                } else if (CheckInputScripts(tx, tx_state, view, (xflags ^ SCRIPT_VERIFY_DISCOURAGE_ANYPREVOUT), false, false, txsdata[i], m_chainman.m_validation_cache, nullptr)) {
+                    LogInfo("APO using transaction %s\n", tx.GetHash().ToString());
+                } else if (CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], m_chainman.m_validation_cache, nullptr)) {
+                    LogInfo("CTV/APO/CAT using transaction %s\n", tx.GetHash().ToString());
+                } else {
+                    // Any transaction validation failure in ConnectBlock is a block consensus failure
+                    state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,
+                                  tx_state.GetRejectReason(), tx_state.GetDebugMessage());
+                    LogError("ConnectBlock(): CheckInputScripts on %s failed with %s\n",
+                        tx.GetHash().ToString(), state.ToString());
+                    return false;
+                }
             }
             control.Add(std::move(vChecks));
         }
12 Likes