1

I have a couple of questions related to validation of script in transaction output (scriptPubKey).

I apologize for a little more text, but I tried to explain in detail what I don't understand.

Since all my confusion is related to the OP_RETURN opcode and OP_RETURN transaction, i.e. the following question and answer from Pieter Wuille all my questions are related to the validation of the scriptPubKey that contains this operator (OP_RETURN transaction), but I assume the same is true for all other output scripts.

Let's begin.

Based on what the Bitcoin wiki says that OP_RETURN marks the transaction as invalid and per Pieter's comment:

Transaction output scripts are only executed at the time they are attempted to be spent.

My first question is:

1. If the transaction output scripts are only executed at the time they are attempted to spent, does it mean that in scriptPubKey (transaction output script) we can write whatever we want and its validity will be only checked at the time of using? I mean if OP_RETURN makes the transaction invalid, and the validation is realized when creating the scriptPubKey (output), then the script with the given code can never be part of the blockchain

I think the answer to first question is false. The scriptPubKey is executed at the time its attempted to spent but its validity is checked at the time of creation of transaction that has that script in its transaction output. It's like a compiling and executing C program. Compiling means checking for syntax and semantic errors, or in case of scriptPubKey check, for example, if all correct opcodes are used, if script size is correct, if it is one of the standard transaction (if any of the above is not satisfied, the transaction containing this UTXO will be marked as invalid and discarded from the network). On the other hand, executing a C program can also cause the program to become invalid, say when dividing by 0. And that's exactly as with scriptPubKey and it's executing (as Pieter said) when attempting to spend it. If at the time of execution the script is marked as invalid (say it remains FALSE on the stack or an OP_RETURN operator is encountered), then the transaction that consumes the UTXO (not the one contains this UTXO) is marked as invalid. Therefore, although validation is performed when creating a transaction output, OP_RETURN is a valid code that passes validation, but executing a script that contains it invalidates the transaction. Since scriptPubKey is only executed when it is consumed, that transaction will be marked as invalid, and not the one that created scriptPubKey.

2. Is the above written true? Is the validity of the transaction output checked when making the transaction, and then while using the UTXO if something in the output script causes invalidity, the transaction that consumes that output will be marked as invalid?

Below is a question related to whether I understand validation correctly in the context of OP_RETURN.

When output containing [OP_RETURN] [DATA_PUSH] [data] is created, that UTXO will be successfully validated (since everything in it is OK) and recognized as standard OP_RETURN output that does not become part of the UTXO set. If everything other in transaction is okay, transaction is valid. However, if we were to try to use this UTXO, the transaction that consumes the given output will be marked as invalid, because it contains OP_RETURN. On the other hand, if we add something additional in front of OP_RETURN (some random opcode) in scriptPubKey, it will not pass validation since it's not recognized as a standard transaction, so a transaction that has this output would be invalidated

3. Did I understand correctly, that is, was the above written correctly?

4. Does everything previously written about validation actually apply to all other types of output (P2PK, P2PKH, P2WPKH, P2SH etc.). That is, validating on creation and then potentially marking an invalid transaction during execution (although with P2PKH this can only happen by combining a locking and unlocking script where the signature is not good, not like with an OP_RETURN transaction that UTXO itself marks an invalid transaction regardless to the unlock script)?

2 Answers 2

3

If the transaction output scripts are only executed at the time they are attempted to spent, does it mean that in scriptPubKey (transaction output script) we can write whatever we want and its validity will be only checked at the time of using?

Yes. Indeed, the scriptPubKey doesn't even need to be a valid script.

For example, take a look at transaction ebc9fa1196a59e192352d76c0f6e73167046b9d37b8302b6bb6968dfd279b767. None of its outputs have a valid script as they all consist of push opcodes without pushing the expected amount of data. This makes these outputs forever unspendable, but because scriptPubKeys aren't checked before spending, transactions that create them are valid.

On the other hand, if we add something additional in front of OP_RETURN (some random opcode) in scriptPubKey, it will not pass validation since it's not recognized as a standard transaction, so a transaction that has this output would be invalidated

You might be confusing validity and standardness. There are only a handful standard output formats, one of which is OP_RETURN which consists of exactly one OP_RETURN opcode and then only push opcodes and data (up to 83 bytes by default). Adding other opcodes to the script would make it non-standard but not invalid, as we've already seen that scriptPubKeys aren't checked for validity.

20
  • 1
    That is correct, except perhaps for the last sentence. Miners don't necessarily run the default Bitcoin Core node policy and can accept non-standard transactions via other channels than the peer-to-peer network. But in general it's correct. Commented Aug 1, 2023 at 18:06
  • 1
    One way in which scriptPubKeys do affect validity is (a) through their size (which contributes to the block weight) and (b) surprisingly, sigops in scriptPubKeys are counted towards the 20000 sigops per block limit, despite only being executed at spending time. Commented Aug 1, 2023 at 18:23
  • 1
    @Filip That's correct. Miners are allowed to put transactions in their blocks with arbitrary scriptPubKey byte arrays (as long as the resulting block doesn't violate any of the many other rules, which do include weight and sigops limits). Commented Aug 1, 2023 at 18:26
  • 1
    No, there is no specific validity check of scriptPubKeys. I'm just talking about the overall "is the block not too big" check that's done once for the block, as an example for how scriptPubKeys (in this case, their length) do have the ability to affect block validity. Commented Aug 1, 2023 at 18:37
  • 1
    @Filip Right, exactly. I just want to make it clear that "no specific check for validity of scriptPubKey" does not mean that the scriptPubKey's contents is irrelevant. As another (trivial) example, you already know that scriptPubKeys are covered by transaction signatures, so the wrong scriptPubKey can lead to a signature check failure. Commented Aug 1, 2023 at 18:47
0

Bitcoin Core will perform some lightweight checks in any incoming transactions and check whether they match a set of Relay Policy standards. If they do, then they broadcast the transaction to its peers and accept to mempool. However, policy checks aren't consensus, nor execute the transaction script. It mostly constrains resource usage and disallows some obscure OPs combination.

As of today, bitcoin core will match all outputs against some known transaction outputs: Bare Multisig, P2PK, Data Carrier (OP_RETURN), P2PKH, P2SH… and will only broadcast transactions matching those know templates. There are many explanations for that, like disincentivising creating transactions that would interfere with SF and because so obscure OPs aren't well tested. But by default, core calls any tx that is not a known template a non-standard tx and if you don't change anything, you can't get core to broadcast those. It doesn't do extensive validations, like validating the public keys because this is costly and can open some DDoS vectors.

This is not a validation itself. As noted, you only ever validate a script once it gets spent. Moreover, all those checks are for mempool transactions and don't apply to transactions that somehow get into a block. Miners can add transactions violating policy rules if they like.

Data Carrier transactions have a special treatment because they are "Provable unspendable", so you can remove them from your UTXO set.

2
  • First of all, thanks for your reply. Yes, I understand that when a non-standard transaction comes it will be discarded, it will not be forwarded to other nodes. But what if a standard transaction comes through? Let's say an OP_RETURN transaction? Does that validation then take place as I described under the first question? That is, the validation of the output is in the context of whether the size of the script is good, whether all opcodes are good, etc, while input validation is based on the execution of the script where during that execution the transaction may also be declared invalid.
    – dassd
    Commented Aug 1, 2023 at 17:06
  • 2
    There is no requirement that all opcodes in a scriptPubKey are good. Literally any byte vector is allowed (but see my comment on the other answer). Commented Aug 1, 2023 at 18:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.