Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v10.6.0 #2590

Merged
merged 88 commits into from
Oct 25, 2024
Merged

v10.6.0 #2590

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
7d97508
Too Much Exception Handling!
adamkrellenstein Oct 20, 2024
973b05e
Working
adamkrellenstein Oct 20, 2024
db15c2f
Significant Cleanup to Thread Handling in API Server
adamkrellenstein Oct 20, 2024
6cd8a8a
Tweaks
adamkrellenstein Oct 20, 2024
7f54524
Fix Debug Logging of Config
adamkrellenstein Oct 20, 2024
b5db5dd
Missing Import
adamkrellenstein Oct 20, 2024
7c9ae4c
Typo
adamkrellenstein Oct 20, 2024
ea3c3c9
Logging of Threading
adamkrellenstein Oct 20, 2024
e45924a
Logging of Threading
adamkrellenstein Oct 20, 2024
b017f93
Thread-Safe DB Closing
adamkrellenstein Oct 20, 2024
7d4b0d1
Typo and Tweak
adamkrellenstein Oct 20, 2024
ea3bc9e
More Tweaks to Threading and Multiprocessing
adamkrellenstein Oct 20, 2024
babb499
Main Event Loop?!?!
adamkrellenstein Oct 20, 2024
3a3fc10
Keyboard Interrupt
adamkrellenstein Oct 20, 2024
c93d2fe
Telemetry Error Message Level
adamkrellenstein Oct 21, 2024
e194639
Ruff
adamkrellenstein Oct 21, 2024
2a572f6
Bug in API Watcher
adamkrellenstein Oct 21, 2024
43688a0
DB Connection Closing
adamkrellenstein Oct 21, 2024
70d4b37
Remove Traceback
adamkrellenstein Oct 21, 2024
e319603
Signal to Main Process when API Server has Stopped
adamkrellenstein Oct 21, 2024
02e80f4
RSFetcher Initialization
adamkrellenstein Oct 21, 2024
3f07a92
RocksDB Lockfile
adamkrellenstein Oct 21, 2024
a661f54
RocksDB Lockfile Fix
adamkrellenstein Oct 21, 2024
4aedca1
Ruff
adamkrellenstein Oct 21, 2024
a370a23
Return all balances
Ouziel Oct 22, 2024
2d2a8b6
rename functions
Ouziel Oct 22, 2024
25e214f
update fixtures
Ouziel Oct 22, 2024
bd0de06
Release Notes for v10.5.1
adamkrellenstein Oct 22, 2024
9a99b70
RSFetcher Lockfile Edge Case
adamkrellenstein Oct 22, 2024
5d0277d
Merge branch 'develop' into multi-threading-cleanup
adamkrellenstein Oct 22, 2024
359ade5
Typo
adamkrellenstein Oct 22, 2024
e9523fc
Fix SQLite3 Logs??
adamkrellenstein Oct 23, 2024
eb5727f
Fix SQLite3 Logs!
adamkrellenstein Oct 23, 2024
4fa5827
Merge pull request #2542 from CounterpartyXCP/fixbalances
adamkrellenstein Oct 23, 2024
0f3b237
Merge branch 'develop' into multi-threading-cleanup
adamkrellenstein Oct 23, 2024
fae1e1a
Fix Startup
adamkrellenstein Oct 23, 2024
f1b7748
Locking for Logging
adamkrellenstein Oct 23, 2024
12db8f1
Tweak Log Messages for RSFetcher Lockfile
adamkrellenstein Oct 23, 2024
403c46d
Refactor RS Fetcher Threading
adamkrellenstein Oct 23, 2024
8e8cf8e
Cleaner Telemetry Shutdown
adamkrellenstein Oct 23, 2024
db494bf
Ruff
adamkrellenstein Oct 23, 2024
1566f88
API fixes and tweaks
Ouziel Oct 23, 2024
339bfb4
Add asset_events filter to issuances routes
Ouziel Oct 23, 2024
2a77e66
add --bootstrap-url support to start command
Ouziel Oct 23, 2024
ee6e250
Correctly catch invalid pubkey in compose API
Ouziel Oct 23, 2024
05cb8ad
Add route /v2/compose/attach/estimatexcpfees
Ouziel Oct 23, 2024
d1879a9
Raise an error on fairmint compose when the fairminter is free and th…
Ouziel Oct 23, 2024
f45d9cc
Tweak reparse message
Ouziel Oct 23, 2024
e667a0b
Don't run reparse if unnecessary
Ouziel Oct 23, 2024
b392508
Merge pull request #2558 from CounterpartyXCP/fixapi
ouziel-slama Oct 23, 2024
39739b0
Fix 'message_data' when retrieving information about fairminter or fa…
Ouziel Oct 23, 2024
71e2ae7
Ruff
adamkrellenstein Oct 23, 2024
f9edaa5
Merge pull request #2566 from CounterpartyXCP/fixapi
ouziel-slama Oct 23, 2024
5af260f
fix tests
Ouziel Oct 23, 2024
0a0a60f
Merge branch 'develop' into multi-threading-cleanup
Ouziel Oct 23, 2024
5fb160f
update release notes
Ouziel Oct 23, 2024
f3b9bcc
Fix regtest
Ouziel Oct 23, 2024
287f12f
Fix regtest
Ouziel Oct 23, 2024
15bab06
Merge pull request #2521 from CounterpartyXCP/multi-threading-cleanup
ouziel-slama Oct 23, 2024
ce56065
Accept only one valid dispenser
Ouziel Oct 24, 2024
b13c749
Fix asset_events filter
Ouziel Oct 24, 2024
d1a97c3
Merge pull request #2574 from CounterpartyXCP/fixapi
ouziel-slama Oct 24, 2024
97152bf
Fix Lock File Not Found Error
Ouziel Oct 24, 2024
9eae661
Add regtest test
Ouziel Oct 24, 2024
2bde51b
update release notes
Ouziel Oct 24, 2024
bac53eb
Merge branch 'develop' into dispense
Ouziel Oct 24, 2024
d4fded7
around one week from now
Ouziel Oct 24, 2024
e4d8cf1
update release notes
Ouziel Oct 24, 2024
abf64c2
Merge pull request #2576 from CounterpartyXCP/fixlock
ouziel-slama Oct 24, 2024
de6c612
Merge branch 'develop' into dispense
Ouziel Oct 24, 2024
11a32b7
update release notes
Ouziel Oct 24, 2024
ef82d8a
Release Notes for v10.6.0
adamkrellenstein Oct 24, 2024
cf1f80d
Merge pull request #2575 from CounterpartyXCP/fixcomposedispense
adamkrellenstein Oct 24, 2024
198bd74
Add regtest scenario for chained utxo move
Ouziel Oct 25, 2024
f0b999b
Don't update utxos cache on mempool transactions
Ouziel Oct 25, 2024
59a9c43
Update utxos balances cache before parsing tx
Ouziel Oct 25, 2024
18c6d31
clean debug
Ouziel Oct 25, 2024
299f88f
update fixtures, blueprint, release notes and config
Ouziel Oct 25, 2024
79dee84
Bump Version; Add checkpoint
Ouziel Oct 25, 2024
e858d42
Merge pull request #2585 from CounterpartyXCP/utxomove
ouziel-slama Oct 25, 2024
77acccb
Merge pull request #2588 from CounterpartyXCP/bump
ouziel-slama Oct 25, 2024
ef7df53
Add get_asset and give_asset arguments for Get Orders endpoint
Ouziel Oct 25, 2024
7a82cb5
Merge pull request #2592 from CounterpartyXCP/giveasset
ouziel-slama Oct 25, 2024
180797b
Tweak Release Notes for v10.6.0
adamkrellenstein Oct 25, 2024
410c196
Fix --bootstrap-url flag with start command
Ouziel Oct 25, 2024
370ed99
Move Protocol Change Back 100 Blocks
adamkrellenstein Oct 25, 2024
647aa69
Merge pull request #2593 from CounterpartyXCP/fix
ouziel-slama Oct 25, 2024
95e60c0
Merge pull request #2594 from CounterpartyXCP/master
ouziel-slama Oct 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5,758 changes: 3,043 additions & 2,715 deletions apiary.apib

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions counterparty-core/counterpartycore/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ def float_range_checker(arg):
"help": "number of threads per worker for the Gunicorn WSGI server (if enabled)",
},
],
[("--bootstrap-url",), {"type": str, "help": "the URL of the bootstrap snapshot to use"}],
]


Expand Down Expand Up @@ -457,9 +458,6 @@ def main():
parser_bootstrap = subparsers.add_parser(
"bootstrap", help="bootstrap database with hosted snapshot"
)
parser_bootstrap.add_argument(
"--bootstrap-url", help="the URL of the bootstrap snapshot to use"
)
setup.add_config_arguments(parser_bootstrap, CONFIG_ARGS, configfile)

parser_checkdb = subparsers.add_parser("check-db", help="do an integrity check on the database")
Expand Down
90 changes: 55 additions & 35 deletions counterparty-core/counterpartycore/lib/api/api_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import logging
import multiprocessing
import os
import threading
import time
from collections import OrderedDict
from multiprocessing import Process, Value
from threading import Thread

import flask
import requests
Expand Down Expand Up @@ -392,74 +392,94 @@
return app


def run_api_server(args, interrupted_value, server_ready_value):
def run_api_server(args, server_ready_value, stop_event):

Check warning

Code scanning / pylint

Unused argument 'stop_event'. Warning

Unused argument 'stop_event'.
logger.info("Starting API Server process...")

# Initialize Sentry, logging, config, etc.
sentry.init()
# Initialise log and config
server.initialise_log_and_config(argparse.Namespace(**args))

watcher = api_watcher.APIWatcher()
watcher.start()

logger.info("Starting API Server...")
app = init_flask_app()

wsgi_server = None
parent_checker = None

try:
# Init the HTTP Server.
wsgi_server = wsgi.WSGIApplication(app, args=args)
parent_checker = ParentProcessChecker(interrupted_value, wsgi_server)
logger.info("Starting Parent Process Checker thread...")
parent_checker = ParentProcessChecker(wsgi_server)
parent_checker.start()

wsgi_server = wsgi.WSGIApplication(app, args=args)

app.app_context().push()
# Run app server (blocking)
server_ready_value.value = 1

wsgi_server.run()
except KeyboardInterrupt:
logger.trace("Keyboard Interrupt!")

except Exception as e:
logger.error("Exception in API Server process!")
raise e

finally:
logger.trace("Shutting down API Server...")

watcher.stop()
watcher.join()
if watcher is not None:
watcher.stop()
watcher.join()

if wsgi_server is not None:
logger.trace("Stopping WSGI Server thread...")
wsgi_server.stop()

if parent_checker is not None:
logger.trace("Stopping Parent Process Checker thread...")
parent_checker.stop()
parent_checker.join()

wsgi_server.stop()
parent_checker.join()
logger.trace("Closing API DB Connection Pool...")
APIDBConnectionPool().close()


# This thread is used for the following two reasons:
# 1. `docker-compose stop` does not send a SIGTERM to the child processes (in this case the API v2 process)
# 2. `process.terminate()` does not trigger a `KeyboardInterrupt` or execute the `finally` block.
class ParentProcessChecker(Thread):
def __init__(self, interruped_value, wsgi_server):
class ParentProcessChecker(threading.Thread):
def __init__(self, wsgi_server):
super().__init__()
self.interruped_value = interruped_value
self.daemon = True
self.wsgi_server = wsgi_server
self._stop_event = threading.Event()

def run(self):
parent_pid = os.getppid()
try:
while True:
if self.interruped_value.value == 0:
time.sleep(0.01)
else:
logger.trace("Parent process is dead. Exiting...")
while not self._stop_event.is_set():
if os.getppid() != parent_pid:
logger.debug("Parent process is dead. Exiting...")
self.wsgi_server.stop()
break
self.wsgi_server.stop()
time.sleep(1)
except KeyboardInterrupt:
pass

def stop(self):
self._stop_event.set()


class APIServer(object):
def __init__(self):
self.process = None
self.interrupted = Value("I", 0)
self.server_ready_value = Value("I", 0)
self.stop_event = multiprocessing.Event()

def start(self, args):
if self.process is not None:
raise Exception("API Server is already running")
self.process = Process(
target=run_api_server, args=(vars(args), self.interrupted, self.server_ready_value)
target=run_api_server, args=(vars(args), self.server_ready_value, self.stop_event)
)
self.process.start()
return self.process
Expand All @@ -468,14 +488,14 @@
return self.server_ready_value.value == 1

def stop(self):
logger.info("Stopping API Server...")
self.interrupted.value = 1 # stop the thread
waiting_start_time = time.time()
while self.process.is_alive():
time.sleep(1)
logger.trace("Waiting for API Server to stop...")
if time.time() - waiting_start_time > 2:
logger.error("API Server did not stop in time. Terminating...")
logger.info("Stopping API Server process...")
if self.process.is_alive():
self.process.terminate()
self.process.join(timeout=2)
if self.process.is_alive():
logger.error("API Server process did not stop in time. Terminating forcefully...")
self.process.kill()
break
logger.trace("API Server stopped.")
logger.info("API Server process stopped.")

def has_stopped(self):
return self.stop_event.is_set()
83 changes: 42 additions & 41 deletions counterparty-core/counterpartycore/lib/api/api_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,59 +448,60 @@
"""Perform regular checks on the state of the backend and the database."""

def __init__(self):
self.last_database_check = 0
threading.Thread.__init__(self)
self.last_database_check = 0
self.stop_event = threading.Event()
self.stopping = False
self.stopped = False
self.db = None

def stop(self):
logger.info("Stopping API Status Poller...")
self.stopping = True
if self.db is not None:
self.db.close()
self.db = None
logger.info("Stopping API v1 Status Poller thread...")
self.stop_event.set()
self.join()
logger.info("API v1 Status Poller thread stopped.")

def run(self):
logger.debug("Starting API Status Poller...")
logger.info("Starting v1 API Status Poller thread...")
global CURRENT_API_STATUS_CODE, CURRENT_API_STATUS_RESPONSE_JSON # noqa: PLW0603
self.db = database.get_db_connection(config.API_DATABASE, read_only=True, check_wal=False)

interval_if_ready = 5 * 60 # 5 minutes
interval_if_not_ready = 60 # 1 minutes
interval_if_not_ready = 60 # 1 minute
interval = interval_if_not_ready

while not self.stopping: # noqa: E712
try:
# Check that backend is running, communicable, and caught up with the blockchain.
# Check that the database has caught up with bitcoind.
if (
time.time() - self.last_database_check > interval
): # Ten minutes since last check.
self.last_database_check = time.time()
if not config.FORCE and self.db is not None:
code = 11
check_backend_state()
code = 12
api_util.check_last_parsed_block(self.db, backend.bitcoind.getblockcount())
interval = interval_if_ready
except (BackendError, exceptions.DatabaseError) as e:
interval = interval_if_not_ready
exception_name = e.__class__.__name__
exception_text = str(e)
logger.debug("API Status Poller: %s", exception_text)
jsonrpc_response = jsonrpc.exceptions.JSONRPCServerError(
message=exception_name, data=exception_text
)
CURRENT_API_STATUS_CODE = code
CURRENT_API_STATUS_RESPONSE_JSON = jsonrpc_response.json.encode()
else:
CURRENT_API_STATUS_CODE = None
CURRENT_API_STATUS_RESPONSE_JSON = None
if not self.stopping:
time.sleep(0.5) # sleep for 0.5 seconds
try:
while not self.stop_event.is_set():
try:
# Check that backend is running, communicable, and caught up with the blockchain.
# Check that the database has caught up with bitcoind.
if time.time() - self.last_database_check > interval:
self.last_database_check = time.time()
if not config.FORCE and self.db is not None:
code = 11
check_backend_state()
code = 12
api_util.check_last_parsed_block(
self.db, backend.bitcoind.getblockcount()
)
interval = interval_if_ready
except (BackendError, exceptions.DatabaseError) as e:
interval = interval_if_not_ready
exception_name = e.__class__.__name__
exception_text = str(e)
logger.debug("API Status Poller: %s", exception_text)
jsonrpc_response = jsonrpc.exceptions.JSONRPCServerError(
message=exception_name, data=exception_text
)
CURRENT_API_STATUS_CODE = code

Check warning

Code scanning / pylint

Using variable 'code' before assignment. Warning

Using variable 'code' before assignment.
CURRENT_API_STATUS_RESPONSE_JSON = jsonrpc_response.json.encode()
else:
CURRENT_API_STATUS_CODE = None
CURRENT_API_STATUS_RESPONSE_JSON = None
self.stop_event.wait(timeout=0.5)
finally:
if self.db is not None:
self.db.close()
self.db = None
logger.info("API v1 Status Poller thread stopped.")


class APIServer(threading.Thread):
Expand All @@ -515,15 +516,15 @@
sentry.init()

def stop(self):
logger.info("Stopping API Server v1...")
logger.info("Stopping API Server v1 thread...")
if self.connection_pool:
self.connection_pool.close()
if self.server:
self.server.shutdown()
self.join()

def run(self):
logger.info("Starting API Server v1...")
logger.info("Starting API Server v1 thread...")
app = flask.Flask(__name__)
auth = HTTPBasicAuth()

Expand Down
Loading
Loading