<p>It is a <em>little-endian</em> double SHA256 hash of the <em>binary</em> transaction data</p>
<hr />
<p>Some subtle mistakes I've seen people make:</p>
<ul>
<li>Not converting hex to binary before hashing. <code>Hash(&quot;DEADBEEF&quot;)</code> is not the same as the required <code>Hash(0xDEADBEEF)</code></li>
<li>Not changing a big-endian result to little-endian - reversing the byte order.</li>
</ul>
<hr />
<p>See <a href="https://go.dev/play/p/PDURm9NTLYm" rel="nofollow noreferrer">https://go.dev/play/p/PDURm9NTLYm</a> for a worked example using your data.</p>
<pre class="lang-go prettyprint-override"><code>package main

import (
    &quot;crypto/sha256&quot;
    &quot;encoding/hex&quot;
    &quot;fmt&quot;
    &quot;log&quot;
    &quot;strings&quot;
)

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 = &quot;f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16&quot;

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

    // 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(&quot;TransactionID is %s as expected\n&quot;, transactionID)
    } else {
        fmt.Println(&quot;We made a mistake somewhere\n&quot;)
        fmt.Printf(&quot;calculated %s\nexpected  %s\n&quot;, 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)
    }
}
</code></pre>
<p>when run ...</p>
<pre><code>TransactionID is f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16 as expected
</code></pre>

CC BY-SA 4.0
2022-06-17T10:54:52.807Z
2023-07-13T18:37:26.747Z
2023-07-13T18:37:26.747Z
RedGrittyBrick
<p>Transaction ID (TXID) are determined by a double SHA256 hash of the transaction data, but represented in <a href="https://learnmeabitcoin.com/technical/little-endian" rel="noreferrer">little-endian</a>.</p>
<p>For example, the transaction data of the coinbase transaction is:</p>
<pre><code>01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0102ffffffff0100f2052a01000000434104d46c4968bde02899d2aa0963367c7a6ce34eec332b32e42e5f3407e052d64ac625da6f0718e7b302140434bd725706957c092db53805b821a85b23a7ac61725bac00000000
</code></pre>
<p>Hash it twice with SHA256.</p>
<pre><code>SHA256(SHA256(tx_data)) = 82501c1178fa0b222c1f3d474ec726b832013f0a532b44bb620cce8624a5feb1
</code></pre>
<p>Reverse the bytes to little-endian:</p>
<pre><code>b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082
</code></pre>
<p>Same goes for every transaction that's included in the block.</p>

CC BY-SA 4.0
2022-06-17T09:28:44.840Z
If i paste the TXDATA into a double SHA256 Hasher, for some reason, I don't get 82501c1178fa0b222c1f3d474ec726b832013f0a532b44bb620cce8624a5feb1.
Jamo
CC BY-SA 4.0
2022-06-17T09:29:05.740Z
Would you happen to know why? This is the generator: https://www.webdevtutor.net/tools/online-hash-generator-sha256d
Jamo
CC BY-SA 4.0
2022-06-17T09:44:16.457Z
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](https://emn178.github.io/online-tools/sha256.html) instead and choose "Hex" from the dropdown.
Angelo
CC BY-SA 4.0
2022-06-17T09:18:36.697Z
2022-06-17T09:19:52.297Z
2022-06-17T09:19:52.297Z
Angelo
<p>Consider the hex data of block 170.
<a href="https://i.sstatic.net/lXGkm.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/lXGkm.jpg" alt="enter image description here" /></a></p>
<p>The coinbase TXID is this: b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082 and the second TXID is: f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16, but how can we extrapolate this from this hex data?</p>

<block><coinbase-transaction><transaction-id>
How are TXIDs determined from the raw hex data of a block? Also, what is the coinbase transaction?
Jamo
# How are TXIDs determined from the raw hex data of a block? Also, what is the coinbase transaction?

(Asked by: username_0 on 2022-06-17)

Consider the hex data of block 170.
[![enter image description here](https://i.sstatic.net/lXGkm.jpg)](https://i.sstatic.net/lXGkm.jpg)

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

**Tags:** block, coinbase-transaction, transaction-id


---

## 2 answers

### Answer by username_2 on 2022-06-17. Score: 5 | Accepted answer

Transaction ID (TXID) are determined by a double SHA256 hash of the transaction data, but represented in [little-endian](https://learnmeabitcoin.com/technical/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.

> **Comments:**
> **username_0**: If i paste the TXDATA into a double SHA256 Hasher, for some reason, I don't get 82501c1178fa0b222c1f3d474ec726b832013f0a532b44bb620cce8624a5feb1.  
> **username_0**: Would you happen to know why? This is the generator: https://www.webdevtutor.net/tools/online-hash-generator-sha256d  
> **username_2**: 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](https://emn178.github.io/online-tools/sha256.html) instead and choose "Hex" from the dropdown.  

---

### Answer by username_1 on 2022-06-17. Score: 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.

```go
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

```


---

