<p>You need to parse the script and get to the script type by examining the opcodes.</p>

<p>If you examine the <code>rpc/rawtransaction.cpp</code> source file on Bitcoin Core you'll see the RPC call that outputs this is <code>getrawtransaction()</code>. Tracing it further it leads us to <code>ScriptPubKeyToUniv</code> in <code>core_write.cpp</code> which calls so let's take a look at that:</p>

<pre><code>const char* GetTxnOutputType(txnouttype t)
{
    switch (t)
    {
    case TX_NONSTANDARD: return "nonstandard";
    case TX_PUBKEY: return "pubkey";
    case TX_PUBKEYHASH: return "pubkeyhash";
    case TX_SCRIPTHASH: return "scripthash";
    case TX_MULTISIG: return "multisig";
    case TX_NULL_DATA: return "nulldata";
    case TX_WITNESS_V0_KEYHASH: return "witness_v0_keyhash";
    case TX_WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
    case TX_WITNESS_UNKNOWN: return "witness_unknown";
    }
    return nullptr;
}
</code></pre>

<p>This subroutine maps script types to the string name which you asked about. In your case you got a <code>TX_WITNESS_V0_SCRIPTHASH</code> whose value is 0x06 per its definition in <code>script/standard.h</code> :</p>

<pre><code>enum txnouttype
{
    TX_NONSTANDARD,
    // 'standard' transaction types:
    TX_PUBKEY,
    TX_PUBKEYHASH,
    TX_SCRIPTHASH,
    TX_MULTISIG,
    TX_NULL_DATA, //!&lt; unspendable OP_RETURN script that carries data
    TX_WITNESS_V0_SCRIPTHASH,
    TX_WITNESS_V0_KEYHASH,
    TX_WITNESS_UNKNOWN, //!&lt; Only for Witness versions not already defined above
};
</code></pre>

<p>We now know how to extract the <code>scriptPubKey</code> type name from the value, but we don't know how to extract that value from the raw bytes, so let's take a look at that next.</p>

<p><code>txnouttype</code> is extracted from <code>scriptPubkey</code> by <code>ExtractDestinations</code> which is defined in <code>script/standard.cpp</code>, the relevant line being <code>typeRet = Solver(scriptPubKey, vSolutions);</code>. So let's step into <code>Solver</code>.</p>

<p>Here's the answer to your question:</p>

<pre><code>txnouttype Solver(const CScript&amp; scriptPubKey, std::vector&lt;std::vector&lt;unsigned char&gt;&gt;&amp; vSolutionsRet)
{
    vSolutionsRet.clear();

    // Shortcut for pay-to-script-hash, which are more constrained than the other types:
    // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
    if (scriptPubKey.IsPayToScriptHash())
    {
        std::vector&lt;unsigned char&gt; hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
        vSolutionsRet.push_back(hashBytes);
        return TX_SCRIPTHASH;
    }

    int witnessversion;
    std::vector&lt;unsigned char&gt; witnessprogram;
    if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
        if (witnessversion == 0 &amp;&amp; witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) {
            vSolutionsRet.push_back(witnessprogram);
            return TX_WITNESS_V0_KEYHASH;
        }
        if (witnessversion == 0 &amp;&amp; witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
            vSolutionsRet.push_back(witnessprogram);
            return TX_WITNESS_V0_SCRIPTHASH;
        }
        if (witnessversion != 0) {
            vSolutionsRet.push_back(std::vector&lt;unsigned char&gt;{(unsigned char)witnessversion});
            vSolutionsRet.push_back(std::move(witnessprogram));
            return TX_WITNESS_UNKNOWN;
        }
        return TX_NONSTANDARD;
    }

    // Provably prunable, data-carrying output
    //
    // So long as script passes the IsUnspendable() test and all but the first
    // byte passes the IsPushOnly() test we don't care what exactly is in the
    // script.
    if (scriptPubKey.size() &gt;= 1 &amp;&amp; scriptPubKey[0] == OP_RETURN &amp;&amp; scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
        return TX_NULL_DATA;
    }

    std::vector&lt;unsigned char&gt; data;
    if (MatchPayToPubkey(scriptPubKey, data)) {
        vSolutionsRet.push_back(std::move(data));
        return TX_PUBKEY;
    }

    if (MatchPayToPubkeyHash(scriptPubKey, data)) {
        vSolutionsRet.push_back(std::move(data));
        return TX_PUBKEYHASH;
    }

    unsigned int required;
    std::vector&lt;std::vector&lt;unsigned char&gt;&gt; keys;
    if (MatchMultisig(scriptPubKey, required, keys)) {
        vSolutionsRet.push_back({static_cast&lt;unsigned char&gt;(required)}); // safe as required is in range 1..16
        vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
        vSolutionsRet.push_back({static_cast&lt;unsigned char&gt;(keys.size())}); // safe as size is in range 1..16
        return TX_MULTISIG;
    }

    vSolutionsRet.clear();
    return TX_NONSTANDARD;
}
</code></pre>

<p>It returns the <code>txnouttype</code> and here's how it determines each one:</p>

<p><strong>TX_SCRIPTHASH</strong></p>

<pre><code>this-&gt;size() == 23 &amp;&amp;
            (*this)[0] == OP_HASH160 &amp;&amp;
            (*this)[1] == 0x14 &amp;&amp;
            (*this)[22] == OP_EQUAL
</code></pre>

<p>If the script size is 23 bytes, the first script byte is OP_HASH160, second byte is 0x14 and byte 22 is OP_EQUAL then it's a TX_SCRIPTHASH.</p>

<p><strong>Witness Program</strong></p>

<p>The following tests if the script is a witness program:</p>

<pre><code>this-&gt;size() == 34 &amp;&amp;
            (*this)[0] == OP_0 &amp;&amp;
            (*this)[1] == 0x20
</code></pre>

<p>So, if the script is 34 bytes long, the first OP is 0 and the second byte is 0x20 then it's a witness program (<em>This is the case in your question.</em>).</p>

<p>If it's a witness program, then there are 4 possible script types:</p>

<p>First Witness Script type: <strong><code>TX_WITNESS_V0_KEYHASH</code></strong></p>

<pre><code>if (witnessversion == 0 &amp;&amp; witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) {
            vSolutionsRet.push_back(witnessprogram);
            return TX_WITNESS_V0_KEYHASH;
        }
</code></pre>

<p>If witness version is zero and the witness program is WITNESS_V0_KEYHASH_SIZE (20 bytes) long then it's a <code>TX_WITNESS_V0_KEYHASH</code>.</p>

<p>Second Witness Script type: <strong><code>TX_WITNESS_V0_SCRIPTHASH</code></strong></p>

<p>If witness version is zer and the witness program is WITNESS_V0_SCRIPTHASH_SIZE (32 bytes) long then it's a <code>TX_WITNESS_V0_SCRIPTHASH</code>. This is the case in your question. </p>

<p><em>Note: We now know the specific answer to your question : you know if it's a <code>witness_v0_scripthash</code> if the script is 34 bytes long, begins with 00 20 and then there are 32 bytes following it.</em></p>

<p>Let's proceed for completeness.</p>

<p>Third Witness Script type: <strong><code>TX_WITNESS_UNKNOWN</code></strong></p>

<p>If the witness version is different from zero, it's unknown.</p>

<p>Fourth and last Witness script type is <strong><code>TX_NONSTANDARD</code></strong>, which means it's not recognized by Bitcon Core.</p>

<p>Now onto the other script types.</p>

<p><strong><code>TX_NULL_DATA</code></strong></p>

<p>If the <code>scriptPubKey</code> size is more than one byte long and the first <code>OP</code> is a <code>RETURN</code>, then everything that follows is <code>NULL</code> data.</p>

<p><strong><code>TX_PUBKEY</code></strong></p>

<p>If the script is <code>CPubKey::PUBLIC_KEY_SIZE</code> (65) bytes long and the first byte on the script is 65 (<code>CPubKey::PUBLIC_KEY_SIZE</code>) and if the last OP on the script is <code>OP_CHECKSIG</code> then it's a legacy <code>TX_PUBKEY</code> script.</p>

<p><strong><code>TX_PUBKEYHASH</code></strong></p>

<p>If the script is 25 bytes long (this length is harcoded in <code>script/standard.cpp</code>), the first operation is <code>OP_DUP</code>, the second operation is <code>OP_HASH160</code> and script[23] is OP_EQUALVERIFY and script[24] is <code>OP_CHECKSIG</code> then it's the most common type of script of all: <code>TX_PUBKEYHASH</code>.</p>

<p><strong><code>TX_MULTISIG</code></strong></p>

<p>Multisig is solved by <code>MatchMultisig</code> in <code>script/standard.cpp</code>. What it does is parse the script looping through it and calling <code>GetOp</code> (<code>script/script.h</code>) to parse the sig out and <code>CPubKey::ValidSize(data)</code> which checks if each signature is the right size. If at the end of this check we are at the end of the script, verified by <code>(it + 1 == script.end())</code>, then it's a valid multisig script.</p>

<p><strong><code>TX_NONSTANDARD</code></strong></p>

<p>Lastly if none of the above rules match, then it's a nonstandard script containing undefined contents. Most nodes would probably reject this script but miners and pools are able to insert stuff here if they want to.</p>

<p>These are all the script types in Bitcoin. The rules  presented for each one is how you get the type out of scriptPubKey. To turn it into a string you use the enum map in <code>GetTxnOutputType</code>.</p>

CC BY-SA 4.0
2019-10-17T20:02:54.223Z
2019-10-17T20:02:54.223Z
Jose Fonseca
<p>Internally, Bitcoin does not have the concept of <code>scriptPubKey</code> type. To the system, <code>scriptPubKey</code> is simply a mathematical equation into which some bitcoins have been locked (UTXO) and the spender must satisfy the unlocking conditions, which most of the times are the signature(s) and public key(s), in order to spend those bitcoins. These basic construct can be used to build higher level concepts like the <code>scriptPubKey</code> type that you are referring in your question.</p>
<p>Since Bitcoin is a programmable money, a user can lock their bitcoins in a number of different ways. The Bitcoin community has accepted certain output types as standard locking scripts. Below are some of the standard output scripts (<code>scriptPubKey</code>) that can be used to determine the script address type (main net address types have been used):</p>
<ol>
<li><strong>Pay to Public Key Hash (P2PKH):</strong> In this type of script, the bitcoins are locked in the hash of a public key. The output script will look like the following:
<pre><code>{
  &quot;value&quot;: 0.00200000,
  &quot;n&quot;: 0,
  &quot;scriptPubKey&quot;: {
    &quot;asm&quot;: &quot;OP_DUP OP_HASH160 243f1394f44554f4ce3fd68649c19adc483ce924 OP_EQUALVERIFY OP_CHECKSIG&quot;
    &quot;hex&quot;: &quot;76a914243f1394f44554f4ce3fd68649c19adc483ce92488ac&quot;,
    &quot;reqSigs&quot;: 1,
    &quot;type&quot;: &quot;pubkeyhash&quot;,
    &quot;addresses&quot;: [
      &quot;14JetYAhLevTRaePcAAX1vRMwaJt2QGRzp&quot;
    ]
  }
}
</code></pre>
</li>
<li><strong>Pay to Script Hash (P2SH):</strong> In this type of script, the bitcoins are locked in the hash of script. The script can be a multi-sig output, time-locked output, P2SH-P2WPKH (SegWit address in P2SH format) and others. The output script looks like the following:
<pre><code>{
  &quot;value&quot;: 0.00200000,
  &quot;n&quot;: 0,
  &quot;scriptPubKey&quot;: {
    &quot;asm&quot;: &quot;OP_HASH160 243f1394f44554f4ce3fd68649c19adc483ce924 OP_EQUAL&quot;
    &quot;hex&quot;: &quot;a914243f1394f44554f4ce3fd68649c19adc483ce92487&quot;,
    &quot;reqSigs&quot;: 1,
    &quot;type&quot;: &quot;scripthash&quot;,
    &quot;addresses&quot;: [
      &quot;34zfp5f8tZEqWkLpjFq7SYnJ66bbdaTmt&quot;
    ]
  }
}
</code></pre>
</li>
<li><strong>Pay to Witness Public Key Hash (P2WPKH):</strong> In this script, the bitcoins are locked in the hash of the public key, but follows SegWit. The leading <code>00</code> indicate that it is SegWit version 0. The output script looks like the following:
<pre><code>{
  &quot;value&quot;: 0.00200000,
  &quot;n&quot;: 0,
  &quot;scriptPubKey&quot;: {
    &quot;asm&quot;: &quot;0 eb308eb99tb8ff3797d2e5cfb33a9231700d6195&quot;
    &quot;hex&quot;: &quot;0014eb308eb99tb8ff3797d2e5cfb33a9231700d6195&quot;,
    &quot;reqSigs&quot;: 1,
    &quot;type&quot;: &quot;witness_v0_keyhash&quot;,
    &quot;addresses&quot;: [
      &quot;bc1qavcgawvmerln097juh8mxw5jx9cq6cv46xmzxk&quot;
    ]
  }
}
</code></pre>
</li>
<li><strong>Pay to Witness Script Hash (P2WSH):</strong> In this script, the bitcoins are locked in the hash of a script, but follows SegWit. Similar to P2SH, the redeemScript can be a multi-sig output, time-locked output, etc. The leading <code>00</code> byte indicate that it is SegWit version 0. Below is how the locking script looks like (your example in the question):
<pre><code>{
  &quot;value&quot;: 0.00200000,
  &quot;n&quot;: 0,
  &quot;scriptPubKey&quot;: {
    &quot;asm&quot;: &quot;0 e3307e8e0b630e53c2f1f817067bce01c43892833e022dadf5e95f31be89b122&quot;
    &quot;hex&quot;: &quot;0020e3307e8e0b630e53c2f1f817067bce01c43892833e022dadf5e95f31be89b122&quot;,
    &quot;reqSigs&quot;: 1,
    &quot;type&quot;: &quot;witness_v0_scripthash&quot;,
    &quot;addresses&quot;: [
      &quot;bc1quvc8arstvv898sh3lqtsv77wq8zr3y5r8cpzmt04a90nr05fky3qwnkvta&quot;
    ]
  }
}
</code></pre>
</li>
<li><strong>Pay to Public Key (P2PK)</strong>: This type of output script pays the public key directly. Note: Although currently Bitcoin Core shows an address starting with 1 for P2PK, it is an error that will be rectified in the next release of Bitcoin-Core. Below is how the output script looks like:
<pre><code>{
  &quot;value&quot;: 0.00200000,
  &quot;n&quot;: 0,
  &quot;scriptPubKey&quot;: {
    &quot;asm&quot;: &quot;02d2a6892c51741f83759088d9eed12c2c52eea9b999ecc36af1cb569b733b6ff1 OP_CHECKSIG&quot;
    &quot;hex&quot;: &quot;2102d2a6892c51741f83759088d9eed12c2c52eea9b999ecc36af1cb569b733b6ff1ac&quot;,
    &quot;reqSigs&quot;: 1,
    &quot;type&quot;: &quot;pubkey&quot;,
    &quot;addresses&quot;: [
      &quot;1FK1FmLuTY19JGdb9SsKHs68HxRD69jtc1&quot;
    ]
  }
}
</code></pre>
</li>
</ol>
<p>As I said earlier, bitcoins can be locked in any allowed operator operations. However, if the output script does not belong to the above five types, the output script will be non-standard and you will see the type as &quot;nonstandard&quot; in the <code>scriptPubKey</code> field.</p>

CC BY-SA 4.0
2019-10-17T19:49:44.907Z
So, If I understand well, in your first example:
76 -> OP_DUP
a9 -> OP_HASH160
14 data to be pushed onto the stack ( 0x14 = 20 bytes = 40 chars)
   -> 243f1394f44554f4ce3fd68649c19adc483ce924
88 -> OP_EQUALVERIFY
ac -> OP_CHECKSIG
from this pattern we can conclude the scriptPubKey type is pubkeyhash ?
jfjobidon
CC BY-SA 4.0
2019-10-17T20:32:31.560Z
@jfjobidon Yep, absolutely correct.
Ugam Kamat
CC BY-SA 4.0
2023-05-02T02:25:32.677Z
Are you sure of #5 P2PK? A compressed pubkey must be 33 bytes, and that one is, so surely the opcode to push it should be 21 not 20.
dave_thompson_085
CC BY-SA 4.0
2023-08-15T10:20:55.427Z
@dave_thompson_085 you are right my friend. Thanks for pointing it out.
Ugam Kamat
CC BY-SA 4.0
2023-08-15T12:13:28.990Z
May you provide P2TR script pub key please ?
Loopite
CC BY-SA 4.0
2019-10-17T19:23:20.927Z
2023-08-15T10:21:54.067Z
2023-08-15T10:21:54.067Z
Ugam Kamat
<p>I use zeroMQ to get the transactions from Bitcoin Core.
The output looks like this:</p>

<pre><code>{ value: 200000,
  script: &lt;Buffer 00 20 e3 30 7e 8e 0b 63 0e 53 c2 f1 f8 17 06 7b ce 01 c4 38 92 83 3e 02 2d ad f5 e9 5f 31 be 89 b1 22&gt;
}
</code></pre>

<p>The same output looks like this in Bitcoin Core:</p>

<pre><code>{
      "value": 0.00200000,
      "n": 0,
      "scriptPubKey": {
        "asm": "0 e3307e8e0b630e53c2f1f817067bce01c43892833e022dadf5e95f31be89b122",
        "hex": "0020e3307e8e0b630e53c2f1f817067bce01c43892833e022dadf5e95f31be89b122",
        "reqSigs": 1,
        "type": "witness_v0_scripthash",
        "addresses": [
          "tb1quvc8arstvv898sh3lqtsv77wq8zr3y5r8cpzmt04a90nr05fky3qemqr3j"
        ]
      }
    }
</code></pre>

<p>Question: How do I get the <code>scriptPubKey</code> type from the script buffer ?</p>

<bitcoin-core><transactions><zeromq>
How do I get the scriptPubKey type from the raw output script?
jfjobidon
# How do I get the scriptPubKey type from the raw output script?

(Asked by: username_0 on 2019-10-17)

I use zeroMQ to get the transactions from Bitcoin Core.
The output looks like this:

```
{ value: 200000,
  script: <Buffer 00 20 e3 30 7e 8e 0b 63 0e 53 c2 f1 f8 17 06 7b ce 01 c4 38 92 83 3e 02 2d ad f5 e9 5f 31 be 89 b1 22>
}

```

The same output looks like this in Bitcoin Core:

```
{
      "value": 0.00200000,
      "n": 0,
      "scriptPubKey": {
        "asm": "0 e3307e8e0b630e53c2f1f817067bce01c43892833e022dadf5e95f31be89b122",
        "hex": "0020e3307e8e0b630e53c2f1f817067bce01c43892833e022dadf5e95f31be89b122",
        "reqSigs": 1,
        "type": "witness_v0_scripthash",
        "addresses": [
          "tb1quvc8arstvv898sh3lqtsv77wq8zr3y5r8cpzmt04a90nr05fky3qemqr3j"
        ]
      }
    }

```

Question: How do I get the `scriptPubKey` type from the script buffer ?

**Tags:** bitcoin-core, transactions, zeromq


---

## 2 answers

### Answer by username_2 on 2019-10-17. Score: 6 | Accepted answer

Internally, Bitcoin does not have the concept of `scriptPubKey` type. To the system, `scriptPubKey` is simply a mathematical equation into which some bitcoins have been locked (UTXO) and the spender must satisfy the unlocking conditions, which most of the times are the signature(s) and public key(s), in order to spend those bitcoins. These basic construct can be used to build higher level concepts like the `scriptPubKey` type that you are referring in your question.

Since Bitcoin is a programmable money, a user can lock their bitcoins in a number of different ways. The Bitcoin community has accepted certain output types as standard locking scripts. Below are some of the standard output scripts (`scriptPubKey`) that can be used to determine the script address type (main net address types have been used):

1. **Pay to Public Key Hash (P2PKH):** In this type of script, the bitcoins are locked in the hash of a public key. The output script will look like the following:

   ```
   {
     "value": 0.00200000,
     "n": 0,
     "scriptPubKey": {
       "asm": "OP_DUP OP_HASH160 243f1394f44554f4ce3fd68649c19adc483ce924 OP_EQUALVERIFY OP_CHECKSIG"
       "hex": "76a914243f1394f44554f4ce3fd68649c19adc483ce92488ac",
       "reqSigs": 1,
       "type": "pubkeyhash",
       "addresses": [
         "14JetYAhLevTRaePcAAX1vRMwaJt2QGRzp"
       ]
     }
   }

   ```
2. **Pay to Script Hash (P2SH):** In this type of script, the bitcoins are locked in the hash of script. The script can be a multi-sig output, time-locked output, P2SH-P2WPKH (SegWit address in P2SH format) and others. The output script looks like the following:

   ```
   {
     "value": 0.00200000,
     "n": 0,
     "scriptPubKey": {
       "asm": "OP_HASH160 243f1394f44554f4ce3fd68649c19adc483ce924 OP_EQUAL"
       "hex": "a914243f1394f44554f4ce3fd68649c19adc483ce92487",
       "reqSigs": 1,
       "type": "scripthash",
       "addresses": [
         "34zfp5f8tZEqWkLpjFq7SYnJ66bbdaTmt"
       ]
     }
   }

   ```
3. **Pay to Witness Public Key Hash (P2WPKH):** In this script, the bitcoins are locked in the hash of the public key, but follows SegWit. The leading `00` indicate that it is SegWit version 0. The output script looks like the following:

   ```
   {
     "value": 0.00200000,
     "n": 0,
     "scriptPubKey": {
       "asm": "0 eb308eb99tb8ff3797d2e5cfb33a9231700d6195"
       "hex": "0014eb308eb99tb8ff3797d2e5cfb33a9231700d6195",
       "reqSigs": 1,
       "type": "witness_v0_keyhash",
       "addresses": [
         "bc1qavcgawvmerln097juh8mxw5jx9cq6cv46xmzxk"
       ]
     }
   }

   ```
4. **Pay to Witness Script Hash (P2WSH):** In this script, the bitcoins are locked in the hash of a script, but follows SegWit. Similar to P2SH, the redeemScript can be a multi-sig output, time-locked output, etc. The leading `00` byte indicate that it is SegWit version 0. Below is how the locking script looks like (your example in the question):

   ```
   {
     "value": 0.00200000,
     "n": 0,
     "scriptPubKey": {
       "asm": "0 e3307e8e0b630e53c2f1f817067bce01c43892833e022dadf5e95f31be89b122"
       "hex": "0020e3307e8e0b630e53c2f1f817067bce01c43892833e022dadf5e95f31be89b122",
       "reqSigs": 1,
       "type": "witness_v0_scripthash",
       "addresses": [
         "bc1quvc8arstvv898sh3lqtsv77wq8zr3y5r8cpzmt04a90nr05fky3qwnkvta"
       ]
     }
   }

   ```
5. **Pay to Public Key (P2PK)**: This type of output script pays the public key directly. Note: Although currently Bitcoin Core shows an address starting with 1 for P2PK, it is an error that will be rectified in the next release of Bitcoin-Core. Below is how the output script looks like:

   ```
   {
     "value": 0.00200000,
     "n": 0,
     "scriptPubKey": {
       "asm": "02d2a6892c51741f83759088d9eed12c2c52eea9b999ecc36af1cb569b733b6ff1 OP_CHECKSIG"
       "hex": "2102d2a6892c51741f83759088d9eed12c2c52eea9b999ecc36af1cb569b733b6ff1ac",
       "reqSigs": 1,
       "type": "pubkey",
       "addresses": [
         "1FK1FmLuTY19JGdb9SsKHs68HxRD69jtc1"
       ]
     }
   }

   ```

As I said earlier, bitcoins can be locked in any allowed operator operations. However, if the output script does not belong to the above five types, the output script will be non-standard and you will see the type as "nonstandard" in the `scriptPubKey` field.

> **Comments:**
> **username_0**: So, If I understand well, in your first example: 76 -> OP_DUP a9 -> OP_HASH160 14 data to be pushed onto the stack ( 0x14 = 20 bytes = 40 chars)    -> 243f1394f44554f4ce3fd68649c19adc483ce924 88 -> OP_EQUALVERIFY ac -> OP_CHECKSIG from this pattern we can conclude the scriptPubKey type is pubkeyhash ?  
> **username_2**: @username_0 Yep, absolutely correct.  
> **username_3**: Are you sure of #5 P2PK? A compressed pubkey must be 33 bytes, and that one is, so surely the opcode to push it should be 21 not 20.  
> **username_2**: @username_3 you are right my friend. Thanks for pointing it out.  
> **username_4**: May you provide P2TR script pub key please ?  

---

### Answer by username_1 on 2019-10-17. Score: 3

You need to parse the script and get to the script type by examining the opcodes.

If you examine the `rpc/rawtransaction.cpp` source file on Bitcoin Core you'll see the RPC call that outputs this is `getrawtransaction()`. Tracing it further it leads us to `ScriptPubKeyToUniv` in `core_write.cpp` which calls so let's take a look at that:

```
const char* GetTxnOutputType(txnouttype t)
{
    switch (t)
    {
    case TX_NONSTANDARD: return "nonstandard";
    case TX_PUBKEY: return "pubkey";
    case TX_PUBKEYHASH: return "pubkeyhash";
    case TX_SCRIPTHASH: return "scripthash";
    case TX_MULTISIG: return "multisig";
    case TX_NULL_DATA: return "nulldata";
    case TX_WITNESS_V0_KEYHASH: return "witness_v0_keyhash";
    case TX_WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
    case TX_WITNESS_UNKNOWN: return "witness_unknown";
    }
    return nullptr;
}

```

This subroutine maps script types to the string name which you asked about. In your case you got a `TX_WITNESS_V0_SCRIPTHASH` whose value is 0x06 per its definition in `script/standard.h` :

```
enum txnouttype
{
    TX_NONSTANDARD,
    // 'standard' transaction types:
    TX_PUBKEY,
    TX_PUBKEYHASH,
    TX_SCRIPTHASH,
    TX_MULTISIG,
    TX_NULL_DATA, //!< unspendable OP_RETURN script that carries data
    TX_WITNESS_V0_SCRIPTHASH,
    TX_WITNESS_V0_KEYHASH,
    TX_WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above
};

```

We now know how to extract the `scriptPubKey` type name from the value, but we don't know how to extract that value from the raw bytes, so let's take a look at that next.

`txnouttype` is extracted from `scriptPubkey` by `ExtractDestinations` which is defined in `script/standard.cpp`, the relevant line being `typeRet = Solver(scriptPubKey, vSolutions);`. So let's step into `Solver`.

Here's the answer to your question:

```
txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet)
{
    vSolutionsRet.clear();

    // Shortcut for pay-to-script-hash, which are more constrained than the other types:
    // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
    if (scriptPubKey.IsPayToScriptHash())
    {
        std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
        vSolutionsRet.push_back(hashBytes);
        return TX_SCRIPTHASH;
    }

    int witnessversion;
    std::vector<unsigned char> witnessprogram;
    if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
        if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) {
            vSolutionsRet.push_back(witnessprogram);
            return TX_WITNESS_V0_KEYHASH;
        }
        if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
            vSolutionsRet.push_back(witnessprogram);
            return TX_WITNESS_V0_SCRIPTHASH;
        }
        if (witnessversion != 0) {
            vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion});
            vSolutionsRet.push_back(std::move(witnessprogram));
            return TX_WITNESS_UNKNOWN;
        }
        return TX_NONSTANDARD;
    }

    // Provably prunable, data-carrying output
    //
    // So long as script passes the IsUnspendable() test and all but the first
    // byte passes the IsPushOnly() test we don't care what exactly is in the
    // script.
    if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
        return TX_NULL_DATA;
    }

    std::vector<unsigned char> data;
    if (MatchPayToPubkey(scriptPubKey, data)) {
        vSolutionsRet.push_back(std::move(data));
        return TX_PUBKEY;
    }

    if (MatchPayToPubkeyHash(scriptPubKey, data)) {
        vSolutionsRet.push_back(std::move(data));
        return TX_PUBKEYHASH;
    }

    unsigned int required;
    std::vector<std::vector<unsigned char>> keys;
    if (MatchMultisig(scriptPubKey, required, keys)) {
        vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..16
        vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
        vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..16
        return TX_MULTISIG;
    }

    vSolutionsRet.clear();
    return TX_NONSTANDARD;
}

```

It returns the `txnouttype` and here's how it determines each one:

**TX\_SCRIPTHASH**

```
this->size() == 23 &&
            (*this)[0] == OP_HASH160 &&
            (*this)[1] == 0x14 &&
            (*this)[22] == OP_EQUAL

```

If the script size is 23 bytes, the first script byte is OP\_HASH160, second byte is 0x14 and byte 22 is OP\_EQUAL then it's a TX\_SCRIPTHASH.

**Witness Program**

The following tests if the script is a witness program:

```
this->size() == 34 &&
            (*this)[0] == OP_0 &&
            (*this)[1] == 0x20

```

So, if the script is 34 bytes long, the first OP is 0 and the second byte is 0x20 then it's a witness program (*This is the case in your question.*).

If it's a witness program, then there are 4 possible script types:

First Witness Script type: **`TX_WITNESS_V0_KEYHASH`**

```
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) {
            vSolutionsRet.push_back(witnessprogram);
            return TX_WITNESS_V0_KEYHASH;
        }

```

If witness version is zero and the witness program is WITNESS\_V0\_KEYHASH\_SIZE (20 bytes) long then it's a `TX_WITNESS_V0_KEYHASH`.

Second Witness Script type: **`TX_WITNESS_V0_SCRIPTHASH`**

If witness version is zer and the witness program is WITNESS\_V0\_SCRIPTHASH\_SIZE (32 bytes) long then it's a `TX_WITNESS_V0_SCRIPTHASH`. This is the case in your question.

*Note: We now know the specific answer to your question : you know if it's a `witness_v0_scripthash` if the script is 34 bytes long, begins with 00 20 and then there are 32 bytes following it.*

Let's proceed for completeness.

Third Witness Script type: **`TX_WITNESS_UNKNOWN`**

If the witness version is different from zero, it's unknown.

Fourth and last Witness script type is **`TX_NONSTANDARD`**, which means it's not recognized by Bitcon Core.

Now onto the other script types.

**`TX_NULL_DATA`**

If the `scriptPubKey` size is more than one byte long and the first `OP` is a `RETURN`, then everything that follows is `NULL` data.

**`TX_PUBKEY`**

If the script is `CPubKey::PUBLIC_KEY_SIZE` (65) bytes long and the first byte on the script is 65 (`CPubKey::PUBLIC_KEY_SIZE`) and if the last OP on the script is `OP_CHECKSIG` then it's a legacy `TX_PUBKEY` script.

**`TX_PUBKEYHASH`**

If the script is 25 bytes long (this length is harcoded in `script/standard.cpp`), the first operation is `OP_DUP`, the second operation is `OP_HASH160` and script[23] is OP\_EQUALVERIFY and script[24] is `OP_CHECKSIG` then it's the most common type of script of all: `TX_PUBKEYHASH`.

**`TX_MULTISIG`**

Multisig is solved by `MatchMultisig` in `script/standard.cpp`. What it does is parse the script looping through it and calling `GetOp` (`script/script.h`) to parse the sig out and `CPubKey::ValidSize(data)` which checks if each signature is the right size. If at the end of this check we are at the end of the script, verified by `(it + 1 == script.end())`, then it's a valid multisig script.

**`TX_NONSTANDARD`**

Lastly if none of the above rules match, then it's a nonstandard script containing undefined contents. Most nodes would probably reject this script but miners and pools are able to insert stuff here if they want to.

These are all the script types in Bitcoin. The rules presented for each one is how you get the type out of scriptPubKey. To turn it into a string you use the enum map in `GetTxnOutputType`.


---

