2

I was reading this from the Bitcoin wiki (https://en.bitcoin.it/wiki/From_address). I understand the concept of UTXOs and that any input to a transaction is an output from a previous transaction. I also have a rough understanding of how ScriptSig and ScriptPubKey interact. The article mentions "advanced transactions will probably defeat most block explorers" and gives examples of some transactions one of them being:

54fabd73f1d20c980a0686bf0035078e07f69c58437e4d586fb29aa0bee9814f

When looking at this transaction in say blockchain.com the input is marked as "unknown" and when looking at the JSON for the transaction the input address is "null"

  "inputs": [
    {
      "coinbase": false,
      "txid": "a60143eb3f8d3cd1f42cca874f35736186d67c488efd3c1b7214bbd74b310e0c",
      "output": 0,
      "sigscript": "483045022100d92e4b61452d91a473a43cde4b469a472467c0ba0cbd5ebba0834e4f4762810402204802b76b7783db57ac1f61d2992799810e173e91055938750815b6d8a675902e014f",
      "sequence": 4294967295,
      "pkscript": "76009f69905160a56b210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71ad6c",
      "value": 9000000,
      "address": null,
      "witness": []
    }
  ],

I then looked at the input TXID a60143eb3f8d3cd1f42cca874f35736186d67c488efd3c1b7214bbd74b310e0c and the output address is also "null"

  "outputs": [
    {
      "address": null,
      "pkscript": "76009f69905160a56b210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71ad6c",
      "value": 9000000,
      "spent": true,
      "spender": {
        "txid": "54fabd73f1d20c980a0686bf0035078e07f69c58437e4d586fb29aa0bee9814f",
        "input": 0
      }
    }
  ]

Can someone explain for me what is going on here? And how one goes about creating these "advanced transactions" that apparently defeat block explorers that the article mentions (as in what makes them special to break block explorers?)

I have seen the question at Can PUSHDATA/OP_RETURN be used to break a trail of transactions permanently? and the answer talking about the "nonstandard" vout type but I don't understand what this means.

EDIT: I have seen "null" addresses in the context of OP_RETURN as outputs but my understanding is that those can't ever be spent so I don't understand how they are used as inputs.

0

1 Answer 1

4

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 standardized output script templates that cover the most common uses. 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_DUP
OP_0
OP_LESSTHAN
OP_VERIFY
OP_ABS
OP_PUSHNUM_1
OP_PUSHNUM_16
OP_WITHIN
OP_TOALTSTACK
OP_PUSHBYTES_33 0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71
OP_CHECKSIGVERIFY
OP_FROMALTSTACK

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

OP_PUSHBYTES_72 
3045022100d92e4b61452d91a473a43cde4b469a472467c0ba0cbd5ebba0834e4f4762810402204802b76b7783db57ac1f61d2992799810e173e91055938750815b6d8a675902e01
OP_PUSHNUM_NEG1

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.

6
  • Can you please elaborate a bit more on the first part? I don't quite understand what you mean. I understand the coin flow is from 1HHRAfK7sS9QVNsmYqfEHy4sY7dfJDXMT1 to 1GMaxweLLbo8mdXvnnC19Wt2wigiYUKgEB but what accounts for/what is the "unknown" in the middle? Jan 18 at 4:34
  • 1
    I added the actual output script and input script. Does that answer your question or could you rephrase what you are looking for?
    – Murch
    Jan 18 at 13:27
  • Sorry I posted a comment, then I thought I got it, then I didn't and so posted and deleted a bunch of comments. So I've learned these are called non-standard P2SH addresses. Can you elaborate on why this particular script creates a non-standard address as opposed to a 3 address? Also I find it rather odd that the input JSON I put in my original question has a pkscript as part of it. I thought pkscripts were only present in outputs. What exactly does it do here? Jan 19 at 5:10
  • 1
    This is not a P2SH address, it’s a bare output. The input lists the prior transaction’s output as a convenience because both the input and output script are required to validate an input. I think you were looking at the input of a601…0e0c though, rather than the input of 54Fa…814f when you saw the P2KPH output script of the transaction output it was spending—I updated my answer to provide a bit more context.
    – Murch
    Jan 19 at 13:24
  • 1
    @user2334659 The Bitcoin Core decodescript RPC can decode scripts given in hex to opcode format. Jan 20 at 12:51

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.