[Pkg-bitcoin-commits] [electrum] 02/05: Imported Upstream version 2.5.2

Tristan Seligmann mithrandi at moszumanska.debian.org
Fri Oct 30 06:54:58 UTC 2015


This is an automated email from the git hooks/post-receive script.

mithrandi pushed a commit to branch master
in repository electrum.

commit 95debb3129ce43783eef81eb554b2f3155e14aac
Author: Tristan Seligmann <mithrandi at debian.org>
Date:   Thu Oct 29 02:23:54 2015 +0200

    Imported Upstream version 2.5.2
---
 Electrum.egg-info/PKG-INFO    |  2 +-
 PKG-INFO                      |  2 +-
 RELEASE-NOTES                 |  6 +++
 electrum                      | 55 +++++++++++---------------
 gui/qt/address_dialog.py      | 27 +++----------
 gui/qt/history_widget.py      |  7 +++-
 gui/qt/icons_rc.py            |  2 +-
 gui/qt/installwizard.py       | 68 ++++++++++++--------------------
 gui/qt/main_window.py         |  3 +-
 gui/qt/network_dialog.py      | 15 ++++++--
 lib/commands.py               | 32 +++++++--------
 lib/interface.py              |  6 +--
 lib/tests/test_transaction.py | 55 --------------------------
 lib/transaction.py            |  9 ++++-
 lib/version.py                |  2 +-
 lib/wallet.py                 | 90 +++++++++++++++++++++++++++----------------
 lib/websockets.py             |  6 +--
 plugins/exchange_rate.py      |  5 ++-
 18 files changed, 167 insertions(+), 225 deletions(-)

diff --git a/Electrum.egg-info/PKG-INFO b/Electrum.egg-info/PKG-INFO
index 272c4e2..d3a75a7 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.5.1
+Version: 2.5.2
 Summary: Lightweight Bitcoin Wallet
 Home-page: https://electrum.org
 Author: Thomas Voegtlin
diff --git a/PKG-INFO b/PKG-INFO
index 272c4e2..d3a75a7 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: Electrum
-Version: 2.5.1
+Version: 2.5.2
 Summary: Lightweight Bitcoin Wallet
 Home-page: https://electrum.org
 Author: Thomas Voegtlin
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 0d7b9b1..41a87c0 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -1,3 +1,9 @@
+# Release 2.5.2 (bugfixes)
+ * fix bug #1513 (client tries to broadcast transaction while not connected)
+ * fix synchronization bug (#1520)
+ * fix command line bug (#1494)
+ * fixes for exchange rate plugin
+
 # Release 2.5.1 (bugfixes)
  * signatures in transactions were still using the old class
  * make sure that setup.py uses python2
diff --git a/electrum b/electrum
index 39a43f4..11877bc 100755
--- a/electrum
+++ b/electrum
@@ -87,7 +87,7 @@ from electrum.commands import get_parser, known_commands, Commands, config_varia
 # get password routine
 def prompt_password(prompt, confirm=True):
     import getpass
-    password = getpass.getpass(prompt)
+    password = getpass.getpass(prompt, stream=None)
     if password and confirm:
         password2 = getpass.getpass("Confirm: ")
         if password != password2:
@@ -136,42 +136,31 @@ def init_cmdline(config):
     if cmd.name in ['create', 'restore']:
         if storage.file_exists:
             sys.exit("Error: Remove the existing wallet first!")
-        if config.get('password') is not None:
-            password = config.get('password')
-        elif cmd.name == 'restore' and config.get('mpk'):
-            password = None
-        else:
-            password = prompt_password("Password (hit return if you do not wish to encrypt your wallet):")
 
-        if cmd.name == 'restore':
-            mpk = config.get('mpk')
-            if mpk:
-                if Wallet.is_old_mpk(mpk):
-                    wallet = Wallet.from_old_mpk(mpk, storage)
-                if Wallet.is_xpub(mpk):
-                    wallet = Wallet.from_xpub(mpk, storage)
-            else:
-                import getpass
-                seed = getpass.getpass(prompt="seed:", stream=None) if config.get('concealed') else raw_input("seed:")
-                if not Wallet.is_seed(seed):
-                    sys.exit("Error: Invalid seed")
-                wallet = Wallet.from_seed(seed, password, storage)
+        def password_dialog():
+            return prompt_password("Password (hit return if you do not wish to encrypt your wallet):")
 
+        if cmd.name == 'restore':
+            text = config.get('text')
+            password = password_dialog() if Wallet.is_seed(text) or Wallet.is_xprv(text) or Wallet.is_private_key(text) else None
+            try:
+                wallet = Wallet.from_text(text, password, storage)
+            except BaseException as e:
+                sys.exit(str(e))
             if not config.get('offline'):
                 network = Network(config)
                 network.start()
                 wallet.start_threads(network)
                 print_msg("Recovering wallet...")
+                wallet.synchronize()
                 wallet.restore(lambda x: x)
-                if wallet.is_found():
-                    print_msg("Recovery successful")
-                else:
-                    print_msg("Warning: Found no history for this wallet")
+                msg = "Recovery successful" if wallet.is_found() else "Found no history for this wallet"
             else:
-                wallet.synchronize()
-                print_msg("Warning: This wallet was restored offline. It may contain more addresses than displayed.")
+                msg = "This wallet was restored offline. It may contain more addresses than displayed."
+            print_msg(msg)
 
         else:
+            password = password_dialog()
             wallet = Wallet(storage)
             seed = wallet.make_seed()
             wallet.add_seed(seed, password)
@@ -182,10 +171,9 @@ def init_cmdline(config):
             print_msg("Please keep it in a safe place; if you lose it, you will not be able to restore your wallet.")
 
         print_msg("Wallet saved in '%s'" % wallet.storage.path)
-        # terminate
         sys.exit(0)
 
-    if cmd.name not in ['create', 'restore'] and cmd.requires_wallet and not storage.file_exists:
+    if cmd.requires_wallet and not storage.file_exists:
         print_msg("Error: Wallet file not found.")
         print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option")
         sys.exit(0)
@@ -256,6 +244,9 @@ def run_command(config, network, password):
     storage = WalletStorage(config.get_wallet_path())
     # create wallet instance
     wallet = Wallet(storage) if cmd.requires_wallet else None
+    # start threads
+    if wallet and network:
+        wallet.start_threads(network)
     # arguments passed to function
     args = map(lambda x: config.get(x), cmd.params)
     # decode json arguments
@@ -272,10 +263,9 @@ def run_command(config, network, password):
     cmd_runner.password = password
     func = getattr(cmd_runner, cmd.name)
     result = func(*args)
-
+    # stop threads
     if wallet:
         wallet.stop_threads()
-
     return result
 
 
@@ -432,6 +422,8 @@ if __name__ == '__main__':
             else:
                 raise BaseException('Cannot get argument from stdin')
         elif arg == '?':
+            sys.argv[i] = raw_input("Enter argument:")
+        elif arg == ':':
             sys.argv[i] = prompt_password('Enter argument (will not echo):', False)
 
     # parse command line
@@ -462,9 +454,6 @@ if __name__ == '__main__':
     # check uri
     uri = config_options.get('url')
     if uri:
-        if os.path.exists(uri):
-            # assume this is a payment request
-            uri = "bitcoin:?r=file://"+ os.path.join(os.getcwd(), uri)
         if not re.match('^bitcoin:', uri):
             print_stderr('unknown command:', uri)
             sys.exit(1)
diff --git a/gui/qt/address_dialog.py b/gui/qt/address_dialog.py
index edf90f3..d4812a1 100644
--- a/gui/qt/address_dialog.py
+++ b/gui/qt/address_dialog.py
@@ -16,23 +16,11 @@
 # You should have received a copy of the GNU General Public License
 # along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-import sys, time, datetime, re, threading
-from electrum.i18n import _, set_language
-from electrum.util import print_error, print_msg
-import os.path, json, ast, traceback
-import shutil
-import StringIO
-
-
-try:
-    import PyQt4
-except Exception:
-    sys.exit("Error: Could not import PyQt4 on Linux systems, you may try 'sudo apt-get install python-qt4'")
+from electrum.i18n import _
 
+import PyQt4
 from PyQt4.QtGui import *
 from PyQt4.QtCore import *
-import PyQt4.QtCore as QtCore
-
 
 from util import *
 from history_widget import HistoryWidget
@@ -63,16 +51,16 @@ class AddressDialog(QDialog):
 
         vbox.addWidget(QLabel(_("History")))
         self.hw = HistoryWidget(self.parent)
+        self.hw.get_domain = self.get_domain
         vbox.addWidget(self.hw)
 
         vbox.addStretch(1)
         vbox.addLayout(Buttons(CloseButton(self)))
         self.format_amount = self.parent.format_amount
+        self.hw.update()
 
-        h = self.wallet.get_history([self.address])
-        self.hw.update(h)
-
-
+    def get_domain(self):
+        return [self.address]
 
     def show_qr(self):
         text = self.address
@@ -80,6 +68,3 @@ class AddressDialog(QDialog):
             self.parent.show_qrcode(text, 'Address')
         except Exception as e:
             self.show_message(str(e))
-
-
-
diff --git a/gui/qt/history_widget.py b/gui/qt/history_widget.py
index 0266abb..dc34ff2 100644
--- a/gui/qt/history_widget.py
+++ b/gui/qt/history_widget.py
@@ -55,10 +55,13 @@ class HistoryWidget(MyTreeWidget):
             icon = QIcon(":icons/confirmed.png")
         return icon, time_str
 
+    def get_domain(self):
+        '''Replaced in address_dialog.py'''
+        return self.wallet.get_account_addresses(self.parent.current_account)
+
     def on_update(self):
         self.wallet = self.parent.wallet
-        domain = self.wallet.get_account_addresses(self.parent.current_account)
-        h = self.wallet.get_history(domain)
+        h = self.wallet.get_history(self.get_domain())
 
         item = self.currentItem()
         current_tx = item.data(0, Qt.UserRole).toString() if item else None
diff --git a/gui/qt/icons_rc.py b/gui/qt/icons_rc.py
index 5f06e27..f886258 100644
--- a/gui/qt/icons_rc.py
+++ b/gui/qt/icons_rc.py
@@ -2,7 +2,7 @@
 
 # Resource object code
 #
-# Created: dim. oct. 18 13:04:10 2015
+# Created: mer. oct. 28 13:56:56 2015
 #      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 0118f65..278d003 100644
--- a/gui/qt/installwizard.py
+++ b/gui/qt/installwizard.py
@@ -561,47 +561,27 @@ class InstallWizard(QDialog):
 
 
     def restore(self, t):
-
-            if t == 'standard':
-                text = self.enter_seed_dialog(MSG_ENTER_ANYTHING, None)
-                if not text:
-                    return
-                if Wallet.is_xprv(text):
-                    password = self.password_dialog()
-                    wallet = Wallet.from_xprv(text, password, self.storage)
-                elif Wallet.is_old_mpk(text):
-                    wallet = Wallet.from_old_mpk(text, self.storage)
-                elif Wallet.is_xpub(text):
-                    wallet = Wallet.from_xpub(text, self.storage)
-                elif Wallet.is_address(text):
-                    wallet = Wallet.from_address(text, self.storage)
-                elif Wallet.is_private_key(text):
-                    password = self.password_dialog()
-                    wallet = Wallet.from_private_key(text, password, self.storage)
-                elif Wallet.is_seed(text):
-                    password = self.password_dialog()
-                    wallet = Wallet.from_seed(text, password, self.storage)
-                else:
-                    raise BaseException('unknown wallet type')
-
-            elif re.match('(\d+)of(\d+)', t):
-                n = int(re.match('(\d+)of(\d+)', t).group(2))
-                key_list = self.multi_seed_dialog(n - 1)
-                if not key_list:
-                    return
-                password = self.password_dialog() if any(map(lambda x: Wallet.is_seed(x) or Wallet.is_xprv(x), key_list)) else None
-                wallet = Wallet.from_multisig(key_list, password, self.storage, t)
-
-            else:
-                self.storage.put('wallet_type', t, False)
-                # call the constructor to load the plugin (side effect)
-                Wallet(self.storage)
-                wallet = always_hook('installwizard_restore', self, self.storage)
-                if not wallet:
-                    util.print_error("no wallet")
-                    return
-
-            # create first keys offline
-            self.waiting_dialog(wallet.synchronize)
-
-            return wallet
+        if t == 'standard':
+            text = self.enter_seed_dialog(MSG_ENTER_ANYTHING, None)
+            if not text:
+                return
+            password = self.password_dialog() if Wallet.is_seed(text) or Wallet.is_xprv(text) or Wallet.is_private_key(text) else None
+            wallet = Wallet.from_text(text, password, self.storage)
+        elif re.match('(\d+)of(\d+)', t):
+            n = int(re.match('(\d+)of(\d+)', t).group(2))
+            key_list = self.multi_seed_dialog(n - 1)
+            if not key_list:
+                return
+            password = self.password_dialog() if any(map(lambda x: Wallet.is_seed(x) or Wallet.is_xprv(x), key_list)) else None
+            wallet = Wallet.from_multisig(key_list, password, self.storage, t)
+        else:
+            self.storage.put('wallet_type', t, False)
+            # call the constructor to load the plugin (side effect)
+            Wallet(self.storage)
+            wallet = always_hook('installwizard_restore', self, self.storage)
+            if not wallet:
+                util.print_error("no wallet")
+                return
+        # create first keys offline
+        self.waiting_dialog(wallet.synchronize)
+        return wallet
diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
index 00aa442..fa868b8 100644
--- a/gui/qt/main_window.py
+++ b/gui/qt/main_window.py
@@ -2482,7 +2482,8 @@ class ElectrumWindow(QMainWindow, PrintError):
         keys_e.setTabChangesFocus(True)
         vbox.addWidget(keys_e)
 
-        h, address_e = address_field(self.wallet.addresses(False))
+        addresses = self.wallet.get_unused_addresses(self.current_account)
+        h, address_e = address_field(addresses)
         vbox.addLayout(h)
 
         vbox.addStretch(1)
diff --git a/gui/qt/network_dialog.py b/gui/qt/network_dialog.py
index 6d4baa2..0eb6702 100644
--- a/gui/qt/network_dialog.py
+++ b/gui/qt/network_dialog.py
@@ -17,13 +17,15 @@
 # along with this program. If not, see <http://www.gnu.org/licenses/>.
 
 import sys, time, datetime, re, threading
-from electrum.i18n import _
-from electrum.util import print_error, print_msg
 import os.path, json, ast, traceback
 
 from PyQt4.QtGui import *
 from PyQt4.QtCore import *
+
+from electrum.i18n import _
+from electrum.util import print_error, print_msg
 from electrum import DEFAULT_PORTS
+from electrum.network import serialize_server, deserialize_server
 
 from util import *
 
@@ -224,9 +226,14 @@ class NetworkDialog(QDialog):
         if not self.exec_():
             return
 
-        host = str( self.server_host.text() )
-        port = str( self.server_port.text() )
+        host = str(self.server_host.text())
+        port = str(self.server_port.text())
         protocol = 's' if self.ssl_cb.isChecked() else 't'
+        # sanitize
+        try:
+            deserialize_server(serialize_server(host, port, protocol))
+        except:
+            return
 
         if self.proxy_mode.currentText() != 'NONE':
             proxy = { 'mode':str(self.proxy_mode.currentText()).lower(),
diff --git a/lib/commands.py b/lib/commands.py
index 344c776..0943275 100644
--- a/lib/commands.py
+++ b/lib/commands.py
@@ -101,19 +101,26 @@ class Commands:
     @command('')
     def create(self):
         """Create a new wallet"""
+        raise BaseException('Not a JSON-RPC command')
 
-    @command('')
-    def restore(self, concealed=False, mpk=None):
-        """Restore a wallet from seed. """
+    @command('wn')
+    def restore(self, text):
+        """Restore a wallet from text. Text can be a seed phrase, a master
+        public key, a master private key, a list of bitcoin addresses
+        or bitcoin private keys. If you want to be prompted for your
+        seed, type '?' or ':' (concealed) """
+        raise BaseException('Not a JSON-RPC command')
 
     @command('w')
     def deseed(self):
         """Remove seed from wallet. This creates a seedless, watching-only
         wallet."""
+        raise BaseException('Not a JSON-RPC command')
 
     @command('wp')
     def password(self):
         """Change wallet password. """
+        raise BaseException('Not a JSON-RPC command')
 
     @command('')
     def getconfig(self, key):
@@ -412,26 +419,18 @@ class Commands:
         return tx
 
     @command('wp')
-    def payto(self, destination, amount, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, deserialized=False, broadcast=False):
+    def payto(self, destination, amount, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, deserialized=False):
         """Create a transaction. """
         domain = [from_addr] if from_addr else None
         tx = self._mktx([(destination, amount)], tx_fee, change_addr, domain, nocheck, unsigned)
-        if broadcast:
-            r, h = self.wallet.sendtx(tx)
-            return h
-        else:
-            return tx.deserialize() if deserialized else tx
+        return tx.deserialize() if deserialized else tx
 
     @command('wp')
-    def paytomany(self, outputs, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, deserialized=False, broadcast=False):
+    def paytomany(self, outputs, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, deserialized=False):
         """Create a multi-output transaction. """
         domain = [from_addr] if from_addr else None
         tx = self._mktx(outputs, tx_fee, change_addr, domain, nocheck, unsigned)
-        if broadcast:
-            r, h = self.wallet.sendtx(tx)
-            return h
-        else:
-            return tx.deserialize() if deserialized else tx
+        return tx.deserialize() if deserialized else tx
 
     @command('wn')
     def history(self):
@@ -620,9 +619,7 @@ param_descriptions = {
 }
 
 command_options = {
-    'broadcast':   (None, "--broadcast",   "Broadcast the transaction to the Bitcoin network"),
     'password':    ("-W", "--password",    "Password"),
-    'concealed':   ("-C", "--concealed",   "Don't echo seed to console when restoring"),
     'receiving':   (None, "--receiving",   "Show only receiving addresses"),
     'change':      (None, "--change",      "Show only change addresses"),
     'frozen':      (None, "--frozen",      "Show only frozen addresses"),
@@ -638,7 +635,6 @@ command_options = {
     'entropy':     (None, "--entropy",     "Custom entropy"),
     'language':    ("-L", "--lang",        "Default language for wordlist"),
     'gap_limit':   ("-G", "--gap",         "Gap limit"),
-    'mpk':         (None, "--mpk",         "Restore from master public key"),
     'deserialized':("-d", "--deserialized","Return deserialized transaction"),
     'privkey':     (None, "--privkey",     "Private key. Set to '?' to get a prompt."),
     'unsigned':    ("-u", "--unsigned",    "Do not sign transaction"),
diff --git a/lib/interface.py b/lib/interface.py
index 8fea853..659e272 100644
--- a/lib/interface.py
+++ b/lib/interface.py
@@ -117,7 +117,7 @@ class TcpConnection(threading.Thread, util.PrintError):
                     return
                 # try with CA first
                 try:
-                    s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1, cert_reqs=ssl.CERT_REQUIRED, ca_certs=ca_path, do_handshake_on_connect=True)
+                    s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv23, cert_reqs=ssl.CERT_REQUIRED, ca_certs=ca_path, do_handshake_on_connect=True)
                 except ssl.SSLError, e:
                     s = None
                 if s and self.check_host_name(s.getpeercert(), self.host):
@@ -130,7 +130,7 @@ class TcpConnection(threading.Thread, util.PrintError):
                 if s is None:
                     return
                 try:
-                    s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1, cert_reqs=ssl.CERT_NONE, ca_certs=None)
+                    s = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv23, cert_reqs=ssl.CERT_NONE, ca_certs=None)
                 except ssl.SSLError, e:
                     self.print_error("SSL error retrieving SSL certificate:", e)
                     return
@@ -153,7 +153,7 @@ class TcpConnection(threading.Thread, util.PrintError):
         if self.use_ssl:
             try:
                 s = ssl.wrap_socket(s,
-                                    ssl_version=ssl.PROTOCOL_TLSv1,
+                                    ssl_version=ssl.PROTOCOL_SSLv23,
                                     cert_reqs=ssl.CERT_REQUIRED,
                                     ca_certs= (temporary_path if is_new else cert_path),
                                     do_handshake_on_connect=True)
diff --git a/lib/tests/test_transaction.py b/lib/tests/test_transaction.py
index ed893ed..1030065 100644
--- a/lib/tests/test_transaction.py
+++ b/lib/tests/test_transaction.py
@@ -141,61 +141,6 @@ class TestTransaction(unittest.TestCase):
         res = transaction.parse_xpub('fd007d260305ef27224bbcf6cf5238d2b3638b5a78d5')
         self.assertEquals(res, (None, '1CQj15y1N7LDHp7wTt28eoD1QhHgFgxECH'))
 
-    def test_sign_tx(self):
-        tx = transaction.Transaction(unsigned_blob)
-        tx.deserialize()
-
-        x_pubkey = 'ff0488b21e03ef2afea18000000089689bff23e1e7fb2f161daa37270a97a3d8c2e537584b2d304ecb47b86d21fc021b010d3bd425f8cf2e04824bfdf1f1f5ff1d51fadd9a41f9e3fb8dd3403b1bfe00000000'
-        privkey = 'L187zmkzzGgf9QdB23MrZvwJ52WoZuQHtkddjmePtbVjXxicJND2'
-
-        tx.sign(keypairs={x_pubkey: privkey})
-        self.assertEquals(tx.serialize(), signed_blob)
-
-        tx.sign(keypairs={x_pubkey: privkey})
-        self.assertEquals(tx.serialize(), signed_blob)
-
-    def test_sweep(self):
-        privkeys = ['5HuH1SHoSVrgtPEwew9JzVAHGoKyp47x564mBCTgVmUT2Me1Q18']
-        unspent = [
-            {
-                "height": 371447,
-                "tx_hash": "8e4d173db094786cc128b0c12eebc2200c0d8bfc3ad04ba39f487222d18bae3c",
-                "tx_pos": 0,
-                "value": 599995800
-            }
-        ]
-        to_address = '1JtBahwvii2pRkBmb4QMfcJQux1rk3Jkbq'
-        network = NetworkMock(unspent)
-        tx = transaction.Transaction.sweep(privkeys, network, to_address, fee=5000)
-        result = transaction.deserialize(tx.serialize())
-        expected = {
-            'inputs': [{
-                'address': '1t28kmZypcPQrunmJk212dcPGPxbBtB6Y',
-                'is_coinbase': False,
-                'num_sig': 1,
-                'prevout_hash': '8e4d173db094786cc128b0c12eebc2200c0d8bfc3ad04ba39f487222d18bae3c',
-                'prevout_n': 0,
-                'pubkeys': ['047b9f9014f8d0d6f24dcaf5681b6ab185bd821e0fcce29d84e0452845baf1b2dbe332a7cd4dbdab786adda6d71b2188298c756b265c63de2794f7317b71a7ac02'],
-                'scriptSig': '48304502203f1ff200490d18bcb802c7cf7ba4264727b089f1db6746a62997285b5ac77969022100e495591ea5111bb23a782984736f32942570fda781b7ed085fc8c88a9756aaac0141047b9f9014f8d0d6f24dcaf5681b6ab185bd821e0fcce29d84e0452845baf1b2dbe332a7cd4dbdab786adda6d71b2188298c756b265c63de2794f7317b71a7ac02',
-                'sequence': 4294967295,
-                'signatures': ['304502203f1ff200490d18bcb802c7cf7ba4264727b089f1db6746a62997285b5ac77969022100e495591ea5111bb23a782984736f32942570fda781b7ed085fc8c88a9756aaac'],
-                'x_pubkeys': ['047b9f9014f8d0d6f24dcaf5681b6ab185bd821e0fcce29d84e0452845baf1b2dbe332a7cd4dbdab786adda6d71b2188298c756b265c63de2794f7317b71a7ac02']}],
-            'lockTime': 0,
-            'outputs': [{'address': '1JtBahwvii2pRkBmb4QMfcJQux1rk3Jkbq',
-                'prevout_n': 0,
-                'scriptPubKey': '76a914c4282f6060b811ee695ebb2068b8788213451d6a88ac',
-                'type': 'address',
-                'value': 599990800}],
-            'version': 1}
-        self.assertEquals(result, expected)
-
-        network = NetworkMock([])
-        tx = transaction.Transaction.sweep(privkeys, network, to_address, fee=5000)
-        self.assertEquals(tx, None)
-
-        privkeys = []
-        tx = transaction.Transaction.sweep(privkeys, network, to_address, fee=5000)
-        self.assertEquals(tx, None)
 
 class NetworkMock(object):
 
diff --git a/lib/transaction.py b/lib/transaction.py
index fa4636f..16202b7 100644
--- a/lib/transaction.py
+++ b/lib/transaction.py
@@ -470,7 +470,14 @@ class Transaction:
         return self.raw
 
     def __init__(self, raw):
-        self.raw = raw.strip() if raw else None
+        if raw is None:
+            self.raw = None
+        elif type(raw) in [str, unicode]:
+            self.raw = raw.strip() if raw else None
+        elif type(raw) is dict:
+            self.raw = raw['hex']
+        else:
+            raise BaseException("cannot initialize transaction", raw)
         self.inputs = None
 
     def update(self, raw):
diff --git a/lib/version.py b/lib/version.py
index 887effa..2a2f71c 100644
--- a/lib/version.py
+++ b/lib/version.py
@@ -1,4 +1,4 @@
-ELECTRUM_VERSION = '2.5.1'  # version of the client package
+ELECTRUM_VERSION = '2.5.2'  # version of the client package
 PROTOCOL_VERSION = '0.10'   # protocol version requested
 NEW_SEED_VERSION = 11       # electrum versions >= 2.0
 OLD_SEED_VERSION = 4        # electrum versions < 2.0
diff --git a/lib/wallet.py b/lib/wallet.py
index 0fab120..b54af7a 100644
--- a/lib/wallet.py
+++ b/lib/wallet.py
@@ -125,6 +125,10 @@ class WalletStorage(PrintError):
             f.write(s)
             f.flush()
             os.fsync(f.fileno())
+
+        if 'ANDROID_DATA' not in os.environ:
+            import stat
+            mode = os.stat(self.path).st_mode if os.path.exists(self.path) else stat.S_IREAD | stat.S_IWRITE
         # perform atomic write on POSIX systems
         try:
             os.rename(temp_path, self.path)
@@ -133,7 +137,7 @@ class WalletStorage(PrintError):
             os.rename(temp_path, self.path)
         if 'ANDROID_DATA' not in os.environ:
             import stat
-            os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE)
+            os.chmod(self.path, mode)
         self.print_error("saved")
 
 
@@ -772,7 +776,7 @@ class Abstract_Wallet(PrintError):
             try:
                 self.txi.pop(tx_hash)
                 self.txo.pop(tx_hash)
-            except KeyErrror:
+            except KeyError:
                 self.print_error("tx was not in history", tx_hash)
 
     def receive_tx_callback(self, tx_hash, tx, tx_height):
@@ -1043,6 +1047,8 @@ class Abstract_Wallet(PrintError):
     def send_tx(self, tx):
         # asynchronous
         self.tx_event.clear()
+        # fixme: this does not handle the case where server does not answer
+        assert self.network.interface, "Not connected."
         self.network.send([('blockchain.transaction.broadcast', [str(tx)])], self.on_broadcast)
         return tx.hash()
 
@@ -1129,8 +1135,28 @@ class Abstract_Wallet(PrintError):
             self.verifier = None
             self.storage.put('stored_height', self.get_local_height(), True)
 
-    def restore(self, cb):
-        pass
+    def restore(self, callback):
+        from i18n import _
+        def wait_for_wallet():
+            self.set_up_to_date(False)
+            while not self.is_up_to_date():
+                msg = "%s\n%s %d"%(
+                    _("Please wait..."),
+                    _("Addresses generated:"),
+                    len(self.addresses(True)))
+                apply(callback, (msg,))
+                time.sleep(0.1)
+        def wait_for_network():
+            while not self.network.is_connected():
+                msg = "%s \n" % (_("Connecting..."))
+                apply(callback, (msg,))
+                time.sleep(0.1)
+        # wait until we are connected, because the user might have selected another server
+        if self.network:
+            wait_for_network()
+            wait_for_wallet()
+        else:
+            self.synchronize()
 
     def get_accounts(self):
         return self.accounts
@@ -1254,12 +1280,16 @@ class Abstract_Wallet(PrintError):
     def can_change_password(self):
         return not self.is_watching_only()
 
-    def get_unused_address(self, account):
+    def get_unused_addresses(self, account):
         # fixme: use slots from expired requests
         domain = self.get_account_addresses(account, include_change=False)
-        for addr in domain:
-            if not self.history.get(addr) and addr not in self.receive_requests.keys():
-                return addr
+        return [addr for addr in domain if not self.history.get(addr)
+                and addr not in self.receive_requests.keys()]
+
+    def get_unused_address(self, account):
+        addrs = self.get_unused_addresses(account)
+        if addrs:
+            return addrs[0]
 
     def get_payment_request(self, addr, config):
         import util
@@ -1499,32 +1529,6 @@ class Deterministic_Wallet(Abstract_Wallet):
             for account in self.accounts.values():
                 account.synchronize(self)
 
-    def restore(self, callback):
-        from i18n import _
-        def wait_for_wallet():
-            self.set_up_to_date(False)
-            while not self.is_up_to_date():
-                msg = "%s\n%s %d"%(
-                    _("Please wait..."),
-                    _("Addresses generated:"),
-                    len(self.addresses(True)))
-
-                apply(callback, (msg,))
-                time.sleep(0.1)
-
-        def wait_for_network():
-            while not self.network.is_connected():
-                msg = "%s \n" % (_("Connecting..."))
-                apply(callback, (msg,))
-                time.sleep(0.1)
-
-        # wait until we are connected, because the user might have selected another server
-        if self.network:
-            wait_for_network()
-            wait_for_wallet()
-        else:
-            self.synchronize()
-
     def is_beyond_limit(self, address, account, is_change):
         if type(account) == ImportedAccount:
             return False
@@ -2077,3 +2081,21 @@ class Wallet(object):
         self.storage.put('use_encryption', self.use_encryption, True)
         self.create_main_account(password)
         return self
+
+    @classmethod
+    def from_text(klass, text, password, storage):
+        if Wallet.is_xprv(text):
+            wallet = klass.from_xprv(text, password, storage)
+        elif Wallet.is_old_mpk(text):
+            wallet = klass.from_old_mpk(text, storage)
+        elif Wallet.is_xpub(text):
+            wallet = klass.from_xpub(text, storage)
+        elif Wallet.is_address(text):
+            wallet = klass.from_address(text, storage)
+        elif Wallet.is_private_key(text):
+            wallet = klass.from_private_key(text, password, storage)
+        elif Wallet.is_seed(text):
+            wallet = klass.from_seed(text, password, storage)
+        else:
+            raise BaseException('Invalid seedphrase or key')
+        return wallet
diff --git a/lib/websockets.py b/lib/websockets.py
index 8014ef2..65c9ded 100644
--- a/lib/websockets.py
+++ b/lib/websockets.py
@@ -21,8 +21,8 @@ from collections import defaultdict
 try:
     from SimpleWebSocketServer import WebSocket, SimpleSSLWebSocketServer
 except ImportError:
-    print "install SimpleWebSocketServer"
-    sys.exit()
+    import sys
+    sys.exit("install SimpleWebSocketServer")
 
 import util
 
@@ -93,7 +93,7 @@ class WsClientThread(util.DaemonThread):
             except Queue.Empty:
                 continue
             id = r.get('id')
-            if id is None: 
+            if id is None:
                 method = r.get('method')
                 params = r.get('params')
             else:
diff --git a/plugins/exchange_rate.py b/plugins/exchange_rate.py
index c8a8e8b..7e08d87 100644
--- a/plugins/exchange_rate.py
+++ b/plugins/exchange_rate.py
@@ -112,8 +112,9 @@ class BitcoinAverage(ExchangeBase):
 class BitcoinVenezuela(ExchangeBase):
     def get_rates(self, ccy):
         json = self.get_json('api.bitcoinvenezuela.com', '/')
-        return dict([(r, Decimal(json['BTC'][r]))
-                     for r in json['BTC']])
+        rates = [(r, json['BTC'][r]) for r in json['BTC']
+                 if json['BTC'][r] is not None]  # Giving NULL for LTC
+        return dict(rates)
 
     def protocol(self):
         return "http"

-- 
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