2

Consider the hex data of block 170. enter image description here

The coinbase TXID is this: b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082 and the second TXID is: f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16, but how can we extrapolate this from this hex data?

2 Answers 2

5

Transaction ID (TXID) are determined by a double SHA256 hash of the transaction data, but represented in little-endian.

For example, the transaction data of the coinbase transaction is:

01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0102ffffffff0100f2052a01000000434104d46c4968bde02899d2aa0963367c7a6ce34eec332b32e42e5f3407e052d64ac625da6f0718e7b302140434bd725706957c092db53805b821a85b23a7ac61725bac00000000

Hash it twice with SHA256.

SHA256(SHA256(tx_data)) = 82501c1178fa0b222c1f3d474ec726b832013f0a532b44bb620cce8624a5feb1

Reverse the bytes to little-endian:

b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082

Same goes for every transaction that's included in the block.

3
  • If i paste the TXDATA into a double SHA256 Hasher, for some reason, I don't get 82501c1178fa0b222c1f3d474ec726b832013f0a532b44bb620cce8624a5feb1.
    – Jamo
    Commented Jun 17, 2022 at 9:28
  • Would you happen to know why? This is the generator: webdevtutor.net/tools/online-hash-generator-sha256d
    – Jamo
    Commented Jun 17, 2022 at 9:29
  • 1
    Yes. Your generator behaves your input as string, not as bytes, while the block header is already meant to be considered as bytes. Use this generator instead and choose "Hex" from the dropdown.
    – Angelo
    Commented Jun 17, 2022 at 9:44
4

It is a little-endian double SHA256 hash of the binary transaction data


Some subtle mistakes I've seen people make:

  • Not converting hex to binary before hashing. Hash("DEADBEEF") is not the same as the required Hash(0xDEADBEEF)
  • Not changing a big-endian result to little-endian - reversing the byte order.

See https://go.dev/play/p/PDURm9NTLYm for a worked example using your data.

package main

import (
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "log"
    "strings"
)

const data string = `0100000001c997a5 e56e104102fa209c 
6a852dd90660a20b 2d9c352423edce25 857fcd3704000000 004847304402204e 
45e16932b8af5149 61a1d3a1a25fdf3f 4f7732e9d624c6c6 1548ab5fb8cd4102 
20181522ec8eca07 de4860a4acdd1290 9d831cc56cbbac46 22082221a8768d1d 
0901ffffffff0200 ca9a3b0000000043 4104ae1a62fe09c5 f51b13905f07f06b 
99a2f7159b2225f3 74cd378d71302fa2 8414e7aab37397f5 54a7df5f142c21c1 
b7303b8a0626f1ba ded5c72a704f7e6c d84cac00286bee00 00000043410411db 
93e1dcdb8a016b49 840f8c53bc1eb68a 382e97b1482ecad7 b148a6909a5cb2e0 
eaddfb84ccf97444 64f82e160bfa9b8b 64f9d4c03f999b86 43f656b412a3ac00 
000000`

const expectedID string = "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16"

func main() {
    // Remove whitespace in our hex string
    transactionHex := strings.Join(strings.Fields(data), "")

    // Convert hex representation back into binary data
    transactionBin := make([]byte, hex.DecodedLen(len(transactionHex)))
    _, err := hex.Decode(transactionBin, []byte(transactionHex))
    Check(err)

    // Calculate the transaction ID using a double SHA256 hash
    sum := sha256.Sum256(transactionBin)
    sum = sha256.Sum256(sum[:])

    // Reverse the bytes because Bitcoin uses little-endian byte-ordering!
    // and convert binary value to a hex string representation for human readability
    transactionID := hex.EncodeToString(Reverse(sum[:]))

    // See if we got the correct value
    if transactionID == expectedID {
        fmt.Printf("TransactionID is %s as expected\n", transactionID)
    } else {
        fmt.Println("We made a mistake somewhere\n")
        fmt.Printf("calculated %s\nexpected  %s\n", transactionID, expectedID)
    }
}

func Reverse(input []byte) []byte {
    l := len(input)
    reversed := make([]byte, l)
    for i, n := range input {
        j := l - i - 1
        reversed[j] = n
    }
    return reversed
}

func Check(err error) {
    if err != nil {
        log.Fatal(err)
    }
}

when run ...

TransactionID is f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16 as expected

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.