Browse Source

do not include fee in the transaction amount shown in history. adapt history to the case where it was recovered from a pruning server

283
thomasv 12 years ago
parent
commit
650a9b6074
  1. 23
      electrum
  2. 37
      lib/gui.py
  3. 11
      lib/gui_lite.py
  4. 59
      lib/gui_qt.py
  5. 20
      lib/gui_text.py
  6. 6
      lib/history_widget.py
  7. 116
      lib/wallet.py

23
electrum

@ -484,23 +484,20 @@ if __name__ == '__main__':
print flags, m_addr, b, label print flags, m_addr, b, label
if cmd == 'history': if cmd == 'history':
lines = wallet.get_tx_history() import datetime
b = 0 for item in wallet.get_tx_history():
for line in lines: tx_hash, conf, is_mine, value, fee, balance, timestamp = item
import datetime
v = wallet.get_tx_value(line['tx_hash'])
b += v
try: try:
time_str = str( datetime.datetime.fromtimestamp( line['timestamp'])) time_str = datetime.datetime.fromtimestamp( timestamp).isoformat(' ')[:-3]
except: except:
print line['timestamp'] time_str = "----"
time_str = 'pending'
label = line.get('label') label, is_default_label = wallet.get_label(tx_hash)
if not label: label = line['tx_hash'] if not label: label = tx_hash
else: label = label + ' '*(64 - len(label) ) else: label = label + ' '*(64 - len(label) )
print time_str , " " + label + " " + format_satoshis(v)+ " "+ format_satoshis(b) print "%17s"%time_str, " " + label + " " + format_satoshis(value)+ " "+ format_satoshis(balance)
print "# balance: ", format_satoshis(b) print "# balance: ", format_satoshis(balance)
elif cmd == 'label': elif cmd == 'label':
try: try:

37
lib/gui.py

@ -1223,39 +1223,26 @@ class ElectrumWindow:
def update_history_tab(self): def update_history_tab(self):
cursor = self.history_treeview.get_cursor()[0] cursor = self.history_treeview.get_cursor()[0]
self.history_list.clear() self.history_list.clear()
balance = 0
for tx in self.wallet.get_tx_history(): for item in self.wallet.get_tx_history():
tx_hash = tx['tx_hash'] tx_hash, conf, is_mine, value, fee, balance, timestamp = item
conf = self.wallet.verifier.get_confirmations(tx_hash)
if conf: if conf:
time_str = datetime.datetime.fromtimestamp( tx['timestamp']).isoformat(' ')[:-3] try:
time_str = datetime.datetime.fromtimestamp( timestamp).isoformat(' ')[:-3]
except:
time_str = "------"
conf_icon = gtk.STOCK_APPLY conf_icon = gtk.STOCK_APPLY
else: else:
time_str = 'pending' time_str = 'pending'
conf_icon = gtk.STOCK_EXECUTE conf_icon = gtk.STOCK_EXECUTE
v = self.wallet.get_tx_value(tx_hash)
balance += v
label, is_default_label = self.wallet.get_label(tx_hash) label, is_default_label = self.wallet.get_label(tx_hash)
tooltip = tx_hash + "\n%d confirmations"%conf tooltip = tx_hash + "\n%d confirmations"%conf if tx_hash else ''
details = self.wallet.get_tx_details(tx_hash)
inputs = map(lambda x: x.get('address'), tx['inputs'])
outputs = map(lambda x: x.get('address'), tx['outputs'])
details = "Transaction Details:\n\n" \
+ "Transaction ID:\n" + tx_hash + "\n\n" \
+ "Status: %d confirmations\n\n"%conf \
+ "Date: %s\n\n"%time_str \
+ "Inputs:\n-"+ '\n-'.join(inputs) + "\n\n" \
+ "Outputs:\n-"+ '\n-'.join(outputs)
r = self.wallet.receipts.get(tx_hash)
if r:
details += "\n_______________________________________" \
+ '\n\nSigned URI: ' + r[2] \
+ "\n\nSigned by: " + r[0] \
+ '\n\nSignature: ' + r[1]
self.history_list.prepend( [tx_hash, conf_icon, time_str, label, is_default_label, self.history_list.prepend( [tx_hash, conf_icon, time_str, label, is_default_label,
format_satoshis(v,True,self.wallet.num_zeros), format_satoshis(balance,False,self.wallet.num_zeros), tooltip, details] ) format_satoshis(value,True,self.wallet.num_zeros),
format_satoshis(balance,False,self.wallet.num_zeros), tooltip, details] )
if cursor: self.history_treeview.set_cursor( cursor ) if cursor: self.history_treeview.set_cursor( cursor )

11
lib/gui_lite.py

@ -438,12 +438,13 @@ class MiniWindow(QDialog):
self.address_completions.setStringList(completions) self.address_completions.setStringList(completions)
def update_history(self, tx_history): def update_history(self, tx_history):
for tx in tx_history[-10:]: from util import format_satoshis
tx_hash = tx['tx_hash'] for item in tx_history[-10:]:
tx_hash, conf, is_mine, value, fee, balance, timestamp = item
label = self.actuator.wallet.get_label(tx_hash)[0] label = self.actuator.wallet.get_label(tx_hash)[0]
value = self.actuator.wallet.get_tx_value(tx_hash) #amount = D(value) / 10**8
amount = D(value) / 10**8 v_str = format_satoshis(value, True)
self.history_list.append(label, amount) self.history_list.append(label, v_str)
def acceptbit(self): def acceptbit(self):
self.actuator.acceptbit(self.quote_currencies[0]) self.actuator.acceptbit(self.quote_currencies[0])

59
lib/gui_qt.py

@ -323,38 +323,16 @@ class ElectrumWindow(QMainWindow):
item = self.history_list.currentItem() item = self.history_list.currentItem()
if not item: return if not item: return
tx_hash = str(item.toolTip(0)) tx_hash = str(item.toolTip(0))
if not tx_hash: return
menu = QMenu() menu = QMenu()
menu.addAction(_("Copy ID to Clipboard"), lambda: self.app.clipboard().setText(tx_hash)) menu.addAction(_("Copy ID to Clipboard"), lambda: self.app.clipboard().setText(tx_hash))
menu.addAction(_("Details"), lambda: self.tx_details(tx_hash)) menu.addAction(_("Details"), lambda: self.tx_details(tx_hash))
menu.addAction(_("Edit description"), lambda: self.tx_label_clicked(item,2)) menu.addAction(_("Edit description"), lambda: self.tx_label_clicked(item,2))
menu.exec_(self.contacts_list.viewport().mapToGlobal(position)) menu.exec_(self.contacts_list.viewport().mapToGlobal(position))
def tx_details(self, tx_hash):
tx = self.wallet.transactions.get(tx_hash)
conf = self.wallet.verifier.get_confirmations(tx_hash)
timestamp = tx.get('timestamp')
if conf and timestamp:
time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
else:
time_str = 'pending'
inputs = map(lambda x: x.get('address'), tx['inputs'])
outputs = map(lambda x: x.get('address'), tx['outputs'])
tx_details = _("Transaction Details") +"\n\n" \
+ "Transaction ID:\n" + tx_hash + "\n\n" \
+ "Status: %d confirmations\n\n"%conf \
+ "Date: %s\n\n"%time_str \
+ "Inputs:\n-"+ '\n-'.join(inputs) + "\n\n" \
+ "Outputs:\n-"+ '\n-'.join(outputs)
r = self.wallet.receipts.get(tx_hash)
if r:
tx_details += "\n_______________________________________" \
+ '\n\nSigned URI: ' + r[2] \
+ "\n\nSigned by: " + r[0] \
+ '\n\nSignature: ' + r[1]
def tx_details(self, tx_hash):
tx_details = self.wallet.get_tx_details(tx_hash)
QMessageBox.information(self, 'Details', tx_details, 'OK') QMessageBox.information(self, 'Details', tx_details, 'OK')
@ -432,14 +410,13 @@ class ElectrumWindow(QMainWindow):
def update_history_tab(self): def update_history_tab(self):
self.history_list.clear() self.history_list.clear()
balance = 0 for item in self.wallet.get_tx_history():
for tx in self.wallet.get_tx_history(): tx_hash, conf, is_mine, value, fee, balance, timestamp = item
tx_hash = tx['tx_hash']
conf = self.wallet.verifier.get_confirmations(tx_hash)
if conf: if conf:
try: try:
time_str = datetime.datetime.fromtimestamp( tx['timestamp']).isoformat(' ')[:-3] time_str = datetime.datetime.fromtimestamp( timestamp).isoformat(' ')[:-3]
except: except:
time_str = "unknown" time_str = "unknown"
if conf == -1: if conf == -1:
@ -453,20 +430,32 @@ class ElectrumWindow(QMainWindow):
else: else:
time_str = 'pending' time_str = 'pending'
icon = QIcon(":icons/unconfirmed.png") icon = QIcon(":icons/unconfirmed.png")
v = self.wallet.get_tx_value(tx_hash)
balance += v
label, is_default_label = self.wallet.get_label(tx_hash)
item = QTreeWidgetItem( [ '', time_str, label, format_satoshis(v,True,self.wallet.num_zeros), format_satoshis(balance,False,self.wallet.num_zeros)] ) if value is not None:
v_str = format_satoshis(value, True, self.wallet.num_zeros)
else:
v_str = '--'
balance_str = format_satoshis(balance, False, self.wallet.num_zeros)
if tx_hash:
label, is_default_label = self.wallet.get_label(tx_hash)
else:
label = _('Pruned transaction outputs')
is_default_label = False
item = QTreeWidgetItem( [ '', time_str, label, v_str, balance_str] )
item.setFont(2, QFont(MONOSPACE_FONT)) item.setFont(2, QFont(MONOSPACE_FONT))
item.setFont(3, QFont(MONOSPACE_FONT)) item.setFont(3, QFont(MONOSPACE_FONT))
item.setFont(4, QFont(MONOSPACE_FONT)) item.setFont(4, QFont(MONOSPACE_FONT))
item.setToolTip(0, tx_hash) if tx_hash:
item.setToolTip(0, tx_hash)
if is_default_label: if is_default_label:
item.setForeground(2, QBrush(QColor('grey'))) item.setForeground(2, QBrush(QColor('grey')))
item.setIcon(0, icon) item.setIcon(0, icon)
self.history_list.insertTopLevelItem(0,item) self.history_list.insertTopLevelItem(0,item)
self.history_list.setCurrentItem(self.history_list.topLevelItem(0)) self.history_list.setCurrentItem(self.history_list.topLevelItem(0))

20
lib/gui_text.py

@ -66,19 +66,19 @@ class ElectrumGui:
b = 0 b = 0
messages = [] messages = []
for tx in self.wallet.get_tx_history():
v = self.wallet.get_tx_value(tx['tx_hash']) for item in self.wallet.get_tx_history():
b += v tx_hash, conf, is_mine, value, fee, balance, timestamp = item
try: if conf:
time_str = str( datetime.datetime.fromtimestamp( tx['timestamp'])) try:
except: time_str = datetime.datetime.fromtimestamp( timestamp).isoformat(' ')[:-3]
print tx['timestamp'] except:
time_str = "------"
else:
time_str = 'pending' time_str = 'pending'
tx_hash = tx['tx_hash']
label, is_default_label = self.wallet.get_label(tx_hash) label, is_default_label = self.wallet.get_label(tx_hash)
#label += ' '*(40 - len(label) ) messages.append( format_str%( time_str, label, format_satoshis(value), format_satoshis(balance) ) )
messages.append( format_str%( time_str, label, format_satoshis(v), format_satoshis(b) ) )
self.print_list(messages[::-1], format_str%( _("Date"), _("Description"), _("Amount"), _("Balance"))) self.print_list(messages[::-1], format_str%( _("Date"), _("Description"), _("Amount"), _("Balance")))

6
lib/history_widget.py

@ -10,10 +10,6 @@ class HistoryWidget(QTreeWidget):
self.setIndentation(0) self.setIndentation(0)
def append(self, address, amount): def append(self, address, amount):
if amount >= 0: item = QTreeWidgetItem([amount, address])
display_amount = "+%s" % amount
else:
display_amount = "-%s" % (-amount)
item = QTreeWidgetItem([display_amount, address])
self.insertTopLevelItem(0, item) self.insertTopLevelItem(0, item)

116
lib/wallet.py

@ -76,7 +76,7 @@ class Wallet:
self.transactions = config.get('transactions',{}) # txid -> deserialised self.transactions = config.get('transactions',{}) # txid -> deserialised
# not saved # not saved
self.prevout_values = {} self.prevout_values = {} # my own transaction outputs
self.spent_outputs = [] self.spent_outputs = []
self.receipt = None # next receipt self.receipt = None # next receipt
self.banner = '' self.banner = ''
@ -355,7 +355,8 @@ class Wallet:
def fill_addressbook(self): def fill_addressbook(self):
for tx_hash, tx in self.transactions.items(): for tx_hash, tx in self.transactions.items():
if self.get_tx_value(tx_hash)<0: is_send, _, _ = self.get_tx_value(tx_hash)
if is_send:
for o in tx['outputs']: for o in tx['outputs']:
addr = o.get('address') addr = o.get('address')
if not self.is_mine(addr) and addr not in self.addressbook: if not self.is_mine(addr) and addr not in self.addressbook:
@ -374,24 +375,79 @@ class Wallet:
# return the balance for that tx # return the balance for that tx
if addresses is None: addresses = self.all_addresses() if addresses is None: addresses = self.all_addresses()
with self.lock: with self.lock:
v = 0 is_send = False
is_pruned = False
v_in = v_out = v = 0
d = self.transactions.get(tx_hash) d = self.transactions.get(tx_hash)
if not d: return 0 if not d: return 0
for item in d.get('inputs'): for item in d.get('inputs'):
addr = item.get('address') addr = item.get('address')
if addr in addresses: if addr in addresses:
is_send = True
key = item['prevout_hash'] + ':%d'%item['prevout_n'] key = item['prevout_hash'] + ':%d'%item['prevout_n']
value = self.prevout_values.get( key ) value = self.prevout_values.get( key )
if value is None: continue if value is None:
is_pruned = True
break
v -= value v -= value
v_in += value
if is_pruned: v = 0
for item in d.get('outputs'): for item in d.get('outputs'):
addr = item.get('address') addr = item.get('address')
if addr in addresses: value = item.get('value')
value = item.get('value') v_out += value
v += value if not is_pruned:
return v if addr in addresses: v += value
else:
if addr not in addresses: v -= value
# I can compute the fee only if I am the spender and inputs were not pruned
fee = v_in - v_out if is_send and not is_pruned else None
return is_send, v, fee
def get_tx_details(self, tx_hash):
import datetime
if not tx_hash: return ''
tx = self.transactions.get(tx_hash)
is_mine, v, fee = self.get_tx_value(tx_hash)
conf = self.verifier.get_confirmations(tx_hash)
timestamp = tx.get('timestamp')
if conf and timestamp:
time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
else:
time_str = 'pending'
inputs = map(lambda x: x.get('address'), tx['inputs'])
outputs = map(lambda x: x.get('address'), tx['outputs'])
tx_details = "Transaction Details" +"\n\n" \
+ "Transaction ID:\n" + tx_hash + "\n\n" \
+ "Status: %d confirmations\n"%conf
if is_mine:
if fee:
tx_details += "Amount sent: %s\n"% format_satoshis(v+fee, False) \
+ "Transaction fee: %s\n"% format_satoshis(fee, False)
else:
tx_details += "Amount sent: %s\n"% format_satoshis(v, False) \
+ "Transaction fee: unknown\n"
else:
tx_details += "Amount received: %s\n"% format_satoshis(v, False) \
tx_details += "Date: %s\n\n"%time_str \
+ "Inputs:\n-"+ '\n-'.join(inputs) + "\n\n" \
+ "Outputs:\n-"+ '\n-'.join(outputs)
r = self.receipts.get(tx_hash)
if r:
tx_details += "\n_______________________________________" \
+ '\n\nSigned URI: ' + r[2] \
+ "\n\nSigned by: " + r[0] \
+ '\n\nSignature: ' + r[1]
return tx_details
def update_tx_outputs(self, tx_hash): def update_tx_outputs(self, tx_hash):
tx = self.transactions.get(tx_hash) tx = self.transactions.get(tx_hash)
@ -412,8 +468,13 @@ class Wallet:
h = self.history.get(addr,[]) h = self.history.get(addr,[])
if h == ['*']: return 0,0 if h == ['*']: return 0,0
c = u = 0 c = u = 0
for tx_hash, tx_height in h: for tx_hash, tx_height in h:
v = self.get_tx_value(tx_hash, [addr]) # if the tx is mine, then I know its outputs and input values
# if it is not mine, I only need its outputs
is_mine, v, fee = self.get_tx_value(tx_hash, [addr])
if v is None:raise
if tx_height: if tx_height:
c += v c += v
else: else:
@ -455,7 +516,6 @@ class Wallet:
output['tx_hash'] = tx_hash output['tx_hash'] = tx_hash
coins.append(output) coins.append(output)
#coins = sorted( coins, key = lambda x: x[1]['timestamp'] )
for addr in self.prioritized_addresses: for addr in self.prioritized_addresses:
h = self.history.get(addr, []) h = self.history.get(addr, [])
@ -468,7 +528,6 @@ class Wallet:
output['tx_hash'] = tx_hash output['tx_hash'] = tx_hash
prioritized_coins.append(output) prioritized_coins.append(output)
#prioritized_coins = sorted( prioritized_coins, key = lambda x: x[1]['timestamp'] )
inputs = [] inputs = []
coins = prioritized_coins + coins coins = prioritized_coins + coins
@ -584,9 +643,35 @@ class Wallet:
def get_tx_history(self): def get_tx_history(self):
with self.lock: with self.lock:
lines = self.transactions.values() history = self.transactions.values()
lines.sort(key = lambda x: x.get('timestamp') if x.get('timestamp') else 1e12) history.sort(key = lambda x: x.get('timestamp') if x.get('timestamp') else 1e12)
return lines result = []
balance = 0
for tx in history:
is_mine, v, fee = self.get_tx_value(tx['tx_hash'])
if v is not None: balance += v
c, u = self.get_balance()
if balance != c+u:
v_str = format_satoshis( c+u - balance, True, self.num_zeros)
result.append( ('', 1000, 0, c+u-balance, None, c+u-balance, None ) )
balance = c + u - balance
for tx in history:
tx_hash = tx['tx_hash']
timestamp = tx.get('timestamp')
conf = self.verifier.get_confirmations(tx_hash) if self.verifier else None
is_mine, v, fee = self.get_tx_value(tx_hash)
if v is not None:
balance += v
value = v + fee if fee is not None else v
else:
value = None
result.append( (tx_hash, conf, is_mine, value, fee, balance, timestamp) )
return result
def get_transactions_at_height(self, height): def get_transactions_at_height(self, height):
with self.lock: with self.lock:
@ -609,7 +694,8 @@ class Wallet:
tx = self.transactions.get(tx_hash) tx = self.transactions.get(tx_hash)
if tx: if tx:
default_label = '' default_label = ''
if self.get_tx_value(tx_hash)<0: is_mine, _, _ = self.get_tx_value(tx_hash)
if is_mine:
for o in tx['outputs']: for o in tx['outputs']:
o_addr = o.get('address') o_addr = o.get('address')
if not self.is_mine(o_addr): if not self.is_mine(o_addr):

Loading…
Cancel
Save