Fix merge conflict

This commit is contained in:
Maran 2013-03-12 21:27:27 +01:00
commit ca6890a622
6 changed files with 74 additions and 44 deletions

View File

@ -1,14 +1,21 @@
# Release 1.7 # Release 1.7
* The wallet does not create new addresses until transactions have 2 * The Classic GUI can be extended with plugins. Developers who want to
confirmations. This makes recovery from seed more robust. Note that it 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 might create unwanted gaps if you use Electrum 1.7 together with older
versions of Electrum. versions of Electrum.
* An interactive Python console replaces the 'wall' tab. The provided * An interactive Python console replaces the 'Wall' tab. The provided
python environment gives users access to the wallet and gui. Custom python environment gives users access to the wallet and gui. Most
scripts an be loaded with a "run(filename)" command. Tab-completions electrum commands are available as python function in the
are available. 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 * The location of the Electrum folder in Windows changed from
LOCALAPPDATA to APPDATA. Discussion on this topic can be found here: 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). 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). 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. * It is possible to create, sign and redeem multisig transaction using the
This is made possible by the following new commands: command line interface. This is made possible by the following new commands:
dumpprivkey, listunspent, createmultisig, createrawtransaction, decoderawtransaction, signrawtransaction dumpprivkey, listunspent, createmultisig, createrawtransaction, decoderawtransaction, signrawtransaction
The syntax of these commands is similar to their bitcoind counterpart. The syntax of these commands is similar to their bitcoind counterpart.
For an example, see Gavin's tutorial: https://gist.github.com/gavinandresen/3966071 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. * Offline wallets now work in a way similar to Armory:
For this, use 'signrawtransaction'. ('signtx' is deprecated'). 1. user creates an unsigned transaction using the online (watching-only) wallet.
See the help in docs/offline_wallets 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 # Release 1.6.2

View File

@ -326,6 +326,9 @@ class ElectrumWindow(QMainWindow):
# set initial message # set initial message
self.console.showMessage(self.wallet.banner) self.console.showMessage(self.wallet.banner)
# plugins that need to change the GUI do it here
self.run_hook('init')
# plugins # plugins
def init_plugins(self): def init_plugins(self):
@ -358,7 +361,8 @@ class ElectrumWindow(QMainWindow):
if callback in h: h.remove(callback) if callback in h: h.remove(callback)
self.plugin_hooks[name] = h 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,[]): for cb in self.plugin_hooks.get(name,[]):
apply(cb, args) apply(cb, args)
@ -374,8 +378,8 @@ class ElectrumWindow(QMainWindow):
if old_text: if old_text:
self.wallet.labels.pop(name) self.wallet.labels.pop(name)
changed = True changed = True
self.run_hook('set_label', (name, text, changed))
self.run_hook('set_label', (name, text, changed,))
return changed return changed
@ -399,14 +403,14 @@ class ElectrumWindow(QMainWindow):
def close(self): def close(self):
QMainWindow.close(self) QMainWindow.close(self)
self.run_hook('close_main_window', (self,)) self.run_hook('close_main_window')
def connect_slots(self, sender): def connect_slots(self, sender):
self.connect(sender, QtCore.SIGNAL('timersignal'), self.timer_actions) self.connect(sender, QtCore.SIGNAL('timersignal'), self.timer_actions)
self.previous_payto_e='' self.previous_payto_e=''
def timer_actions(self): def timer_actions(self):
self.run_hook('timer_actions', (self,)) self.run_hook('timer_actions')
if self.payto_e.hasFocus(): if self.payto_e.hasFocus():
return return
@ -601,11 +605,11 @@ class ElectrumWindow(QMainWindow):
self.current_item_changed(item) 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): 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.amount_e.textChanged.connect(lambda: entry_changed(False) )
self.fee_e.textChanged.connect(lambda: entry_changed(True) ) 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 return w2
@ -811,7 +815,7 @@ class ElectrumWindow(QMainWindow):
self.show_message(str(e)) self.show_message(str(e))
return return
self.run_hook('send_tx', (self.wallet, self, tx)) self.run_hook('send_tx', (tx,))
if label: if label:
self.set_label(tx.hash(), 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") t = _("Unprioritize") if addr in self.wallet.prioritized_addresses else _("Prioritize")
menu.addAction(t, lambda: self.toggle_priority(addr)) 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)) menu.exec_(self.receive_list.viewport().mapToGlobal(position))
@ -1064,7 +1068,7 @@ class ElectrumWindow(QMainWindow):
label = self.wallet.labels.get(address,'') label = self.wallet.labels.get(address,'')
item.setData(1,0,label) 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) c, u = self.wallet.get_addr_balance(address)
balance = format_satoshis( c + u, False, self.wallet.num_zeros ) balance = format_satoshis( c + u, False, self.wallet.num_zeros )
@ -2041,7 +2045,7 @@ class ElectrumWindow(QMainWindow):
cb.setChecked(p.is_enabled()) cb.setChecked(p.is_enabled())
cb.clicked.connect(mk_toggle(cb,p)) cb.clicked.connect(mk_toggle(cb,p))
grid_plugins.addWidget(cb, i, 0) grid_plugins.addWidget(cb, i, 0)
grid_plugins.addWidget(HelpButton(description), i, 2) grid_plugins.addWidget(HelpButton(description), i, 1)
except: except:
print_msg("Error: cannot display plugin", p) print_msg("Error: cannot display plugin", p)
traceback.print_exc(file=sys.stdout) traceback.print_exc(file=sys.stdout)

View File

@ -1,12 +1,19 @@
# source: http://stackoverflow.com/questions/2758159/how-to-embed-a-python-interpreter-in-a-pyqt-widget # source: http://stackoverflow.com/questions/2758159/how-to-embed-a-python-interpreter-in-a-pyqt-widget
import sys, os, re import sys, os, re
import traceback import traceback, platform
from PyQt4 import QtCore from PyQt4 import QtCore
from PyQt4 import QtGui from PyQt4 import QtGui
from electrum import util 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): class Console(QtGui.QPlainTextEdit):
def __init__(self, prompt='>> ', startup_message='', parent=None): def __init__(self, prompt='>> ', startup_message='', parent=None):
@ -20,7 +27,7 @@ class Console(QtGui.QPlainTextEdit):
self.setGeometry(50, 75, 600, 400) self.setGeometry(50, 75, 600, 400)
self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere) self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere)
self.setUndoRedoEnabled(False) 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.showMessage(startup_message)
self.updateNamespace({'run':self.run_script}) self.updateNamespace({'run':self.run_script})

View File

@ -825,7 +825,7 @@ class Transaction:
for i in self.inputs: for i in self.inputs:
e = { 'txid':i['tx_hash'], 'vout':i['index'], e = { 'txid':i['tx_hash'], 'vout':i['index'],
'scriptPubKey':i.get('raw_output_script'), 'scriptPubKey':i.get('raw_output_script'),
'electrumKeyID':i.get('electrumKeyID'), 'KeyID':i.get('KeyID'),
'redeemScript':i.get('redeemScript'), 'redeemScript':i.get('redeemScript'),
'signatures':i.get('signatures'), 'signatures':i.get('signatures'),
'pubkeys':i.get('pubkeys'), 'pubkeys':i.get('pubkeys'),

View File

@ -256,7 +256,7 @@ class Wallet:
if item.get('txid') == txin['tx_hash'] and item.get('vout') == txin['index']: if item.get('txid') == txin['tx_hash'] and item.get('vout') == txin['index']:
txin['raw_output_script'] = item['scriptPubKey'] txin['raw_output_script'] = item['scriptPubKey']
txin['redeemScript'] = item.get('redeemScript') txin['redeemScript'] = item.get('redeemScript')
txin['electrumKeyID'] = item.get('electrumKeyID') txin['KeyID'] = item.get('KeyID')
break break
else: else:
for item in unspent_coins: for item in unspent_coins:
@ -268,8 +268,9 @@ class Wallet:
raise raise
# find the address: # find the address:
if txin.get('electrumKeyID'): if txin.get('KeyID'):
account, sequence = txin.get('electrumKeyID') account, name, sequence = txin.get('KeyID')
if name != 'Electrum': continue
sec = self.sequences[account].get_private_key(sequence, seed) sec = self.sequences[account].get_private_key(sequence, seed)
addr = self.sequences[account].get_address(sequence) addr = self.sequences[account].get_address(sequence)
txin['address'] = addr txin['address'] = addr
@ -639,7 +640,7 @@ class Wallet:
def receive_tx_callback(self, tx_hash, tx, tx_height): def receive_tx_callback(self, tx_hash, tx, tx_height):
if not self.check_new_tx(tx_hash, tx): 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: with self.lock:
self.transactions[tx_hash] = tx self.transactions[tx_hash] = tx
@ -771,7 +772,7 @@ class Wallet:
pk_addresses.append(address) pk_addresses.append(address)
continue continue
account, sequence = self.get_address_index(address) 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) pk_addr, redeemScript = self.sequences[account].get_input_info(sequence)
if redeemScript: txin['redeemScript'] = redeemScript if redeemScript: txin['redeemScript'] = redeemScript
pk_addresses.append(pk_addr) pk_addresses.append(pk_addr)
@ -1197,9 +1198,6 @@ class WalletSynchronizer(threading.Thread):
while not self.interface.is_connected: while not self.interface.is_connected:
time.sleep(1) time.sleep(1)
# request banner, because 'connected' event happens before this thread is started
self.interface.send([('server.banner',[])],'synchronizer')
# subscriptions # subscriptions
self.subscribe_to_addresses(self.wallet.addresses(True)) self.subscribe_to_addresses(self.wallet.addresses(True))

View File

@ -103,6 +103,7 @@ def init(gui):
gui.requested_amounts = config.get('requested_amounts',{}) gui.requested_amounts = config.get('requested_amounts',{})
gui.merchant_name = config.get('merchant_name', 'Invoice') gui.merchant_name = config.get('merchant_name', 'Invoice')
gui.qr_window = None gui.qr_window = None
do_enable(gui, is_enabled())
def is_enabled(): def is_enabled():
return config.get('pointofsale') is True return config.get('pointofsale') is True
@ -110,35 +111,47 @@ def is_enabled():
def is_available(): def is_available():
return True return True
def toggle(gui):
if not is_enabled(): def toggle(gui):
enabled = not is_enabled()
config.set_key('pointofsale', enabled, True)
do_enable(gui, enabled)
update_gui(gui)
return enabled
def do_enable(gui, enabled):
if enabled:
gui.expert_mode = True gui.expert_mode = True
gui.receive_list.setHeaderLabels([ _('Address'), _('Label'), _('Balance'), _('Request')])
gui.set_hook('item_changed', item_changed) gui.set_hook('item_changed', item_changed)
gui.set_hook('current_item_changed', recv_changed) gui.set_hook('current_item_changed', recv_changed)
gui.set_hook('receive_menu', receive_menu) gui.set_hook('receive_menu', receive_menu)
gui.set_hook('update_receive_item', update_receive_item) gui.set_hook('update_receive_item', update_receive_item)
gui.set_hook('timer_actions', timer_actions) gui.set_hook('timer_actions', timer_actions)
gui.set_hook('close_main_window', close_main_window) gui.set_hook('close_main_window', close_main_window)
enabled = True gui.set_hook('init', update_gui)
else: else:
gui.receive_list.setHeaderLabels([ _('Address'), _('Label'), _('Balance'), _('Tx')])
gui.unset_hook('item_changed', item_changed) gui.unset_hook('item_changed', item_changed)
gui.unset_hook('current_item_changed', recv_changed) gui.unset_hook('current_item_changed', recv_changed)
gui.unset_hook('receive_menu', receive_menu) gui.unset_hook('receive_menu', receive_menu)
gui.unset_hook('update_receive_item', update_receive_item) gui.unset_hook('update_receive_item', update_receive_item)
gui.unset_hook('timer_actions', timer_actions) gui.unset_hook('timer_actions', timer_actions)
gui.unset_hook('close_main_window', close_main_window) 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) toggle_QR_window(gui, enabled)
return enabled
def toggle_QR_window(self, show): def toggle_QR_window(self, show):
if show and not self.qr_window: if show and not self.qr_window:
self.qr_window = QR_Window(self.exchanger) self.qr_window = QR_Window(self.exchanger)