<blockquote>
<p>Is there a quick and dirty way to detect all transactions whose tx-id can be found in more than one transaction since the genesis block?</p>
</blockquote>
<p>There are multiple ways to read your question.</p>
<h3>Are there cases where the same transaction has been included into the blockchain multiple times?</h3>
<p><a href="https://blockexplorer.com/block/00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721" rel="nofollow noreferrer">Yes</a>. There is one recorded instance of the same coinbase appearing twice. The problem this causes is that only one of these can be redeemed. It also makes it possible to reduce a fully-confirmed transaction to one confirmation, though I don't understand the details. <a href="https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki" rel="nofollow noreferrer">BIP34</a> fixed this.</p>
<h3>Are there cases where the same input hash appears in multiple transactions?</h3>
<p>Yes. It happens all the time. For example, transaction <a href="https://blockchain.info/tx/9fa3d63d7a251da39c3785f7140975c96d5c985889d0867042dddc4be5218cc3" rel="nofollow noreferrer">9fa3...</a> has two outputs. Those two outputs were spent by two different transactions. Each transaction needed to include the same input hash (though the vout field was different.)</p>
<h3>Are there are any known collisions in SHA256?</h3>
<p>No.</p>
<blockquote>
<p>I would also like to see mutated transactions as well although I am not sure if the blockchain keeps a historical track of the mutated transactions.</p>
</blockquote>
<p>It doesn't.</p>

CC BY-SA 3.0
2014-12-26T22:28:03.207Z
Thanks, Nick. "There are multiple ways to read your question." What I need is a fast way to query the blockchain: `SELECT TxId, COUNT(*) c FROM blockchain GROUP BY TxId HAVING c > 1`;
Doug Peters
CC BY-SA 3.0
2014-12-26T22:31:23.680Z
@DougPeters Is that different from the first interpretation of your question?
Nick ODell
CC BY-SA 3.0
2014-12-26T23:52:20.830Z
Not really, I was just wondering if you are aware of a neat way to achieve this without having to look it up on blockchain.info or any other third-party service.
Doug Peters
CC BY-SA 3.0
2014-12-26T20:14:30.057Z
2014-12-26T22:31:44.027Z
2020-06-16T11:10:03.350Z
Nick ODell
<p>The coinbase transactions <a href="https://www.blockchain.com/btc/tx/e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468" rel="nofollow noreferrer">e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468</a> and d5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599 both exist in two blocks. </p>

<p>This problem was solved in <a href="https://github.com/bitcoin/bitcoin/commit/a206b0ea12eb4606b93323268fc81a4f1f952531" rel="nofollow noreferrer">BIP30</a> so this cannot happen again.</p>

<p>BIP30 also dictates that it is the newest version of these transactions that is spendable.</p>

CC BY-SA 4.0
2019-06-26T15:36:38.660Z
2019-06-26T15:36:38.660Z
Thorkil Værge
<p>I've written a NodeJS script that uses Bitcoin Core's REST API to scan up to block 227835, which is the <a href="https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki#result" rel="nofollow noreferrer">last version 1 block</a>. It takes about half an hour to run and it reports the full list of duplicate coinbase transactions as:</p>

<pre><code>454279874213763724535987336644243549a273058910332236515429488599 91812 91842
5356640744203756384561725255950751537320676481287559742658862468 91722 91880
</code></pre>

<p>The script (sometimes when requests timeout, it reports the request for which block failed, so you can see the progress):</p>



<pre><code>const { performance } = require("perf_hooks");
const fetch = require("node-fetch");

const LAST_V1_BLOCK = 227835;
var hashes = [];
var hashes_len = 0;
var block_heights = [];

async function getBlockHash(height) {
  return (await fetch("http://127.0.0.1:8332/rest/blockhashbyheight/" + height + ".json")
    .then((response) =&gt; {
      return response.json();
    }).catch((err) =&gt; {
      console.log("Retrying " + height);
      return getBlockHash(height);
    }))
}

async function getCoinbaseHash(hash) {
  return (await fetch("http://127.0.0.1:8332/rest/block/" + hash + ".json")
    .then((response) =&gt; {
      return response.json();
    }).catch((err) =&gt; {
      console.log("Retrying " + hash);
      return getCoinbaseHash(hash);
    }))
}

async function getCoinbaseHashByHeight(height) {
  return (await getCoinbaseHash((await getBlockHash(height)).blockhash)).tx[0].txid
}

const hex_alphabet = Uint32Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15]);
const hex_encode = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"];

// I'm forcing big endian, even though order doesn't matter in this code
// It means you can use this code to find the block with the lowest hash
function eightTo32(a) {
  var out = new Uint32Array(8);
  for (var i = 0; i &lt; 8; i++)
    out[i] = a[4 * i] &lt;&lt; 24 | a[4 * i + 1] &lt;&lt; 16 | a[4 * i + 2] &lt;&lt; 8 | a[4 * i + 3];
  return out;
}

function thirty2To8(a) {
  var out = new Uint8Array(32);
  for (var i = 0; i &lt; 8; i++) {
    out[4 * i] = (a[i] &gt;&gt; 24) &amp; 255;
    out[4 * i + 1] = (a[i] &gt;&gt; 16) &amp; 255;
    out[4 * i + 2] = (a[i] &gt;&gt; 8) &amp; 255;
    out[4 * i + 3] = (a[i]) &amp; 255;
  }
  return out;
}

function decodeHex(str) {
  var out = new Uint8Array(32);
  var scratch = new Uint32Array(64);
  for (var i = 0; i &lt; 64; i++)
    scratch[i] = str.charCodeAt(i);
  for (var i = 0; i &lt; 64; i++)
    scratch[i] -= 48;
  for (var i = 0; i &lt; 32; i++)
    out[i] = scratch[i &lt;&lt; 1];
  for (var i = 0; i &lt; 32; i++)
    out[i] &lt;&lt;= 4;
  for (var i = 0; i &lt; 64; i += 2)
    out[i &gt;&gt;&gt; 1] += scratch[i + 1];
  return eightTo32(out);
}

function encodeHex(arr) {
  var x = thirty2To8(arr)
  var s = "";
  for (var i = 0; i &lt; 32; i++)
    s += hex_encode[x[i] &gt;&gt;&gt; 4] + hex_encode[x[i] &amp; 15];
  return s;
}

function compareHashes(a, b) {
  for (var i = 0; i &lt; 8; i++)
    if (a[i] &lt; b[i])
      return -1;
    else if (a[i] &gt; b[i])
      return 1;
  return 0;
}

// We need a binary tree
// Taken from https://stackoverflow.com/q/1344500
// Start = 0
// End = length
function locationOf(element, start, end) {
  const pivot = start + ((end - start) &gt;&gt;&gt; 1);
  const arrPiv = hashes[pivot];
  const com = compareHashes(arrPiv, element)
  if (!com) return pivot;
  if (end - start &lt;= 1) {
    if (com == 1)
      return pivot - 1;
    return pivot;
  }
  if (com == -1)
    return locationOf(element, pivot, end);
  return locationOf(element, start, pivot);
}

// Taken from https://stackoverflow.com/q/1344500
function insert(element, height) {
  var l = locationOf(element, 0, hashes_len);
  hashes.splice(l + 1, 0, element);
  block_heights.splice(l + 1, 0, height);
  hashes_len++;
  return 0;
}

async function run() {
  var t0 = performance.now();

  // Process the genesis block out of the loop
  hashes.push(decodeHex(await getCoinbaseHashByHeight(0)));
  block_heights.push(0);
  hashes_len++;

  var pre_hashes = [];
  // Batches of 5 for await
  for (var i = 0, r = (LAST_V1_BLOCK / 5 | 0) * 5; i &lt; r; i += 5) {
    for (var x = 0; x &lt; 5; x++)
      pre_hashes[i + x] = getCoinbaseHashByHeight(i + x + 1);
    for (var x = 0; x &lt; 5; x++)
      pre_hashes[i + x] = await pre_hashes[i + x];
  }
  for (; i &lt; LAST_V1_BLOCK; i++) pre_hashes[i] = await getCoinbaseHashByHeight(i + 1);

  console.log("Done acquiring");

  for (var i = 0; i &lt; LAST_V1_BLOCK; i++)
    pre_hashes[i] = decodeHex(pre_hashes[i]);
  for (var i = 0; i &lt; LAST_V1_BLOCK; i++)
    insert(pre_hashes[i], i + 1);

  console.log("Sorting done")

  for (var i = 1; i &lt; hashes_len; i++)
    if (!compareHashes(hashes[i - 1], hashes[i]))
      console.log(encodeHex(hashes[i]) + " " + block_heights[i - 1] + " " + block_heights[i]);
  console.log("Duplicate check done")
  var t1 = performance.now();
  console.log("Took " + (t1 - t0) + " ms.");
}

run()
</code></pre>

CC BY-SA 4.0
2020-04-20T14:05:25.550Z
2020-04-20T14:05:25.550Z
MCCCS
<p>Is there a quick and dirty way to detect all transactions whose <code>tx-id</code> can be found in more than one transaction since the genesis block? </p>

<p>I would also like to see mutated transactions as well although I am not sure if the blockchain keeps a historical track of the mutated transactions.</p>

CC BY-SA 3.0
2014-12-26T18:39:48.527Z
Are you asking for duplicate transactions, that is 2 transactions with the same id? If so there aren't any.
ike
CC BY-SA 3.0
2014-12-26T18:47:50.437Z
@ike how did you come up to this conclusion? Tx-ids are not supposed to be unique https://bitcointalk.org/index.php?topic=28387.0
Doug Peters
CC BY-SA 3.0
2014-12-26T18:49:54.040Z
They are sha-256 hashes, and it would take more computing power than exists in the world to create one deliberately. You want to look for an improbable scenario to make sure it didn't happen? I'm sure there are people who've searched and found none; if there was, we'd hear about it.
ike
CC BY-SA 3.0
2014-12-26T18:50:15.737Z
In the same way that I didn't just generate your private key on my computer.
ike
CC BY-SA 3.0
2014-12-26T19:03:10.037Z
@ike I understand that the propabilty for this to happen is close to zero but not zero and that the 55 million txs that took place since `genesis` in total is not even close to what it would normally take to brute-force the sha256 algo, all I am asking is if there is a handy way to query the bitcoin network for such scenarios.
Doug Peters
CC BY-SA 3.0
2014-12-26T19:04:43.797Z
Ok, the way to do it would be to have a copy of the blockchain, list all txids, and scan for dups. I'll lookup the commands and put that as an answer.
ike
CC BY-SA 3.0
2014-12-26T19:19:40.457Z
It looks complicated, I'd have to write a couple of scripts. This may help you if you know a little bash, though. https://bitcoin.stackexchange.com/questions/4601/how-can-i-read-information-from-the-blockchain
ike
<transactions><transaction-malleability><transaction-id>
Duplicate tx ids
Doug Peters
# Duplicate tx ids

(Asked by: username_0 on 2014-12-26)

Is there a quick and dirty way to detect all transactions whose `tx-id` can be found in more than one transaction since the genesis block?

I would also like to see mutated transactions as well although I am not sure if the blockchain keeps a historical track of the mutated transactions.

**Tags:** transactions, transaction-malleability, transaction-id

> **Comments:**
> **username_1**: Are you asking for duplicate transactions, that is 2 transactions with the same id? If so there aren't any.  
> **username_0**: @username_1 how did you come up to this conclusion? Tx-ids are not supposed to be unique https://bitcointalk.org/index.php?topic=28387.0  
> **username_1**: They are sha-256 hashes, and it would take more computing power than exists in the world to create one deliberately. You want to look for an improbable scenario to make sure it didn't happen? I'm sure there are people who've searched and found none; if there was, we'd hear about it.  
> **username_1**: In the same way that I didn't just generate your private key on my computer.  
> **username_0**: @username_1 I understand that the propabilty for this to happen is close to zero but not zero and that the 55 million txs that took place since `genesis` in total is not even close to what it would normally take to brute-force the sha256 algo, all I am asking is if there is a handy way to query the bitcoin network for such scenarios.  
> **username_1**: Ok, the way to do it would be to have a copy of the blockchain, list all txids, and scan for dups. I'll lookup the commands and put that as an answer.  
> **username_1**: It looks complicated, I'd have to write a couple of scripts. This may help you if you know a little bash, though. https://bitcoin.stackexchange.com/questions/4601/how-can-i-read-information-from-the-blockchain  

---

## 3 answers

### Answer by username_2 on 2014-12-26. Score: 5

> Is there a quick and dirty way to detect all transactions whose tx-id can be found in more than one transaction since the genesis block?

There are multiple ways to read your question.

### Are there cases where the same transaction has been included into the blockchain multiple times?

[Yes](https://blockexplorer.com/block/00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721). There is one recorded instance of the same coinbase appearing twice. The problem this causes is that only one of these can be redeemed. It also makes it possible to reduce a fully-confirmed transaction to one confirmation, though I don't understand the details. [BIP34](https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki) fixed this.

### Are there cases where the same input hash appears in multiple transactions?

Yes. It happens all the time. For example, transaction [9fa3...](https://blockchain.info/tx/9fa3d63d7a251da39c3785f7140975c96d5c985889d0867042dddc4be5218cc3) has two outputs. Those two outputs were spent by two different transactions. Each transaction needed to include the same input hash (though the vout field was different.)

### Are there are any known collisions in SHA256?

No.

> I would also like to see mutated transactions as well although I am not sure if the blockchain keeps a historical track of the mutated transactions.

It doesn't.

> **Comments:**
> **username_0**: Thanks, username_2. "There are multiple ways to read your question." What I need is a fast way to query the blockchain: `SELECT TxId, COUNT(*) c FROM blockchain GROUP BY TxId HAVING c > 1`;  
> **username_2**: @username_0 Is that different from the first interpretation of your question?  
> **username_0**: Not really, I was just wondering if you are aware of a neat way to achieve this without having to look it up on blockchain.info or any other third-party service.  

---

### Answer by username_3 on 2019-06-26. Score: 0

The coinbase transactions [e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468](https://www.blockchain.com/btc/tx/e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468) and d5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599 both exist in two blocks.

This problem was solved in [BIP30](https://github.com/bitcoin/bitcoin/commit/a206b0ea12eb4606b93323268fc81a4f1f952531) so this cannot happen again.

BIP30 also dictates that it is the newest version of these transactions that is spendable.


---

### Answer by username_4 on 2020-04-20. Score: 0

I've written a NodeJS script that uses Bitcoin Core's REST API to scan up to block 227835, which is the [last version 1 block](https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki#result). It takes about half an hour to run and it reports the full list of duplicate coinbase transactions as:

```
454279874213763724535987336644243549a273058910332236515429488599 91812 91842
5356640744203756384561725255950751537320676481287559742658862468 91722 91880

```

The script (sometimes when requests timeout, it reports the request for which block failed, so you can see the progress):

```
const { performance } = require("perf_hooks");
const fetch = require("node-fetch");

const LAST_V1_BLOCK = 227835;
var hashes = [];
var hashes_len = 0;
var block_heights = [];

async function getBlockHash(height) {
  return (await fetch("http://127.0.0.1:8332/rest/blockhashbyheight/" + height + ".json")
    .then((response) => {
      return response.json();
    }).catch((err) => {
      console.log("Retrying " + height);
      return getBlockHash(height);
    }))
}

async function getCoinbaseHash(hash) {
  return (await fetch("http://127.0.0.1:8332/rest/block/" + hash + ".json")
    .then((response) => {
      return response.json();
    }).catch((err) => {
      console.log("Retrying " + hash);
      return getCoinbaseHash(hash);
    }))
}

async function getCoinbaseHashByHeight(height) {
  return (await getCoinbaseHash((await getBlockHash(height)).blockhash)).tx[0].txid
}

const hex_alphabet = Uint32Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15]);
const hex_encode = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"];

// I'm forcing big endian, even though order doesn't matter in this code
// It means you can use this code to find the block with the lowest hash
function eightTo32(a) {
  var out = new Uint32Array(8);
  for (var i = 0; i < 8; i++)
    out[i] = a[4 * i] << 24 | a[4 * i + 1] << 16 | a[4 * i + 2] << 8 | a[4 * i + 3];
  return out;
}

function thirty2To8(a) {
  var out = new Uint8Array(32);
  for (var i = 0; i < 8; i++) {
    out[4 * i] = (a[i] >> 24) & 255;
    out[4 * i + 1] = (a[i] >> 16) & 255;
    out[4 * i + 2] = (a[i] >> 8) & 255;
    out[4 * i + 3] = (a[i]) & 255;
  }
  return out;
}

function decodeHex(str) {
  var out = new Uint8Array(32);
  var scratch = new Uint32Array(64);
  for (var i = 0; i < 64; i++)
    scratch[i] = str.charCodeAt(i);
  for (var i = 0; i < 64; i++)
    scratch[i] -= 48;
  for (var i = 0; i < 32; i++)
    out[i] = scratch[i << 1];
  for (var i = 0; i < 32; i++)
    out[i] <<= 4;
  for (var i = 0; i < 64; i += 2)
    out[i >>> 1] += scratch[i + 1];
  return eightTo32(out);
}

function encodeHex(arr) {
  var x = thirty2To8(arr)
  var s = "";
  for (var i = 0; i < 32; i++)
    s += hex_encode[x[i] >>> 4] + hex_encode[x[i] & 15];
  return s;
}

function compareHashes(a, b) {
  for (var i = 0; i < 8; i++)
    if (a[i] < b[i])
      return -1;
    else if (a[i] > b[i])
      return 1;
  return 0;
}

// We need a binary tree
// Taken from https://stackoverflow.com/q/1344500
// Start = 0
// End = length
function locationOf(element, start, end) {
  const pivot = start + ((end - start) >>> 1);
  const arrPiv = hashes[pivot];
  const com = compareHashes(arrPiv, element)
  if (!com) return pivot;
  if (end - start <= 1) {
    if (com == 1)
      return pivot - 1;
    return pivot;
  }
  if (com == -1)
    return locationOf(element, pivot, end);
  return locationOf(element, start, pivot);
}

// Taken from https://stackoverflow.com/q/1344500
function insert(element, height) {
  var l = locationOf(element, 0, hashes_len);
  hashes.splice(l + 1, 0, element);
  block_heights.splice(l + 1, 0, height);
  hashes_len++;
  return 0;
}

async function run() {
  var t0 = performance.now();

  // Process the genesis block out of the loop
  hashes.push(decodeHex(await getCoinbaseHashByHeight(0)));
  block_heights.push(0);
  hashes_len++;

  var pre_hashes = [];
  // Batches of 5 for await
  for (var i = 0, r = (LAST_V1_BLOCK / 5 | 0) * 5; i < r; i += 5) {
    for (var x = 0; x < 5; x++)
      pre_hashes[i + x] = getCoinbaseHashByHeight(i + x + 1);
    for (var x = 0; x < 5; x++)
      pre_hashes[i + x] = await pre_hashes[i + x];
  }
  for (; i < LAST_V1_BLOCK; i++) pre_hashes[i] = await getCoinbaseHashByHeight(i + 1);

  console.log("Done acquiring");

  for (var i = 0; i < LAST_V1_BLOCK; i++)
    pre_hashes[i] = decodeHex(pre_hashes[i]);
  for (var i = 0; i < LAST_V1_BLOCK; i++)
    insert(pre_hashes[i], i + 1);

  console.log("Sorting done")

  for (var i = 1; i < hashes_len; i++)
    if (!compareHashes(hashes[i - 1], hashes[i]))
      console.log(encodeHex(hashes[i]) + " " + block_heights[i - 1] + " " + block_heights[i]);
  console.log("Duplicate check done")
  var t1 = performance.now();
  console.log("Took " + (t1 - t0) + " ms.");
}

run()

```


---

