def update_and_broadcast(self, identifier, value, transfer_to):
        if transfer_to.toPlainText() == "":
            # User left the recipient blank, so this isn't a transfer.
            recipient_address = None
        else:
            # The user entered something into the recipient text box.

            recipient = transfer_to.get_recipient()

            if recipient is None:
                recipient_type, recipient_address = None, transfer_to.toPlainText(
                )
            else:
                recipient_type, recipient_address = recipient

            if recipient_type != TYPE_ADDRESS:
                self.main_window.show_error(
                    _("Invalid address ") + recipient_address)
                return

        name_update = self.main_window.console.namespace.get('name_update')
        broadcast = self.main_window.console.namespace.get('broadcast')

        try:
            # TODO: support non-ASCII encodings
            tx = name_update(identifier.decode('ascii'),
                             value.decode('ascii'),
                             destination=recipient_address,
                             wallet=self.wallet)
        except (NotEnoughFunds, NoDynamicFeeEstimates) as e:
            formatted_name = format_name_identifier(identifier)
            self.main_window.show_message(
                _("Error creating update for ") + formatted_name + ": " +
                str(e))
            return
        except InternalAddressCorruption as e:
            formatted_name = format_name_identifier(identifier)
            self.main_window.show_error(
                _("Error creating update for ") + formatted_name + ": " +
                str(e))
            raise
        except BaseException as e:
            traceback.print_exc(file=sys.stdout)
            formatted_name = format_name_identifier(identifier)
            self.main_window.show_message(
                _("Error creating update for ") + formatted_name + ": " +
                str(e))
            return

        try:
            broadcast(tx)
        except Exception as e:
            formatted_name = format_name_identifier(identifier)
            self.main_window.show_error(
                _("Error broadcasting update for ") + formatted_name + ": " +
                str(e))
            return
    def register_and_broadcast(self, identifier, value, transfer_to):
        if transfer_to.toPlainText() == "":
            # User left the recipient blank, so this isn't a transfer.
            recipient_address = None
        else:
            # The user entered something into the recipient text box.

            recipient = transfer_to.get_recipient()

            if recipient is None:
                recipient_type, recipient_address = None, transfer_to.toPlainText(
                )
            else:
                recipient_type, recipient_address = recipient

            if recipient_type != TYPE_ADDRESS:
                self.main_window.show_error(
                    _("Invalid address ") + recipient_address)
                return

        name_autoregister = self.main_window.console.namespace.get(
            'name_autoregister')

        try:
            # TODO: support non-ASCII encodings
            name_autoregister(identifier.decode('ascii'),
                              value.decode('ascii'),
                              destination=recipient_address,
                              wallet=self.wallet)
        except NameAlreadyExistsError as e:
            formatted_name = format_name_identifier(identifier)
            self.main_window.show_message(
                _("Error registering ") + formatted_name + ": " + str(e))
            return
        except (NotEnoughFunds, NoDynamicFeeEstimates) as e:
            formatted_name = format_name_identifier(identifier)
            self.main_window.show_message(
                _("Error registering ") + formatted_name + ": " + str(e))
            return
        except InternalAddressCorruption as e:
            formatted_name = format_name_identifier(identifier)
            self.main_window.show_error(
                _("Error registering ") + formatted_name + ": " + str(e))
            raise
        except TxBroadcastError as e:
            msg = e.get_message_for_gui()
            self.main_window.show_error(msg)
        except BestEffortRequestFailed as e:
            msg = repr(e)
            self.main_window.show_error(msg)
        except BaseException as e:
            traceback.print_exc(file=sys.stdout)
            formatted_name = format_name_identifier(identifier)
            self.main_window.show_message(
                _("Error registering ") + formatted_name + ": " + str(e))
            return
Example #3
0
    def renew_selected_items(self):
        selected = self.selected_in_column(0)
        if not selected:
            return

        name_update = self.parent.console.namespace.get('name_update')
        broadcast = self.parent.console.namespace.get('broadcast')
        addtransaction = self.parent.console.namespace.get('addtransaction')

        for item in selected:
            identifier = item.data(Qt.UserRole + USER_ROLE_NAME)

            try:
                # TODO: support non-ASCII encodings
                tx = name_update(identifier.decode('ascii'),
                                 wallet=self.wallet)
            except NameUpdatedTooRecentlyError:
                # The name was recently updated, so skip it and don't renew.
                continue
            except (NotEnoughFunds, NoDynamicFeeEstimates) as e:
                self.parent.show_message(str(e))
                return
            except InternalAddressCorruption as e:
                self.parent.show_error(str(e))
                raise
            except BaseException as e:
                traceback.print_exc(file=sys.stdout)
                self.parent.show_message(str(e))
                return

            try:
                broadcast(tx)
            except Exception as e:
                formatted_name = format_name_identifier(identifier)
                self.parent.show_error(
                    _("Error broadcasting renewal for ") + formatted_name +
                    ": " + str(e))
                continue

            # We add the transaction to the wallet explicitly because
            # otherwise, the wallet will only learn that the transaction's
            # inputs are spent once the ElectrumX server sends us a copy of the
            # transaction, which is several seconds later, which will cause us
            # to double-spend those inputs in subsequent renewals during this
            # loop.
            status = addtransaction(tx)
            if not status:
                formatted_name = format_name_identifier(identifier)
                self.parent.show_error(
                    _("Error adding renewal for ") + formatted_name +
                    _(" to wallet"))
                continue
    def __init__(self, identifier, value, parent, is_new):
        # We want to be a top-level window
        QDialog.__init__(self, parent=None)

        self.main_window = parent

        self.setMinimumWidth(545)
        self.setMinimumHeight(245)
        if is_new:
            self.setWindowTitle(_("Configure New Name"))
        else:
            self.setWindowTitle(_("Reconfigure Name"))

        form_layout = QFormLayout()

        self.identifier = identifier
        formatted_name = format_name_identifier(identifier)
        form_layout.addRow(QLabel(formatted_name))

        self.dataEdit = QLineEdit()
        # TODO: support non-ASCII encodings
        self.dataEdit.setText(value.decode('ascii'))
        form_layout.addRow(_("Data:"), self.dataEdit)

        self.transferTo = PayToEdit(self.main_window)
        form_layout.addRow(_("Transfer to:"), self.transferTo)

        form = QWidget()
        form.setLayout(form_layout)

        self.buttons_box = QDialogButtonBox()
        self.buttons_box.setStandardButtons(QDialogButtonBox.Cancel
                                            | QDialogButtonBox.Ok)

        buttons_hbox = QHBoxLayout()
        buttons_hbox.addStretch()
        buttons_hbox.addWidget(self.buttons_box)
        buttons = QWidget()
        buttons.setLayout(buttons_hbox)

        vbox = QVBoxLayout()
        vbox.addWidget(form)
        vbox.addWidget(buttons)
        self.setLayout(vbox)

        self.buttons_box.accepted.connect(self.accept)
        self.buttons_box.rejected.connect(self.reject)

        if is_new:
            self.accepted.connect(lambda: self.register_and_broadcast(
                self.identifier,
                self.dataEdit.text().encode('ascii'), self.transferTo))
        else:
            # TODO: handle non-ASCII encodings
            self.accepted.connect(lambda: self.update_and_broadcast(
                self.identifier,
                self.dataEdit.text().encode('ascii'), self.transferTo))
Example #5
0
    def insert_utxo(self, idx, utxo: PartialTxInput):
        txid = utxo.prevout.txid.hex()
        vout = utxo.prevout.out_idx
        name_op = utxo.name_op
        if name_op is None:
            return

        height = utxo.block_height
        header_at_tip = self.network.blockchain().header_at_tip()

        if height is None or height <= 0:
            # TODO: Namecoin: Take into account the fact that transactions may
            # not be mined in the next block.
            blocks_until_mined = 1

            height_estimated = header_at_tip[
                'block_height'] + blocks_until_mined
        else:
            height_estimated = height

        if 'name' not in name_op:
            # Upstream handles a name_new here, which doesn't exist in Xaya.
            assert False
        else:
            if height is not None and height > 0:
                # utxo is confirmed
                status = ''
            else:
                # utxo is name_update
                status = _('Update Pending')

        if 'name' in name_op:
            # utxo is name_anyupdate or a name_new that we've queued a name_firstupdate for
            name = name_op['name']
            formatted_name = format_name_identifier(name)
            value = name_op['value']
            formatted_value = format_name_value(value)
        else:
            # utxo is a name_new that we haven't queued a name_firstupdate for
            name = None
            formatted_name = ''
            value = None
            formatted_value = ''

        txout = txid + ":%d" % vout

        self._utxo_dict[txout] = utxo

        labels = [formatted_name, formatted_value, status]
        utxo_item = [QStandardItem(x) for x in labels]
        self.set_editability(utxo_item)

        utxo_item[self.Columns.NAME].setFont(QFont(MONOSPACE_FONT))
        utxo_item[self.Columns.VALUE].setFont(QFont(MONOSPACE_FONT))

        utxo_item[self.Columns.NAME].setData(txout, Qt.UserRole)
        utxo_item[self.Columns.NAME].setData(name,
                                             Qt.UserRole + USER_ROLE_NAME)
        utxo_item[self.Columns.NAME].setData(value,
                                             Qt.UserRole + USER_ROLE_VALUE)

        address = utxo.address
        if self.wallet.is_frozen_address(
                address) or self.wallet.is_frozen_coin(utxo):
            utxo_item[self.Columns.NAME].setBackground(
                ColorScheme.BLUE.as_color(True))
            if self.wallet.is_frozen_address(
                    address) and self.wallet.is_frozen_coin(utxo):
                utxo_item[self.Columns.NAME].setToolTip(
                    _('Address and coin are frozen'))
            elif self.wallet.is_frozen_address(address):
                utxo_item[self.Columns.NAME].setToolTip(_('Address is frozen'))
            elif self.wallet.is_frozen_coin(utxo):
                utxo_item[self.Columns.NAME].setToolTip(_('Coin is frozen'))
        self.model().appendRow(utxo_item)
    def __init__(self, identifier, value, parent, is_new):
        # We want to be a top-level window
        QDialog.__init__(self, parent=None)

        self.main_window = parent
        self.wallet = self.main_window.wallet

        self.setMinimumWidth(545)
        self.setMinimumHeight(245)
        if is_new:
            self.setWindowTitle(_("Configure New Name"))
        else:
            self.setWindowTitle(_("Reconfigure Name"))

        form_layout = QFormLayout()

        self.identifier = identifier
        formatted_name = format_name_identifier(identifier)
        form_layout.addRow(QLabel(formatted_name))

        self.dataEdit = QLineEdit()
        self.set_value(value)

        self.namespace = identifier_to_namespace(identifier)
        self.namespace_is_dns = self.namespace in ["d", "dd"]

        if self.namespace_is_dns:
            self.dnsButton = QPushButton(_('DNS Editor...'))
            self.dnsButton.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            self.dnsButton.setMinimumSize(150, 0)
            # TODO: tooltip?
            self.dnsButton.clicked.connect(lambda: show_configure_dns(
                self.dataEdit.text().encode('ascii'), self))

        data_layout = QHBoxLayout()
        data_layout.setContentsMargins(0, 0, 0, 0)
        data_layout.addWidget(self.dataEdit)
        if self.namespace_is_dns:
            data_layout.addWidget(self.dnsButton)

        self.data = QWidget()
        self.data.setLayout(data_layout)

        form_layout.addRow(_("Data:"), self.data)

        self.transferTo = PayToEdit(self.main_window)
        form_layout.addRow(_("Transfer to:"), self.transferTo)

        form = QWidget()
        form.setLayout(form_layout)

        self.buttons_box = QDialogButtonBox()
        self.buttons_box.setStandardButtons(QDialogButtonBox.Cancel
                                            | QDialogButtonBox.Ok)

        buttons_hbox = QHBoxLayout()
        buttons_hbox.addStretch()
        buttons_hbox.addWidget(self.buttons_box)
        buttons = QWidget()
        buttons.setLayout(buttons_hbox)

        vbox = QVBoxLayout()

        vbox.addWidget(form)
        vbox.addWidget(buttons)
        self.setLayout(vbox)

        self.buttons_box.accepted.connect(self.accept)
        self.buttons_box.rejected.connect(self.reject)

        if is_new:
            self.accepted.connect(lambda: self.register_and_broadcast(
                self.identifier,
                self.dataEdit.text().encode('ascii'), self.transferTo))
        else:
            # TODO: handle non-ASCII encodings
            self.accepted.connect(lambda: self.update_and_broadcast(
                self.identifier,
                self.dataEdit.text().encode('ascii'), self.transferTo))
Example #7
0
    def insert_utxo(self, idx, utxo: PartialTxInput):
        txid = utxo.prevout.txid.hex()
        vout = utxo.prevout.out_idx
        name_op = utxo.name_op
        if name_op is None:
            return

        height = utxo.block_height
        header_at_tip = self.network.blockchain().header_at_tip()

        if height is None or height <= 0:
            # TODO: Doichain: Take into account the fact that transactions may
            # not be mined in the next block.
            blocks_until_mined = 1

            height_estimated = header_at_tip[
                'block_height'] + blocks_until_mined
        else:
            height_estimated = height

        if 'name' not in name_op:
            # utxo is name_new
            queue_item, firstupdate_output = get_queued_firstupdate_from_new(
                self.wallet, txid, vout)
            if firstupdate_output is not None:
                if firstupdate_output.name_op is not None:
                    name_op = firstupdate_output.name_op
            expires_in, expires_datetime = None, None

            if height is not None and header_at_tip is not None and queue_item is not None:
                sendwhen_depth = queue_item["sendWhen"]["confirmations"]
                blocks_until_firstupdate_sent = blocks_remaining_until_confirmations(
                    height_estimated, header_at_tip['block_height'],
                    sendwhen_depth)

                # TODO: Doichain: Take into account the fact that transactions
                # may not be mined in the next block.
                blocks_until_firstupdate_confirmed = blocks_until_firstupdate_sent + 1

                minutes_remaining_until_firstupdate_confirmed = 10 * blocks_until_firstupdate_confirmed

                status = _('Registration Pending, ETA ') + str(
                    minutes_remaining_until_firstupdate_confirmed) + _("min")
            else:
                status = _('Registration Pending')
        else:
            # utxo is name_anyupdate
            if header_at_tip is not None:
                expires_in, expires_datetime = name_expiration_datetime_estimate(
                    height_estimated, header_at_tip['block_height'],
                    header_at_tip['timestamp'])
            else:
                expires_in, expires_datetime = None, None

            if height is not None and height > 0:
                # utxo is confirmed
                status = ''
            else:
                # utxo is unconfirmed
                if name_op['op'] == OP_NAME_UPDATE:
                    # utxo is name_update
                    status = _('Update Pending')
                else:
                    # utxo is name_firstupdate
                    # TODO: Doichain: Take into account the fact that
                    # transactions may not be mined in the next block.
                    status = _('Registration Pending, ETA 10min')

        if 'name' in name_op:
            # utxo is name_anyupdate or a name_new that we've queued a name_firstupdate for
            name = name_op['name']
            formatted_name = format_name_identifier(name)
            value = name_op['value']
            formatted_value = format_name_value(value)
        else:
            # utxo is a name_new that we haven't queued a name_firstupdate for
            name = None
            formatted_name = ''
            value = None
            formatted_value = ''

        formatted_expires_in = (_(
            'Expires in %d blocks\nDate/time is only an estimate; do not rely on it!'
        ) % expires_in) if expires_in is not None else ''
        formatted_expires_datetime = expires_datetime.isoformat(
            ' ') if expires_datetime is not None else ''

        txout = txid + ":%d" % vout

        self._utxo_dict[txout] = utxo

        labels = [
            formatted_name, formatted_value, formatted_expires_datetime, status
        ]
        utxo_item = [QStandardItem(x) for x in labels]
        self.set_editability(utxo_item)

        utxo_item[self.Columns.NAME].setFont(QFont(MONOSPACE_FONT))
        utxo_item[self.Columns.VALUE].setFont(QFont(MONOSPACE_FONT))

        utxo_item[self.Columns.NAME].setData(txout, Qt.UserRole)
        utxo_item[self.Columns.NAME].setData(name,
                                             Qt.UserRole + USER_ROLE_NAME)
        utxo_item[self.Columns.NAME].setData(value,
                                             Qt.UserRole + USER_ROLE_VALUE)

        utxo_item[self.Columns.EXPIRES_IN].setToolTip(formatted_expires_in)

        address = utxo.address
        if self.wallet.is_frozen_address(
                address) or self.wallet.is_frozen_coin(utxo):
            utxo_item[self.Columns.NAME].setBackground(
                ColorScheme.BLUE.as_color(True))
            if self.wallet.is_frozen_address(
                    address) and self.wallet.is_frozen_coin(utxo):
                utxo_item[self.Columns.NAME].setToolTip(
                    _('Address and coin are frozen'))
            elif self.wallet.is_frozen_address(address):
                utxo_item[self.Columns.NAME].setToolTip(_('Address is frozen'))
            elif self.wallet.is_frozen_coin(utxo):
                utxo_item[self.Columns.NAME].setToolTip(_('Coin is frozen'))
        self.model().appendRow(utxo_item)
    def insert_utxo(self, idx, x):
        txid = x.get('prevout_hash')
        vout = x.get('prevout_n')
        output = self.wallet.db.transactions[txid].outputs()[vout]
        name_op = output.name_op
        if name_op is None:
            return

        if 'name' not in name_op:
            # Upstream handles a name_new here, which doesn't exist in Xaya.
            assert False
        else:
            # utxo is name_anyupdate
            height = x.get('height')
            header_at_tip = self.network.blockchain().header_at_tip()
            #chain_height = self.network.blockchain().height()
            pending = (height <= 0)
            status = '' if not pending else _('Update Pending')

        if 'name' in name_op:
            # utxo is name_anyupdate or a name_new that we've queued a name_firstupdate for
            name = name_op['name']
            formatted_name = format_name_identifier(name)
            value = name_op['value']
            formatted_value = format_name_value(value)
        else:
            # utxo is a name_new that we haven't queued a name_firstupdate for
            name = None
            formatted_name = ''
            value = None
            formatted_value = ''

        txout = txid + ":%d" % vout

        self.utxo_dict[txout] = x

        labels = [formatted_name, formatted_value, status]
        utxo_item = [QStandardItem(x) for x in labels]
        self.set_editability(utxo_item)

        utxo_item[self.Columns.NAME].setFont(QFont(MONOSPACE_FONT))
        utxo_item[self.Columns.VALUE].setFont(QFont(MONOSPACE_FONT))

        utxo_item[self.Columns.NAME].setData(txout, Qt.UserRole)
        utxo_item[self.Columns.NAME].setData(name,
                                             Qt.UserRole + USER_ROLE_NAME)
        utxo_item[self.Columns.NAME].setData(value,
                                             Qt.UserRole + USER_ROLE_VALUE)

        address = x.get('address')
        if self.wallet.is_frozen_address(
                address) or self.wallet.is_frozen_coin(x):
            utxo_item[self.Columns.NAME].setBackground(
                ColorScheme.BLUE.as_color(True))
            if self.wallet.is_frozen_address(
                    address) and self.wallet.is_frozen_coin(x):
                utxo_item[self.Columns.NAME].setToolTip(
                    _('Address and coin are frozen'))
            elif self.wallet.is_frozen_address(address):
                utxo_item[self.Columns.NAME].setToolTip(_('Address is frozen'))
            elif self.wallet.is_frozen_coin(x):
                utxo_item[self.Columns.NAME].setToolTip(_('Coin is frozen'))
        self.model().appendRow(utxo_item)
Example #9
0
    def insert_utxo(self, idx, x):
        txid = x.get('prevout_hash')
        vout = x.get('prevout_n')
        output = self.wallet.db.transactions[txid].outputs()[vout]
        name_op = output.name_op
        if name_op is None:
            return

        if 'name' not in name_op:
            # utxo is name_new
            firstupdate_output = get_queued_firstupdate_from_new(
                self.wallet, txid, vout)
            if firstupdate_output is not None:
                if firstupdate_output.name_op is not None:
                    name_op = firstupdate_output.name_op
            expires_in, expires_datetime = None, None
            status = _('Registration Pending')
        else:
            # utxo is name_anyupdate
            height = x.get('height')
            header_at_tip = self.network.blockchain().header_at_tip()
            #chain_height = self.network.blockchain().height()
            expires_in, expires_datetime = name_expiration_datetime_estimate(
                height, header_at_tip['block_height'],
                header_at_tip['timestamp'])
            status = '' if expires_in is not None else _('Update Pending')

        if 'name' in name_op:
            # utxo is name_anyupdate or a name_new that we've queued a name_firstupdate for
            name = name_op['name']
            formatted_name = format_name_identifier(name)
            value = name_op['value']
            formatted_value = format_name_value(value)
        else:
            # utxo is a name_new that we haven't queued a name_firstupdate for
            name = None
            formatted_name = ''
            value = None
            formatted_value = ''

        formatted_expires_in = (_(
            'Expires in %d blocks\nDate/time is only an estimate; do not rely on it!'
        ) % expires_in) if expires_in is not None else ''
        formatted_expires_datetime = expires_datetime.isoformat(
            ' ') if expires_datetime is not None else ''

        txout = txid + ":%d" % vout

        self.utxo_dict[txout] = x

        labels = [
            formatted_name, formatted_value, formatted_expires_datetime, status
        ]
        utxo_item = [QStandardItem(x) for x in labels]
        self.set_editability(utxo_item)

        utxo_item[self.Columns.NAME].setFont(QFont(MONOSPACE_FONT))
        utxo_item[self.Columns.VALUE].setFont(QFont(MONOSPACE_FONT))

        utxo_item[self.Columns.NAME].setData(txout, Qt.UserRole)
        utxo_item[self.Columns.NAME].setData(name,
                                             Qt.UserRole + USER_ROLE_NAME)
        utxo_item[self.Columns.NAME].setData(value,
                                             Qt.UserRole + USER_ROLE_VALUE)

        utxo_item[self.Columns.EXPIRES_IN].setToolTip(formatted_expires_in)

        address = x.get('address')
        if self.wallet.is_frozen_address(
                address) or self.wallet.is_frozen_coin(x):
            utxo_item[self.Columns.NAME].setBackground(
                ColorScheme.BLUE.as_color(True))
            if self.wallet.is_frozen_address(
                    address) and self.wallet.is_frozen_coin(x):
                utxo_item[self.Columns.NAME].setToolTip(
                    _('Address and coin are frozen'))
            elif self.wallet.is_frozen_address(address):
                utxo_item[self.Columns.NAME].setToolTip(_('Address is frozen'))
            elif self.wallet.is_frozen_coin(x):
                utxo_item[self.Columns.NAME].setToolTip(_('Coin is frozen'))
        self.model().appendRow(utxo_item)