diff --git a/apiary.apib b/apiary.apib index ffe6e79b0b..f574d66555 100644 --- a/apiary.apib +++ b/apiary.apib @@ -1437,7 +1437,7 @@ Returns server information and the list of documented routes in JSON format. "result": { "server_ready": true, "network": "mainnet", - "version": "10.5.0-alpha.1", + "version": "10.5.0-alpha.2", "backend_height": 850214, "counterparty_height": 850214, "documentation": "https://counterpartycore.docs.apiary.io/", diff --git a/counterparty-core/counterpartycore/cli.py b/counterparty-core/counterpartycore/cli.py index f98399bc15..5164c8460f 100755 --- a/counterparty-core/counterpartycore/cli.py +++ b/counterparty-core/counterpartycore/cli.py @@ -255,6 +255,14 @@ def float_range_checker(arg): ("--no-log-files",), {"action": "store_true", "default": False, "help": "Don't write log files"}, ], + [ + ("--max-log-file-size",), + {"type": int, "default": 40 * 1024 * 1024, "help": "maximum size of log files in bytes"}, + ], + [ + ("--max-log-file-rotations",), + {"type": int, "default": 20, "help": "maximum number of log file rotations"}, + ], [ ("--utxo-locks-max-addresses",), { diff --git a/counterparty-core/counterpartycore/lib/api/migrations/0012.add_index_on_event_index.sql b/counterparty-core/counterpartycore/lib/api/migrations/0012.add_index_on_event_index.sql new file mode 100644 index 0000000000..4ffdf4a259 --- /dev/null +++ b/counterparty-core/counterpartycore/lib/api/migrations/0012.add_index_on_event_index.sql @@ -0,0 +1,3 @@ +-- depends: 0011.fix_close_block_index + +CREATE INDEX IF NOT EXISTS address_events_event_index_idx ON address_events (event_index); \ No newline at end of file diff --git a/counterparty-core/counterpartycore/lib/config.py b/counterparty-core/counterpartycore/lib/config.py index 113f9d2aab..653615d03e 100644 --- a/counterparty-core/counterpartycore/lib/config.py +++ b/counterparty-core/counterpartycore/lib/config.py @@ -5,7 +5,7 @@ # Semantic Version -__version__ = "10.5.0-alpha.1" # for hatch +__version__ = "10.5.0-alpha.2" # for hatch VERSION_STRING = __version__ version = VERSION_STRING.split("-")[0].split(".") VERSION_MAJOR = int(version[0]) diff --git a/counterparty-core/counterpartycore/lib/database.py b/counterparty-core/counterpartycore/lib/database.py index 1554651ea7..69990a1714 100644 --- a/counterparty-core/counterpartycore/lib/database.py +++ b/counterparty-core/counterpartycore/lib/database.py @@ -15,13 +15,10 @@ def rowtracer(cursor, sql): """Converts fetched SQL data into dict-style""" - dictionary = {} - for index, (name, field_type) in enumerate(cursor.getdescription()): # noqa: B007 - if str(field_type) == "BOOL": - dictionary[name] = bool(sql[index]) - else: - dictionary[name] = sql[index] - return dictionary + return { + name: (bool(value) if str(field_type) == "BOOL" else value) + for (name, field_type), value in zip(cursor.getdescription(), sql) + } def get_file_openers(filename): diff --git a/counterparty-core/counterpartycore/lib/gettxinfo.py b/counterparty-core/counterpartycore/lib/gettxinfo.py index 85c0eb43e2..74ff07c7cb 100644 --- a/counterparty-core/counterpartycore/lib/gettxinfo.py +++ b/counterparty-core/counterpartycore/lib/gettxinfo.py @@ -359,7 +359,6 @@ def get_tx_info_new(db, decoded_tx, block_index, p2sh_is_segwit=False, composing raise DecodeError("unrecognised output type") destinations, btc_amount, fee, data, potential_dispensers = decoded_tx["parsed_vouts"] else: - logger.trace("parsed_vouts not in decoded_tx") destinations, btc_amount, fee, data, potential_dispensers = parse_transaction_vouts( decoded_tx ) diff --git a/counterparty-core/counterpartycore/lib/log.py b/counterparty-core/counterpartycore/lib/log.py index 8b4d41e9c6..ba5bac0ea9 100644 --- a/counterparty-core/counterpartycore/lib/log.py +++ b/counterparty-core/counterpartycore/lib/log.py @@ -122,7 +122,14 @@ def json_record(self, message: str, extra: dict, record: logging.LogRecord) -> d return super(CustomisedJSONFormatter, self).json_record(message, extra, record) -def set_up(verbose=0, quiet=True, log_file=None, json_logs=False): +def set_up( + verbose=0, + quiet=True, + log_file=None, + json_logs=False, + max_log_file_size=40 * 1024 * 1024, + max_log_file_rotations=20, +): logging.Logger.trace = trace logging.Logger.event = event @@ -150,8 +157,9 @@ def set_up(verbose=0, quiet=True, log_file=None, json_logs=False): # File Logging if log_file: - max_log_size = 20 * 1024 * 1024 # 20 MB - fileh = RotatingFileHandler(log_file, maxBytes=max_log_size, backupCount=5) + fileh = RotatingFileHandler( + log_file, maxBytes=max_log_file_size, backupCount=max_log_file_rotations + ) fileh.setLevel(logging.TRACE) fileh.setFormatter(CustomisedJSONFormatter()) logger.addHandler(fileh) diff --git a/counterparty-core/counterpartycore/lib/messages/fairminter.py b/counterparty-core/counterpartycore/lib/messages/fairminter.py index ddef16b902..640ea64408 100644 --- a/counterparty-core/counterpartycore/lib/messages/fairminter.py +++ b/counterparty-core/counterpartycore/lib/messages/fairminter.py @@ -147,9 +147,8 @@ def validate( if existing_asset["issuer"] != source: problems.append(f"Asset `{asset_name}` is not issued by `{source}`.") # check if description is locked - # TODO - # if description != "" and existing_asset["description_locked"]: - # problems.append(f"Description of asset `{asset_name}` is locked.") + if description != "" and existing_asset["description_locked"]: + problems.append(f"Description of asset `{asset_name}` is locked.") # check if hard cap is already reached if hard_cap and existing_asset["supply"] + premint_quantity >= hard_cap: problems.append(f"Hard cap of asset `{asset_name}` is already reached.") @@ -157,11 +156,17 @@ def validate( if premint_quantity > 0 and premint_quantity >= hard_cap: problems.append("Premint quantity must be < hard cap.") - if existing_asset is None and asset_parent != "": - # if the asset does not exist its parent must exist - existing_parent = ledger.get_asset(db, asset_parent) - if existing_parent is None: - problems.append("Asset parent does not exist") + if existing_asset is None: + if asset_parent != "": + # if the asset does not exist its parent must exist + existing_parent = ledger.get_asset(db, asset_parent) + if existing_parent is None: + problems.append("Asset parent does not exist") + elif not asset.startswith("A"): + fee = 0.5 * config.UNIT + balance = ledger.get_balance(db, source, config.XCP) + if balance < fee: + problems.append("insufficient XCP balance to pay fee") if price == 0 and max_mint_per_tx == 0: problems.append("Price or max_mint_per_tx must be > 0.") diff --git a/counterparty-core/counterpartycore/lib/messages/issuance.py b/counterparty-core/counterpartycore/lib/messages/issuance.py index 9cfb4ebe37..4a6b7591bd 100644 --- a/counterparty-core/counterpartycore/lib/messages/issuance.py +++ b/counterparty-core/counterpartycore/lib/messages/issuance.py @@ -164,6 +164,7 @@ def initialise(db): ["source"], ["asset_longname"], ["status", "asset", "tx_index DESC"], + ["status", "asset_longname", "tx_index DESC"], ["issuer"], ], ) diff --git a/counterparty-core/counterpartycore/server.py b/counterparty-core/counterpartycore/server.py index 47d7ab8e13..cc47fdb191 100755 --- a/counterparty-core/counterpartycore/server.py +++ b/counterparty-core/counterpartycore/server.py @@ -62,6 +62,8 @@ def initialise(*args, **kwargs): regtest=kwargs.get("regtest", False), action=kwargs.get("action", None), json_logs=kwargs.get("json_logs", False), + max_log_file_size=kwargs.get("max_log_file_size", None), + max_log_file_rotations=kwargs.get("max_log_file_rotations", None), ) initialise_config(*args, **kwargs) return database.initialise_db() @@ -78,6 +80,8 @@ def initialise_log_config( regtest=False, action=None, json_logs=False, + max_log_file_size=40 * 1024 * 1024, + max_log_file_rotations=20, ): # Log directory log_dir = appdirs.user_log_dir(appauthor=config.XCP_NAME, appname=config.APP_NAME) @@ -126,6 +130,9 @@ def initialise_log_config( config.LOG_IN_CONSOLE = action == "start" or config.VERBOSE > 0 config.JSON_LOGS = json_logs + config.MAX_LOG_FILE_SIZE = max_log_file_size + config.MAX_LOG_FILE_ROTATIONS = max_log_file_rotations + def initialise_config( database_file=None, @@ -658,6 +665,8 @@ def initialise_log_and_config(args): quiet=config.QUIET, log_file=config.LOG, json_logs=config.JSON_LOGS, + max_log_file_size=config.MAX_LOG_FILE_SIZE, + max_log_file_rotations=config.MAX_LOG_FILE_ROTATIONS, ) initialise_config(**init_args) diff --git a/counterparty-core/counterpartycore/test/conftest.py b/counterparty-core/counterpartycore/test/conftest.py index ec0de0b892..595c3f4524 100644 --- a/counterparty-core/counterpartycore/test/conftest.py +++ b/counterparty-core/counterpartycore/test/conftest.py @@ -317,6 +317,8 @@ def api_server_v2(request, cp_server): "json_logs": False, "wsgi_server": "waitress", "gunicorn_workers": 2, + "max_log_file_size": 40 * 1024 * 1024, + "max_log_file_rotations": 20, } server_config = ( default_config diff --git a/counterparty-core/counterpartycore/test/regtest/apidoc/blueprint-template.md b/counterparty-core/counterpartycore/test/regtest/apidoc/blueprint-template.md index 50fe0f5b5f..be0639201a 100644 --- a/counterparty-core/counterpartycore/test/regtest/apidoc/blueprint-template.md +++ b/counterparty-core/counterpartycore/test/regtest/apidoc/blueprint-template.md @@ -158,7 +158,7 @@ Returns server information and the list of documented routes in JSON format. "result": { "server_ready": true, "network": "mainnet", - "version": "10.5.0-alpha.1", + "version": "10.5.0-alpha.2", "backend_height": 850214, "counterparty_height": 850214, "documentation": "https://counterpartycore.docs.apiary.io/", diff --git a/counterparty-core/requirements.txt b/counterparty-core/requirements.txt index 723dd44963..be7b643915 100644 --- a/counterparty-core/requirements.txt +++ b/counterparty-core/requirements.txt @@ -34,4 +34,4 @@ JSON-log-formatter==1.0 yoyo-migrations==8.2.0 gunicorn==23.0.0 waitress==3.0.0 -counterparty-rs==10.5.0-alpha.1 +counterparty-rs==10.5.0-alpha.2 diff --git a/counterparty-rs/Cargo.lock b/counterparty-rs/Cargo.lock index 3348119139..26024420be 100644 --- a/counterparty-rs/Cargo.lock +++ b/counterparty-rs/Cargo.lock @@ -382,7 +382,7 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "counterparty-rs" -version = "10.5.0-alpha.1" +version = "10.5.0-alpha.2" dependencies = [ "bip32", "bitcoin 0.29.2", diff --git a/counterparty-rs/Cargo.toml b/counterparty-rs/Cargo.toml index 230a24431b..06947f7539 100644 --- a/counterparty-rs/Cargo.toml +++ b/counterparty-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "counterparty-rs" -version = "10.5.0-alpha.1" +version = "10.5.0-alpha.2" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/counterparty-wallet/requirements.txt b/counterparty-wallet/requirements.txt index 4f19eb8c4c..7522201442 100644 --- a/counterparty-wallet/requirements.txt +++ b/counterparty-wallet/requirements.txt @@ -5,4 +5,4 @@ colorlog==6.8.0 python-dateutil==2.8.2 requests==2.32.0 termcolor==2.4.0 -counterparty-core==10.5.0-alpha.1 +counterparty-core==10.5.0-alpha.2 diff --git a/docker-compose.yml b/docker-compose.yml index 362766fdf5..96ed578c28 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,7 +15,7 @@ x-addrindexrs-common: &addrindexrs-common restart: unless-stopped x-counterparty-common: &counterparty-common - image: counterparty/counterparty:v10.5.0-alpha.1 + image: counterparty/counterparty:v10.5.0-alpha.2 stop_grace_period: 1m volumes: - data:/root/.bitcoin diff --git a/release-notes/release-notes-v10.5.0.md b/release-notes/release-notes-v10.5.0.md index f78812aaad..f0152f4f57 100644 --- a/release-notes/release-notes-v10.5.0.md +++ b/release-notes/release-notes-v10.5.0.md @@ -1,30 +1,36 @@ # Release Notes - Counterparty Core v10.5.0 (2024-10-18) -This is a hotfix release to fix non-determinitic bug is asset name generation. +This is a hotfix release to fix a non-deterministic bug in asset name generation. # Upgrading -This update requires an automatic reparse from block 865999 +This update requires an automatic reparse from block 865999. # ChangeLog ## Bugfixes -- Fix non-determinitic bug is asset name generation +- Fix non-deterministic bug in asset name generation - Fix sub-asset name in `issuances` table when created by a fairminter +- Fix missing index on `address_events.event_index` +- Fix missing balance checking when creating a fairminter +- Fix missing check of locked description +- Fix missing compound index on `status`, `tx_index` and `asset_longname` ## Codebase - Support several required reparsing by major version +- Optimize database `rowtracer` ## API ## CLI +- Add `--max-log-file-size` and `--max-log-file-rotations` flags # Credits * Ouziel Slama * Warren Puffett -* Adam Krellenstein \ No newline at end of file +* Adam Krellenstein