class Script(CScript):
    """Transaction script.

    Subclassed from CScript to provide methods for
    getting/setting according to certain formats.
    """
    @classmethod
    def from_human(cls, data):
        hex_str = []
        try:
            d = shlex.split(data, posix=False)
        except Exception:
            d = data.split()
        while 1:
            if len(d) == 0:
                break
            word = d[0]
            d = d[1:]

            if word.startswith('PUSHDATA'):
                continue

            opcode = opcodes.opcodes_by_name.get(word)
            if opcode is not None:
                hex_str.append(format_hex_string(hex(opcode), with_prefix=False))
                continue

            # data to be pushed
            pushdata = word

            # Make sure hex is formatted.
            if is_hex(pushdata):
                if pushdata.startswith('0x'):
                    pushdata = pushdata[2:]
                if len(pushdata) % 2 != 0:
                    pushdata = ''.join(['0', pushdata])
            # Hex-encode text.
            else:
                if pushdata.startswith('"') and pushdata.endswith('"'):
                    pushdata = pushdata[1:-1]
                pushdata = pushdata.encode('hex')
            hex_str.append(push_script(pushdata))

        hex_str = ''.join(hex_str)
        return cls(hex_str.decode('hex'))

    def get_hex(self):
        """Get the script as a hex-encoded string."""
        s = []
        iterator = self.raw_iter()
        while 1:
            try:
                opcode, data, byte_index = next(iterator)
                hexcode = hex(opcode)[2:]
                if len(hexcode) % 2 != 0:
                    hexcode = ''.join(['0', hexcode])
                s.append(hexcode)
                if data:
                    s.append(data.encode('hex'))
            except StopIteration:
                break
            except Exception:
                s.append('(CANNOT_PARSE)')

        return ''.join(s)

    def human_iter(self):
        iterator = self.raw_iter()
        s = ''
        while 1:
            try:
                opcode, data, byte_index = next(iterator)
                op_name = opcodes.opcode_names.get(opcode)
                if op_name and not 'DATA' in op_name:
                    s = op_name
                else:
                    if all(ord(c) < 128 and ord(c) > 31 for c in data):
                        s = ''.join(['"', data, '"'])
                    else:
                        s = ''.join(['0x', data.encode('hex')])
                yield s
            except StopIteration:
                break
            except Exception:
                yield '(CANNOT_PARSE)'

    def get_human(self):
        """Get the script as a human-readable string."""
        s = []
        iterator = self.human_iter()
        while 1:
            try:
                s.append(next(iterator))
            except StopIteration:
                break
            except Exception:
                break
        return ' '.join(s) class ParamsPreset(object):
    def __init__(self, **kwargs):
    def raw_signature_hash(cls, script, txTo, inIdx, hashtype):
    def signature_hash(cls, script, txTo, inIdx, hashtype):
def add_preset(preset):
def remove_preset(preset):
def get_presets():
def get_tx_fields():
def set_tx_fields(fields):
def set_tx_serializer(cls):
def get_block_header_fields():
def set_block_header_fields(fields):
def get_block_fields():
def set_block_fields(fields):
def get_opcode_overrides():
def set_opcode_overrides(ops):
def set_opcodes(op_names, ops_by_name, disabled_ops):
def get_script_engine_class():
def set_script_engine_class(cls):
def set_to_preset(name):
def signature_hash(script, txTo, inIdx, hashtype):
        HASH_ONE = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' def sig_hash_name(hash_type):
def sig_hash_explanation(hash_type):
    def stream_deserialize(self, tx, f):
    def stream_serialize(self, tx, f):
    def deserialize_field(self, tx, kwargs, attr, fmt, num_bytes, f):
    def serialize_field(self, tx, attr, fmt, num_bytes, f):
    def __init__(self, vin=None, vout=None, locktime=0, version=1, fields=None, kwfields=None):
    def set_serializer_class(cls, ser_class):
    def set_serialization(self, fields=None):
    def stream_deserialize(cls, f):
    def stream_serialize(self, f):
    def from_tx(cls, tx):
    def as_hex(self):
    def deserialize_field(self, tx, kwargs, attr, fmt, num_bytes, f):
    def serialize_field(self, tx, attr, fmt, num_bytes, f):
class TransactionSerializer(object):
class Transaction(CMutableTransaction):
class ClamsTxSerializer(TransactionSerializer): def is_hex(x):
    try:
        i = int(x, 16)
        return True
    except ValueError:
        pass
    return False def format_hex_string(x, with_prefix=True):
    """Ensure hex-encoded value has an even length."""
    if not is_hex(x):
        return
    # Add '0x' prefix
    new_val = x
    if not x.startswith('0x'):
        if x.startswith('x'):
            new_val = ''.join(['0', x])
        else:
            new_val = ''.join(['0x', x])
    # Even-length string
    if len(new_val) % 2 != 0:
        new_val = ''.join([new_val[0:2], '0', new_val[2:]])
    return new_val if with_prefix else new_val[2:] class TxWidget(QWidget):
    """Displays the deserialized fields of a transaction."""
    def __init__(self, parent=None):
        super(TxWidget, self).__init__(parent)
        self.config = config.get_config()
        self.config.optionChanged.connect(self.on_option_changed)
        # Widgets for tx fields
        self.field_widgets = OrderedDict()

        form = QFormLayout()

        self.tx_id = QLineEdit()
        self.tx_id.setReadOnly(True)
        self.tx_id.setToolTip('Transaction ID')
        self.tx_id.setWhatsThis('The ID (hash) of the transaction is displayed here.')

        self.version_edit = QLineEdit()
        self.version_edit.setReadOnly(True)
        self.inputs_tree = inputs = InputsTree()
        self.outputs_tree = outputs = OutputsTree()
        self.locktime_edit = LockTimeWidget()

        self.field_widgets.update({'nVersion': self.version_edit})
        self.field_widgets.update({'vin': self.inputs_tree})
        self.field_widgets.update({'vout': self.outputs_tree})
        self.field_widgets.update({'nLockTime': self.locktime_edit})

        self.tx_properties = TxProperties()

        self.tx_fields_layout = QFormLayout()
        self.tx_fields_layout.setContentsMargins(0, 0, 0, 0)
        self.tx_fields_layout.addRow(QLabel('Version:'), self.version_edit)
        self.tx_fields_layout.addRow(QLabel('Inputs:'), inputs)
        self.tx_fields_layout.addRow(QLabel('Outputs:'), outputs)
        self.tx_fields_layout.addRow(QLabel('LockTime:'), self.locktime_edit)

        form.addRow('Tx ID:', self.tx_id)
        form.addRow(self.tx_fields_layout)
        form.addRow('Metadata:', self.tx_properties)

        self.adjust_field_widgets()

        self.setLayout(form)

    def set_tx(self, tx):
        self.version_edit.setText(str(tx.nVersion))

        self.inputs_tree.model.set_tx(tx)
        self.outputs_tree.model.set_tx(tx)

        self.locktime_edit.set_locktime(tx.nLockTime)

        for name, w in self.field_widgets.items():
            # We already handle these four.
            if name in ['nVersion', 'vin', 'vout', 'nLockTime']:
                continue
            if not name in [field[0] for field in tx.fields]:
                continue
            value = getattr(tx, name)
            w.setText(str(value))

        self.tx_properties.set_tx(tx)

        self.tx_id.setText(bitcoin.core.b2lx(tx.GetHash()))

    def clear(self):
        self.tx_id.clear()
        self.tx_properties.clear()
        for w in self.field_widgets.values():
            w.clear()

    def add_input(self, i):
        self.inputs_tree.add_input(i)

    def add_output(self, o):
        self.outputs_tree.add_output(o)

    def on_option_changed(self, key):
        if key != 'chainparams':
            return
        self.adjust_field_widgets()

    def adjust_field_widgets(self):
        """Add widgets and adjust visibility for tx field widgets."""
        tx_fields = chainparams.get_tx_fields()
        for i, field in enumerate(tx_fields):
            name = field[0]
            # Create a new widget for the tx field.
            if name not in self.field_widgets.keys():
                widget = QLineEdit()
                widget.setReadOnly(True)
                if name == 'Timestamp':
                    widget = TimestampWidget()
                label = QLabel(''.join([name, ':']))
                # Add the widget to our dict and to the layout.
                self.field_widgets[name] = widget
                self.tx_fields_layout.insertRow(i, label, widget)

            # Make sure the existing widget for the tx field is visible.
            else:
                w = self.field_widgets[name]
                l = self.tx_fields_layout.labelForField(w)
                w.show()
                l.show()

        # Hide unnecessary widgets
        tx_field_names = [i[0] for i in tx_fields]
        for name, w in self.field_widgets.items():
            if name not in tx_field_names:
                l = self.tx_fields_layout.labelForField(w)
                w.hide()
                l.hide() class InputsTree(QWidget):
    """Model and View showing a transaction's inputs."""
    def __init__(self, parent=None):
        super(InputsTree, self).__init__(parent)
        self.model = InputsModel()
        self.view = QTableView()
        self.view.setAlternatingRowColors(True)
        self.view.setModel(self.model)
        self.view.horizontalHeader().setStretchLastSection(False)
        self.view.horizontalHeader().setResizeMode(0, QHeaderView.Interactive)
        self.view.horizontalHeader().setResizeMode(1, QHeaderView.ResizeToContents)
        self.view.horizontalHeader().setResizeMode(2, QHeaderView.Stretch)
        self.view.horizontalHeader().setResizeMode(3, QHeaderView.Interactive)
        self.view.horizontalHeader().setHighlightSections(False)
        self.view.verticalHeader().setDefaultSectionSize(22)
        self.view.verticalHeader().setVisible(False)
        self.view.setSelectionMode(QAbstractItemView.SingleSelection)
        self.view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.view.customContextMenuRequested.connect(self.customContextMenu)
        vbox = QVBoxLayout()
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.addWidget(self.view)
        self.setLayout(vbox)

    def clear(self):
        self.model.clear()

    def copy_prev_tx(self):
        """Copy the previous transaction ID to clipboard."""
        idx = self.view.selectedIndexes()[0]
        data = self.model.data(idx)
        QApplication.clipboard().setText(data.toString())

    def copy_script(self):
        """Copy the scriptSig to clipboard."""
        idx = self.view.selectedIndexes()[2]
        data = self.model.data(idx)
        QApplication.clipboard().setText(data.toString())

    def copy_script_hex(self):
        """Copy the scriptSig to clipboard as hex."""
        idx = self.view.selectedIndexes()[2]
        data = self.model.data(idx, RawRole)
        QApplication.clipboard().setText(data.toString())

    def context_menu(self):
        menu = QMenu()
        copy = menu.addMenu('Copy')
        copy.addAction('Previous Transaction ID', self.copy_prev_tx)
        copy.addAction('Input Script', self.copy_script)
        copy.addAction('Input Script (Hex)', self.copy_script_hex)

        def copy_serialized():
            row = self.view.selectedIndexes()[0].row()
            inp = self.model.tx.vin[row]
            data = b2x(inp.serialize())
            QApplication.clipboard().setText(data)
        copy.addAction('Serialized Input', copy_serialized)
        return menu

    def customContextMenu(self, pos):
        if len(self.view.selectedIndexes()) == 0:
            return
        menu = self.context_menu()
        menu.exec_(self.view.viewport().mapToGlobal(pos))

    def add_input(self, i):
        self.model.add_input(i)
        return

    def get_inputs(self):
        return self.model.get_inputs() class OutputsTree(QWidget):
    """Model and View showing a transaction's outputs."""
    def __init__(self, parent=None):
        super(OutputsTree, self).__init__(parent)
        self.model = OutputsModel()
        self.view = QTableView()
        self.view.setAlternatingRowColors(True)
        self.view.setModel(self.model)
        self.view.horizontalHeader().setResizeMode(0, QHeaderView.Interactive)
        self.view.horizontalHeader().setResizeMode(1, QHeaderView.Stretch)
        self.view.horizontalHeader().setHighlightSections(False)
        self.view.verticalHeader().setDefaultSectionSize(22)
        self.view.verticalHeader().setVisible(False)
        self.view.setSelectionMode(QAbstractItemView.SingleSelection)
        self.view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.view.customContextMenuRequested.connect(self.customContextMenu)
        vbox = QVBoxLayout()
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.addWidget(self.view)
        self.setLayout(vbox)
        config.get_config().optionChanged.connect(self.on_option_changed)

    def clear(self):
        self.model.clear()

    def copy_script(self):
        """Copy the scriptPubKey to clipboard."""
        idx = self.view.selectedIndexes()[1]
        data = self.model.data(idx)
        QApplication.clipboard().setText(data.toString())

    def copy_script_hex(self):
        """Copy the scriptPubKey to clipboard as hex."""
        idx = self.view.selectedIndexes()[1]
        data = self.model.data(idx, RawRole)
        QApplication.clipboard().setText(data.toString())

    def copy_amount(self):
        """Copy the output amount to clipboard."""
        idx = self.view.selectedIndexes()[0]
        data = self.model.data(idx)
        QApplication.clipboard().setText(data.toString())

    def context_menu(self):
        menu = QMenu()
        copy = menu.addMenu('Copy')
        copy.addAction('Amount', self.copy_amount)
        copy.addAction('Output Script', self.copy_script)
        copy.addAction('Output Script (Hex)', self.copy_script_hex)
        def copy_serialized():
            row = self.view.selectedIndexes()[0].row()
            out = self.model.tx.vout[row]
            data = b2x(out.serialize())
            QApplication.clipboard().setText(data)
        copy.addAction('Serialized Output', copy_serialized)
        return menu

    def customContextMenu(self, pos):
        if len(self.view.selectedIndexes()) == 0:
            return
        menu = self.context_menu()
        menu.exec_(self.view.viewport().mapToGlobal(pos))

    def add_output(self, o):
        self.model.add_output(o)

    def get_outputs(self):
        return self.model.get_outputs()

    def on_option_changed(self, key):
        if key == 'amount_format':
            self.model.amount_format = config.get_config().get_option('amount_format', 'coins')
            self.model.amount_format_changed() class TimestampWidget(QWidget):
    """Displays a transaction's timestamp.

    This is only used by certain chains. Namely, Peercoin descendants.
    Displays the raw int and the human-readable time side-by-side.
    """
    def __init__(self, parent=None):
        super(TimestampWidget, self).__init__(parent)
        self.timestamp_raw = QLineEdit()
        self.timestamp_human = QLineEdit()
        for i in [self.timestamp_raw, self.timestamp_human]:
            i.setReadOnly(True)
        hbox = HBox(self.timestamp_raw, self.timestamp_human)
        hbox.setContentsMargins(0, 0, 0, 0)
        self.setLayout(hbox)
        self.timestamp_raw.textChanged.connect(self.update_time)

    def clear(self):
        self.timestamp_raw.clear()
        self.timestamp_human.clear()

    def update_time(self):
        """Update human-readable time to reflect raw."""
        timestamp_str = self.timestamp_raw.text()
        if not timestamp_str:
            self.timestamp_human.clear()
            return
        if not str(timestamp_str).isdigit():
            self.timestamp_raw.setText(str(int(time.time())))
            return
        timestamp = int(timestamp_str)
        date_time = datetime.datetime.utcfromtimestamp(timestamp)
        self.timestamp_human.setText(' '.join([date_time.strftime('%Y-%m-%d %H:%M:%S'), 'UTC']))
        self.setToolTip('{} ({})'.format(str(timestamp), str(self.timestamp_human.text())))

    def set_time(self, timestamp):
        """Formats the raw and human-readable timestamps."""
        self.timestamp_raw.setText(str(timestamp))
        self.update_time()

    def setText(self, text):
        self.set_time(int(text))

    def text(self):
        return self.timestamp_raw.text()

    def get_amount(self):
        """This is for compatibility with AmountEdit."""
        return int(self.text()) class ScriptEditor(ScriptEdit):
    """Main script editor.

    Requires the main window as an argument so it can integrate tools.
    """
    def __init__(self, gui, parent=None):
        super(ScriptEditor, self).__init__(gui)
        self.gui = gui
        self.highlighter = ScriptHighlighter(self.gui, self)

    def contextMenuEvent(self, e):
        menu = self.createStandardContextMenu()
        menu.addAction('Copy Hex', self.copy_hex)
        menu.exec_(e.globalPos())

    def set_data(self, text, fmt):
        script = None
        if fmt == 'Hex' and len(text) % 2 == 0:
            try:
                script = Script(text.decode('hex'))
            except Exception:
                pass
        elif fmt == 'Human':
            txt, self.context = transform_human_script(text, self.gui)
            script = Script.from_human(txt)
        self.script = script

    @pyqtProperty(str)
    def humanText(self):
        return self.get_data(fmt='Human')

    @humanText.setter
    def humanText(self, value):
        self.setText(str(value)) def HBox(*widgets):
def floated_buttons(btns, left=False):
def add_shortcuts(items):
    def __init__(self, parent=None):
    def sizeHint(self):
    def __init__(self, satoshis=0):
    def known_formats():
    def get_str(self):
    def __init__(self, parent=None):
    def satoshis(self):
    def satoshis(self, value):
    def get_satoshis(self):
    def set_satoshis(self, amount):
    def check_text(self):
    def update_format(self):
    def on_option_changed(self, key):
    def __init__(self, max_value=0xffffffff, parent=None):
    def amount(self):
    def amount(self, value):
    def get_amount(self):
    def set_amount(self, amount):
    def check_text(self):
    def __init__( self, *args ):
    def isReadOnly( self ):
    def mousePressEvent( self, event ):
    def mouseMoveEvent( self, event ):
    def mouseReleaseEvent( self, event ):
    def keyPressEvent( self, event ):
    def setReadOnly( self, state ):
class Separator(QFrame):
class Amount(object):
class OutputAmountEdit(QLineEdit):
class AmountEdit(QLineEdit):
class ReadOnlyCheckBox(QtGui.QCheckBox):
import bitcoin
from bitcoin.core import x, b2x, CMutableOutPoint, CMutableTxIn, CMutableTxOut
from bitcoin.core.script import SIGHASH_ALL, SIGHASH_ANYONECANPAY
from bitcoin.core.scripteval import VerifyScript, SCRIPT_VERIFY_P2SH
from bitcoin.wallet import CBitcoinSecret
from PyQt4.QtGui import *
from PyQt4 import QtCore
from PyQt4.QtCore import QAbstractTableModel, QModelIndex, Qt, QVariant
from hashmal_lib.core.script import Script
from hashmal_lib.core import chainparams
from hashmal_lib.core.transaction import Transaction, sig_hash_name, sig_hash_explanation, sighash_types, sighash_types_by_value
from hashmal_lib.core.utils import is_hex, format_hex_string
from hashmal_lib.widgets.tx import TxWidget, InputsTree, OutputsTree, TimestampWidget
from hashmal_lib.widgets.script import ScriptEditor
from hashmal_lib.gui_utils import Separator, floated_buttons, AmountEdit, HBox, monospace_font, OutputAmountEdit, RawRole
from base import BaseDock, Plugin, Category, augmenter
from item_types import ItemAction
        self.tx_widget.set_tx(tx)
        self.sighash_widget.set_tx(tx)

    def on_option_changed(self, key):
        if key == 'chainparams':
            self.needsUpdate.emit()

    def adjust_tx_fields(self):
        """Show or hide tx field widgets."""
        tx_fields = chainparams.get_tx_fields()
        for field in tx_fields:
            name = field[0]
            if name in ['nVersion', 'vin', 'vout', 'nLockTime']:
                continue

            default_value = field[3]
            if name not in [j[0] for j in self.tx_field_widgets]:
                widget = QLineEdit()
                if isinstance(default_value, int):
                    # Special case for timestamp fields.
                    if name == 'Timestamp':
                        widget = TimestampWidget()
                        widget.timestamp_raw.setReadOnly(False)
                    else:
                        widget = AmountEdit()
                widget.setText(str(default_value))
                label = QLabel(''.join([name, ':']))
                self.tx_field_widgets.append((name, widget))
                self.tx_fields_layout.addRow(label, widget)

        tx_field_names = [i[0] for i in tx_fields]
        for name, w in self.tx_field_widgets:
            l = self.tx_fields_layout.labelForField(w)
            if name in tx_field_names:
                w.show()
                l.show()
            else:
                w.hide()
                l.hide()

        if tx_field_names == ['nVersion', 'vin', 'vout', 'nLockTime']:
            self.tabs.setTabEnabled(3, False)
        else:
            self.tabs.setTabEnabled(3, True)

    def refresh_data(self):
        self.adjust_tx_fields()
        self.build_transaction()

class BaseEditor(QWidget):
    """Item editor for inputs or outputs."""
    def __init__(self, tree, parent=None):
        super(BaseEditor, self).__init__(parent)
        self.tree = tree
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.tree.model)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.tree.view.selectionModel().selectionChanged.connect(self.selection_changed)

    def selection_changed(self, selected, deselected):
        try:
            index = selected.indexes()[0]
            self.setEnabled(True)
        except IndexError:
            self.setEnabled(False)
            return
        self.mapper.setCurrentIndex(index.row())

    def do_delete(self):
        index = self.mapper.currentIndex()
        self.tree.model.removeRow(index)

    def do_submit(self):
        self.mapper.submit()

class InputsEditor(BaseEditor):
    def __init__(self, main_window, tree, parent=None):
        super(InputsEditor, self).__init__(tree, parent)
        self.prev_tx = QLineEdit()
        self.prev_tx.setToolTip('Transaction ID of the tx with the output being spent')
        self.prev_tx.setWhatsThis('Use this field to specify the transaction that contains the output you\'re spending.')

        self.prev_vout = AmountEdit()
        self.prev_vout.setToolTip('Output index of the previous transaction')
        self.prev_vout.setWhatsThis('Use this field to specify the output you are spending of the previous transaction.')

        self.script = ScriptEditor(main_window)
        self.script.setToolTip('Script that will be put on the stack before the previous output\'s script.')
        self.script.setWhatsThis('Enter a script here. This script will be evaluated directly before the script of the output you are spending. Any values that are pushed onto the stack when this script finishes its execution are present when the output script is evaluated afterward.')

        self.sequence = AmountEdit()
        self.sequence.setText('4294967295')
        self.sequence.setWhatsThis('Use this field to specify the sequence value. It\'s likely that you should leave this as its default (maximum) value.')
        maxify_input_sequence = QPushButton('Max')
        maxify_input_sequence.clicked.connect(lambda: self.sequence.setText('0xffffffff'))
        maxify_input_sequence.setWhatsThis('This button will set the sequence to its default value.')

        for i in [self.prev_tx, self.prev_vout, self.script, self.sequence]:
            i.setFont(monospace_font)

        self.mapper.addMapping(self.prev_tx, 0)
        self.mapper.addMapping(self.prev_vout, 1, 'amount')
        self.mapper.addMapping(self.script, 2, 'humanText')
        self.mapper.addMapping(self.sequence, 3, 'amount')

        delete_button = QPushButton('Remove Input')
        delete_button.setToolTip('Remove this input from the transaction')
        delete_button.clicked.connect(self.do_delete)
        submit_button = QPushButton('Save')
        submit_button.setToolTip('Update input with the above data')
        submit_button.clicked.connect(self.do_submit)

        form = QFormLayout()
        form.setContentsMargins(0, 0, 0, 0)
        form.addRow('Previous Transaction: ', self.prev_tx)
        form.addRow('Previous Tx Output: ', self.prev_vout)
        form.addRow('Input script: ', self.script)
        seq_desc = QLabel('Sequence is mostly deprecated.\nIf an input has a sequence that\'s not the maximum value, the transaction\'s locktime will apply.')
        seq_desc.setWordWrap(True)
        form.addRow(seq_desc)

        form.addRow('Sequence: ', HBox(self.sequence, maxify_input_sequence))