diff --git a/tools/cointool.py b/tools/cointool.py index b5fbad2aa7..6d96836fc6 100755 --- a/tools/cointool.py +++ b/tools/cointool.py @@ -143,6 +143,7 @@ def render_file(src, dst, coins, support_info): def highlight_key(coin, color): + """Return a colorful string where the SYMBOL part is bold.""" keylist = coin["key"].split(":") if keylist[-1].isdigit(): keylist[-2] = crayon(color, keylist[-2], bold=True) @@ -166,6 +167,7 @@ def check_btc(coins): check_passed = True support_infos = coin_info.support_info(coins) + # validate individual coin data for coin in coins: errors = coin_info.validate_btc(coin) if errors: @@ -174,6 +176,7 @@ def check_btc(coins): print("\n".join(errors)) def collision_str(bucket): + """Generate a colorful string out of a bucket of colliding coins.""" coin_strings = [] for coin in bucket: name = coin["name"] @@ -192,6 +195,13 @@ def check_btc(coins): return ", ".join(coin_strings) def print_collision_buckets(buckets, prefix): + """Intelligently print collision buckets. + + For each bucket, if there are any collision with a mainnet, print it. + If the collision is with unsupported networks or testnets, it's just INFO. + If the collision is with supported mainnets, it's WARNING. + If the collision with any supported network includes Bitcoin, it's an ERROR. + """ failed = False for key, bucket in buckets.items(): mainnets = [c for c in bucket if not c["name"].endswith("Testnet")] @@ -227,6 +237,7 @@ def check_btc(coins): if print_collision_buckets(slip44, "key"): check_passed = False + # only check address_type on coins that don't use cashaddr nocashaddr = [coin for coin in coins if not coin.get("cashaddr_prefix")] print("Checking address_type collisions...") @@ -242,8 +253,20 @@ def check_btc(coins): return check_passed -def check_dups(buckets, show_tok_notok, show_erc20): +def check_dups(buckets, print_at_level=logging.ERROR): + """Analyze and pretty-print results of `coin_info.mark_duplicate_shortcuts`. + + `print_at_level` can be one of logging levels. + + The results are buckets of colliding symbols. + If the collision is only between ERC20 tokens, it's DEBUG. + If the collision includes one non-token, it's INFO. + If the collision includes more than one non-token, it's ERROR and printed always. + """ def coin_str(coin): + """Colorize coins. Tokens are cyan, nontokens are red. Coins that are NOT + marked duplicate get a green asterisk. + """ if coin_info.is_token(coin): color = "cyan" else: @@ -275,9 +298,7 @@ def check_dups(buckets, show_tok_notok, show_erc20): check_passed = False # deciding whether to print - if not nontokens and not show_erc20: - continue - if len(nontokens) == 1 and not show_tok_notok: + if level < print_at_level: continue if symbol == "_override": @@ -433,13 +454,12 @@ def cli(colors): @cli.command() # fmt: off -@click.option("--missing-support/--no-missing-support", "-s", default=False, help="Fail if support info for a coin is missing") @click.option("--backend/--no-backend", "-b", default=False, help="Check blockbook/bitcore responses") @click.option("--icons/--no-icons", default=True, help="Check icon files") @click.option("-d", "--show-duplicates", type=click.Choice(("all", "nontoken", "errors")), default="errors", help="How much information about duplicate shortcuts should be shown.") # fmt: on -def check(missing_support, backend, icons, show_duplicates): +def check(backend, icons, show_duplicates): """Validate coin definitions. Checks that every btc-like coin is properly filled out, reports duplicate symbols, @@ -450,18 +470,21 @@ def check(missing_support, backend, icons, show_duplicates): expected. The `--show-duplicates` option can be set to: - * all: all shortcut collisions are shown, including colliding ERC20 tokens - * nontoken: only collisions that affect non-ERC20 coins are shown - * errors: only collisions between non-ERC20 tokens are shown. This is the default, - as a collision between two or more non-ERC20 tokens is an error. + + - all: all shortcut collisions are shown, including colliding ERC20 tokens + + - nontoken: only collisions that affect non-ERC20 coins are shown + + - errors: only collisions between non-ERC20 tokens are shown. This is the default, + as a collision between two or more non-ERC20 tokens is an error. In the output, duplicate ERC tokens will be shown in cyan; duplicate non-tokens in red. An asterisk (*) next to symbol name means that even though it was detected as duplicate, it is still included in results. - The code checks that SLIP44 numbers don't collide between different mainnets - (testnet collisions are allowed), that `address_prefix` doesn't collide with - Bitcoin (other collisions are reported as warnings). `address_prefix_p2sh` + The collision detection checks that SLIP44 numbers don't collide between different + mainnets (testnet collisions are allowed), that `address_prefix` doesn't collide + with Bitcoin (other collisions are reported as warnings). `address_prefix_p2sh` is also checked but we have a bunch of collisions there and can't do much about them, so it's not an error. @@ -484,16 +507,13 @@ def check(missing_support, backend, icons, show_duplicates): all_checks_passed = False if show_duplicates == "all": - show_tok_notok = True - show_erc20 = True + dup_level = logging.DEBUG elif show_duplicates == "nontoken": - show_tok_notok = True - show_erc20 = False + dup_level = logging.INFO else: - show_tok_notok = False - show_erc20 = False + dup_level = logging.ERROR print("Checking unexpected duplicates...") - if not check_dups(buckets, show_tok_notok, show_erc20): + if not check_dups(buckets, dup_level): all_checks_passed = False if icons: