[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