How Script Type is Detected by Wallets
11. How Script Type is Detected by Wallets
Overview
Bitcoin wallets and nodes identify script types through pattern matching on the scriptPubKey. This detection determines how to generate addresses, decode UTXOs for balance calculation, construct spending transactions, and display information to users. The detection logic has evolved alongside Bitcoin's script types.
Detection Algorithm
Wallets inspect the scriptPubKey byte sequence, typically using template matching:
def classify_script(script: bytes) -> str:
n = len(script)
# P2PKH: OP_DUP OP_HASH160 PUSH20 <20 bytes> OP_EQUALVERIFY OP_CHECKSIG
if (n == 25 and script[0] == 0x76 and script[1] == 0xa9
and script[2] == 0x14 and script[23] == 0x88 and script[24] == 0xac):
return "P2PKH"
# P2SH: OP_HASH160 PUSH20 <20 bytes> OP_EQUAL
if (n == 23 and script[0] == 0xa9 and script[1] == 0x14 and script[22] == 0x87):
return "P2SH"
# P2WPKH: OP_0 PUSH20 <20 bytes>
if n == 22 and script[0] == 0x00 and script[1] == 0x14:
return "P2WPKH"
# P2WSH: OP_0 PUSH32 <32 bytes>
if n == 34 and script[0] == 0x00 and script[1] == 0x20:
return "P2WSH"
# P2TR: OP_1 PUSH32 <32 bytes>
if n == 34 and script[0] == 0x51 and script[1] == 0x20:
return "P2TR"
# P2PK: PUSH33 <33 bytes> OP_CHECKSIG (compressed)
if n == 35 and script[0] == 0x21 and script[34] == 0xac:
return "P2PK (compressed)"
# P2PK: PUSH65 <65 bytes> OP_CHECKSIG (uncompressed)
if n == 67 and script[0] == 0x41 and script[66] == 0xac:
return "P2PK (uncompressed)"
# OP_RETURN: data carrier
if script[0] == 0x6a:
return "OP_RETURN (unspendable)"
return "UNKNOWN / NON-STANDARD"
Address Encoding by Type
P2PKH → Base58Check, version byte 0x00 → "1..." addresses
P2SH → Base58Check, version byte 0x05 → "3..." addresses
P2WPKH → Bech32, HRP "bc", version 0 → "bc1q..." (20-byte program)
P2WSH → Bech32, HRP "bc", version 0 → "bc1q..." (32-byte program)
P2TR → Bech32m, HRP "bc", version 1 → "bc1p..." addresses
Note that P2WPKH and P2WSH both use Bech32 with bc1q prefix; they're distinguished by the length of the decoded data (20 vs 32 bytes). P2TR uses Bech32m (BIP 350), a modified checksum scheme.
Descriptor Wallets
Modern wallets use output descriptors (BIP 380–386) to formally describe which scripts they manage:
pkh(<key>) → P2PKH
sh(multi(2,<k1>,<k2>,<k3>)) → P2SH 2-of-3 multisig
wpkh(<key>) → P2WPKH
wsh(multi(2,<k1>,<k2>,<k3>)) → P2WSH multisig
sh(wpkh(<key>)) → P2SH-P2WPKH
tr(<key>) → P2TR key path only
tr(<key>,{pk(<k2>),multi_a(2,<k1>,<k2>,<k3>)}) → P2TR with script tree
TeachMeBitcoin is an ad-free, open-source educational repository curated by a passionate team of Bitcoin researchers and educators for public benefit. If you found our articles helpful, please consider supporting our hosting and ongoing content updates with a clean donation: