electrum

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

commit ca6890a622b9ee3f368c1bacdd1bce30869e4cbf
parent 9df4451c6f7847203a5b24b152b0912e7c910562
Author: Maran <maran.hidskes@gmail.com>
Date:   Tue, 12 Mar 2013 21:27:27 +0100

Fix merge conflict

Diffstat:
MRELEASE-NOTES | 34+++++++++++++++++++++-------------
Mgui/gui_classic.py | 26+++++++++++++++-----------
Mgui/qt_console.py | 11+++++++++--
Mlib/bitcoin.py | 2+-
Mlib/wallet.py | 14++++++--------
Mplugins/pointofsale.py | 29+++++++++++++++++++++--------
6 files changed, 73 insertions(+), 43 deletions(-)

diff --git a/RELEASE-NOTES b/RELEASE-NOTES @@ -1,14 +1,21 @@ # Release 1.7 -* The wallet does not create new addresses until transactions have 2 -confirmations. This makes recovery from seed more robust. Note that it +* The Classic GUI can be extended with plugins. Developers who want to +add new features or third-party services to Electrum are invited to +write plugins. Some previously existing and non-essential features of +Electrum (point-of-sale mode, qrcode scanner) were removed from the +core and are now available as plugins. + +* The wallet waits for 2 confirmations before creating new +addresses. This makes recovery from seed more robust. Note that it might create unwanted gaps if you use Electrum 1.7 together with older versions of Electrum. -* An interactive Python console replaces the 'wall' tab. The provided -python environment gives users access to the wallet and gui. Custom -scripts an be loaded with a "run(filename)" command. Tab-completions -are available. +* An interactive Python console replaces the 'Wall' tab. The provided +python environment gives users access to the wallet and gui. Most +electrum commands are available as python function in the +console. Custom scripts an be loaded with a "run(filename)" +command. Tab-completions are available. * The location of the Electrum folder in Windows changed from LOCALAPPDATA to APPDATA. Discussion on this topic can be found here: @@ -18,19 +25,20 @@ https://bitcointalk.org/index.php?topic=144575.0 For a single address, use the address menu (right-click). To export the keys of your entire wallet, use the settings dialog (import/export tab). -* It is possible to create, sign and redeem multisig transaction, using the command line interface. -This is made possible by the following new commands: +* It is possible to create, sign and redeem multisig transaction using the +command line interface. This is made possible by the following new commands: dumpprivkey, listunspent, createmultisig, createrawtransaction, decoderawtransaction, signrawtransaction The syntax of these commands is similar to their bitcoind counterpart. For an example, see Gavin's tutorial: https://gist.github.com/gavinandresen/3966071 -* Offline wallets do not need to be resynchronized in order to sign a transaction. - For this, use 'signrawtransaction'. ('signtx' is deprecated'). - See the help in docs/offline_wallets +* Offline wallets now work in a way similar to Armory: + 1. user creates an unsigned transaction using the online (watching-only) wallet. + 2. unsigned transaction is copied to the offline computer, and signed by the offline wallet. + 3. signed transaction is copied to the online computer, broadcasted by the online client. +* Raw transactions can also be loaded/signed/broadcasted via the GUI. - - +* Many command line commands have been renamed in order to make the syntax consistent with bitcoind. # Release 1.6.2 diff --git a/gui/gui_classic.py b/gui/gui_classic.py @@ -326,6 +326,9 @@ class ElectrumWindow(QMainWindow): # set initial message self.console.showMessage(self.wallet.banner) + # plugins that need to change the GUI do it here + self.run_hook('init') + # plugins def init_plugins(self): @@ -358,7 +361,8 @@ class ElectrumWindow(QMainWindow): if callback in h: h.remove(callback) self.plugin_hooks[name] = h - def run_hook(self, name, args): + def run_hook(self, name, args = ()): + args = (self,) + args for cb in self.plugin_hooks.get(name,[]): apply(cb, args) @@ -374,8 +378,8 @@ class ElectrumWindow(QMainWindow): if old_text: self.wallet.labels.pop(name) changed = True + self.run_hook('set_label', (name, text, changed)) - self.run_hook('set_label', (name, text, changed,)) return changed @@ -399,14 +403,14 @@ class ElectrumWindow(QMainWindow): def close(self): QMainWindow.close(self) - self.run_hook('close_main_window', (self,)) + self.run_hook('close_main_window') def connect_slots(self, sender): self.connect(sender, QtCore.SIGNAL('timersignal'), self.timer_actions) self.previous_payto_e='' def timer_actions(self): - self.run_hook('timer_actions', (self,)) + self.run_hook('timer_actions') if self.payto_e.hasFocus(): return @@ -601,11 +605,11 @@ class ElectrumWindow(QMainWindow): self.current_item_changed(item) - self.run_hook('item_changed',(self, item, column)) + self.run_hook('item_changed', (item, column)) def current_item_changed(self, a): - self.run_hook('current_item_changed',(self, a)) + self.run_hook('current_item_changed', (a,)) @@ -751,7 +755,7 @@ class ElectrumWindow(QMainWindow): self.amount_e.textChanged.connect(lambda: entry_changed(False) ) self.fee_e.textChanged.connect(lambda: entry_changed(True) ) - self.run_hook('create_send_tab',(self,grid)) + self.run_hook('create_send_tab', (grid,)) return w2 @@ -811,7 +815,7 @@ class ElectrumWindow(QMainWindow): self.show_message(str(e)) return - self.run_hook('send_tx', (self.wallet, self, tx)) + self.run_hook('send_tx', (tx,)) if label: self.set_label(tx.hash(), label) @@ -1007,7 +1011,7 @@ class ElectrumWindow(QMainWindow): t = _("Unprioritize") if addr in self.wallet.prioritized_addresses else _("Prioritize") menu.addAction(t, lambda: self.toggle_priority(addr)) - self.run_hook('receive_menu', (self, menu,)) + self.run_hook('receive_menu', (menu,)) menu.exec_(self.receive_list.viewport().mapToGlobal(position)) @@ -1064,7 +1068,7 @@ class ElectrumWindow(QMainWindow): label = self.wallet.labels.get(address,'') item.setData(1,0,label) - self.run_hook('update_receive_item', (self, address, item)) + self.run_hook('update_receive_item', (address, item)) c, u = self.wallet.get_addr_balance(address) balance = format_satoshis( c + u, False, self.wallet.num_zeros ) @@ -2041,7 +2045,7 @@ class ElectrumWindow(QMainWindow): cb.setChecked(p.is_enabled()) cb.clicked.connect(mk_toggle(cb,p)) grid_plugins.addWidget(cb, i, 0) - grid_plugins.addWidget(HelpButton(description), i, 2) + grid_plugins.addWidget(HelpButton(description), i, 1) except: print_msg("Error: cannot display plugin", p) traceback.print_exc(file=sys.stdout) diff --git a/gui/qt_console.py b/gui/qt_console.py @@ -1,12 +1,19 @@ # source: http://stackoverflow.com/questions/2758159/how-to-embed-a-python-interpreter-in-a-pyqt-widget import sys, os, re -import traceback +import traceback, platform from PyQt4 import QtCore from PyQt4 import QtGui from electrum import util +if platform.system() == 'Windows': + MONOSPACE_FONT = 'Lucida Console' +elif platform.system() == 'Darwin': + MONOSPACE_FONT = 'Monaco' +else: + MONOSPACE_FONT = 'monospace' + class Console(QtGui.QPlainTextEdit): def __init__(self, prompt='>> ', startup_message='', parent=None): @@ -20,7 +27,7 @@ class Console(QtGui.QPlainTextEdit): self.setGeometry(50, 75, 600, 400) self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere) self.setUndoRedoEnabled(False) - self.document().setDefaultFont(QtGui.QFont("monospace", 10, QtGui.QFont.Normal)) + self.document().setDefaultFont(QtGui.QFont(MONOSPACE_FONT, 10, QtGui.QFont.Normal)) self.showMessage(startup_message) self.updateNamespace({'run':self.run_script}) diff --git a/lib/bitcoin.py b/lib/bitcoin.py @@ -825,7 +825,7 @@ class Transaction: for i in self.inputs: e = { 'txid':i['tx_hash'], 'vout':i['index'], 'scriptPubKey':i.get('raw_output_script'), - 'electrumKeyID':i.get('electrumKeyID'), + 'KeyID':i.get('KeyID'), 'redeemScript':i.get('redeemScript'), 'signatures':i.get('signatures'), 'pubkeys':i.get('pubkeys'), diff --git a/lib/wallet.py b/lib/wallet.py @@ -256,7 +256,7 @@ class Wallet: if item.get('txid') == txin['tx_hash'] and item.get('vout') == txin['index']: txin['raw_output_script'] = item['scriptPubKey'] txin['redeemScript'] = item.get('redeemScript') - txin['electrumKeyID'] = item.get('electrumKeyID') + txin['KeyID'] = item.get('KeyID') break else: for item in unspent_coins: @@ -268,8 +268,9 @@ class Wallet: raise # find the address: - if txin.get('electrumKeyID'): - account, sequence = txin.get('electrumKeyID') + if txin.get('KeyID'): + account, name, sequence = txin.get('KeyID') + if name != 'Electrum': continue sec = self.sequences[account].get_private_key(sequence, seed) addr = self.sequences[account].get_address(sequence) txin['address'] = addr @@ -639,7 +640,7 @@ class Wallet: def receive_tx_callback(self, tx_hash, tx, tx_height): if not self.check_new_tx(tx_hash, tx): - raise BaseException("error: received transaction is not consistent with history"%tx_hash) + raise BaseException("error: received transaction is not consistent with history", tx_hash) with self.lock: self.transactions[tx_hash] = tx @@ -771,7 +772,7 @@ class Wallet: pk_addresses.append(address) continue account, sequence = self.get_address_index(address) - txin['electrumKeyID'] = (account, sequence) # used by the server to find the key + txin['KeyID'] = (account, 'Electrum', sequence) # used by the server to find the key pk_addr, redeemScript = self.sequences[account].get_input_info(sequence) if redeemScript: txin['redeemScript'] = redeemScript pk_addresses.append(pk_addr) @@ -1197,9 +1198,6 @@ class WalletSynchronizer(threading.Thread): while not self.interface.is_connected: time.sleep(1) - # request banner, because 'connected' event happens before this thread is started - self.interface.send([('server.banner',[])],'synchronizer') - # subscriptions self.subscribe_to_addresses(self.wallet.addresses(True)) diff --git a/plugins/pointofsale.py b/plugins/pointofsale.py @@ -103,6 +103,7 @@ def init(gui): gui.requested_amounts = config.get('requested_amounts',{}) gui.merchant_name = config.get('merchant_name', 'Invoice') gui.qr_window = None + do_enable(gui, is_enabled()) def is_enabled(): return config.get('pointofsale') is True @@ -110,35 +111,47 @@ def is_enabled(): def is_available(): return True + def toggle(gui): + enabled = not is_enabled() + config.set_key('pointofsale', enabled, True) + do_enable(gui, enabled) + update_gui(gui) + return enabled + - if not is_enabled(): +def do_enable(gui, enabled): + if enabled: gui.expert_mode = True - gui.receive_list.setHeaderLabels([ _('Address'), _('Label'), _('Balance'), _('Request')]) gui.set_hook('item_changed', item_changed) gui.set_hook('current_item_changed', recv_changed) gui.set_hook('receive_menu', receive_menu) gui.set_hook('update_receive_item', update_receive_item) gui.set_hook('timer_actions', timer_actions) gui.set_hook('close_main_window', close_main_window) - enabled = True + gui.set_hook('init', update_gui) else: - gui.receive_list.setHeaderLabels([ _('Address'), _('Label'), _('Balance'), _('Tx')]) gui.unset_hook('item_changed', item_changed) gui.unset_hook('current_item_changed', recv_changed) gui.unset_hook('receive_menu', receive_menu) gui.unset_hook('update_receive_item', update_receive_item) gui.unset_hook('timer_actions', timer_actions) gui.unset_hook('close_main_window', close_main_window) - enabled = False + gui.unset_hook('init', update_gui) + + + +def update_gui(gui): + enabled = is_enabled() + if enabled: + gui.receive_list.setHeaderLabels([ _('Address'), _('Label'), _('Balance'), _('Request')]) + else: + gui.receive_list.setHeaderLabels([ _('Address'), _('Label'), _('Balance'), _('Tx')]) - config.set_key('pointofsale', enabled, True) toggle_QR_window(gui, enabled) - return enabled - def toggle_QR_window(self, show): if show and not self.qr_window: self.qr_window = QR_Window(self.exchanger)