1

there, I've already looked at other similar posts on here but with little luck. All im trying to do is calculate the TXID of a transaction after downloading the transaction in hexadecimal from a blockchain explorer VIA an API.

The problem is that the TXID calculated Isn't the TXID we expect.

Here's the code, I'm using bitcoin-utils


from bitcoinutils.transactions import Transaction
import requests

Fetch the raw transaction data from the blockchain.info API

tx_hash = '9d2d91b764ba2559b098cdd30525e2160bb15c6e27d6869e7b121a9037d8bd86' api_response = requests.get(f'https://blockchain.info/rawtx/{tx_hash}?format=hex')

if api_response.status_code == 200: raw_tx_hex = str(api_response.text) else: print(f"Error fetching transaction data: {api_response.status_code}")

mytrans = Transaction.from_raw(raw_tx_hex) print(mytrans.get_txid())

1 Answers1

3

That's a SegWit transaction, not all of it is part of the transaction hash preimage (see here for details). You have to exclude the SegWit parts. This Bash one-liner returns the correct TXID:

echo '0100000001189a3f6fbfb614264c8176cd2d3836882afc3c0940d698d6b481f3e5cb733c200000000000ffffffff0240420f00000000001976a914341b568f59229818c460b1795ad48cd78895c54d88ac6eeefa4a00000000160014d701ce5e753bd9454d343c8a3b86d84a3c34dbf500000000' | tr -d '\n' | xxd -r -p | sha256sum | grep -oE '^[0-9a-f]+' | xxd -r -p | sha256sum | grep -oE '^[0-9a-f]+' | tac -rs '..'; echo

Output

9d2d91b764ba2559b098cdd30525e2160bb15c6e27d6869e7b121a9037d8bd86

Explanation

Your TX can be disassembled as follows, and you have to hash everything except the bold parts:

TX version: 01000000
Witness marker and flag: 0001
Input count: 01
Prevout reference: 189a3f6fbfb614264c8176cd2d3836882afc3c0940d698d6b481f3e5cb733c2000000000
Unlocking script length: 00
Unlocking script: EMPTY (note: non-SegWit inputs will have script length >0 and have the unlocking script here instead of in the witness, so for non-SegWit this will not be EMPTY)
Sequence: ffffffff
Output count: 02
Output 01: 40420f00000000001976a914341b568f59229818c460b1795ad48cd78895c54d88ac
Output 02: 6eeefa4a00000000160014d701ce5e753bd9454d343c8a3b86d84a3c34dbf5
Witness count: 02
Witness 01: 473044022001609cd43eb8e9b8f8438eded9f6b10bad32efd7620724ccd2ed5277c0c6a3ae02200f0c1c3f4c409ada536d2363a2d8bdad418df67fed9b36bfa4482bd9985bf39601
Witness 02: 2102ee3c98964dd1bfe13bee16c0b95fcf8281f12c5885d1fcb7b59fc2cb01ca7632
TX locktime: 00000000

Concatenating only the non-SegWit parts gives us the TX hash preimage: 0100000001189a3f6fbfb614264c8176cd2d3836882afc3c0940d698d6b481f3e5cb733c200000000000ffffffff0240420f00000000001976a914341b568f59229818c460b1795ad48cd78895c54d88ac6eeefa4a00000000160014d701ce5e753bd9454d343c8a3b86d84a3c34dbf500000000

bca-0353f40e
  • 1,025
  • 2
  • 14
  • Thank you bca-0353f40e for you answer, would you be able to edit my python code so that all is needed from the user is the TXID? Thanks – RabbitHole6565 Nov 07 '23 at 11:45
  • 1
    That's too much work for me. You can figure it out, just parse the transaction according to format specification and skip over SegWit parts. – bca-0353f40e Nov 07 '23 at 11:48
  • Do you know of any API's which will return a TX hash preimage, from a TXID? – RabbitHole6565 Nov 07 '23 at 12:26
  • Don't know, but maybe you can look for a library. I found PyPI which implements "tx_hash : (hex or bin tx) -> hash" https://pypi.org/project/pycryptotools/0.2.1/ – bca-0353f40e Nov 07 '23 at 13:42
  • Source seems to have been deleted, here's a mirror: https://bitcointalk.org/index.php?topic=5445428.0

    Link to tx_hash implementation: https://github.com/ZenulAbidin/pycryptotools/blob/main/pycryptotools/transaction.py#L278

    – bca-0353f40e Nov 07 '23 at 13:42