electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

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:
Melectrum/gui/qt/paytoedit.py | 3+--
Melectrum/transaction.py | 218+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
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: