1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
"""
Original version: https://raw.githubusercontent.com/bitcoin-core/HWI/3fe369d0379212fae1c72729a179d133b0adc872/hwilib/_script.py
Distributed under the MIT License.
Bitcoin Script utilities
************************
"""
from typing import (
Optional,
Sequence,
Tuple,
)
def is_opreturn(script: bytes) -> bool:
"""
Determine whether a script is an OP_RETURN output script.
:param script: The script
:returns: Whether the script is an OP_RETURN output script
"""
return script[0] == 0x6a
def is_p2sh(script: bytes) -> bool:
"""
Determine whether a script is a P2SH output script.
:param script: The script
:returns: Whether the script is a P2SH output script
"""
return len(script) == 23 and script[0] == 0xa9 and script[1] == 0x14 and script[22] == 0x87
def is_p2pkh(script: bytes) -> bool:
"""
Determine whether a script is a P2PKH output script.
:param script: The script
:returns: Whether the script is a P2PKH output script
"""
return len(script) == 25 and script[0] == 0x76 and script[1] == 0xa9 and script[2] == 0x14 and script[23] == 0x88 and script[24] == 0xac
def is_p2pk(script: bytes) -> bool:
"""
Determine whether a script is a P2PK output script.
:param script: The script
:returns: Whether the script is a P2PK output script
"""
return (len(script) == 35 or len(script) == 67) and (script[0] == 0x21 or script[0] == 0x41) and script[-1] == 0xac
def is_p2tr(script: bytes) -> bool:
"""
Determine whether a script is a P2TR output script.
:param script: The script
:returns: Whether the script is a P2TR output script
"""
return len(script) == 34 and script[0] == 0x51 and script[1] == 0x20
def is_witness(script: bytes) -> Tuple[bool, int, bytes]:
"""
Determine whether a script is a segwit output script.
If so, also returns the witness version and witness program.
:param script: The script
:returns: A tuple of a bool indicating whether the script is a segwit output script,
an int representing the witness version,
and the bytes of the witness program.
"""
if len(script) < 4 or len(script) > 42:
return (False, 0, b"")
if script[0] != 0 and (script[0] < 81 or script[0] > 96):
return (False, 0, b"")
if script[1] + 2 == len(script):
return (True, script[0] - 0x50 if script[0] else 0, script[2:])
return (False, 0, b"")
def is_p2wpkh(script: bytes) -> bool:
"""
Determine whether a script is a P2WPKH output script.
:param script: The script
:returns: Whether the script is a P2WPKH output script
"""
is_wit, wit_ver, wit_prog = is_witness(script)
if not is_wit:
return False
elif wit_ver != 0:
return False
return len(wit_prog) == 20
def is_p2wsh(script: bytes) -> bool:
"""
Determine whether a script is a P2WSH output script.
:param script: The script
:returns: Whether the script is a P2WSH output script
"""
is_wit, wit_ver, wit_prog = is_witness(script)
if not is_wit:
return False
elif wit_ver != 0:
return False
return len(wit_prog) == 32
# Only handles up to 15 of 15. Returns None if this script is not a
# multisig script. Returns (m, pubkeys) otherwise.
def parse_multisig(script: bytes) -> Optional[Tuple[int, Sequence[bytes]]]:
"""
Determine whether a script is a multisig script. If so, determine the parameters of that multisig.
:param script: The script
:returns: ``None`` if the script is not multisig.
If multisig, returns a tuple of the number of signers required,
and a sequence of public key bytes.
"""
# Get m
m = script[0] - 80
if m < 1 or m > 15:
return None
# Get pubkeys
pubkeys = []
offset = 1
while True:
pubkey_len = script[offset]
if pubkey_len != 33:
break
offset += 1
pubkeys.append(script[offset:offset + 33])
offset += 33
# Check things at the end
n = script[offset] - 80
if n != len(pubkeys):
return None
offset += 1
op_cms = script[offset]
if op_cms != 174:
return None
return (m, pubkeys)
|