[Pkg-bitcoin-commits] [electrum] 03/06: New upstream version 2.9.3
Tristan Seligmann
mithrandi at moszumanska.debian.org
Sun Oct 22 12:07:20 UTC 2017
This is an automated email from the git hooks/post-receive script.
mithrandi pushed a commit to branch master
in repository electrum.
commit 0162cee546ca17262478450b13284d0dbbca6b97
Author: Tristan Seligmann <mithrandi at debian.org>
Date: Sun Oct 22 13:52:45 2017 +0200
New upstream version 2.9.3
---
Electrum.egg-info/PKG-INFO | 2 +-
PKG-INFO | 2 +-
RELEASE-NOTES | 14 ++++++++++++++
gui/kivy/main_window.py | 6 +++---
gui/kivy/uix/dialogs/installwizard.py | 2 +-
gui/qt/history_list.py | 10 ++++++++++
gui/qt/icons_rc.py | 2 +-
gui/qt/installwizard.py | 2 +-
gui/qt/main_window.py | 4 ++--
gui/qt/util.py | 2 +-
icons/electrum.ico | Bin 17790 -> 51631 bytes
lib/base_wizard.py | 4 ++--
lib/blockchain.py | 4 +++-
lib/commands.py | 27 +++++++++++++++++++--------
lib/contacts.py | 14 +++++++++++++-
lib/network.py | 9 ++++++---
lib/simple_config.py | 9 +++++++--
lib/transaction.py | 3 ++-
lib/util.py | 2 ++
lib/version.py | 2 +-
lib/wallet.py | 2 +-
plugins/ledger/ledger.py | 2 +-
plugins/trezor/plugin.py | 2 +-
23 files changed, 93 insertions(+), 33 deletions(-)
diff --git a/Electrum.egg-info/PKG-INFO b/Electrum.egg-info/PKG-INFO
index af00a00..3fd27dc 100644
--- a/Electrum.egg-info/PKG-INFO
+++ b/Electrum.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: Electrum
-Version: 2.9.0
+Version: 2.9.3
Summary: Lightweight Bitcoin Wallet
Home-page: https://electrum.org
Author: Thomas Voegtlin
diff --git a/PKG-INFO b/PKG-INFO
index af00a00..3fd27dc 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: Electrum
-Version: 2.9.0
+Version: 2.9.3
Summary: Lightweight Bitcoin Wallet
Home-page: https://electrum.org
Author: Thomas Voegtlin
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 19cac26..fc9ae98 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -1,3 +1,17 @@
+# Release 2.9.3
+ * fix configuration file issue #2719
+ * fix ledger signing of non-RBF transactions
+ * disable 'spend confirmed only' option by default
+
+# Release 2.9.2
+ * force headers download if headers file is corrupted
+ * add websocket to windows builds
+
+# Release 2.9.1
+ * fix initial headers download
+ * validate contacts on import
+ * command-line option for locktime
+
# Release 2.9 - Independence (July 27th, 2017)
* Multiple Chain Validation: Electrum will download and validate
block headers sent by servers that may follow different branches
diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py
index d66ae88..1956d73 100644
--- a/gui/kivy/main_window.py
+++ b/gui/kivy/main_window.py
@@ -262,7 +262,7 @@ class ElectrumWindow(App):
self.use_rbf = config.get('use_rbf', False)
self.use_change = config.get('use_change', True)
- self.use_unconfirmed = not config.get('confirmed_only', True)
+ self.use_unconfirmed = not config.get('confirmed_only', False)
# create triggers so as to minimize updation a max of 2 times a sec
self._trigger_update_wallet = Clock.create_trigger(self.update_wallet, .5)
@@ -841,7 +841,7 @@ class ElectrumWindow(App):
if self.wallet.has_password():
self.password_dialog(msg, f, args)
else:
- apply(f, args + (None,))
+ f(*(args + (None,)))
def delete_wallet(self):
from uix.dialogs.question import Question
@@ -918,7 +918,7 @@ class ElectrumWindow(App):
def password_dialog(self, msg, f, args):
def callback(pw):
- Clock.schedule_once(lambda x: apply(f, args + (pw,)), 0.1)
+ Clock.schedule_once(lambda _: f(*(args + (pw,))), 0.1)
if self._password_dialog is None:
from uix.dialogs.password_dialog import PasswordDialog
self._password_dialog = PasswordDialog()
diff --git a/gui/kivy/uix/dialogs/installwizard.py b/gui/kivy/uix/dialogs/installwizard.py
index aef768a..f869350 100644
--- a/gui/kivy/uix/dialogs/installwizard.py
+++ b/gui/kivy/uix/dialogs/installwizard.py
@@ -767,7 +767,7 @@ class InstallWizard(BaseWizard, Widget):
WizardChoiceDialog(self, **kwargs).open()
else:
f = kwargs['run_next']
- apply(f, (choices[0][0],))
+ f(choices[0][0])
def multisig_dialog(self, **kwargs): WizardMultisigDialog(self, **kwargs).open()
def show_seed_dialog(self, **kwargs): ShowSeedDialog(self, **kwargs).open()
diff --git a/gui/qt/history_list.py b/gui/qt/history_list.py
index f36cea9..da04369 100644
--- a/gui/qt/history_list.py
+++ b/gui/qt/history_list.py
@@ -92,6 +92,7 @@ class HistoryList(MyTreeWidget):
entry.append(text)
item = QTreeWidgetItem(entry)
item.setIcon(0, icon)
+ item.setToolTip(0, str(conf) + " confirmation" + ("s" if conf != 1 else ""))
if has_invoice:
item.setIcon(3, QIcon(":icons/seal"))
for i in range(len(entry)):
@@ -99,6 +100,7 @@ class HistoryList(MyTreeWidget):
item.setTextAlignment(i, Qt.AlignRight)
if i!=2:
item.setFont(i, QFont(MONOSPACE_FONT))
+ item.setTextAlignment(i, Qt.AlignVCenter)
if value < 0:
item.setForeground(3, QBrush(QColor("#BC1E1E")))
item.setForeground(4, QBrush(QColor("#BC1E1E")))
@@ -108,6 +110,14 @@ class HistoryList(MyTreeWidget):
if current_tx == tx_hash:
self.setCurrentItem(item)
+ def on_doubleclick(self, item, column):
+ if self.permit_edit(item, column):
+ super(HistoryList, self).on_doubleclick(item, column)
+ else:
+ tx_hash = str(item.data(0, Qt.UserRole).toString())
+ tx = self.wallet.transactions.get(tx_hash)
+ self.parent.show_transaction(tx)
+
def update_labels(self):
root = self.invisibleRootItem()
child_count = root.childCount()
diff --git a/gui/qt/icons_rc.py b/gui/qt/icons_rc.py
index 8be40eb..c3cc38e 100644
--- a/gui/qt/icons_rc.py
+++ b/gui/qt/icons_rc.py
@@ -2,7 +2,7 @@
# Resource object code
#
-# Created: jeu. juil. 27 13:43:17 2017
+# Created: jeu. août 10 18:24:52 2017
# by: The Resource Compiler for PyQt (Qt v4.8.6)
#
# WARNING! All changes made in this file will be lost!
diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py
index e8902d6..885d1ac 100644
--- a/gui/qt/installwizard.py
+++ b/gui/qt/installwizard.py
@@ -87,7 +87,7 @@ def wizard_dialog(func):
# out = ()
if type(out) is not tuple:
out = (out,)
- apply(run_next, out)
+ run_next(*out)
return func_wrapper
diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
index f2c1b13..0d4ee15 100644
--- a/gui/qt/main_window.py
+++ b/gui/qt/main_window.py
@@ -1708,7 +1708,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
c = commands.Commands(self.config, self.wallet, self.network, lambda: self.console.set_json(True))
methods = {}
def mkfunc(f, method):
- return lambda *args: apply( f, (method, args, self.password_dialog ))
+ return lambda *args: f(method, args, self.password_dialog)
for m in dir(c):
if m[0]=='_' or m in ['network','wallet']: continue
methods[m] = mkfunc(c._run, m)
@@ -2619,7 +2619,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def on_unconf(x):
self.config.set_key('confirmed_only', bool(x))
- conf_only = self.config.get('confirmed_only', True)
+ conf_only = self.config.get('confirmed_only', False)
unconf_cb = QCheckBox(_('Spend only confirmed coins'))
unconf_cb.setToolTip(_('Spend only confirmed inputs.'))
unconf_cb.setChecked(conf_only)
diff --git a/gui/qt/util.py b/gui/qt/util.py
index ff070dc..1a2b8f4 100644
--- a/gui/qt/util.py
+++ b/gui/qt/util.py
@@ -69,7 +69,7 @@ class EnterButton(QPushButton):
def keyPressEvent(self, e):
if e.key() == Qt.Key_Return:
- apply(self.func,())
+ self.func()
class ThreadedButton(QPushButton):
diff --git a/icons/electrum.ico b/icons/electrum.ico
index 3b4d53a..618bc99 100644
Binary files a/icons/electrum.ico and b/icons/electrum.ico differ
diff --git a/lib/base_wizard.py b/lib/base_wizard.py
index d9513c9..aaa984a 100644
--- a/lib/base_wizard.py
+++ b/lib/base_wizard.py
@@ -54,10 +54,10 @@ class BaseWizard(object):
self.plugin, action = action
if self.plugin and hasattr(self.plugin, action):
f = getattr(self.plugin, action)
- apply(f, (self,) + args)
+ f(self, *args)
elif hasattr(self, action):
f = getattr(self, action)
- apply(f, args)
+ f(*args)
else:
raise BaseException("unknown action", action)
diff --git a/lib/blockchain.py b/lib/blockchain.py
index 2cd7412..ba9d7d2 100644
--- a/lib/blockchain.py
+++ b/lib/blockchain.py
@@ -242,6 +242,8 @@ class Blockchain(util.PrintError):
def read_header(self, height):
assert self.parent_id != self.checkpoint
+ if height < 0:
+ return
if height < self.checkpoint:
return self.parent().read_header(height)
if height > self.height():
@@ -256,7 +258,7 @@ class Blockchain(util.PrintError):
return deserialize_header(h, height)
def get_hash(self, height):
- return bitcoin.GENESIS if height == 0 else hash_header(self.read_header(height))
+ return hash_header(self.read_header(height))
def BIP9(self, height, flag):
v = self.read_header(height)['version']
diff --git a/lib/commands.py b/lib/commands.py
index e055276..642ccae 100644
--- a/lib/commands.py
+++ b/lib/commands.py
@@ -97,13 +97,20 @@ class Commands:
# this wrapper is called from the python console
cmd = known_commands[method]
if cmd.requires_password and self.wallet.has_password():
- password = apply(password_getter, ())
+ password = password_getter()
if password is None:
return
+ else:
+ password = None
+
f = getattr(self, method)
- result = f(*args, **{'password':password})
+ if cmd.requires_password:
+ result = f(*args, **{'password':password})
+ else:
+ result = f(*args)
+
if self._callback:
- apply(self._callback, ())
+ self._callback()
return result
@command('')
@@ -401,7 +408,7 @@ class Commands:
sig = base64.b64decode(signature)
return bitcoin.verify_message(address, sig, message)
- def _mktx(self, outputs, fee, change_addr, domain, nocheck, unsigned, rbf, password):
+ def _mktx(self, outputs, fee, change_addr, domain, nocheck, unsigned, rbf, password, locktime=None):
self.nocheck = nocheck
change_addr = self._resolver(change_addr)
domain = None if domain is None else map(self._resolver, domain)
@@ -413,6 +420,8 @@ class Commands:
coins = self.wallet.get_spendable_coins(domain, self.config)
tx = self.wallet.make_unsigned_transaction(coins, final_outputs, self.config, fee, change_addr)
+ if locktime != None:
+ tx.locktime = locktime
if rbf:
tx.set_rbf(True)
if not unsigned:
@@ -420,19 +429,19 @@ class Commands:
return tx
@command('wp')
- def payto(self, destination, amount, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, rbf=False, password=None):
+ def payto(self, destination, amount, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, rbf=False, password=None, locktime=None):
"""Create a transaction. """
tx_fee = satoshis(tx_fee)
domain = [from_addr] if from_addr else None
- tx = self._mktx([(destination, amount)], tx_fee, change_addr, domain, nocheck, unsigned, rbf, password)
+ tx = self._mktx([(destination, amount)], tx_fee, change_addr, domain, nocheck, unsigned, rbf, password, locktime)
return tx.as_dict()
@command('wp')
- def paytomany(self, outputs, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, rbf=False, password=None):
+ def paytomany(self, outputs, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, rbf=False, password=None, locktime=None):
"""Create a multi-output transaction. """
tx_fee = satoshis(tx_fee)
domain = [from_addr] if from_addr else None
- tx = self._mktx(outputs, tx_fee, change_addr, domain, nocheck, unsigned, rbf, password)
+ tx = self._mktx(outputs, tx_fee, change_addr, domain, nocheck, unsigned, rbf, password, locktime)
return tx.as_dict()
@command('w')
@@ -703,6 +712,7 @@ command_options = {
'privkey': (None, "--privkey", "Private key. Set to '?' to get a prompt."),
'unsigned': ("-u", "--unsigned", "Do not sign transaction"),
'rbf': (None, "--rbf", "Replace-by-fee transaction"),
+ 'locktime': (None, "--locktime", "Set locktime block number"),
'domain': ("-D", "--domain", "List of addresses"),
'memo': ("-m", "--memo", "Description of the request"),
'expiration': (None, "--expiration", "Time in seconds"),
@@ -729,6 +739,7 @@ arg_types = {
'outputs': json_loads,
'tx_fee': lambda x: str(Decimal(x)) if x is not None else None,
'amount': lambda x: str(Decimal(x)) if x != '!' else '!',
+ 'locktime': int,
}
config_variables = {
diff --git a/lib/contacts.py b/lib/contacts.py
index 90b4d9a..a7cd972 100644
--- a/lib/contacts.py
+++ b/lib/contacts.py
@@ -55,7 +55,7 @@ class Contacts(dict):
def import_file(self, path):
try:
with open(path, 'r') as f:
- d = json.loads(f.read())
+ d = self._validate(json.loads(f.read()))
except:
return
self.update(d)
@@ -116,4 +116,16 @@ class Contacts(dict):
return regex.search(haystack).groups()[0]
except AttributeError:
return None
+
+ def _validate(self, data):
+ for k,v in data.items():
+ if k == 'contacts':
+ return self._validate(v)
+ if not bitcoin.is_address(k):
+ data.pop(k)
+ else:
+ _type,_ = v
+ if _type != 'address':
+ data.pop(k)
+ return data
diff --git a/lib/network.py b/lib/network.py
index d3835af..676ba64 100644
--- a/lib/network.py
+++ b/lib/network.py
@@ -774,6 +774,7 @@ class Network(util.DaemonThread):
connect = interface.blockchain.connect_chunk(index, result)
# If not finished, get the next chunk
if not connect:
+ self.connection_down(interface.server)
return
if interface.blockchain.height() < interface.tip:
self.request_chunk(interface, index+1)
@@ -946,10 +947,11 @@ class Network(util.DaemonThread):
self.process_responses(interface)
def init_headers_file(self):
- filename = self.blockchains[0].path()
- if os.path.exists(filename):
+ b = self.blockchains[0]
+ if b.get_hash(0) == bitcoin.GENESIS:
self.downloading_headers = False
return
+ filename = b.path()
def download_thread():
try:
import urllib, socket
@@ -961,6 +963,8 @@ class Network(util.DaemonThread):
except Exception:
self.print_error("download failed. creating file", filename)
open(filename, 'wb+').close()
+ b = self.blockchains[0]
+ with b.lock: b.update_size()
self.downloading_headers = False
self.downloading_headers = True
t = threading.Thread(target = download_thread)
@@ -1019,7 +1023,6 @@ class Network(util.DaemonThread):
def blockchain(self):
if self.interface and self.interface.blockchain is not None:
self.blockchain_index = self.interface.blockchain.checkpoint
- self.config.set_key('blockchain_index', self.blockchain_index)
return self.blockchains[self.blockchain_index]
def get_blockchains(self):
diff --git a/lib/simple_config.py b/lib/simple_config.py
index 748702a..c163288 100644
--- a/lib/simple_config.py
+++ b/lib/simple_config.py
@@ -117,6 +117,8 @@ class SimpleConfig(PrintError):
return
with self.lock:
+ if key in self.user_config and self.user_config[key] == value:
+ return
self.user_config[key] = value
if save:
self.save_user_config()
@@ -199,7 +201,10 @@ class SimpleConfig(PrintError):
self.set_key('gui_last_wallet', path)
def max_fee_rate(self):
- return self.get('max_fee_rate', MAX_FEE_RATE)
+ f = self.get('max_fee_rate', MAX_FEE_RATE)
+ if f==0:
+ f = MAX_FEE_RATE
+ return f
def dynfee(self, i):
if i < 4:
@@ -276,7 +281,7 @@ def read_user_config(path):
data = f.read()
result = json.loads(data)
except:
- print_msg("Warning: Cannot read config file.", config_path)
+ print_error("Warning: Cannot read config file.", config_path)
return {}
if not type(result) is dict:
return {}
diff --git a/lib/transaction.py b/lib/transaction.py
index dcb1104..5317f71 100644
--- a/lib/transaction.py
+++ b/lib/transaction.py
@@ -720,7 +720,8 @@ class Transaction:
hashSequence = Hash(''.join(int_to_hex(txin.get('sequence', 0xffffffff - 1), 4) for txin in inputs).decode('hex')).encode('hex')
hashOutputs = Hash(''.join(self.serialize_output(o) for o in outputs).decode('hex')).encode('hex')
outpoint = self.serialize_outpoint(txin)
- scriptCode = push_script(self.get_preimage_script(txin))
+ preimage_script = self.get_preimage_script(txin)
+ scriptCode = var_int(len(preimage_script)/2) + preimage_script
amount = int_to_hex(txin['value'], 8)
nSequence = int_to_hex(txin.get('sequence', 0xffffffff - 1), 4)
preimage = nVersion + hashPrevouts + hashSequence + outpoint + scriptCode + amount + nSequence + hashOutputs + nLocktime + nHashType
diff --git a/lib/util.py b/lib/util.py
index cfc8436..0bbaf29 100644
--- a/lib/util.py
+++ b/lib/util.py
@@ -366,6 +366,8 @@ mainnet_block_explorers = {
{'tx': 'tx', 'addr': 'address'}),
'BlockCypher.com': ('https://live.blockcypher.com/btc',
{'tx': 'tx', 'addr': 'address'}),
+ 'Blockchair.com': ('https://blockchair.com/bitcoin',
+ {'tx': 'transaction', 'addr': 'address'}),
'system default': ('blockchain:',
{'tx': 'tx', 'addr': 'address'}),
}
diff --git a/lib/version.py b/lib/version.py
index 8943296..8031dfd 100644
--- a/lib/version.py
+++ b/lib/version.py
@@ -1,4 +1,4 @@
-ELECTRUM_VERSION = '2.9.0' # version of the client package
+ELECTRUM_VERSION = '2.9.3' # version of the client package
PROTOCOL_VERSION = '0.10' # protocol version requested
# The hash of the mnemonic seed must begin with this
diff --git a/lib/wallet.py b/lib/wallet.py
index ba510ce..82d944e 100644
--- a/lib/wallet.py
+++ b/lib/wallet.py
@@ -536,7 +536,7 @@ class Abstract_Wallet(PrintError):
return c, u, x
def get_spendable_coins(self, domain, config):
- confirmed_only = config.get('confirmed_only', True)
+ confirmed_only = config.get('confirmed_only', False)
return self.get_utxos(domain, exclude_frozen=True, mature=True, confirmed_only=confirmed_only)
def get_utxos(self, domain = None, exclude_frozen = False, mature = False, confirmed_only = False):
diff --git a/plugins/ledger/ledger.py b/plugins/ledger/ledger.py
index dd32109..556ba71 100644
--- a/plugins/ledger/ledger.py
+++ b/plugins/ledger/ledger.py
@@ -299,7 +299,7 @@ class Ledger_KeyStore(Hardware_KeyStore):
self.give_error("No matching x_key for sign_transaction") # should never happen
redeemScript = Transaction.get_preimage_script(txin)
- inputs.append([txin['prev_tx'].raw, txin['prevout_n'], redeemScript, txin['prevout_hash'], signingPos, txin.get('sequence', 0xffffffff) ])
+ inputs.append([txin['prev_tx'].raw, txin['prevout_n'], redeemScript, txin['prevout_hash'], signingPos, txin.get('sequence', 0xffffffff - 1) ])
inputsPaths.append(hwAddress)
pubKeys.append(pubkeys)
diff --git a/plugins/trezor/plugin.py b/plugins/trezor/plugin.py
index ac9eb40..edfe318 100644
--- a/plugins/trezor/plugin.py
+++ b/plugins/trezor/plugin.py
@@ -281,7 +281,7 @@ class TrezorCompatiblePlugin(HW_PluginBase):
pubkeys = map(f, x_pubkeys)
multisig = self.types.MultisigRedeemScriptType(
pubkeys=pubkeys,
- signatures=map(lambda x: x.decode('hex') if x else '', txin.get('signatures')),
+ signatures=map(lambda x: x.decode('hex')[:-1] if x else '', txin.get('signatures')),
m=txin.get('num_sig'),
)
txinputtype = self.types.TxInputType(
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-bitcoin/electrum.git
More information about the Pkg-bitcoin-commits
mailing list