Skip to content

Commit fa87be3

Browse files
authored
Bugfix: Miscellanous changes (#30)
* version v0.3.0 * No stacktrace for failed ping * black * tiny bit of more testing * fixing logger error issues * better progress for syncing
1 parent 3d54c74 commit fa87be3

File tree

12 files changed

+245
-147
lines changed

12 files changed

+245
-147
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .cli import entry_point
2-
import logging
2+
import logging
3+
34
if __name__ == "__main__":
45
entry_point()

src/cryptoadvance/spectrum/cli/__init__.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,24 @@
88

99
from .cli_server import server
1010

11+
1112
@click.group()
1213
@click.option("--debug", is_flag=True, help="Show debug information on errors.")
1314
def entry_point(debug):
1415
setup_logging(debug)
1516

17+
1618
entry_point.add_command(server)
1719

20+
1821
def setup_logging(debug=False):
19-
''' central and early configuring of logging see
20-
https://flask.palletsprojects.com/en/1.1.x/logging/#basic-configuration
21-
However the dictConfig doesn't work, so let's do something similiar programatically
22-
'''
22+
"""central and early configuring of logging see
23+
https://flask.palletsprojects.com/en/1.1.x/logging/#basic-configuration
24+
However the dictConfig doesn't work, so let's do something similiar programatically
25+
"""
2326
ch = logging.StreamHandler()
2427
ch.setLevel(logging.DEBUG)
25-
logger = logging.getLogger('cryptoadvance')
28+
logger = logging.getLogger("cryptoadvance")
2629
if debug:
2730
formatter = logging.Formatter("[%(levelname)7s] in %(module)15s: %(message)s")
2831
logger.setLevel(logging.DEBUG)
@@ -40,10 +43,10 @@ def setup_logging(debug=False):
4043
)
4144
logger.setLevel(logging.INFO)
4245
ch.setFormatter(formatter)
43-
46+
4447
for logger in [
45-
#app.logger,
46-
#logging.getLogger('sqlalchemy'),
48+
# app.logger,
49+
# logging.getLogger('sqlalchemy'),
4750
]:
4851
logger.setLevel(logging.DEBUG)
4952

src/cryptoadvance/spectrum/cli/cli_server.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55

66
logger = logging.getLogger(__name__)
77

8+
89
@click.group()
910
def cli():
1011
pass
1112

13+
1214
@cli.command()
13-
@click.option("--port", default="5000")
15+
@click.option("--port", default="5000")
1416
# set to 0.0.0.0 to make it available outside
1517
@click.option("--host", default="127.0.0.1")
1618
# for https:
@@ -21,13 +23,13 @@ def cli():
2123
default="cryptoadvance.spectrum.config.LocalElectrumConfig",
2224
help="A class which sets reasonable default values.",
2325
)
24-
def server( port, host, cert, key, config):
26+
def server(port, host, cert, key, config):
2527
# a hack as the pass_context is broken for some reason
2628
# we determine debug from what is set in the entry_point via the debug-level.
27-
debug=logger.isEnabledFor(logging.DEBUG)
29+
debug = logger.isEnabledFor(logging.DEBUG)
2830
logger.info(f"DEBUG is {debug}")
29-
31+
3032
app = create_app(config)
3133
init_app(app)
3234
logger.info("Starting up ...")
33-
app.run(debug=debug, port=app.config["PORT"], host=host)
35+
app.run(debug=debug, port=app.config["PORT"], host=host)
Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
''' A config module contains static configuration '''
1+
""" A config module contains static configuration """
22
import configparser
33
import datetime
44
import logging
@@ -10,58 +10,75 @@
1010

1111
logger = logging.getLogger(__name__)
1212

13+
1314
class BaseConfig(object):
1415
"""Base configuration."""
15-
SECRET_KEY='development key'
16-
USERNAME='admin'
17-
HOST="127.0.0.1"
18-
PORT=8081
19-
SPECTRUM_DATADIR="data" # used for sqlite but also for txs-cache
16+
17+
SECRET_KEY = "development key"
18+
USERNAME = "admin"
19+
HOST = "127.0.0.1"
20+
PORT = 8081
21+
SPECTRUM_DATADIR = "data" # used for sqlite but also for txs-cache
22+
2023

2124
# Level 1: How does persistence work?
2225
# Convention: BlaConfig
2326

27+
2428
class LiteConfig(BaseConfig):
25-
DATABASE=os.path.abspath(os.path.join(BaseConfig.SPECTRUM_DATADIR, "wallets.sqlite"))
26-
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + DATABASE
27-
SQLALCHEMY_TRACK_MODIFICATIONS=False
29+
DATABASE = os.path.abspath(
30+
os.path.join(BaseConfig.SPECTRUM_DATADIR, "wallets.sqlite")
31+
)
32+
SQLALCHEMY_DATABASE_URI = "sqlite:///" + DATABASE
33+
SQLALCHEMY_TRACK_MODIFICATIONS = False
34+
2835

2936
class PostgresConfig(BaseConfig):
3037
"""Development configuration with Postgres."""
38+
3139
DEBUG = True
32-
DB_USERNAME = os.environ.get('DB_USER', default='spectrum')
33-
DB_PASSWORD = os.environ.get('DB_PASSWORD')
34-
DB_HOST = os.environ.get('DB_HOST', default='127.0.0.1') # will be overridden in docker-compose, but good for dev
35-
DB_PORT = os.environ.get('DB_PORT', default='5432')
36-
DB_DATABASE = os.environ.get('DB_DATABASE', default='spectrum')
40+
DB_USERNAME = os.environ.get("DB_USER", default="spectrum")
41+
DB_PASSWORD = os.environ.get("DB_PASSWORD")
42+
DB_HOST = os.environ.get(
43+
"DB_HOST", default="127.0.0.1"
44+
) # will be overridden in docker-compose, but good for dev
45+
DB_PORT = os.environ.get("DB_PORT", default="5432")
46+
DB_DATABASE = os.environ.get("DB_DATABASE", default="spectrum")
3747
SQL_ALCHEMY_TRACK_MODIFICATIONS = False
38-
SQLALCHEMY_DATABASE_URI = f'postgresql+psycopg2://{DB_HOST}:{DB_PORT}/{DB_DATABASE}?user={DB_USERNAME}&password={DB_PASSWORD}' # &ssl=true
48+
SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://{DB_HOST}:{DB_PORT}/{DB_DATABASE}?user={DB_USERNAME}&password={DB_PASSWORD}" # &ssl=true
49+
3950

4051
# Level 2: Where do we get an electrum from ?
4152
# Convention: Prefix a level 1 config with the electrum solution
4253
class NigiriLocalElectrumLiteConfig(LiteConfig):
43-
ELECTRUM_HOST="127.0.0.1"
44-
ELECTRUM_PORT=50000
45-
ELECTRUM_USES_SSL=_get_bool_env_var('ELECTRUM_USES_SSL', default="false") # Nigiri doesn't use SSL
54+
ELECTRUM_HOST = "127.0.0.1"
55+
ELECTRUM_PORT = 50000
56+
ELECTRUM_USES_SSL = _get_bool_env_var(
57+
"ELECTRUM_USES_SSL", default="false"
58+
) # Nigiri doesn't use SSL
59+
4660

4761
class EmzyElectrumLiteConfig(LiteConfig):
48-
ELECTRUM_HOST=os.environ.get('ELECTRUM_HOST', default='electrum.emzy.de')
49-
ELECTRUM_PORT=int(os.environ.get('ELECTRUM_PORT', default='50002'))
50-
ELECTRUM_USES_SSL=_get_bool_env_var('ELECTRUM_USES_SSL', default="true")
62+
ELECTRUM_HOST = os.environ.get("ELECTRUM_HOST", default="electrum.emzy.de")
63+
ELECTRUM_PORT = int(os.environ.get("ELECTRUM_PORT", default="50002"))
64+
ELECTRUM_USES_SSL = _get_bool_env_var("ELECTRUM_USES_SSL", default="true")
65+
5166

5267
class EmzyElectrumPostgresConfig(PostgresConfig):
53-
ELECTRUM_HOST=os.environ.get('ELECTRUM_HOST', default='electrum.emzy.de')
54-
ELECTRUM_PORT=int(os.environ.get('ELECTRUM_PORT', default='50002'))
55-
ELECTRUM_USES_SSL=_get_bool_env_var('ELECTRUM_USES_SSL', default="true")
68+
ELECTRUM_HOST = os.environ.get("ELECTRUM_HOST", default="electrum.emzy.de")
69+
ELECTRUM_PORT = int(os.environ.get("ELECTRUM_PORT", default="50002"))
70+
ELECTRUM_USES_SSL = _get_bool_env_var("ELECTRUM_USES_SSL", default="true")
71+
5672

5773
# Level 2: Back to the problem-Space.
5874
# Convention: ProblemConfig where problem is usually one of Test/Production or so
5975

76+
6077
class TestConfig(NigiriLocalElectrumLiteConfig):
6178
pass
6279

63-
class ProductionConfig(EmzyElectrumPostgresConfig):
64-
''' Not sure whether we're production ready, though '''
65-
SECRET_KEY = os.getenv("SECRET_KEY", secrets.token_urlsafe(16))
6680

81+
class ProductionConfig(EmzyElectrumPostgresConfig):
82+
"""Not sure whether we're production ready, though"""
6783

84+
SECRET_KEY = os.getenv("SECRET_KEY", secrets.token_urlsafe(16))

src/cryptoadvance/spectrum/db.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
'''
1+
"""
22
[![](https://mermaid.ink/img/pako:eNp9VMtuwjAQ_BXLpz7gB3Ks4NBTD1CVA1K02Eti4diRHxQU5d_rPAiJA80pnhl7Z8ebVJRpjjShTIK1KwGZgWKvSHh-QEp05G25JCu0zIjSadNR93VLb9rFbNcT-Hu7--rAThCBI-V2N9M1UAe2hnt11UGEvG-cESojCgocsIPWkpRGnMFhesKrTVHBQSKPd1mcY2Wo8qsNTy3Ivpd6bOAeRTUtCMyJc2RCKIdGgYyL8CjfwAQpUXhxqVAcLw8Kd6FUkw0j7air0TXEaA42nzEu5DSAHyL7DCczrY7CFKN8esKrOQWcG7T25XWwPTbeXPXUtrsIPgHO2rsJkKPIchfXhkJ75aYRS81ONyv1jeqesYnt7h8LfRCH5qxJQs-ttFon4qkzWEpg2EzbQKyVLwgLGWfaXJ-3_bjHgDbKI_bn1XRBCzQFCB4-4ranPXU5BiM0Ca8cj-DD4NK9aqS-5KHwmoswajQ5grS4oOCd3lwVo4kzHm-i_l_Qq-o_ZgxJhg)](https://mermaid-js.github.io/mermaid-live-editor/edit#pako:eNp9VMtuwjAQ_BXLpz7gB3Ks4NBTD1CVA1K02Eti4diRHxQU5d_rPAiJA80pnhl7Z8ebVJRpjjShTIK1KwGZgWKvSHh-QEp05G25JCu0zIjSadNR93VLb9rFbNcT-Hu7--rAThCBI-V2N9M1UAe2hnt11UGEvG-cESojCgocsIPWkpRGnMFhesKrTVHBQSKPd1mcY2Wo8qsNTy3Ivpd6bOAeRTUtCMyJc2RCKIdGgYyL8CjfwAQpUXhxqVAcLw8Kd6FUkw0j7air0TXEaA42nzEu5DSAHyL7DCczrY7CFKN8esKrOQWcG7T25XWwPTbeXPXUtrsIPgHO2rsJkKPIchfXhkJ75aYRS81ONyv1jeqesYnt7h8LfRCH5qxJQs-ttFon4qkzWEpg2EzbQKyVLwgLGWfaXJ-3_bjHgDbKI_bn1XRBCzQFCB4-4ranPXU5BiM0Ca8cj-DD4NK9aqS-5KHwmoswajQ5grS4oOCd3lwVo4kzHm-i_l_Qq-o_ZgxJhg)
33
44
5-
'''
5+
"""
66

77
from flask_sqlalchemy import SQLAlchemy
88
from embit.descriptor import Descriptor as EmbitDescriptor
@@ -20,17 +20,19 @@
2020
class NoNameMeta(BindMetaMixin, DeclarativeMeta):
2121
pass
2222

23+
2324
CustomModel = declarative_base(cls=Model, metaclass=NoNameMeta, name="Model")
2425

2526
db = SQLAlchemy(model_class=CustomModel)
26-
#db = SQLAlchemy()
27+
# db = SQLAlchemy()
2728

2829

2930
class SpectrumModel(db.Model):
3031
__abstract__ = True
32+
3133
@declared_attr
3234
def __tablename__(cls):
33-
return 'spectrum_' + snake_case2camelcase(cls.__name__)
35+
return "spectrum_" + snake_case2camelcase(cls.__name__)
3436

3537

3638
class TxCategory(Enum):
@@ -68,8 +70,11 @@ def get_keypool(self, internal=False):
6870

6971
class Descriptor(SpectrumModel):
7072
"""Descriptors tracked by the wallet"""
73+
7174
id = db.Column(db.Integer, primary_key=True)
72-
wallet_id = db.Column(db.Integer, db.ForeignKey(f"{Wallet.__tablename__}.id"), nullable=False)
75+
wallet_id = db.Column(
76+
db.Integer, db.ForeignKey(f"{Wallet.__tablename__}.id"), nullable=False
77+
)
7378
wallet = db.relationship("Wallet", backref=db.backref("descriptors", lazy=True))
7479
# if we should use this descriptor for new addresses
7580
active = db.Column(db.Boolean, default=True)
@@ -109,11 +114,16 @@ def get_descriptor(self, index=None):
109114
# We store script pubkeys instead of addresses as database is chain-agnostic
110115
class Script(SpectrumModel):
111116
id = db.Column(db.Integer, primary_key=True)
112-
wallet_id = db.Column(db.Integer, db.ForeignKey(f"{Wallet.__tablename__}.id"), nullable=False)
117+
wallet_id = db.Column(
118+
db.Integer, db.ForeignKey(f"{Wallet.__tablename__}.id"), nullable=False
119+
)
113120
wallet = db.relationship("Wallet", backref=db.backref("scripts", lazy=True))
114121
# this must be nullable as we may need to label external scripts
115122
descriptor_id = db.Column(
116-
db.Integer, db.ForeignKey(f"{Descriptor.__tablename__}.id"), nullable=True, default=None
123+
db.Integer,
124+
db.ForeignKey(f"{Descriptor.__tablename__}.id"),
125+
nullable=True,
126+
default=None,
117127
)
118128
descriptor = db.relationship("Descriptor", backref=db.backref("scripts", lazy=True))
119129
# derivation index if it's our address
@@ -138,7 +148,7 @@ def script_pubkey(self):
138148
return EmbitScript(bytes.fromhex(self.script))
139149

140150

141-
class UTXO( SpectrumModel):
151+
class UTXO(SpectrumModel):
142152
id = db.Column(db.Integer, primary_key=True)
143153
txid = db.Column(db.String(64))
144154
vout = db.Column(db.Integer)
@@ -150,11 +160,13 @@ class UTXO( SpectrumModel):
150160
# refs
151161
script_id = db.Column(db.Integer, db.ForeignKey(f"{Script.__tablename__}.id"))
152162
script = db.relationship("Script", backref=db.backref("utxos", lazy=True))
153-
wallet_id = db.Column(db.Integer, db.ForeignKey(f"{Wallet.__tablename__}.id"), nullable=False)
163+
wallet_id = db.Column(
164+
db.Integer, db.ForeignKey(f"{Wallet.__tablename__}.id"), nullable=False
165+
)
154166
wallet = db.relationship("Wallet", backref=db.backref("utxos", lazy=True))
155167

156168

157-
class Tx( SpectrumModel):
169+
class Tx(SpectrumModel):
158170
id = db.Column(db.Integer, primary_key=True)
159171
txid = db.Column(db.String(64))
160172
blockhash = db.Column(db.String(64), default=None)
@@ -168,7 +180,9 @@ class Tx( SpectrumModel):
168180
# refs
169181
script_id = db.Column(db.Integer, db.ForeignKey(f"{Script.__tablename__}.id"))
170182
script = db.relationship("Script", backref=db.backref("txs", lazy=True))
171-
wallet_id = db.Column(db.Integer, db.ForeignKey(f"{Wallet.__tablename__}.id"), nullable=False)
183+
wallet_id = db.Column(
184+
db.Integer, db.ForeignKey(f"{Wallet.__tablename__}.id"), nullable=False
185+
)
172186
wallet = db.relationship("Wallet", backref=db.backref("txs", lazy=True))
173187

174188
def to_dict(self, blockheight, network):

src/cryptoadvance/spectrum/elsock.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@
1212

1313
logger = logging.getLogger(__name__)
1414

15+
1516
class ElectrumSocket:
16-
def __init__(self, host="127.0.0.1", port=50001, use_ssl=False, callback=None, timeout=10):
17+
def __init__(
18+
self, host="127.0.0.1", port=50001, use_ssl=False, callback=None, timeout=10
19+
):
1720
logger.info(f"Initializing ElectrumSocket with {host}:{port} (ssl: {ssl})")
1821
self._host = host
1922
self._port = port
@@ -55,7 +58,7 @@ def write_loop(self):
5558
req = self._requests.pop()
5659
self._socket.sendall(json.dumps(req).encode() + b"\n")
5760
except Exception as e:
58-
logger.error("Error in write", e)
61+
logger.error(f"Error in write: {e}")
5962
handle_exception(e)
6063
time.sleep(0.01)
6164

@@ -68,10 +71,11 @@ def ping_loop(self):
6871
tries = 0
6972
except Exception as e:
7073
tries = tries + 1
71-
logger.error("Error in ping", e)
74+
logger.error(f"Error in ping {e}")
7275
if tries > 10:
73-
logger.fatal("Ping failure. I guess we lost the connection. What to do now?!")
74-
handle_exception(e)
76+
logger.fatal(
77+
"Ping failure. I guess we lost the connection. What to do now?!"
78+
)
7579

7680
def recv_loop(self):
7781
while self.running:
@@ -85,7 +89,7 @@ def recv_loop(self):
8589
def recv(self):
8690
while self.running:
8791
data = self._socket.recv(2048)
88-
while not data.endswith(b"\n"): # b"\n" is the end of the message
92+
while not data.endswith(b"\n"): # b"\n" is the end of the message
8993
data += self._socket.recv(2048)
9094
# data looks like this:
9195
# b'{"jsonrpc": "2.0", "result": {"hex": "...", "height": 761086}, "id": 2210736436}\n'
@@ -111,7 +115,7 @@ def notify(self, data):
111115
try:
112116
self._callback(data)
113117
except Exception as e:
114-
logger.error("Error in callback:", e)
118+
logger.error(f"Error in callback: {e}")
115119
handle_exception(e)
116120
else:
117121
logger.debug("Notification:", data)
@@ -121,18 +125,19 @@ def call(self, method, params=[]):
121125
obj = {"jsonrpc": "2.0", "method": method, "params": params, "id": uid}
122126
self._requests.append(obj)
123127
start = time.time()
124-
128+
125129
while uid not in self._results: # wait for response
126-
#time.sleep(1)
130+
# time.sleep(1)
127131
time.sleep(0.01)
128132
if time.time() - start > self._timeout:
129-
raise SpectrumException(f"Timeout ({self._timeout} seconds) waiting for {method} on {self._socket}")
133+
raise SpectrumException(
134+
f"Timeout ({self._timeout} seconds) waiting for {method} on {self._socket}"
135+
)
130136
res = self._results.pop(uid)
131137
if "error" in res:
132138
raise ValueError(res["error"])
133139
if "result" in res:
134140
return res["result"]
135-
136141

137142
def wait(self):
138143
self._waiting = True
@@ -141,12 +146,9 @@ def wait(self):
141146

142147
def ping(self):
143148
start = time.time()
144-
self.call("server.ping") # result None
149+
self.call("server.ping") # result None
145150
return time.time() - start
146151

147-
148152
def __del__(self):
149153
logger.info("Closing socket ...")
150154
self._socket.close()
151-
152-

0 commit comments

Comments
 (0)