output – What’s going on with this “NULL address input” transaction?


    When a receiver asks to be sent money, they specify the conditions under which they want to be able to spend the funds in an output script. Later when the receiver wants to spend their funds, they need to provide an input script that satisfies the output script of the output they are spending. In transaction validation, the input script is evaluated first, then the resulting stack is used as the starting point to evaluate the output script.

    For example with P2PKH, the input script contains a signature and a public key, the output script contains OP_DUP OP_HASH160 pubkeyhash OP_EQUALVERIFY OP_CHECKSIG.

    In evaluation the input script pushes first the signature then the pubkey on the stack. The stack is then passed to the output script which:

    1. duplicates the pubkey
    2. replaces the first of the two pubkey copies with a hash of the pubkey
    3. pushes the pubkeyhash to the stack
    4. Verifies that the pubkeyhash pushed from the output script and the pubkeyhash hashed from the pubkey in the input are equal
    5. Checks that the remaining pubkey and signature amount to a valid signature of the transaction.

    There are a number of output scripts that are standardized for frequent use. Some of these cover single-sig usecases, but there are also multiple standard output types for complex scripts. Addresses are a convenient shorthand to communicate the receiver’s output scripts to the sender for standard output script types. Even before P2SH was introduced, a receiver could define arbitrary conditions by writing out the corresponding output script using the opcodes defined in Bitcoin Script. These bare scripts are uncommon, since their arbitrary content does not lend itself to an address standard. The UX is horrible: instead of an address with a checksum, the receiver and sender have to exchange the actual script, and the sender needs to create a raw transaction manually specifying the output script. (P2SH was introduced to improve the UX around defining your own spending conditions while allowing for an address standard.)

    The transaction you are looking at contains such a bare script: instead of following one of the standard output schemes, the receiver defined their own output script and satisfied it accordingly in the succeeding input.

    The output script specified in the output a601…0e0c:0 of the preceding transaction is:

    OP_PUSHBYTES_33 0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71

    The input script in the first input of 54fa…814f is:


    The script essentially amounts to an obfuscated version of a P2PK output as can be seen by evaluating the script execution:

    1. The input script pushes a signature onto the stack.
      Current Stack (left is bottom): SIG
    2. The number -1 is pushed onto the stack
      Stack: SIG -1
    3. The stack is passed to output script validation
    4. The number -1 is duplicated
      Stack: SIG -1 -1
    5. A 0 is pushed onto the stack
      Stack: SIG -1 -1 0
    6. OP_LESSTHAN consumes two items (a, b) from the stack returns a 1 to the stack because a (-1) is less than b (0).
      Stack: SIG -1 1
    7. OP_VERIFY consumes the 1 on top of the stack and succeeds
      Stack: SIG -1
    8. OP_ABS replaces the top stack item with its absolute value
      Stack: SIG 1
    9. A 1 is pushed to the stack
      Stack: SIG 1 1
    10. A 16 is pushed to the stack
      Stack: SIG 1 1 16
    11. OP_WITHIN consumes three values (x min max) and returns a 1 because x is greater than or equal to the minimum and smaller than the maximum
      Stack: SIG 1
    12. OP_TOALTSTACK removes the top element from the stack and puts it on the alternative stack.
      Stack: SIG, Altstack: 1
    13. A pubkey is pushed on the stack:
      Stack: SIG PUBKEY, Altstack: 1
    14. OP_CHECKSIGVERIFY consumes the signature and pubkey and verifies that the signature is valid in the context of the transaction and pubkey.
      Stack: <empty>, Altstack: 1
    15. OP_FROMALTSTACK removes the top value of the alt stack and places it on the stack:
      Stack: 1, Altstack: <empty>
    16. The script succeeds because it ends with a single truthy value 1 on the stack.

    These transactions may break some block explorers in the sense that some block explorers may only have support for standard scripts and would not properly display bare outputs. It seems to me that modern block explorers no longer suffer from that: Mempool.space shows the entire output sc appears to doript just fine
    e.g. mempool.space shows the output script in the preceding transaction…

    enter image description here
    … and the spending transaction just fine.

    In case “breaking block explorers” was understood as a privacy benefit, this transaction is not more private. In Bitcoin transactions do not spend funds from addresses: addresses merely specify the conditions under which funds can be spent, but each input must specify exactly which transaction output it is spending.
    The preceding transaction a601…0e0c created a single output a601…0e0c:0 with the mentioned bare output script that could be spent by the owner of that script, and the first input of 54fa…814f explicitly spent that a601…0e0c:0, to create another transaction output 54fa…814f:0 that can be spent by the receiver in control of the address 1GMaxweLLbo8mdXvnnC19Wt2wigiYUKgEB.
    I.e. every UTXO is uniquely identifiable and the transaction graph is public information. The absence of an address has no privacy benefit.


    Source link

    Leave a Reply

    Your email address will not be published. Required fields are marked *