Fix merge conflict
This commit is contained in:
commit
ca6890a622
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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})
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
@ -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,32 +111,44 @@ 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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue