42

I'm trying to calculate the hash of transactions in bitcoin blocks, but I'm not getting the right answers.

For example, the genesis block has a single transaction.

Here's how I'm attempting to calculate its hash...

Transactions are encoded as:

  • a 32 bit 'nVersion'
  • a list of input transactions, vin
  • a list of output transactions, vout
  • a 32 bit 'nLockTime'

For the transaction in the genesis block, these are:

  • nVersion: 01000000
  • inputs
    • count: 01
    • 1st input:
      • prevout_hash: 0000000000000000000000000000000000000000000000000000000000000000
      • prevout_n: ffffffff
      • scriptSig: 4d:04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73
      • sequence: ffffffff
  • outputs
    • count: 01
    • 1st output:
      • value: 00f2052a01000000 (hex(50*10^8) is 0000012a05f200, and bitcoin puts the bytes in reverse order)
      • scriptPubKey: 43:4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac
  • nLockTime: 00000000

If I string all those together end to end, I get 204 bytes: 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000

Taking the sha256 hash of this gives 27362e66e032c731c1c8519f43063fe0e5d070db1c0c3552bb04afa18a31c6bf.

Taking the sha256 hash of that hash gives 3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a.

But the real transaction hash according to blockexplorer.com is 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b.

What am I doing wrong? How can I get to the correct transaction hash?

Here's my working in Python:

>>> import Crypto.Hash.SHA256 as hash, binascii
>>> tx = '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'
>>> len(binascii.unhexlify(tx))
204
>>> hash.new(binascii.unhexlify(tx)).digest().encode('hex_codec')
'27362e66e032c731c1c8519f43063fe0e5d070db1c0c3552bb04afa18a31c6bf'
>>> hash.new(hash.new(binascii.unhexlify(tx)).digest()).digest().encode('hex_codec')
'3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a'
1

2 Answers 2

39

Taking the sha256 hash of that hash gives

3b a3 ed fd 7a 7b ..............

But the real transaction hash according to blockexplorer.com is

.............. 7b 7a fd ed a3 3b

The answer I was getting was correct, but bytewise reversed. I need to get used to Bitcoin using little-endian storage.

4
  • 1
    I found the answer to my own question shortly after asking it. Should I delete the question and the answer or leave them both? Commented Feb 6, 2012 at 6:31
  • 4
    It's a valid question, it's a correct answer and you did the work to find it. I'd give it a few days to make sure someone doesn't post a more complete (or awesome) answer and then just accept your own answer. Ideally it's not the way StackExchange works, but it's perfectly valid to self-answer - trust me you're not a trend-setter on this one ;) Commented Feb 6, 2012 at 8:27
  • 1
    Actually, it is encouraged to post and share your own answer, when applicable. stackoverflow.com/help/self-answer Commented Mar 8, 2014 at 22:25
  • 1
    You just saved me so many hours of research . i was facing exactly the same issue. cheers
    – Karan
    Commented May 23, 2018 at 18:15
1

I've come across this several times when trying to come up with an easy way to calculate a txid, and I finally decided to try and write a little script to do the same. I used built-in libraries and figured this would be a good place to share the script:

#!/usr/bin/env python3
import hashlib
import sys
inhex = sys.argv[1]
tx = bytes.fromhex(inhex)
h1 = hashlib.sha256(tx).hexdigest()
b1 = bytes.fromhex(h1)
h2 = hashlib.sha256(b1).hexdigest()
ba = bytearray.fromhex(h2)
ba.reverse()
id = ''.join(format(x, '02x') for x in ba)
print(id)

I called the script txhash.py. For validation's sake, running ./txhash.py 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000 returns 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b as expected in the original question.

1
  • 2
    It is worth noting that this won't work for Segwit transactions, which probably form the majority of transactions nowadays. There is now a distinction between TXID and WTXID. For a Segwit transaction this would give the WTXID not the TXID. Commented May 14 at 10:27

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.