commit c03c17f1c7714a9a1db08ef91bf7bece9ef8dfe7
parent 9dedf51afdeb96590c49ff2d438ae7deec2f3448
Author: SomberNight <somber.night@protonmail.com>
Date: Fri, 22 Feb 2019 16:52:08 +0100
transaction: replace custom enum type for opcodes with stdlib enum
based on Electron-Cash/Electron-Cash@99e60b49413e103dd8e9b7cfaf22e69626db6594
Diffstat:
2 files changed, 141 insertions(+), 80 deletions(-)
diff --git a/electrum/gui/qt/paytoedit.py b/electrum/gui/qt/paytoedit.py
@@ -95,8 +95,7 @@ class PayToEdit(CompletionTextEdit, ScanQRTextEdit, PrintError):
script = ''
for word in x.split():
if word[0:3] == 'OP_':
- assert word in opcodes.lookup
- opcode_int = opcodes.lookup[word]
+ opcode_int = opcodes[word]
assert opcode_int < 256 # opcode is single-byte
script += bitcoin.int_to_hex(opcode_int)
else:
diff --git a/electrum/transaction.py b/electrum/transaction.py
@@ -32,6 +32,7 @@ import traceback
import sys
from typing import (Sequence, Union, NamedTuple, Tuple, Optional, Iterable,
Callable, List, Dict)
+from enum import IntEnum
from . import ecc, bitcoin, constants, segwit_addr
from .util import print_error, profiler, to_bytes, bh2u, bfh
@@ -190,81 +191,146 @@ class BCDataStream(object):
self.write(s)
-# enum-like type
-# From the Python Cookbook, downloaded from http://code.activestate.com/recipes/67107/
-class EnumException(Exception):
- pass
-
+class opcodes(IntEnum):
+ # push value
+ OP_0 = 0x00
+ OP_FALSE = OP_0
+ OP_PUSHDATA1 = 0x4c
+ OP_PUSHDATA2 = 0x4d
+ OP_PUSHDATA4 = 0x4e
+ OP_1NEGATE = 0x4f
+ OP_RESERVED = 0x50
+ OP_1 = 0x51
+ OP_TRUE = OP_1
+ OP_2 = 0x52
+ OP_3 = 0x53
+ OP_4 = 0x54
+ OP_5 = 0x55
+ OP_6 = 0x56
+ OP_7 = 0x57
+ OP_8 = 0x58
+ OP_9 = 0x59
+ OP_10 = 0x5a
+ OP_11 = 0x5b
+ OP_12 = 0x5c
+ OP_13 = 0x5d
+ OP_14 = 0x5e
+ OP_15 = 0x5f
+ OP_16 = 0x60
+
+ # control
+ OP_NOP = 0x61
+ OP_VER = 0x62
+ OP_IF = 0x63
+ OP_NOTIF = 0x64
+ OP_VERIF = 0x65
+ OP_VERNOTIF = 0x66
+ OP_ELSE = 0x67
+ OP_ENDIF = 0x68
+ OP_VERIFY = 0x69
+ OP_RETURN = 0x6a
+
+ # stack ops
+ OP_TOALTSTACK = 0x6b
+ OP_FROMALTSTACK = 0x6c
+ OP_2DROP = 0x6d
+ OP_2DUP = 0x6e
+ OP_3DUP = 0x6f
+ OP_2OVER = 0x70
+ OP_2ROT = 0x71
+ OP_2SWAP = 0x72
+ OP_IFDUP = 0x73
+ OP_DEPTH = 0x74
+ OP_DROP = 0x75
+ OP_DUP = 0x76
+ OP_NIP = 0x77
+ OP_OVER = 0x78
+ OP_PICK = 0x79
+ OP_ROLL = 0x7a
+ OP_ROT = 0x7b
+ OP_SWAP = 0x7c
+ OP_TUCK = 0x7d
+
+ # splice ops
+ OP_CAT = 0x7e
+ OP_SUBSTR = 0x7f
+ OP_LEFT = 0x80
+ OP_RIGHT = 0x81
+ OP_SIZE = 0x82
+
+ # bit logic
+ OP_INVERT = 0x83
+ OP_AND = 0x84
+ OP_OR = 0x85
+ OP_XOR = 0x86
+ OP_EQUAL = 0x87
+ OP_EQUALVERIFY = 0x88
+ OP_RESERVED1 = 0x89
+ OP_RESERVED2 = 0x8a
+
+ # numeric
+ OP_1ADD = 0x8b
+ OP_1SUB = 0x8c
+ OP_2MUL = 0x8d
+ OP_2DIV = 0x8e
+ OP_NEGATE = 0x8f
+ OP_ABS = 0x90
+ OP_NOT = 0x91
+ OP_0NOTEQUAL = 0x92
+
+ OP_ADD = 0x93
+ OP_SUB = 0x94
+ OP_MUL = 0x95
+ OP_DIV = 0x96
+ OP_MOD = 0x97
+ OP_LSHIFT = 0x98
+ OP_RSHIFT = 0x99
+
+ OP_BOOLAND = 0x9a
+ OP_BOOLOR = 0x9b
+ OP_NUMEQUAL = 0x9c
+ OP_NUMEQUALVERIFY = 0x9d
+ OP_NUMNOTEQUAL = 0x9e
+ OP_LESSTHAN = 0x9f
+ OP_GREATERTHAN = 0xa0
+ OP_LESSTHANOREQUAL = 0xa1
+ OP_GREATERTHANOREQUAL = 0xa2
+ OP_MIN = 0xa3
+ OP_MAX = 0xa4
+
+ OP_WITHIN = 0xa5
+
+ # crypto
+ OP_RIPEMD160 = 0xa6
+ OP_SHA1 = 0xa7
+ OP_SHA256 = 0xa8
+ OP_HASH160 = 0xa9
+ OP_HASH256 = 0xaa
+ OP_CODESEPARATOR = 0xab
+ OP_CHECKSIG = 0xac
+ OP_CHECKSIGVERIFY = 0xad
+ OP_CHECKMULTISIG = 0xae
+ OP_CHECKMULTISIGVERIFY = 0xaf
+
+ # expansion
+ OP_NOP1 = 0xb0
+ OP_CHECKLOCKTIMEVERIFY = 0xb1
+ OP_NOP2 = OP_CHECKLOCKTIMEVERIFY
+ OP_CHECKSEQUENCEVERIFY = 0xb2
+ OP_NOP3 = OP_CHECKSEQUENCEVERIFY
+ OP_NOP4 = 0xb3
+ OP_NOP5 = 0xb4
+ OP_NOP6 = 0xb5
+ OP_NOP7 = 0xb6
+ OP_NOP8 = 0xb7
+ OP_NOP9 = 0xb8
+ OP_NOP10 = 0xb9
+
+ OP_INVALIDOPCODE = 0xff
+
+ def hex(self) -> str:
+ return bytes([self]).hex()
-class Enumeration:
- def __init__(self, name, enumList):
- self.__doc__ = name
- lookup = { }
- reverseLookup = { }
- i = 0
- uniqueNames = [ ]
- uniqueValues = [ ]
- for x in enumList:
- if isinstance(x, tuple):
- x, i = x
- if not isinstance(x, str):
- raise EnumException("enum name is not a string: " + x)
- if not isinstance(i, int):
- raise EnumException("enum value is not an integer: " + i)
- if x in uniqueNames:
- raise EnumException("enum name is not unique: " + x)
- if i in uniqueValues:
- raise EnumException("enum value is not unique for " + x)
- uniqueNames.append(x)
- uniqueValues.append(i)
- lookup[x] = i
- reverseLookup[i] = x
- i = i + 1
- self.lookup = lookup
- self.reverseLookup = reverseLookup
-
- def __getattr__(self, attr):
- if attr not in self.lookup:
- raise AttributeError
- return self.lookup[attr]
- def whatis(self, value):
- return self.reverseLookup[value]
-
-
-# This function comes from bitcointools, bct-LICENSE.txt.
-def long_hex(bytes):
- return bytes.encode('hex_codec')
-
-# This function comes from bitcointools, bct-LICENSE.txt.
-def short_hex(bytes):
- t = bytes.encode('hex_codec')
- if len(t) < 11:
- return t
- return t[0:4]+"..."+t[-4:]
-
-
-
-opcodes = Enumeration("Opcodes", [
- ("OP_0", 0), ("OP_PUSHDATA1",76), "OP_PUSHDATA2", "OP_PUSHDATA4", "OP_1NEGATE", "OP_RESERVED",
- "OP_1", "OP_2", "OP_3", "OP_4", "OP_5", "OP_6", "OP_7",
- "OP_8", "OP_9", "OP_10", "OP_11", "OP_12", "OP_13", "OP_14", "OP_15", "OP_16",
- "OP_NOP", "OP_VER", "OP_IF", "OP_NOTIF", "OP_VERIF", "OP_VERNOTIF", "OP_ELSE", "OP_ENDIF", "OP_VERIFY",
- "OP_RETURN", "OP_TOALTSTACK", "OP_FROMALTSTACK", "OP_2DROP", "OP_2DUP", "OP_3DUP", "OP_2OVER", "OP_2ROT", "OP_2SWAP",
- "OP_IFDUP", "OP_DEPTH", "OP_DROP", "OP_DUP", "OP_NIP", "OP_OVER", "OP_PICK", "OP_ROLL", "OP_ROT",
- "OP_SWAP", "OP_TUCK", "OP_CAT", "OP_SUBSTR", "OP_LEFT", "OP_RIGHT", "OP_SIZE", "OP_INVERT", "OP_AND",
- "OP_OR", "OP_XOR", "OP_EQUAL", "OP_EQUALVERIFY", "OP_RESERVED1", "OP_RESERVED2", "OP_1ADD", "OP_1SUB", "OP_2MUL",
- "OP_2DIV", "OP_NEGATE", "OP_ABS", "OP_NOT", "OP_0NOTEQUAL", "OP_ADD", "OP_SUB", "OP_MUL", "OP_DIV",
- "OP_MOD", "OP_LSHIFT", "OP_RSHIFT", "OP_BOOLAND", "OP_BOOLOR",
- "OP_NUMEQUAL", "OP_NUMEQUALVERIFY", "OP_NUMNOTEQUAL", "OP_LESSTHAN",
- "OP_GREATERTHAN", "OP_LESSTHANOREQUAL", "OP_GREATERTHANOREQUAL", "OP_MIN", "OP_MAX",
- "OP_WITHIN", "OP_RIPEMD160", "OP_SHA1", "OP_SHA256", "OP_HASH160",
- "OP_HASH256", "OP_CODESEPARATOR", "OP_CHECKSIG", "OP_CHECKSIGVERIFY", "OP_CHECKMULTISIG",
- "OP_CHECKMULTISIGVERIFY",
- ("OP_NOP1", 0xB0),
- ("OP_CHECKLOCKTIMEVERIFY", 0xB1), ("OP_CHECKSEQUENCEVERIFY", 0xB2),
- "OP_NOP4", "OP_NOP5", "OP_NOP6", "OP_NOP7", "OP_NOP8", "OP_NOP9", "OP_NOP10",
- ("OP_INVALIDOPCODE", 0xFF),
-])
def script_GetOp(_bytes : bytes):
@@ -294,10 +360,6 @@ def script_GetOp(_bytes : bytes):
yield opcode, vch, i
-def script_GetOpName(opcode):
- return (opcodes.whatis(opcode)).replace("OP_", "")
-
-
class OPPushDataGeneric:
def __init__(self, pushlen: Callable=None):
if pushlen is not None: