transaction: replace custom enum type for opcodes with stdlib enum

based on Electron-Cash/Electron-Cash@99e60b4941
This commit is contained in:
SomberNight 2019-02-22 16:52:08 +01:00
parent 9dedf51afd
commit c03c17f1c7
No known key found for this signature in database
GPG key ID: B33B5F232C6271E9
2 changed files with 133 additions and 72 deletions

View file

@ -95,8 +95,7 @@ class PayToEdit(CompletionTextEdit, ScanQRTextEdit, PrintError):
script = '' script = ''
for word in x.split(): for word in x.split():
if word[0:3] == 'OP_': if word[0:3] == 'OP_':
assert word in opcodes.lookup opcode_int = opcodes[word]
opcode_int = opcodes.lookup[word]
assert opcode_int < 256 # opcode is single-byte assert opcode_int < 256 # opcode is single-byte
script += bitcoin.int_to_hex(opcode_int) script += bitcoin.int_to_hex(opcode_int)
else: else:

View file

@ -32,6 +32,7 @@ import traceback
import sys import sys
from typing import (Sequence, Union, NamedTuple, Tuple, Optional, Iterable, from typing import (Sequence, Union, NamedTuple, Tuple, Optional, Iterable,
Callable, List, Dict) Callable, List, Dict)
from enum import IntEnum
from . import ecc, bitcoin, constants, segwit_addr from . import ecc, bitcoin, constants, segwit_addr
from .util import print_error, profiler, to_bytes, bh2u, bfh from .util import print_error, profiler, to_bytes, bh2u, bfh
@ -190,81 +191,146 @@ class BCDataStream(object):
self.write(s) self.write(s)
# enum-like type class opcodes(IntEnum):
# From the Python Cookbook, downloaded from http://code.activestate.com/recipes/67107/ # push value
class EnumException(Exception): OP_0 = 0x00
pass 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
class Enumeration: # stack ops
def __init__(self, name, enumList): OP_TOALTSTACK = 0x6b
self.__doc__ = name OP_FROMALTSTACK = 0x6c
lookup = { } OP_2DROP = 0x6d
reverseLookup = { } OP_2DUP = 0x6e
i = 0 OP_3DUP = 0x6f
uniqueNames = [ ] OP_2OVER = 0x70
uniqueValues = [ ] OP_2ROT = 0x71
for x in enumList: OP_2SWAP = 0x72
if isinstance(x, tuple): OP_IFDUP = 0x73
x, i = x OP_DEPTH = 0x74
if not isinstance(x, str): OP_DROP = 0x75
raise EnumException("enum name is not a string: " + x) OP_DUP = 0x76
if not isinstance(i, int): OP_NIP = 0x77
raise EnumException("enum value is not an integer: " + i) OP_OVER = 0x78
if x in uniqueNames: OP_PICK = 0x79
raise EnumException("enum name is not unique: " + x) OP_ROLL = 0x7a
if i in uniqueValues: OP_ROT = 0x7b
raise EnumException("enum value is not unique for " + x) OP_SWAP = 0x7c
uniqueNames.append(x) OP_TUCK = 0x7d
uniqueValues.append(i)
lookup[x] = i
reverseLookup[i] = x
i = i + 1
self.lookup = lookup
self.reverseLookup = reverseLookup
def __getattr__(self, attr): # splice ops
if attr not in self.lookup: OP_CAT = 0x7e
raise AttributeError OP_SUBSTR = 0x7f
return self.lookup[attr] OP_LEFT = 0x80
def whatis(self, value): OP_RIGHT = 0x81
return self.reverseLookup[value] 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
# This function comes from bitcointools, bct-LICENSE.txt. # numeric
def long_hex(bytes): OP_1ADD = 0x8b
return bytes.encode('hex_codec') OP_1SUB = 0x8c
OP_2MUL = 0x8d
OP_2DIV = 0x8e
OP_NEGATE = 0x8f
OP_ABS = 0x90
OP_NOT = 0x91
OP_0NOTEQUAL = 0x92
# This function comes from bitcointools, bct-LICENSE.txt. OP_ADD = 0x93
def short_hex(bytes): OP_SUB = 0x94
t = bytes.encode('hex_codec') OP_MUL = 0x95
if len(t) < 11: OP_DIV = 0x96
return t OP_MOD = 0x97
return t[0:4]+"..."+t[-4:] 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()
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): def script_GetOp(_bytes : bytes):
@ -294,10 +360,6 @@ def script_GetOp(_bytes : bytes):
yield opcode, vch, i yield opcode, vch, i
def script_GetOpName(opcode):
return (opcodes.whatis(opcode)).replace("OP_", "")
class OPPushDataGeneric: class OPPushDataGeneric:
def __init__(self, pushlen: Callable=None): def __init__(self, pushlen: Callable=None):
if pushlen is not None: if pushlen is not None: