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: check_passed = False print_log(logging.ERROR, "invalid definition for", coin["name"]) 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"] prefix = "" if name.endswith("Testnet"): color = "green" elif name == "Bitcoin": color = "red" elif coin.get("unsupported"): color = "grey" prefix = crayon("blue", "(X)", bold=True) else: color = "blue" hl = highlight_key(coin, color) coin_strings.append(prefix + hl) return ", ".join(coin_strings) def print_collision_buckets(buckets, prefix, maxlevel=logging.ERROR, strict=False): """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")] have_bitcoin = False for coin in mainnets: if coin["name"] == "Bitcoin": have_bitcoin = True if all(v is False for k, v in support_infos[coin["key"]].items()): coin["unsupported"] = True supported_mainnets = [ c for c in mainnets if not c.get("unsupported") ] supported_networks = [ c for c in bucket if not c.get("unsupported") ] if len(mainnets) > 1: if (have_bitcoin or strict) and len(supported_networks) > 1: # ANY collision with Bitcoin is bad level = maxlevel failed = True elif len(supported_mainnets) > 1: # collision between supported networks is still pretty bad level = logging.WARNING else: # collision between some unsupported networks is OK level = logging.INFO print_log(level, "{} {}:".format(prefix, key), collision_str(bucket)) return failed # slip44 collisions print("Checking SLIP44 values collisions...") slip44 = find_collisions(coins, "slip44") if print_collision_buckets(slip44, "value", strict=True): 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...") address_type = find_collisions(nocashaddr, "address_type") if print_collision_buckets(address_type, "address type"): check_passed = False print("Checking address_type_p2sh collisions...") address_type_p2sh = find_collisions(nocashaddr, "address_type_p2sh") # we ignore failed checks on P2SH, because reasons print_collision_buckets(address_type_p2sh, "address type", logging.WARNING) print("Checking genesis block collisions...") genesis = find_collisions(coins, "hash_genesis_block") print_collision_buckets(genesis, "genesis block", logging.WARNING) return check_passed
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: check_passed = False print_log(logging.ERROR, "invalid definition for", coin["name"]) 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"] prefix = "" if name.endswith("Testnet"): color = "green" elif name == "Bitcoin": color = "red" elif coin.get("unsupported"): color = "grey" prefix = crayon("blue", "(X)", bold=True) else: color = "blue" hl = highlight_key(coin, color) coin_strings.append(prefix + hl) return ", ".join(coin_strings) def print_collision_buckets(buckets, prefix, maxlevel=logging.ERROR, strict=False): """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")] have_bitcoin = False for coin in mainnets: if coin["name"] == "Bitcoin": have_bitcoin = True if all(v is False for k, v in support_infos[coin["key"]].items()): coin["unsupported"] = True supported_mainnets = [c for c in mainnets if not c.get("unsupported")] supported_networks = [c for c in bucket if not c.get("unsupported")] if len(mainnets) > 1: if (have_bitcoin or strict) and len(supported_networks) > 1: # ANY collision with Bitcoin is bad level = maxlevel failed = True elif len(supported_mainnets) > 1: # collision between supported networks is still pretty bad level = logging.WARNING else: # collision between some unsupported networks is OK level = logging.INFO print_log(level, "{} {}:".format(prefix, key), collision_str(bucket)) return failed # slip44 collisions print("Checking SLIP44 values collisions...") slip44 = find_collisions(coins, "slip44") if print_collision_buckets(slip44, "value", strict=True): 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...") address_type = find_collisions(nocashaddr, "address_type") if print_collision_buckets(address_type, "address type"): check_passed = False print("Checking address_type_p2sh collisions...") address_type_p2sh = find_collisions(nocashaddr, "address_type_p2sh") # we ignore failed checks on P2SH, because reasons print_collision_buckets(address_type_p2sh, "address type", logging.WARNING) print("Checking genesis block collisions...") genesis = find_collisions(coins, "hash_genesis_block") print_collision_buckets(genesis, "genesis block", logging.WARNING) return check_passed