Skip to content

Commit

Permalink
Namecoin: Add Renew button to Qt Manage Names tab
Browse files Browse the repository at this point in the history
  • Loading branch information
JeremyRand committed Oct 6, 2018
1 parent 9b2c77f commit ddc903a
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 16 deletions.
11 changes: 8 additions & 3 deletions electrum_nmc/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class NameAlreadyExistsError(Exception):
class NamePreRegistrationPendingError(Exception):
pass

class NameUpdatedTooRecentlyError(Exception):
pass

def satoshis(amount):
# satoshi conversion must not be performed by the parser
return int(COIN*Decimal(amount)) if amount not in ['!', None] else amount
Expand Down Expand Up @@ -576,9 +579,11 @@ def name_update(self, identifier, value=None, destination=None, amount=0.0, fee=
# This check is in place to prevent an attack where an ElectrumX
# server supplies an unconfirmed name_update transaction with a
# malicious value and then tricks the wallet owner into signing a
# name renewal with that malicious value.
if list_results["expires_in"] > 36000 - 12:
raise Exception("Name was updated too recently to safely determine current value. Either wait or specify an explicit value.")
# name renewal with that malicious value. expires_in is None when
# the transaction has 0 confirmations.
expires_in = list_results["expires_in"]
if expires_in is None or expires_in > 36000 - 12:
raise NameUpdatedTooRecentlyError("Name was updated too recently to safely determine current value. Either wait or specify an explicit value.")

value = list_results["value"]

Expand Down
13 changes: 10 additions & 3 deletions electrum_nmc/gui/qt/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -3267,15 +3267,22 @@ def create_names_tab(self):

# Components of names_actions_hbox
self.names_configure_button = QPushButton(_('Configure Name...'))
self.names_configure_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.names_configure_button.setMinimumSize(150, 0)
self.names_configure_button.setToolTip(_('Change the value of the selected name or transfer ownership'))
self.names_renew_button = QPushButton(_('Renew Name'))
self.names_renew_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.names_renew_button.setMinimumSize(150, 0)
self.names_renew_button.setToolTip(_('Renew the selected name with its current value (nothing will happen if the name was updated in the last 12 blocks)'))
self.names_renew_button.clicked.connect(l.renew_selected_items)

self.names_actions_hbox.addWidget(self.names_configure_button)
# TODO: enable name configure button
#self.names_actions_hbox.addWidget(self.names_configure_button)
self.names_actions_hbox.addWidget(self.names_renew_button)

self.names_actions = QWidget()
self.names_actions.setLayout(self.names_actions_hbox)
# TODO: enable name actions
#vbox.addWidget(self.names_actions)
vbox.addWidget(self.names_actions)

w = QWidget()
w.setLayout(vbox)
Expand Down
67 changes: 57 additions & 10 deletions electrum_nmc/gui/qt/uno_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,17 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

from electrum_nmc.commands import NameUpdatedTooRecentlyError
from electrum_nmc.i18n import _
from electrum_nmc.names import format_name_identifier, format_name_value, name_expires_in

from .util import *
from .utxo_list import UTXOList

USER_ROLE_TXOUT = 0
USER_ROLE_NAME = 1
USER_ROLE_VALUE = 2

# TODO: It'd be nice if we could further reduce code duplication against
# UTXOList.
class UNOList(UTXOList):
Expand All @@ -55,24 +60,30 @@ def on_update(self):

# TODO: Support name_new
if 'name' in name_op:
name = format_name_identifier(name_op['name'])
value = format_name_value(name_op['value'])
name = name_op['name']
formatted_name = format_name_identifier(name)
value = name_op['value']
formatted_value = format_name_value(value)
else:
name = ''
value = ''
name = None
formatted_name = ''
value = None
formatted_value = ''

height = x.get('height')
chain_height = self.network.blockchain().height()
expires_in = name_expires_in(height, chain_height)
formatted_expires_in = '%d'%expires_in if expires_in is not None else ''

status = '' if expires_in is not None else 'Update Pending'
status = '' if expires_in is not None else _('Update Pending')

utxo_item = SortableTreeWidgetItem([name, value, formatted_expires_in, status])
utxo_item = SortableTreeWidgetItem([formatted_name, formatted_value, formatted_expires_in, status])
utxo_item.setFont(0, QFont(MONOSPACE_FONT))
utxo_item.setFont(1, QFont(MONOSPACE_FONT))

utxo_item.setData(0, Qt.UserRole, self.get_name(x))
utxo_item.setData(1, Qt.UserRole, name)
utxo_item.setData(0, Qt.UserRole + USER_ROLE_NAME, name)
utxo_item.setData(0, Qt.UserRole + USER_ROLE_VALUE, value)

address = x.get('address')
if self.wallet.is_frozen(address):
Expand All @@ -84,10 +95,8 @@ def create_menu(self, position):
if not selected:
return
menu = QMenu()
coins = filter(lambda x: self.get_name(x) in selected, self.utxos)

# TODO: implement Renew
#menu.addAction(_("Renew"), lambda: self.parent.spend_coins(coins))
menu.addAction(_("Renew"), lambda: self.renew_selected_items())
if len(selected) == 1:
txid = selected[0].split(':')[0]
tx = self.wallet.transactions.get(txid)
Expand All @@ -98,3 +107,41 @@ def create_menu(self, position):

menu.exec_(self.viewport().mapToGlobal(position))

# TODO: We should be able to pass a password to this function, which would
# be used for all name_update calls. That way, we wouldn't need to prompt
# the user per name.
def renew_selected_items(self):
selected = [x.data(0, Qt.UserRole + USER_ROLE_NAME) for x in self.selectedItems()]
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 identifier in selected:
try:
# TODO: support non-ASCII encodings
tx = name_update(identifier.decode('ascii'))['hex']
except NameUpdatedTooRecentlyError:
# The name was recently updated, so skip it and don't renew.
continue

status, msg = broadcast(tx)
if not status:
formatted_name = format_name_identifier(identifier)
self.parent.show_error(_("Error broadcasting renewal for ") + formatted_name + ": " + str(msg))
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

0 comments on commit ddc903a

Please sign in to comment.