<p>Addresses that start with <code>3...</code> are <a href="https://btcinformation.org/en/glossary/p2sh-address" rel="nofollow noreferrer">P2SH addresses</a>, and they've been around for almost 6 years now. Historically they saw limited use - used by multisig wallets like Copay and GreenAddress. The compatibility mode of SegWit however also uses P2SH, making their use more common recently.</p>
<p>The main issue is that your code for converting an address to a scriptPubKey does not look at the version byte. After Base58 decoding the address, you should get &lt;1-byte version&gt; &lt;20-byte hash&gt; &lt;4-byte checksum&gt; structure. If that version is 0, which it is for <code>1...</code> addressses, that hash is a public key hash, and you correctly construct the corresponding scriptPubKey.</p>
<p>However, if that version number is 5, it is a P2SH address, which was specified in <a href="https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki" rel="nofollow noreferrer">BIP13</a>, which uses a corresponding scriptPubKey specified in <a href="https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki" rel="nofollow noreferrer">BIP16</a>.</p>
<p>While SegWit initially just used the old P2SH format, A new address format is being introduced for SegWit as well (which gives slightly better performance, flexibility, and error detection capabilities), described in <a href="https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki" rel="nofollow noreferrer">BIP173</a>. (disclaimer: I'm an author of BIP173). These addresses will start with <code>bc1...</code>.</p>
<p>I advise you to stop your service, and at the very least implement verification that the version number is expected, together with a test set you can find in many implementations. If you feel like it, you can also implement BIP13 and BIP173 addresses, both of which will likely become more prevalent soon.</p>

CC BY-SA 3.0
2017-12-01T18:53:03.567Z
Whoa, this is crazy interesting. I don't know how I've spent all these years never dealing with a Bitcoin address starting with something other than '1'. Even outside of my app, all of my Electrum addresses start with '1' too. Ok, so you're right, when I unpack the 18v address it does in fact have a leading byte set to 5.  So you're saying: (1) check that version byte! and (2) if it's a 5, I need to change the structure of that script? What exactly is "BIP"? Is that the reference doc? Why so many people claim that leading '3' is a "segwit" address? So much bad info out there :(
Festus Martingale
CC BY-SA 3.0
2017-12-01T19:07:15.163Z
No, the first thing you need to do is check the checksum and the version number. Thinking that the version is always zero is the cause of this problem. Even if you believe it will always be zero, your software should fail if it isn't.
Pieter Wuille
CC BY-SA 3.0
2017-12-01T19:10:07.480Z
BIPs, or Bitcoin Improvement Proposals is a process for publishing ideas around changes to Bitcoin's rules or their use: https://github.com/bitcoin/bips
Pieter Wuille
CC BY-SA 3.0
2017-12-01T19:12:01.677Z
SegWit needed a way to be compatible with old software (so that old wallets could send to SegWit wallets), so it can be used either in compatibility mode (which uses P2SH 3... addresses) or native mode (which uses BIP173 bc1... addresses). Before SegWit, the only software that would hand out P2SH addresses is multisig wallets like GreenAddress or copay.
Pieter Wuille
CC BY-SA 3.0
2017-12-01T19:16:59.773Z
Gotcha. When the user submits an address to the app, that's when I'm running the checksum validation. I've got that part covered. My mistake was thinking that what I now know is the "version byte" was just a constant zero. Now I can check for it and take action. Thanks! I'm still a bit confused on how the format of my scriptPubKey will change if the version number is 5. Presumably I'll be able to hunt that down somewhere.
Festus Martingale
CC BY-SA 3.0
2017-12-01T19:24:57.687Z
You'll find that in BIP16.
Pieter Wuille
CC BY-SA 3.0
2017-12-04T20:26:42.843Z
hi guys @PieterWuille thanks for this superb QA, awesome.  it has led me to ask a question .. https://bitcoin.stackexchange.com/questions/64166
Fattie
CC BY-SA 3.0
2017-12-09T01:45:24.717Z
Wow, such a great read guys.
Atticus
CC BY-SA 4.0
2017-12-01T18:34:56.703Z
2022-05-24T20:12:22.650Z
2022-05-24T20:12:22.650Z
Pieter Wuille
<p>Years ago I designed a .NET module which facilitates the transmission of BTC to my customers. It creates a binary representation of the desired transaction based on the material presented <a href="http://bitcoin.stackexchange.com/questions/3374/how-to-redeem-a-basic-tx">here</a> and <a href="http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html" rel="noreferrer">here</a>:</p>

<p>The binary representation is then converted to hex and pushed out through various free services like BlockExplorer, BlockCypher, etc. </p>

<p>The system has been running flawlessly for years. Until yesterday. A customer requested that <strong>0.0284377 BTC</strong> to be sent to <strong>38MRMGjMBMp4k7vZhKLHhcM9Pm8AMLy18v</strong>. He never received it. Sure enough, he was right. It was never sent.</p>

<p>I looked through all of my logs and saw that my software did in fact submit a transaction with the following inputs and outputs:</p>

<ul>
<li>input: 13P38hMYJXFdxDJJn8TtPUJZFXmcpf2J99</li>
<li>output #1: 38MRMGjMBMp4k7vZhKLHhcM9Pm8AMLy18v (my customer)</li>
<li>output #2: 1Ny3CV3rAsNMWpLfpxhXW3Fh71YmMEXXU7 (my change address)</li>
</ul>

<p>Everything looked fine on my side but sure enough, when I looked on block explorer, what I saw shocked me. Consider transaction <a href="https://blockexplorer.com/tx/9a138b14dcc8ae740073c06933ae04e3b08fe6be6ada0dc175e6484250dfe269" rel="noreferrer">9a138b14dcc8ae740073c06933ae04e3b08fe6be6ada0dc175e6484250dfe269</a> and look at the inputs and outputs:</p>

<p>As you can see, my input is correct. My change address XU7 is also correct. But now look at my customer's address. It says <strong>17fQRjEudTVgexE8aDfhGyzDFEqSnnJJCA</strong> (which I'll refer to as JCA) instead of the expected <strong>38MRMGjMBMp4k7vZhKLHhcM9Pm8AMLy18v</strong> (which I'll refer to as 18v). What the heck? The JCA address is known neither to me nor to my customer. It's a completely unknown address.</p>

<p>Clearly the problem is in my code somewhere so I dug deeper to find out what made this particular transaction unique. <em>I identified that his desired address (18v) begins with a '3' whereas every other outbound transaction I've completed throughout the history of my app has targeted addresses beginning with '1'.</em></p>

<p>My stopgap measure was to force users to only specify addresses that begin with a 1. But that's a temporary solution. I need to find out what I'm doing wrong.</p>

<p>I turned to Google. Research indicated that addresses beginning with '3' are typically SegWit addresses where as those beginning with '1' are traditional, old-school addresses. I remember all the talk about SegWit a few months back but I figured it didn't affect me and my legacy transactions would still clear properly. Obviously that was a bad judgement call on my part so now I have to figure out what I did incorrectly and where the bogus JCA address came from.</p>

<p>That's where I'm stuck. I think my problem might have to do with uncompressed vs. compressed public keys based upon discussions <a href="https://bitcointalk.org/index.php?topic=129652.0" rel="noreferrer">here</a> and <a href="https://bitcointalk.org/index.php?topic=1692426.msg16985715#msg16985715" rel="noreferrer">here</a>:</p>

<p>Here's what I do know: When it comes time to create the outputs for my transaction, my code does the following (explanation follows):</p>

<pre><code>Func&lt;String,byte[]&gt; makeOutScript=(btcAddrHex)=&gt;{
    byte[] addrBytes=BTCUtils.Base58Decode(btcAddrHex);
    byte[] pubKeyBytes=addrBytes.Take(addrBytes.Length-4).Skip(1).ToArray();

    using(MemoryStream ms=new MemoryStream()){
        using(BinaryWriter bw=new BinaryWriter(ms)){
            bw.Write((byte)0x76);   //op_dup
            bw.Write((byte)0xa9);   //op_hash160
            bw.Write((byte)20);     //size of public key
            bw.Write(pubKeyBytes);  //public key
            bw.Write((byte)0x88);   //op_equalverify
            bw.Write((byte)0xac);   //op_checksig

            bw.Flush();
            return ms.ToArray();
        }
    }
};
</code></pre>

<p>What I'm doing here is: Converting the output address to bytes by Base58 decoding it. I strip off the last four bytes, which are the checksum, and the first byte, which is always 0x00 (apparently a network indicator of some sort). That leaves me with the raw public key. Actually, looking at my internal notes, it's not actually the public key but rather 0x04 prepended to the public key and then passed through SHA256 and then RIPEMD160. But I'll refer to this blob as the public key. From there the byte sequence is 0x76, 0xa9, 20 (the size of the public key blob), the public key blob itself, 0x88, and 0xac.</p>

<p>I don't pretend to understand what all those single-byte entries mean but the blog posts above said to include them so that's what I did, and until now it's worked just fine.</p>

<p>The question is: How on earth did the 18v address get transformed into the JCA address when it was submitted to the network? Is my "size of public key" value (20) incorrect, perhaps? At a gut level, it does seem odd that a compressed (18v) and uncompressed (JCA) public key would both have a constant size of 20. But maybe I'm on the wrong track entirely and compression has nothing to do with it.</p>

<p>I don't have to tell you how awful it would be if this transaction were 100 BTC instead of 0.0284377. I lucked out that my bug was triggered on a low value transaction. But I really want to solve this. Can you point me down the right path?</p>

<raw-transaction><p2sh><address-format>
My raw transaction destroyed 0.0284377 BTC. What did I do wrong?
Festus Martingale
# My raw transaction destroyed 0.0284377 BTC. What did I do wrong?

(Asked by: username_0 on 2017-12-01)

Years ago I designed a .NET module which facilitates the transmission of BTC to my customers. It creates a binary representation of the desired transaction based on the material presented [here](http://bitcoin.stackexchange.com/questions/3374/how-to-redeem-a-basic-tx) and [here](http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html):

The binary representation is then converted to hex and pushed out through various free services like BlockExplorer, BlockCypher, etc.

The system has been running flawlessly for years. Until yesterday. A customer requested that **0.0284377 BTC** to be sent to **38MRMGjMBMp4k7vZhKLHhcM9Pm8AMLy18v**. He never received it. Sure enough, he was right. It was never sent.

I looked through all of my logs and saw that my software did in fact submit a transaction with the following inputs and outputs:

* input: 13P38hMYJXFdxDJJn8TtPUJZFXmcpf2J99
* output #1: 38MRMGjMBMp4k7vZhKLHhcM9Pm8AMLy18v (my customer)
* output #2: 1Ny3CV3rAsNMWpLfpxhXW3Fh71YmMEXXU7 (my change address)

Everything looked fine on my side but sure enough, when I looked on block explorer, what I saw shocked me. Consider transaction [9a138b14dcc8ae740073c06933ae04e3b08fe6be6ada0dc175e6484250dfe269](https://blockexplorer.com/tx/9a138b14dcc8ae740073c06933ae04e3b08fe6be6ada0dc175e6484250dfe269) and look at the inputs and outputs:

As you can see, my input is correct. My change address XU7 is also correct. But now look at my customer's address. It says **17fQRjEudTVgexE8aDfhGyzDFEqSnnJJCA** (which I'll refer to as JCA) instead of the expected **38MRMGjMBMp4k7vZhKLHhcM9Pm8AMLy18v** (which I'll refer to as 18v). What the heck? The JCA address is known neither to me nor to my customer. It's a completely unknown address.

Clearly the problem is in my code somewhere so I dug deeper to find out what made this particular transaction unique. *I identified that his desired address (18v) begins with a '3' whereas every other outbound transaction I've completed throughout the history of my app has targeted addresses beginning with '1'.*

My stopgap measure was to force users to only specify addresses that begin with a 1. But that's a temporary solution. I need to find out what I'm doing wrong.

I turned to Google. Research indicated that addresses beginning with '3' are typically SegWit addresses where as those beginning with '1' are traditional, old-school addresses. I remember all the talk about SegWit a few months back but I figured it didn't affect me and my legacy transactions would still clear properly. Obviously that was a bad judgement call on my part so now I have to figure out what I did incorrectly and where the bogus JCA address came from.

That's where I'm stuck. I think my problem might have to do with uncompressed vs. compressed public keys based upon discussions [here](https://bitcointalk.org/index.php?topic=129652.0) and [here](https://bitcointalk.org/index.php?topic=1692426.msg16985715#msg16985715):

Here's what I do know: When it comes time to create the outputs for my transaction, my code does the following (explanation follows):

```
Func<String,byte[]> makeOutScript=(btcAddrHex)=>{
    byte[] addrBytes=BTCUtils.Base58Decode(btcAddrHex);
    byte[] pubKeyBytes=addrBytes.Take(addrBytes.Length-4).Skip(1).ToArray();

    using(MemoryStream ms=new MemoryStream()){
        using(BinaryWriter bw=new BinaryWriter(ms)){
            bw.Write((byte)0x76);   //op_dup
            bw.Write((byte)0xa9);   //op_hash160
            bw.Write((byte)20);     //size of public key
            bw.Write(pubKeyBytes);  //public key
            bw.Write((byte)0x88);   //op_equalverify
            bw.Write((byte)0xac);   //op_checksig

            bw.Flush();
            return ms.ToArray();
        }
    }
};

```

What I'm doing here is: Converting the output address to bytes by Base58 decoding it. I strip off the last four bytes, which are the checksum, and the first byte, which is always 0x00 (apparently a network indicator of some sort). That leaves me with the raw public key. Actually, looking at my internal notes, it's not actually the public key but rather 0x04 prepended to the public key and then passed through SHA256 and then RIPEMD160. But I'll refer to this blob as the public key. From there the byte sequence is 0x76, 0xa9, 20 (the size of the public key blob), the public key blob itself, 0x88, and 0xac.

I don't pretend to understand what all those single-byte entries mean but the blog posts above said to include them so that's what I did, and until now it's worked just fine.

The question is: How on earth did the 18v address get transformed into the JCA address when it was submitted to the network? Is my "size of public key" value (20) incorrect, perhaps? At a gut level, it does seem odd that a compressed (18v) and uncompressed (JCA) public key would both have a constant size of 20. But maybe I'm on the wrong track entirely and compression has nothing to do with it.

I don't have to tell you how awful it would be if this transaction were 100 BTC instead of 0.0284377. I lucked out that my bug was triggered on a low value transaction. But I really want to solve this. Can you point me down the right path?

**Tags:** raw-transaction, p2sh, address-format


---

## 1 answers

### Answer by username_1 on 2017-12-01. Score: 52 | Accepted answer

Addresses that start with `3...` are [P2SH addresses](https://btcinformation.org/en/glossary/p2sh-address), and they've been around for almost 6 years now. Historically they saw limited use - used by multisig wallets like Copay and GreenAddress. The compatibility mode of SegWit however also uses P2SH, making their use more common recently.

The main issue is that your code for converting an address to a scriptPubKey does not look at the version byte. After Base58 decoding the address, you should get <1-byte version> <20-byte hash> <4-byte checksum> structure. If that version is 0, which it is for `1...` addressses, that hash is a public key hash, and you correctly construct the corresponding scriptPubKey.

However, if that version number is 5, it is a P2SH address, which was specified in [BIP13](https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki), which uses a corresponding scriptPubKey specified in [BIP16](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki).

While SegWit initially just used the old P2SH format, A new address format is being introduced for SegWit as well (which gives slightly better performance, flexibility, and error detection capabilities), described in [BIP173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki). (disclaimer: I'm an author of BIP173). These addresses will start with `bc1...`.

I advise you to stop your service, and at the very least implement verification that the version number is expected, together with a test set you can find in many implementations. If you feel like it, you can also implement BIP13 and BIP173 addresses, both of which will likely become more prevalent soon.

> **Comments:**
> **username_0**: Whoa, this is crazy interesting. I don't know how I've spent all these years never dealing with a Bitcoin address starting with something other than '1'. Even outside of my app, all of my Electrum addresses start with '1' too. Ok, so you're right, when I unpack the 18v address it does in fact have a leading byte set to 5.  So you're saying: (1) check that version byte! and (2) if it's a 5, I need to change the structure of that script? What exactly is "BIP"? Is that the reference doc? Why so many people claim that leading '3' is a "segwit" address? So much bad info out there :(  
> **username_1**: No, the first thing you need to do is check the checksum and the version number. Thinking that the version is always zero is the cause of this problem. Even if you believe it will always be zero, your software should fail if it isn't.  
> **username_1**: BIPs, or Bitcoin Improvement Proposals is a process for publishing ideas around changes to Bitcoin's rules or their use: https://github.com/bitcoin/bips  
> **username_1**: SegWit needed a way to be compatible with old software (so that old wallets could send to SegWit wallets), so it can be used either in compatibility mode (which uses P2SH 3... addresses) or native mode (which uses BIP173 bc1... addresses). Before SegWit, the only software that would hand out P2SH addresses is multisig wallets like GreenAddress or copay.  
> **username_0**: Gotcha. When the user submits an address to the app, that's when I'm running the checksum validation. I've got that part covered. My mistake was thinking that what I now know is the "version byte" was just a constant zero. Now I can check for it and take action. Thanks! I'm still a bit confused on how the format of my scriptPubKey will change if the version number is 5. Presumably I'll be able to hunt that down somewhere.  
> **username_1**: You'll find that in BIP16.  
> **username_2**: hi guys @username_1 thanks for this superb QA, awesome.  it has led me to ask a question .. https://bitcoin.stackexchange.com/questions/64166  
> **username_3**: Wow, such a great read guys.  

---

