|
@ -59,6 +59,10 @@ class NotRecognizedRedeemScript(Exception): |
|
|
pass |
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MalformedBitcoinScript(Exception): |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TxOutput = NamedTuple("TxOutput", [('type', int), ('address', str), ('value', Union[int, str])]) |
|
|
TxOutput = NamedTuple("TxOutput", [('type', int), ('address', str), ('value', Union[int, str])]) |
|
|
# ^ value is str when the output is set to max: '!' |
|
|
# ^ value is str when the output is set to max: '!' |
|
|
|
|
|
|
|
@ -263,13 +267,16 @@ def script_GetOp(_bytes : bytes): |
|
|
if opcode <= opcodes.OP_PUSHDATA4: |
|
|
if opcode <= opcodes.OP_PUSHDATA4: |
|
|
nSize = opcode |
|
|
nSize = opcode |
|
|
if opcode == opcodes.OP_PUSHDATA1: |
|
|
if opcode == opcodes.OP_PUSHDATA1: |
|
|
nSize = _bytes[i] |
|
|
try: nSize = _bytes[i] |
|
|
|
|
|
except IndexError: raise MalformedBitcoinScript() |
|
|
i += 1 |
|
|
i += 1 |
|
|
elif opcode == opcodes.OP_PUSHDATA2: |
|
|
elif opcode == opcodes.OP_PUSHDATA2: |
|
|
(nSize,) = struct.unpack_from('<H', _bytes, i) |
|
|
try: (nSize,) = struct.unpack_from('<H', _bytes, i) |
|
|
|
|
|
except struct.error: raise MalformedBitcoinScript() |
|
|
i += 2 |
|
|
i += 2 |
|
|
elif opcode == opcodes.OP_PUSHDATA4: |
|
|
elif opcode == opcodes.OP_PUSHDATA4: |
|
|
(nSize,) = struct.unpack_from('<I', _bytes, i) |
|
|
try: (nSize,) = struct.unpack_from('<I', _bytes, i) |
|
|
|
|
|
except struct.error: raise MalformedBitcoinScript() |
|
|
i += 4 |
|
|
i += 4 |
|
|
vch = _bytes[i:i + nSize] |
|
|
vch = _bytes[i:i + nSize] |
|
|
i += nSize |
|
|
i += nSize |
|
@ -281,21 +288,11 @@ def script_GetOpName(opcode): |
|
|
return (opcodes.whatis(opcode)).replace("OP_", "") |
|
|
return (opcodes.whatis(opcode)).replace("OP_", "") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def decode_script(bytes): |
|
|
|
|
|
result = '' |
|
|
|
|
|
for (opcode, vch, i) in script_GetOp(bytes): |
|
|
|
|
|
if len(result) > 0: result += " " |
|
|
|
|
|
if opcode <= opcodes.OP_PUSHDATA4: |
|
|
|
|
|
result += "%d:"%(opcode,) |
|
|
|
|
|
result += short_hex(vch) |
|
|
|
|
|
else: |
|
|
|
|
|
result += script_GetOpName(opcode) |
|
|
|
|
|
return result |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def match_decoded(decoded, to_match): |
|
|
def match_decoded(decoded, to_match): |
|
|
|
|
|
if decoded is None: |
|
|
|
|
|
return False |
|
|
if len(decoded) != len(to_match): |
|
|
if len(decoded) != len(to_match): |
|
|
return False; |
|
|
return False |
|
|
for i in range(len(decoded)): |
|
|
for i in range(len(decoded)): |
|
|
if to_match[i] == opcodes.OP_PUSHDATA4 and decoded[i][0] <= opcodes.OP_PUSHDATA4 and decoded[i][0]>0: |
|
|
if to_match[i] == opcodes.OP_PUSHDATA4 and decoded[i][0] <= opcodes.OP_PUSHDATA4 and decoded[i][0]>0: |
|
|
continue # Opcodes below OP_PUSHDATA4 all just push data onto stack, and are equivalent. |
|
|
continue # Opcodes below OP_PUSHDATA4 all just push data onto stack, and are equivalent. |
|
@ -413,7 +410,10 @@ def parse_scriptSig(d, _bytes): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def parse_redeemScript_multisig(redeem_script: bytes): |
|
|
def parse_redeemScript_multisig(redeem_script: bytes): |
|
|
dec2 = [ x for x in script_GetOp(redeem_script) ] |
|
|
try: |
|
|
|
|
|
dec2 = [ x for x in script_GetOp(redeem_script) ] |
|
|
|
|
|
except MalformedBitcoinScript: |
|
|
|
|
|
raise NotRecognizedRedeemScript() |
|
|
try: |
|
|
try: |
|
|
m = dec2[0][0] - opcodes.OP_1 + 1 |
|
|
m = dec2[0][0] - opcodes.OP_1 + 1 |
|
|
n = dec2[-2][0] - opcodes.OP_1 + 1 |
|
|
n = dec2[-2][0] - opcodes.OP_1 + 1 |
|
@ -434,7 +434,10 @@ def parse_redeemScript_multisig(redeem_script: bytes): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_address_from_output_script(_bytes, *, net=None): |
|
|
def get_address_from_output_script(_bytes, *, net=None): |
|
|
decoded = [x for x in script_GetOp(_bytes)] |
|
|
try: |
|
|
|
|
|
decoded = [x for x in script_GetOp(_bytes)] |
|
|
|
|
|
except MalformedBitcoinScript: |
|
|
|
|
|
decoded = None |
|
|
|
|
|
|
|
|
# The Genesis Block, self-payments, and pay-by-IP-address payments look like: |
|
|
# The Genesis Block, self-payments, and pay-by-IP-address payments look like: |
|
|
# 65 BYTES:... CHECKSIG |
|
|
# 65 BYTES:... CHECKSIG |
|
|