§ 05 · Transactions
TXID
A transaction's fingerprint, and its witness twin
On this page 7 sections
A txidTXID: A transaction's ID: the double SHA-256 hash of the transaction without its witness, shown with its bytes reversed. is a transaction’s name: a 32-byte hash of its contents. Change one byte of the transaction and the name changes completely.
Pearl computes it exactly as Bitcoin does. Strip the witness, hash the rest twice with SHA-256, and show the result backwards. A second name, the wtxidWTXID: The witness transaction ID: like the TXID, but the hash covers the witness too., hashes everything including the witness. Here are both, worked out for a real payment.
Try it
SHA256d is just SHA-256, applied to its own output. Try it on any input.
How is a txid computed?
Take this real payment from block 130,825:
| Field | Bytes | Value |
|---|---|---|
| Version version | 4 @0 | 1 int32 little-endian. Pearl wallets and pearld coinbases use version 1; relay policy accepts 1-2. |
| Marker marker | 1 @4 | 0x00 Segwit marker (BIP-144): says witness data follows the outputs. |
| Flag flag | 1 @5 | 0x01 Witness flag; 0x01 is the only value Pearl accepts. |
| Input count vin.length | 1 @6 | 1 CompactSize number of inputs. |
| Previous txid vin[0].txid | 32 @7 | 33218153e215d1a1e80941850a696af178fc83bd6cf266be92e7ba9170553959 The transaction being spent, stored byte-reversed (internal order); shown here in normal display order. |
| Output index vin[0].vout | 4 @39 | 683 Which output of that transaction is spent (uint32 LE). |
| scriptSig length vin[0].scriptSig.length | 1 @43 | 0 Always 0 for non-coinbase inputs in Pearl: every spend uses the witness instead. |
| Sequence vin[0].sequence | 4 @44 | 0xffffffff Final (0xffffffff): no RBF signal, no relative locktime, and locktime is ignored for this input. Pearl wallets use this. |
| Output count vout.length | 1 @48 | 2 CompactSize number of outputs. |
| Amount vout[0].value | 8 @49 | 295,646,640 grains (2.95646640 PRL) int64 little-endian, in grains (1 PRL = 100,000,000 grains). |
| Script length vout[0].scriptPubKey.length | 1 @57 | 34 CompactSize length of the locking script. |
| Locking script vout[0].scriptPubKey | 34 @58 | prl1p674s9jt2xs4amk6aq7ul867kcp8qwll5zsvpzzu6revewsu5z6eqv9d5z4 OP_1 OP_PUSHBYTES_32 <output key Q>: a Taproot output. |
| Amount vout[1].value | 8 @92 | 200,000,000 grains (2.00000000 PRL) int64 little-endian, in grains (1 PRL = 100,000,000 grains). |
| Script length vout[1].scriptPubKey.length | 1 @100 | 34 CompactSize length of the locking script. |
| Locking script vout[1].scriptPubKey | 34 @101 | prl1pvt5a5d5z42egswfv7uscht7rv2rj3z4m8n3qp3w35592ydq88v4seuhn70 OP_1 OP_PUSHBYTES_32 <output key Q>: a Taproot output. |
| Witness items witness[0].length | 1 @135 | 1 Number of witness stack items for input 0. |
| Schnorr signature length witness[0][0].length | 1 @136 | 64 CompactSize length of this witness item. |
| Schnorr signature witness[0][0] | 64 @137 | 4686c7014749649b25555874c7772ecb7a44e85454893ed5888db11ebcdc82a22d74ce1a1671d02810f5ba1dca3277409e95a653ba9644099f7da26be7a86ba2 64-byte BIP-340 signature (R.x ‖ s) with SIGHASH_DEFAULT: a Taproot key-path spend. |
| Locktime locktime | 4 @201 | 0 0: no time lock. |
-
Strip the witness
Remove the marker and flag (00 01) and the witness (01 40 4686c701…a86ba2). What’s left is version, inputs, outputs and locktime: 137 of the 205 bytes. -
Hash once
SHA-256 of those 137 bytes:ab06ab7ff1c853149284c345b20af8a71e5bd69f0ff6aff81abfe5d7d01eb328. -
Hash again
SHA-256 of that 32-byte result:c984b3c142eccd72e50f7ba61f1b4ed2ddf00388d931efce39d7df4a2ae019d9. This is the txid in internal byte order. -
Reverse for display
Read the 32 bytes backwards:d919e02a4adfd739ceef31d98803f0ddd24e1b1fa67b0fe572cdec42c1b384c9. That’s the txid explorers show.
The 137 stripped bytes, for checking at home:
01000000 01 5939557091bae792be66f26cbd83fc78f16a690a854109e8a1d115e253812133 ab020000 00 ffffffff
02 b0359f1100000000 22 5120d7ab02c96a342bdddb5d07b9f3ebd6c04e077ff41418110b9a1e5997439416b2
00c2eb0b00000000 22 512062e9da3682aab288392cf7218bafc36287288abb3ce200c5d1a50aa234073b2b
00000000 (Spaces and line breaks added for reading; hash the bytes without them.)
Why is it shown backwards?
Habit, inherited from Bitcoin. Early Bitcoin code treated a hash as one huge little-endian number and printed it biggest digit first, which reverses the bytes. Every Bitcoin-derived chain kept the convention, Pearl included.
So there are two orders, and both are in use:
| Where | Order | The payment’s txid |
|---|---|---|
| Explorers, RPCs, wallets | display (reversed) | d919e02a…c1b384c9 |
| Inside transactions (outpoints), Merkle trees | internal (as hashed) | c984b3c1…2ae019d9 |
You can see it in the payment itself: its input spends a transaction shown everywhere as 33218153…70553959, but the bytes in the input are 59395570…53812133. Same 32 bytes, opposite order. The byte order page has more.
What is the wtxid?
The same recipe applied to the whole transaction, marker, flag and witness included:
| Internal order | Display order | |
|---|---|---|
| txid (137 bytes hashed) | c984b3c1…2ae019d9 |
d919e02a4adfd739ceef31d98803f0ddd24e1b1fa67b0fe572cdec42c1b384c9 |
| wtxid (205 bytes hashed) | 30cee874…185c7d1e |
1e7d5c18e8982cd32f03a9c1409bb9c92d39dd4312cfffcf2ce9eb0c74e8ce30 |
A transaction with no witness has wtxid = txid. Pearl’s genesis coinbase, serialized the old way with no witness, has both equal to 302f59c6f1239648bd38eddf16b22acc8c8df3c96de2e4f552bd2f38371675c1. Since it’s the only transaction in block 0, that’s also the genesis block’s Merkle root.
Why leave the witness out of the txid?
To make the name unforgeable after the fact. Before segwit, a third party could re-encode a signature in an equivalent form, which changed the txid without invalidating the transaction. Any unconfirmed transaction that spent its outputs, referring to it by the old txid, was suddenly pointing at nothing.
With the witness excluded, the txid is fixed before anyone signs. You can build and sign a chain of transactions that spend each other’s outputs, knowing their names won’t change. The wtxid still changes if the witness does; it’s used where the witness itself must be committed to.
What goes wrong when you compute one?
Four mistakes cover almost every “my txid doesn’t match” puzzle:
- Hashing the hex text. The characters
01000000…are not the bytes01 00 00 00…. Decode first. - Forgetting to strip the witness. Hash all 205 bytes and you get the wtxid,
1e7d5c18…, not the txid. - Hashing once. A single SHA-256 gives
ab06ab7f…. The txid needs a second pass. - Mixing the two orders. An outpoint written with the display-order txid points at a transaction that doesn’t exist. Inside the bytes, always use internal order.
Make a guess
Two different transactions in one block with the same txid: possible?
Think of your answer first, then check it.
Answer No.
Identical txids mean identical stripped bytes, which would be the same transaction twice. Pearl’s block check rejects a block that contains a duplicate txid (the guard Bitcoin added after a 2012 Merkle-tree bug). And BIP-34 makes every coinbase unique by putting the block height in it, so even coinbases can’t collide.
Where are txids and wtxids used?
- Outpoints. Every input names the output it spends by txid (internal order) and index.
- The block’s Merkle root. The header commits to all txids in the block through a Merkle tree.
- The witness commitment. A second Merkle tree over all wtxids, with the coinbase’s wtxid replaced by 32 zero bytes, is committed in the coinbase. See coinbase.
Code: txid in JavaScript
With @noble/hashes:
import { sha256 } from '@noble/hashes/sha2.js';
import { hexToBytes, bytesToHex } from '@noble/hashes/utils.js';
const stripped = hexToBytes('01000000015939…00000000'); // the 137 bytes above, no spaces
const internal = sha256(sha256(stripped));
const txid = bytesToHex(internal.reverse()); // d919e02a…c1b384c9