Skip to content

Commit b6cfc12

Browse files
authored
Merge pull request #8454 from SomberNight/202305_configvar
config: introduce ConfigVars (take 3)
2 parents c049b46 + 328a2bb commit b6cfc12

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+810
-487
lines changed

electrum/address_synchronizer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ def address_is_old(self, address: str, *, req_conf: int = 3) -> bool:
959959
"""
960960
max_conf = -1
961961
h = self.db.get_addr_history(address)
962-
needs_spv_check = not self.config.get("skipmerklecheck", False)
962+
needs_spv_check = not self.config.NETWORK_SKIPMERKLECHECK
963963
for tx_hash, tx_height in h:
964964
if needs_spv_check:
965965
tx_age = self.get_tx_height(tx_hash).conf

electrum/base_crash_reporter.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ class CrashReportResponse(NamedTuple):
4242

4343
class BaseCrashReporter(Logger):
4444
report_server = "https://crashhub.electrum.org"
45-
config_key = "show_crash_reporter"
4645
issue_template = """<h2>Traceback</h2>
4746
<pre>
4847
{traceback}

electrum/base_wizard.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def __init__(self, config: SimpleConfig, plugins: Plugins):
9292
self._stack = [] # type: List[WizardStackItem]
9393
self.plugin = None # type: Optional[BasePlugin]
9494
self.keystores = [] # type: List[KeyStore]
95-
self.is_kivy = config.get('gui') == 'kivy'
95+
self.is_kivy = config.GUI_NAME == 'kivy'
9696
self.seed_type = None
9797

9898
def set_icon(self, icon):
@@ -697,7 +697,7 @@ def show_xpub_and_add_cosigners(self, xpub):
697697
self.show_xpub_dialog(xpub=xpub, run_next=lambda x: self.run('choose_keystore'))
698698

699699
def choose_seed_type(self):
700-
seed_type = 'standard' if self.config.get('nosegwit') else 'segwit'
700+
seed_type = 'standard' if self.config.WIZARD_DONT_CREATE_SEGWIT else 'segwit'
701701
self.create_seed(seed_type)
702702

703703
def create_seed(self, seed_type):

electrum/coinchooser.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,17 @@
2424
# SOFTWARE.
2525
from collections import defaultdict
2626
from math import floor, log10
27-
from typing import NamedTuple, List, Callable, Sequence, Union, Dict, Tuple, Mapping, Type
27+
from typing import NamedTuple, List, Callable, Sequence, Union, Dict, Tuple, Mapping, Type, TYPE_CHECKING
2828
from decimal import Decimal
2929

3030
from .bitcoin import sha256, COIN, is_address
3131
from .transaction import Transaction, TxOutput, PartialTransaction, PartialTxInput, PartialTxOutput
3232
from .util import NotEnoughFunds
3333
from .logging import Logger
3434

35+
if TYPE_CHECKING:
36+
from .simple_config import SimpleConfig
37+
3538

3639
# A simple deterministic PRNG. Used to deterministically shuffle a
3740
# set of coins - the same set of coins should produce the same output.
@@ -484,20 +487,20 @@ def penalty(buckets: List[Bucket]) -> ScoredCandidate:
484487
'Privacy': CoinChooserPrivacy,
485488
} # type: Mapping[str, Type[CoinChooserBase]]
486489

487-
def get_name(config):
488-
kind = config.get('coin_chooser')
490+
def get_name(config: 'SimpleConfig') -> str:
491+
kind = config.WALLET_COIN_CHOOSER_POLICY
489492
if kind not in COIN_CHOOSERS:
490-
kind = 'Privacy'
493+
kind = config.cv.WALLET_COIN_CHOOSER_POLICY.get_default_value()
491494
return kind
492495

493-
def get_coin_chooser(config) -> CoinChooserBase:
496+
def get_coin_chooser(config: 'SimpleConfig') -> CoinChooserBase:
494497
klass = COIN_CHOOSERS[get_name(config)]
495498
# note: we enable enable_output_value_rounding by default as
496499
# - for sacrificing a few satoshis
497500
# + it gives better privacy for the user re change output
498501
# + it also helps the network as a whole as fees will become noisier
499502
# (trying to counter the heuristic that "whole integer sat/byte feerates" are common)
500503
coinchooser = klass(
501-
enable_output_value_rounding=config.get('coin_chooser_output_rounding', True),
504+
enable_output_value_rounding=config.WALLET_COIN_CHOOSER_OUTPUT_ROUNDING,
502505
)
503506
return coinchooser

electrum/commands.py

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ async def getconfig(self, key):
308308

309309
@classmethod
310310
def _setconfig_normalize_value(cls, key, value):
311-
if key not in ('rpcuser', 'rpcpassword'):
311+
if key not in (SimpleConfig.RPC_USERNAME.key(), SimpleConfig.RPC_PASSWORD.key()):
312312
value = json_decode(value)
313313
# call literal_eval for backward compatibility (see #4225)
314314
try:
@@ -321,9 +321,9 @@ def _setconfig_normalize_value(cls, key, value):
321321
async def setconfig(self, key, value):
322322
"""Set a configuration variable. 'value' may be a string or a Python expression."""
323323
value = self._setconfig_normalize_value(key, value)
324-
if self.daemon and key == 'rpcuser':
324+
if self.daemon and key == SimpleConfig.RPC_USERNAME.key():
325325
self.daemon.commands_server.rpc_user = value
326-
if self.daemon and key == 'rpcpassword':
326+
if self.daemon and key == SimpleConfig.RPC_PASSWORD.key():
327327
self.daemon.commands_server.rpc_password = value
328328
self.config.set_key(key, value)
329329
return True
@@ -1149,7 +1149,7 @@ async def lnpay(self, invoice, timeout=120, wallet: Abstract_Wallet = None):
11491149

11501150
@command('wl')
11511151
async def nodeid(self, wallet: Abstract_Wallet = None):
1152-
listen_addr = self.config.get('lightning_listen')
1152+
listen_addr = self.config.LIGHTNING_LISTEN
11531153
return wallet.lnworker.node_keypair.pubkey.hex() + (('@' + listen_addr) if listen_addr else '')
11541154

11551155
@command('wl')
@@ -1545,13 +1545,14 @@ def subparser_call(self, parser, namespace, values, option_string=None):
15451545

15461546

15471547
def add_network_options(parser):
1548-
parser.add_argument("-f", "--serverfingerprint", dest="serverfingerprint", default=None, help="only allow connecting to servers with a matching SSL certificate SHA256 fingerprint." + " " +
1549-
"To calculate this yourself: '$ openssl x509 -noout -fingerprint -sha256 -inform pem -in mycertfile.crt'. Enter as 64 hex chars.")
1550-
parser.add_argument("-1", "--oneserver", action="store_true", dest="oneserver", default=None, help="connect to one server only")
1551-
parser.add_argument("-s", "--server", dest="server", default=None, help="set server host:port:protocol, where protocol is either t (tcp) or s (ssl)")
1552-
parser.add_argument("-p", "--proxy", dest="proxy", default=None, help="set proxy [type:]host[:port] (or 'none' to disable proxy), where type is socks4,socks5 or http")
1553-
parser.add_argument("--noonion", action="store_true", dest="noonion", default=None, help="do not try to connect to onion servers")
1554-
parser.add_argument("--skipmerklecheck", action="store_true", dest="skipmerklecheck", default=None, help="Tolerate invalid merkle proofs from server")
1548+
parser.add_argument("-f", "--serverfingerprint", dest=SimpleConfig.NETWORK_SERVERFINGERPRINT.key(), default=None,
1549+
help="only allow connecting to servers with a matching SSL certificate SHA256 fingerprint. " +
1550+
"To calculate this yourself: '$ openssl x509 -noout -fingerprint -sha256 -inform pem -in mycertfile.crt'. Enter as 64 hex chars.")
1551+
parser.add_argument("-1", "--oneserver", action="store_true", dest=SimpleConfig.NETWORK_ONESERVER.key(), default=None, help="connect to one server only")
1552+
parser.add_argument("-s", "--server", dest=SimpleConfig.NETWORK_SERVER.key(), default=None, help="set server host:port:protocol, where protocol is either t (tcp) or s (ssl)")
1553+
parser.add_argument("-p", "--proxy", dest=SimpleConfig.NETWORK_PROXY.key(), default=None, help="set proxy [type:]host[:port] (or 'none' to disable proxy), where type is socks4,socks5 or http")
1554+
parser.add_argument("--noonion", action="store_true", dest=SimpleConfig.NETWORK_NOONION.key(), default=None, help="do not try to connect to onion servers")
1555+
parser.add_argument("--skipmerklecheck", action="store_true", dest=SimpleConfig.NETWORK_SKIPMERKLECHECK.key(), default=None, help="Tolerate invalid merkle proofs from server")
15551556

15561557
def add_global_options(parser):
15571558
group = parser.add_argument_group('global options')
@@ -1563,13 +1564,13 @@ def add_global_options(parser):
15631564
group.add_argument("--regtest", action="store_true", dest="regtest", default=False, help="Use Regtest")
15641565
group.add_argument("--simnet", action="store_true", dest="simnet", default=False, help="Use Simnet")
15651566
group.add_argument("--signet", action="store_true", dest="signet", default=False, help="Use Signet")
1566-
group.add_argument("-o", "--offline", action="store_true", dest="offline", default=False, help="Run offline")
1567-
group.add_argument("--rpcuser", dest="rpcuser", default=argparse.SUPPRESS, help="RPC user")
1568-
group.add_argument("--rpcpassword", dest="rpcpassword", default=argparse.SUPPRESS, help="RPC password")
1567+
group.add_argument("-o", "--offline", action="store_true", dest=SimpleConfig.NETWORK_OFFLINE.key(), default=None, help="Run offline")
1568+
group.add_argument("--rpcuser", dest=SimpleConfig.RPC_USERNAME.key(), default=argparse.SUPPRESS, help="RPC user")
1569+
group.add_argument("--rpcpassword", dest=SimpleConfig.RPC_PASSWORD.key(), default=argparse.SUPPRESS, help="RPC password")
15691570

15701571
def add_wallet_option(parser):
15711572
parser.add_argument("-w", "--wallet", dest="wallet_path", help="wallet path")
1572-
parser.add_argument("--forgetconfig", action="store_true", dest="forget_config", default=False, help="Forget config on exit")
1573+
parser.add_argument("--forgetconfig", action="store_true", dest=SimpleConfig.CONFIG_FORGET_CHANGES.key(), default=False, help="Forget config on exit")
15731574

15741575
def get_parser():
15751576
# create main parser
@@ -1582,11 +1583,11 @@ def get_parser():
15821583
# gui
15831584
parser_gui = subparsers.add_parser('gui', description="Run Electrum's Graphical User Interface.", help="Run GUI (default)")
15841585
parser_gui.add_argument("url", nargs='?', default=None, help="bitcoin URI (or bip70 file)")
1585-
parser_gui.add_argument("-g", "--gui", dest="gui", help="select graphical user interface", choices=['qt', 'kivy', 'text', 'stdio', 'qml'])
1586-
parser_gui.add_argument("-m", action="store_true", dest="hide_gui", default=False, help="hide GUI on startup")
1587-
parser_gui.add_argument("-L", "--lang", dest="language", default=None, help="default language used in GUI")
1586+
parser_gui.add_argument("-g", "--gui", dest=SimpleConfig.GUI_NAME.key(), help="select graphical user interface", choices=['qt', 'kivy', 'text', 'stdio', 'qml'])
1587+
parser_gui.add_argument("-m", action="store_true", dest=SimpleConfig.GUI_QT_HIDE_ON_STARTUP.key(), default=False, help="hide GUI on startup")
1588+
parser_gui.add_argument("-L", "--lang", dest=SimpleConfig.LOCALIZATION_LANGUAGE.key(), default=None, help="default language used in GUI")
15881589
parser_gui.add_argument("--daemon", action="store_true", dest="daemon", default=False, help="keep daemon running after GUI is closed")
1589-
parser_gui.add_argument("--nosegwit", action="store_true", dest="nosegwit", default=False, help="Do not create segwit wallets")
1590+
parser_gui.add_argument("--nosegwit", action="store_true", dest=SimpleConfig.WIZARD_DONT_CREATE_SEGWIT.key(), default=False, help="Do not create segwit wallets")
15901591
add_wallet_option(parser_gui)
15911592
add_network_options(parser_gui)
15921593
add_global_options(parser_gui)
@@ -1595,10 +1596,10 @@ def get_parser():
15951596
parser_daemon.add_argument("-d", "--detached", action="store_true", dest="detach", default=False, help="run daemon in detached mode")
15961597
# FIXME: all these options are rpc-server-side. The CLI client-side cannot use e.g. --rpcport,
15971598
# instead it reads it from the daemon lockfile.
1598-
parser_daemon.add_argument("--rpchost", dest="rpchost", default=argparse.SUPPRESS, help="RPC host")
1599-
parser_daemon.add_argument("--rpcport", dest="rpcport", type=int, default=argparse.SUPPRESS, help="RPC port")
1600-
parser_daemon.add_argument("--rpcsock", dest="rpcsock", default=None, help="what socket type to which to bind RPC daemon", choices=['unix', 'tcp', 'auto'])
1601-
parser_daemon.add_argument("--rpcsockpath", dest="rpcsockpath", help="where to place RPC file socket")
1599+
parser_daemon.add_argument("--rpchost", dest=SimpleConfig.RPC_HOST.key(), default=argparse.SUPPRESS, help="RPC host")
1600+
parser_daemon.add_argument("--rpcport", dest=SimpleConfig.RPC_PORT.key(), type=int, default=argparse.SUPPRESS, help="RPC port")
1601+
parser_daemon.add_argument("--rpcsock", dest=SimpleConfig.RPC_SOCKET_TYPE.key(), default=None, help="what socket type to which to bind RPC daemon", choices=['unix', 'tcp', 'auto'])
1602+
parser_daemon.add_argument("--rpcsockpath", dest=SimpleConfig.RPC_SOCKET_FILEPATH.key(), help="where to place RPC file socket")
16021603
add_network_options(parser_daemon)
16031604
add_global_options(parser_daemon)
16041605
# commands

electrum/contacts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def resolve(self, k):
9898

9999
def fetch_openalias(self, config):
100100
self.alias_info = None
101-
alias = config.get('alias')
101+
alias = config.OPENALIAS_ID
102102
if alias:
103103
alias = str(alias)
104104
def f():

electrum/daemon.py

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def get_rpcsock_defaultpath(config: SimpleConfig):
6969
return os.path.join(config.path, 'daemon_rpc_socket')
7070

7171
def get_rpcsock_default_type(config: SimpleConfig):
72-
if config.get('rpcport'):
72+
if config.RPC_PORT:
7373
return 'tcp'
7474
# Use unix domain sockets when available,
7575
# with the extra paranoia that in case windows "implements" them,
@@ -106,7 +106,7 @@ def get_file_descriptor(config: SimpleConfig):
106106

107107

108108

109-
def request(config: SimpleConfig, endpoint, args=(), timeout=60):
109+
def request(config: SimpleConfig, endpoint, args=(), timeout: Union[float, int] = 60):
110110
lockfile = get_lockfile(config)
111111
while True:
112112
create_time = None
@@ -152,12 +152,8 @@ async def request_coroutine(
152152

153153

154154
def get_rpc_credentials(config: SimpleConfig) -> Tuple[str, str]:
155-
rpc_user = config.get('rpcuser', None)
156-
rpc_password = config.get('rpcpassword', None)
157-
if rpc_user == '':
158-
rpc_user = None
159-
if rpc_password == '':
160-
rpc_password = None
155+
rpc_user = config.RPC_USERNAME or None
156+
rpc_password = config.RPC_PASSWORD or None
161157
if rpc_user is None or rpc_password is None:
162158
rpc_user = 'user'
163159
bits = 128
@@ -166,8 +162,8 @@ def get_rpc_credentials(config: SimpleConfig) -> Tuple[str, str]:
166162
pw_b64 = b64encode(
167163
pw_int.to_bytes(nbytes, 'big'), b'-_')
168164
rpc_password = to_string(pw_b64, 'ascii')
169-
config.set_key('rpcuser', rpc_user)
170-
config.set_key('rpcpassword', rpc_password, save=True)
165+
config.RPC_USERNAME = rpc_user
166+
config.RPC_PASSWORD = rpc_password
171167
return rpc_user, rpc_password
172168

173169

@@ -252,17 +248,17 @@ async def handle(self, request):
252248

253249
class CommandsServer(AuthenticatedServer):
254250

255-
def __init__(self, daemon, fd):
251+
def __init__(self, daemon: 'Daemon', fd):
256252
rpc_user, rpc_password = get_rpc_credentials(daemon.config)
257253
AuthenticatedServer.__init__(self, rpc_user, rpc_password)
258254
self.daemon = daemon
259255
self.fd = fd
260256
self.config = daemon.config
261-
sockettype = self.config.get('rpcsock', 'auto')
257+
sockettype = self.config.RPC_SOCKET_TYPE
262258
self.socktype = sockettype if sockettype != 'auto' else get_rpcsock_default_type(self.config)
263-
self.sockpath = self.config.get('rpcsockpath', get_rpcsock_defaultpath(self.config))
264-
self.host = self.config.get('rpchost', '127.0.0.1')
265-
self.port = self.config.get('rpcport', 0)
259+
self.sockpath = self.config.RPC_SOCKET_FILEPATH or get_rpcsock_defaultpath(self.config)
260+
self.host = self.config.RPC_HOST
261+
self.port = self.config.RPC_PORT
266262
self.app = web.Application()
267263
self.app.router.add_post("/", self.handle)
268264
self.register_method(self.ping)
@@ -348,12 +344,12 @@ async def run_cmdline(self, config_options):
348344

349345
class WatchTowerServer(AuthenticatedServer):
350346

351-
def __init__(self, network, netaddress):
347+
def __init__(self, network: 'Network', netaddress):
352348
self.addr = netaddress
353349
self.config = network.config
354350
self.network = network
355-
watchtower_user = self.config.get('watchtower_user', '')
356-
watchtower_password = self.config.get('watchtower_password', '')
351+
watchtower_user = self.config.WATCHTOWER_SERVER_USER or ""
352+
watchtower_password = self.config.WATCHTOWER_SERVER_PASSWORD or ""
357353
AuthenticatedServer.__init__(self, watchtower_user, watchtower_password)
358354
self.lnwatcher = network.local_watchtower
359355
self.app = web.Application()
@@ -403,7 +399,7 @@ def __init__(
403399
self.logger.warning("Ignoring parameter 'wallet_path' for daemon. "
404400
"Use the load_wallet command instead.")
405401
self.asyncio_loop = util.get_asyncio_loop()
406-
if not config.get('offline'):
402+
if not self.config.NETWORK_OFFLINE:
407403
self.network = Network(config, daemon=self)
408404
self.fx = FxThread(config=config)
409405
# path -> wallet; make sure path is standardized.
@@ -444,16 +440,16 @@ async def _run(self, jobs: Iterable = None):
444440

445441
def start_network(self):
446442
self.logger.info(f"starting network.")
447-
assert not self.config.get('offline')
443+
assert not self.config.NETWORK_OFFLINE
448444
assert self.network
449445
# server-side watchtower
450-
if watchtower_address := self.config.get_netaddress('watchtower_address'):
446+
if watchtower_address := self.config.get_netaddress(self.config.cv.WATCHTOWER_SERVER_ADDRESS):
451447
self.watchtower = WatchTowerServer(self.network, watchtower_address)
452448
asyncio.run_coroutine_threadsafe(self.taskgroup.spawn(self.watchtower.run), self.asyncio_loop)
453449

454450
self.network.start(jobs=[self.fx.run])
455451
# prepare lightning functionality, also load channel db early
456-
if self.config.get('use_gossip', False):
452+
if self.config.LIGHTNING_USE_GOSSIP:
457453
self.network.start_gossip()
458454

459455
def with_wallet_lock(func):
@@ -582,7 +578,7 @@ async def stop(self):
582578

583579
def run_gui(self, config: 'SimpleConfig', plugins: 'Plugins'):
584580
threading.current_thread().name = 'GUI'
585-
gui_name = config.get('gui', 'qt')
581+
gui_name = config.GUI_NAME
586582
if gui_name in ['lite', 'classic']:
587583
gui_name = 'qt'
588584
self.logger.info(f'launching GUI: {gui_name}')

0 commit comments

Comments
 (0)