commit 81cc20039ea5d45204c00b75b283ea877029fbb0
parent 6958c0ccc3d97edfb7f8504f27270182cb3abcfa
Author: SomberNight <somber.night@protonmail.com>
Date: Mon, 22 Oct 2018 16:41:25 +0200
more type annotations in core lib
Diffstat:
14 files changed, 90 insertions(+), 49 deletions(-)
diff --git a/electrum/address_synchronizer.py b/electrum/address_synchronizer.py
@@ -34,6 +34,9 @@ from .synchronizer import Synchronizer
from .verifier import SPV
from .blockchain import hash_header
from .i18n import _
+from .storage import WalletStorage
+from .network import Network
+
TX_HEIGHT_LOCAL = -2
TX_HEIGHT_UNCONF_PARENT = -1
@@ -53,9 +56,9 @@ class AddressSynchronizer(PrintError):
inherited by wallet
"""
- def __init__(self, storage):
+ def __init__(self, storage: WalletStorage):
self.storage = storage
- self.network = None
+ self.network = None # type: Network
# verifier (SPV) and synchronizer are started in start_network
self.synchronizer = None # type: Synchronizer
self.verifier = None # type: SPV
@@ -807,3 +810,6 @@ class AddressSynchronizer(PrintError):
def is_empty(self, address):
c, u, x = self.get_addr_balance(address)
return c+u+x == 0
+
+ def synchronize(self):
+ pass
diff --git a/electrum/base_wizard.py b/electrum/base_wizard.py
@@ -31,10 +31,15 @@ from functools import partial
from . import bitcoin
from . import keystore
from .keystore import bip44_derivation, purpose48_derivation
-from .wallet import Imported_Wallet, Standard_Wallet, Multisig_Wallet, wallet_types, Wallet
-from .storage import STO_EV_USER_PW, STO_EV_XPUB_PW, get_derivation_used_for_hw_device_encryption
+from .wallet import (Imported_Wallet, Standard_Wallet, Multisig_Wallet,
+ wallet_types, Wallet, Abstract_Wallet)
+from .storage import (WalletStorage, STO_EV_USER_PW, STO_EV_XPUB_PW,
+ get_derivation_used_for_hw_device_encryption)
from .i18n import _
from .util import UserCancelled, InvalidPassword, WalletFileException
+from .simple_config import SimpleConfig
+from .plugin import Plugins
+
# hardware device setup purpose
HWD_SETUP_NEW_WALLET, HWD_SETUP_DECRYPT_WALLET = range(0, 2)
@@ -48,12 +53,12 @@ class GoBack(Exception): pass
class BaseWizard(object):
- def __init__(self, config, plugins, storage):
+ def __init__(self, config: SimpleConfig, plugins: Plugins, storage: WalletStorage):
super(BaseWizard, self).__init__()
self.config = config
self.plugins = plugins
self.storage = storage
- self.wallet = None
+ self.wallet = None # type: Abstract_Wallet
self.stack = []
self.plugin = None
self.keystores = []
diff --git a/electrum/blockchain.py b/electrum/blockchain.py
@@ -28,6 +28,7 @@ from . import util
from .bitcoin import Hash, hash_encode, int_to_hex, rev_hex
from . import constants
from .util import bfh, bh2u
+from .simple_config import SimpleConfig
HEADER_SIZE = 80 # bytes
@@ -77,7 +78,7 @@ blockchains = {} # type: Dict[int, Blockchain]
blockchains_lock = threading.Lock()
-def read_blockchains(config):
+def read_blockchains(config: 'SimpleConfig') -> Dict[int, 'Blockchain']:
blockchains[0] = Blockchain(config, 0, None)
fdir = os.path.join(util.get_headers_dir(config), 'forks')
util.make_dir(fdir)
@@ -100,7 +101,7 @@ class Blockchain(util.PrintError):
Manages blockchain headers and their verification
"""
- def __init__(self, config, forkpoint: int, parent_id: Optional[int]):
+ def __init__(self, config: SimpleConfig, forkpoint: int, parent_id: Optional[int]):
self.config = config
self.forkpoint = forkpoint
self.checkpoints = constants.net.CHECKPOINTS
diff --git a/electrum/commands.py b/electrum/commands.py
@@ -32,6 +32,7 @@ import ast
import base64
from functools import wraps
from decimal import Decimal
+from typing import Optional
from .import util, ecc
from .util import bfh, bh2u, format_satoshis, json_decode, print_error, json_encode
@@ -43,8 +44,11 @@ from .paymentrequest import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED
from .synchronizer import Notifier
from .storage import WalletStorage
from . import keystore
-from .wallet import Wallet, Imported_Wallet
+from .wallet import Wallet, Imported_Wallet, Abstract_Wallet
from .mnemonic import Mnemonic
+from .network import Network
+from .simple_config import SimpleConfig
+
known_commands = {}
@@ -95,7 +99,8 @@ def command(s):
class Commands:
- def __init__(self, config, wallet, network, callback = None):
+ def __init__(self, config: 'SimpleConfig', wallet: Abstract_Wallet,
+ network: Optional['Network'], callback=None):
self.config = config
self.wallet = wallet
self.network = network
diff --git a/electrum/daemon.py b/electrum/daemon.py
@@ -29,7 +29,7 @@ import time
import traceback
import sys
import threading
-from typing import Dict
+from typing import Dict, Optional, Tuple
import jsonrpclib
@@ -46,7 +46,7 @@ from .exchange_rate import FxThread
from .plugin import run_hook
-def get_lockfile(config):
+def get_lockfile(config: SimpleConfig):
return os.path.join(config.path, 'daemon')
@@ -54,7 +54,7 @@ def remove_lockfile(lockfile):
os.unlink(lockfile)
-def get_fd_or_server(config):
+def get_fd_or_server(config: SimpleConfig):
'''Tries to create the lockfile, using O_EXCL to
prevent races. If it succeeds it returns the FD.
Otherwise try and connect to the server specified in the lockfile.
@@ -73,7 +73,7 @@ def get_fd_or_server(config):
remove_lockfile(lockfile)
-def get_server(config):
+def get_server(config: SimpleConfig) -> Optional[jsonrpclib.Server]:
lockfile = get_lockfile(config)
while True:
create_time = None
@@ -99,7 +99,7 @@ def get_server(config):
time.sleep(1.0)
-def get_rpc_credentials(config):
+def get_rpc_credentials(config: SimpleConfig) -> Tuple[str, str]:
rpc_user = config.get('rpcuser', None)
rpc_password = config.get('rpcpassword', None)
if rpc_user is None or rpc_password is None:
@@ -121,7 +121,7 @@ def get_rpc_credentials(config):
class Daemon(DaemonThread):
- def __init__(self, config, fd=None, *, listen_jsonrpc=True):
+ def __init__(self, config: SimpleConfig, fd=None, *, listen_jsonrpc=True):
DaemonThread.__init__(self)
self.config = config
if fd is None and listen_jsonrpc:
@@ -142,7 +142,7 @@ class Daemon(DaemonThread):
self.init_server(config, fd)
self.start()
- def init_server(self, config, fd):
+ def init_server(self, config: SimpleConfig, fd):
host = config.get('rpchost', '127.0.0.1')
port = config.get('rpcport', 0)
rpc_user, rpc_password = get_rpc_credentials(config)
@@ -230,7 +230,7 @@ class Daemon(DaemonThread):
response = "Error: Electrum is running in daemon mode. Please stop the daemon first."
return response
- def load_wallet(self, path, password):
+ def load_wallet(self, path, password) -> Optional[Abstract_Wallet]:
# wizard will be launched if we return
if path in self.wallets:
wallet = self.wallets[path]
@@ -251,7 +251,7 @@ class Daemon(DaemonThread):
self.wallets[path] = wallet
return wallet
- def add_wallet(self, wallet):
+ def add_wallet(self, wallet: Abstract_Wallet):
path = wallet.storage.path
self.wallets[path] = wallet
diff --git a/electrum/exchange_rate.py b/electrum/exchange_rate.py
@@ -17,6 +17,8 @@ from .i18n import _
from .util import PrintError, ThreadJob, make_dir, log_exceptions
from .util import make_aiohttp_session
from .network import Network
+from .simple_config import SimpleConfig
+
# See https://en.wikipedia.org/wiki/ISO_4217
CCY_PRECISIONS = {'BHD': 3, 'BIF': 0, 'BYR': 0, 'CLF': 4, 'CLP': 0,
@@ -434,7 +436,7 @@ def get_exchanges_by_ccy(history=True):
class FxThread(ThreadJob):
- def __init__(self, config, network):
+ def __init__(self, config: SimpleConfig, network: Network):
self.config = config
self.network = network
if self.network:
diff --git a/electrum/interface.py b/electrum/interface.py
@@ -28,7 +28,7 @@ import ssl
import sys
import traceback
import asyncio
-from typing import Tuple, Union, List
+from typing import Tuple, Union, List, TYPE_CHECKING
from collections import defaultdict
import aiorpcx
@@ -43,6 +43,9 @@ from . import blockchain
from .blockchain import Blockchain
from . import constants
+if TYPE_CHECKING:
+ from .network import Network
+
class NotificationSession(ClientSession):
@@ -129,7 +132,7 @@ def serialize_server(host: str, port: Union[str, int], protocol: str) -> str:
class Interface(PrintError):
- def __init__(self, network, server, config_path, proxy):
+ def __init__(self, network: 'Network', server: str, config_path, proxy: dict):
self.ready = asyncio.Future()
self.got_disconnected = asyncio.Future()
self.server = server
diff --git a/electrum/network.py b/electrum/network.py
@@ -164,12 +164,12 @@ class Network(PrintError):
"""
verbosity_filter = 'n'
- def __init__(self, config=None):
+ def __init__(self, config: SimpleConfig=None):
global INSTANCE
INSTANCE = self
if config is None:
config = {} # Do not use mutables as default values!
- self.config = SimpleConfig(config) if isinstance(config, dict) else config
+ self.config = SimpleConfig(config) if isinstance(config, dict) else config # type: SimpleConfig
self.num_server = 10 if not self.config.get('oneserver') else 0
blockchain.blockchains = blockchain.read_blockchains(self.config)
self.print_error("blockchains", list(blockchain.blockchains))
diff --git a/electrum/plugin.py b/electrum/plugin.py
@@ -30,11 +30,13 @@ import pkgutil
import time
import threading
-from .util import print_error
from .i18n import _
-from .util import profiler, PrintError, DaemonThread, UserCancelled, ThreadJob
+from .util import (profiler, PrintError, DaemonThread, UserCancelled,
+ ThreadJob, print_error)
from . import bitcoin
from . import plugins
+from .simple_config import SimpleConfig
+
plugin_loaders = {}
hook_names = set()
@@ -45,7 +47,7 @@ class Plugins(DaemonThread):
verbosity_filter = 'p'
@profiler
- def __init__(self, config, is_local, gui_name):
+ def __init__(self, config: SimpleConfig, is_local, gui_name):
DaemonThread.__init__(self)
self.setName('Plugins')
self.pkgpath = os.path.dirname(plugins.__file__)
diff --git a/electrum/synchronizer.py b/electrum/synchronizer.py
@@ -24,7 +24,7 @@
# SOFTWARE.
import asyncio
import hashlib
-from typing import Dict, List
+from typing import Dict, List, TYPE_CHECKING
from collections import defaultdict
from aiorpcx import TaskGroup, run_in_thread
@@ -33,6 +33,10 @@ from .transaction import Transaction
from .util import bh2u, make_aiohttp_session, NetworkJobOnDefaultServer
from .bitcoin import address_to_scripthash
+if TYPE_CHECKING:
+ from .network import Network
+ from .address_synchronizer import AddressSynchronizer
+
def history_status(h):
if not h:
@@ -47,7 +51,7 @@ class SynchronizerBase(NetworkJobOnDefaultServer):
"""Subscribe over the network to a set of addresses, and monitor their statuses.
Every time a status changes, run a coroutine provided by the subclass.
"""
- def __init__(self, network):
+ def __init__(self, network: 'Network'):
self.asyncio_loop = network.asyncio_loop
NetworkJobOnDefaultServer.__init__(self, network)
@@ -112,7 +116,7 @@ class Synchronizer(SynchronizerBase):
we don't have the full history of, and requests binary transaction
data of any transactions the wallet doesn't have.
'''
- def __init__(self, wallet):
+ def __init__(self, wallet: 'AddressSynchronizer'):
self.wallet = wallet
SynchronizerBase.__init__(self, wallet.network)
diff --git a/electrum/util.py b/electrum/util.py
@@ -23,7 +23,7 @@
import binascii
import os, sys, re, json
from collections import defaultdict
-from typing import NamedTuple, Union
+from typing import NamedTuple, Union, TYPE_CHECKING
from datetime import datetime
import decimal
from decimal import Decimal
@@ -46,6 +46,10 @@ from aiorpcx import TaskGroup
from .i18n import _
+if TYPE_CHECKING:
+ from .network import Network
+ from .interface import Interface
+
def inv_dict(d):
return {v: k for k, v in d.items()}
@@ -923,10 +927,10 @@ class NetworkJobOnDefaultServer(PrintError):
interface. Every time the main interface changes, the job is
restarted, and some of its internals are reset.
"""
- def __init__(self, network):
+ def __init__(self, network: 'Network'):
asyncio.set_event_loop(network.asyncio_loop)
self.network = network
- self.interface = None
+ self.interface = None # type: Interface
self._restart_lock = asyncio.Lock()
self._reset()
asyncio.run_coroutine_threadsafe(self._restart(), network.asyncio_loop)
@@ -938,7 +942,7 @@ class NetworkJobOnDefaultServer(PrintError):
"""
self.group = SilentTaskGroup()
- async def _start(self, interface):
+ async def _start(self, interface: 'Interface'):
self.interface = interface
await interface.group.spawn(self._start_tasks)
diff --git a/electrum/verifier.py b/electrum/verifier.py
@@ -22,7 +22,7 @@
# SOFTWARE.
import asyncio
-from typing import Sequence, Optional
+from typing import Sequence, Optional, TYPE_CHECKING
import aiorpcx
@@ -33,6 +33,10 @@ from .blockchain import hash_header
from .interface import GracefulDisconnect
from . import constants
+if TYPE_CHECKING:
+ from .network import Network
+ from .address_synchronizer import AddressSynchronizer
+
class MerkleVerificationFailure(Exception): pass
class MissingBlockHeader(MerkleVerificationFailure): pass
@@ -43,7 +47,7 @@ class InnerNodeOfSpvProofIsValidTx(MerkleVerificationFailure): pass
class SPV(NetworkJobOnDefaultServer):
""" Simple Payment Verification """
- def __init__(self, network, wallet):
+ def __init__(self, network: 'Network', wallet: 'AddressSynchronizer'):
self.wallet = wallet
NetworkJobOnDefaultServer.__init__(self, network)
diff --git a/electrum/wallet.py b/electrum/wallet.py
@@ -48,7 +48,7 @@ from .util import (NotEnoughFunds, PrintError, UserCancelled, profiler,
from .bitcoin import *
from .version import *
from .keystore import load_keystore, Hardware_KeyStore
-from .storage import multisig_type, STO_EV_PLAINTEXT, STO_EV_USER_PW, STO_EV_XPUB_PW
+from .storage import multisig_type, STO_EV_PLAINTEXT, STO_EV_USER_PW, STO_EV_XPUB_PW, WalletStorage
from . import transaction, bitcoin, coinchooser, paymentrequest, contacts
from .transaction import Transaction, TxOutput, TxOutputHwInfo
from .plugin import run_hook
@@ -57,6 +57,9 @@ from .address_synchronizer import (AddressSynchronizer, TX_HEIGHT_LOCAL,
from .paymentrequest import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED
from .paymentrequest import InvoiceStore
from .contacts import Contacts
+from .network import Network
+from .simple_config import SimpleConfig
+
TX_STATUS = [
_('Unconfirmed'),
@@ -67,18 +70,18 @@ TX_STATUS = [
-def relayfee(network):
+def relayfee(network: Network):
from .simple_config import FEERATE_DEFAULT_RELAY
MAX_RELAY_FEE = 50000
f = network.relay_fee if network and network.relay_fee else FEERATE_DEFAULT_RELAY
return min(f, MAX_RELAY_FEE)
-def dust_threshold(network):
+def dust_threshold(network: Network):
# Change <= dust threshold is added to the tx fee
return 182 * 3 * relayfee(network) / 1000
-def append_utxos_to_inputs(inputs, network, pubkey, txin_type, imax):
+def append_utxos_to_inputs(inputs, network: Network, pubkey, txin_type, imax):
if txin_type != 'p2pk':
address = bitcoin.pubkey_to_address(txin_type, pubkey)
scripthash = bitcoin.address_to_scripthash(address)
@@ -101,7 +104,7 @@ def append_utxos_to_inputs(inputs, network, pubkey, txin_type, imax):
item['num_sig'] = 1
inputs.append(item)
-def sweep_preparations(privkeys, network, imax=100):
+def sweep_preparations(privkeys, network: Network, imax=100):
def find_utxos_for_privkey(txin_type, privkey, compressed):
pubkey = ecc.ECPrivkey(privkey).get_public_key_hex(compressed=compressed)
@@ -127,7 +130,7 @@ def sweep_preparations(privkeys, network, imax=100):
return inputs, keypairs
-def sweep(privkeys, network, config, recipient, fee=None, imax=100):
+def sweep(privkeys, network: Network, config: SimpleConfig, recipient, fee=None, imax=100):
inputs, keypairs = sweep_preparations(privkeys, network, imax)
total = sum(i.get('value') for i in inputs)
if fee is None:
@@ -164,7 +167,7 @@ class Abstract_Wallet(AddressSynchronizer):
gap_limit_for_change = 6
verbosity_filter = 'w'
- def __init__(self, storage):
+ def __init__(self, storage: WalletStorage):
AddressSynchronizer.__init__(self, storage)
# saved fields
@@ -220,9 +223,6 @@ class Abstract_Wallet(AddressSynchronizer):
if not bitcoin.is_address(addrs[0]):
raise WalletFileException('The addresses in this wallet are not bitcoin addresses.')
- def synchronize(self):
- pass
-
def calc_unused_change_addresses(self):
with self.lock:
if hasattr(self, '_unused_change_addresses'):
diff --git a/electrum/websockets.py b/electrum/websockets.py
@@ -27,7 +27,7 @@ import os
import json
from collections import defaultdict
import asyncio
-from typing import Dict, List, Tuple
+from typing import Dict, List, Tuple, TYPE_CHECKING
import traceback
import sys
@@ -40,6 +40,11 @@ from .util import PrintError
from . import bitcoin
from .synchronizer import SynchronizerBase
+if TYPE_CHECKING:
+ from .network import Network
+ from .simple_config import SimpleConfig
+
+
request_queue = asyncio.Queue()
@@ -61,7 +66,7 @@ class ElectrumWebSocket(WebSocket, PrintError):
class BalanceMonitor(SynchronizerBase):
- def __init__(self, config, network):
+ def __init__(self, config: 'SimpleConfig', network: 'Network'):
SynchronizerBase.__init__(self, network)
self.config = config
self.expected_payments = defaultdict(list) # type: Dict[str, List[Tuple[WebSocket, int]]]
@@ -104,7 +109,7 @@ class BalanceMonitor(SynchronizerBase):
class WebSocketServer(threading.Thread):
- def __init__(self, config, network):
+ def __init__(self, config: 'SimpleConfig', network: 'Network'):
threading.Thread.__init__(self)
self.config = config
self.network = network