I'm trying to understand how to validate the first non-coinbase transaction, that is transaction 1 of block 169, as it was validated in the old days.

This transaction has one input, which decoded ScriptSig is exactly:

PUSH (71 bytes: 70 bytes ECDSA signature ANS.1 in DER format and trailing SIGHASH_ALL byte)

This input refers to output 0 of transaction 0 of block 9, which ScriptPubKey is exactly:

PUSH (65 bytes: not-compressed flag byte and 64 public key x and y) OP_CHECKSIG

My question is: in those old days, how did we know that we had to run a P2PKH to validate the transaction? Simply put, did we just concatenate ScriptSig and ScriptPubKey...:

PUSH (71 bytes) PUSH (65 bytes) OP_CHECKSIG

..and run the resulting script (that is: running OP_CHECKSIG as it is coded in EvalScript() in src/interpreter.cpp of the Bitcoin Core), which was supposed to be a P2PKH script, or did we create a more elaborate script from those scripts to validate?

Because nowadays, after some BIPs (witnesses, and so on), the P2PKH script looks more elaborated:



For those like me who are interested in learning about the bitcoin by coding it from scratch and using the first blocks as a data reference, I later found this very good book. You may also find interesting to check the first Bitcoin code here.

  • 2
    The input on transaction f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16 is P2PK not P2PKH.
    – Murch
    Nov 19 at 16:49
  • 1
    This really has absolutely nothing to do with any differences in modern bitcoin, it’s just how it has always been. That’s a pay2ip transaction and they weren’t P2PKH “offline addresses” in the nomenclature of the time.
    – Claris
    Nov 19 at 18:09
  • Thanks, it's more clear now. A follow-up: nowadays, what would be the criteria for a node to identify this transaction as a P2PK transaction ? The length of the scripts ? The contents of the scripts ? Nov 19 at 18:58
  • You could tell because there would be no need for the "OP_DUP OP_HASH160 Public-Key-Hash OP_EQUAL" sequence.
    – hft
    Nov 20 at 2:04
  • 1
    In the original Bitcoin, you sent money by putting an IP address in the "to" field, your node connected to that IP address directly and requested a public key, and then you paid to that public key. Addresses were originally "offline addresses" for when the person wasn't running a node at the time, or for some other reason it wasn't possible to use this method.
    – Claris
    Nov 22 at 17:42

My question is: in those old days, how did we know that we had to run a P2PKH to validate the transaction?

We didn't "know that we had to run..." Rather, in the old days, one would pay to public key instead of pay to public key hash. This made the validation scripts look simple.

The combined validation script for P2PK literally just looks like:

(sig) (pubkey) (checksig)

Contrast this with the P2PKH combined validation script, which looks like:

(sig) (pubkey) (dup) (hash160) (pubkeyhash) (equal?) (checksig),

where all the stuff in the middle of the P2PKH script, between (pubkey) and (checksig), is basically just to go from the public key hash (which is the only thing the person creating the transaction knows) to the actual public key (stored on the sigScript side for P2PKH).

So, you can tell them apart because the validation scripts look different. For example, you could look for the "OP_DUP OP_HASH160 public-key-hash OP_EQUAL" sequence.

  • 1
    Thanks for the explanation! Nov 20 at 19:34
  • P2PK was used with P2IP, meaning nobody had to interact with raw public keys. An exception is block rewards, which remained P2PK long after that went out of fashion.
    – Claris
    Nov 22 at 17:44
  • Support for P2PKH addresses was present in the first released Bitcoin code. And I think this answer misses the most important point: the script interpreter doesn't have to tell scripts apart (and doesn't). It just executes them, indiscriminately. Nov 22 at 17:51
  • 1
    Yeah, that's true. I guess I didn't parse the question fully. (But apparently well enough to answer the question OP must have had in mind.) I didn't mean to imply that the script interpreter has to tell the difference--just that OP can tell the scripts apart using the suggested method. I edited my answer.
    – hft
    Nov 22 at 19:44

My question is: in those old days, how did we know that we had to run a P2PKH to validate the transaction?

We didn't, and we don't.

The validation code simply executes the scripts, instruction by instruction. The fact that we (now) call these particular scripts P2PK or P2PKH scripts is just a human designation, that determines how they get shown by wallets. But the validation code doesn't care.

Perhaps this helps: script is a programming language. Any time a transaction output was created, the wallet would construct in the transaction outputs a little program that determined how that output can be spent. Most commonly, the transaction output would be one of a very small number of specific types (e.g. P2PKH), which we've given special names. But transactions weren't, and aren't, restricted to just those two types. Scripts could use whatever opcodes they wanted, to encode whatever conditions they wanted.

Now, some things have changed since "the old days", which do factor in here:

  • Very early on, the scriptSig (unlocking script in the input) and the scriptPubKey (locking script in the output) were concatenated, and then executed as one, together. This is no longer the case since this was discovered to be trivially insecure, in 2010. Now the scriptSig is executed first, and then the scriptPubKey is executed separately, copying just the final state of the first as initial state for the second.
  • The introduction of P2SH in 2012 (BIP16) did actually introduce a special pattern that validation nodes do specifically recognize. BIP16's rule in short is "IF the scriptPubKey exactly matches this template, some additional validation rules are triggered". That's because P2SH moved the actually executed script logic from the scriptPubKey to the scriptSig, and the scriptPubKey only contains a magic hash of the real script, redirecting execution to the script in the scriptSig. So since P2SH, senders don't actually "know" what script they are sending to anymore, only its hash.
  • Something similar to P2SH was done again in 2017 with the introduction of segwit (BIP141).
  • There used to be support for pay-to-IP addresses, where your node would literally connect to that IP, ask it for a scriptPubKey to send to, and then construct a transaction that paid that did. This was very insecure (no encryption or authentication, just whatever the IP responds), and has long since been removed. Such pay-to-IP scripts were generally P2PK ones.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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