diff --git a/firmware/.gitignore b/firmware/.gitignore index e21cd098b..a35c8127e 100644 --- a/firmware/.gitignore +++ b/firmware/.gitignore @@ -1,6 +1,4 @@ -coins_array.h -coins_count.h - +coin_info.[ch] nem_mosaics.[ch] bl_data.h diff --git a/firmware/Makefile b/firmware/Makefile index 6e6a9d157..88fa9ace0 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -16,6 +16,7 @@ OBJS += trezor.o OBJS += pinmatrix.o OBJS += fsm.o OBJS += coins.o +OBJS += coin_info.o OBJS += transaction.o OBJS += protect.o OBJS += layout2.o @@ -109,14 +110,6 @@ clean:: rm -f $(1).h $(3) endef +$(eval $(call GENERATE_CODE,coin_info,coins.json,coin_info.c)) $(eval $(call GENERATE_CODE,nem_mosaics,nem_mosaics.json,nem_mosaics.c)) $(eval $(call GENERATE_CODE,bl_data,../bootloader/bootloader.bin)) - -coins_count.h: coins-gen.py coins.json - $(PYTHON) $< count > $@ - -coins_array.h: coins-gen.py coins.json - $(PYTHON) $< array > $@ - -clean:: - rm -f coins_count.h coins_array.h diff --git a/firmware/coin_info.py b/firmware/coin_info.py new file mode 100755 index 000000000..c8e8a5cf4 --- /dev/null +++ b/firmware/coin_info.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python2 +import json +import os + +import collections + +HEADER_TEMPLATE = """ +// This file is automatically generated by coin_info.py -- DO NOT EDIT! + +#ifndef __COIN_INFO_H__ +#define __COIN_INFO_H__ + +#include "coins.h" + +#if DEBUG_LINK +#define COINS_COUNT ({stable} + {debug}) +#else +#define COINS_COUNT ({stable}) +#endif + +extern const CoinInfo coins[COINS_COUNT]; + +#endif +""".lstrip() + +CODE_TEMPLATE = """ +// This file is automatically generated by coin_info.py -- DO NOT EDIT! + +#include "coins.h" + +#include "curves.h" +#include "secp256k1.h" + +const CoinInfo coins[COINS_COUNT] = {{ +{stable} +#if DEBUG_LINK +{debug} +#endif +}}; +""".lstrip() + + +def format_bool(value): + if value: + return "true" + else: + return "false" + + +def format_number(value): + if value is None: + value = 0 + return str(value) + + +def format_string(value): + if value is None: + return "NULL" + else: + return json.dumps(value) + + +def format_hex(value): + if value is None: + value = "0" + return "0x{:08x}".format(int(value, 16)) + + +def prepend_varint(string): + assert len(string) < 253 + + varint = "\"\\x{:02x}\"".format(len(string)) + return "{} {}".format(varint, format_string(string)) + + +def coin_to_struct(coin): + return collections.OrderedDict(( + ("coin_name", format_string(coin["coin_name"])), + ("coin_shortcut", format_string(coin["coin_shortcut"])), + ("maxfee_kb", format_number(coin["maxfee_kb"])), + ("signed_message_header", prepend_varint(coin["signed_message_header"])), # noqa: E501 + ("has_address_type", format_bool(coin["address_type"] is not None)), # noqa: E501 + ("has_address_type_p2sh", format_bool(coin["address_type_p2sh"] is not None)), # noqa: E501 + ("has_segwit", format_bool(coin["segwit"])), + ("has_forkid", format_bool(coin["forkid"] is not None)), + ("force_bip143", format_bool(coin["force_bip143"])), + ("address_type", format_number(coin["address_type"])), + ("address_type_p2sh", format_number(coin["address_type_p2sh"])), + ("xpub_magic", format_hex(coin["xpub_magic"])), + ("xprv_magic", format_hex(coin["xprv_magic"])), + ("forkid", format_number(coin["forkid"])), + ("bech32_prefix", format_string(coin["bech32_prefix"])), + ("coin_type", "({} | 0x80000000)".format(format_number(coin["bip44"]))), # noqa: E501 + ("curve_name", "{}_NAME".format(coin["curve_name"].upper())), # noqa: E501 + ("curve", "&{}_info".format(coin["curve_name"])), + )) + + +def format_struct(struct): + return "{\n" + "\n".join( + "\t.{0} = {1},".format(member, value) + for member, value in struct.items() + ) + "\n}" + + +def format_coin(coin): + return format_struct(coin_to_struct(coin)) + + +def format_coins(coins): + return "\n".join("{},".format(format_coin(coin)) for coin in coins) + + +if __name__ == "__main__": + os.chdir(os.path.abspath(os.path.dirname(__file__))) + + coins = collections.defaultdict(list) + + for coin in json.load(open("coins.json")): + firmware = coin["firmware"] + coins[firmware].append(coin) + + with open("coin_info.h", "w+") as f: + f.write(HEADER_TEMPLATE.format(**{ + k: format_number(len(v)) for k, v in coins.items() + })) + + with open("coin_info.c", "w+") as f: + f.write(CODE_TEMPLATE.format(**{ + k: format_coins(v) for k, v in coins.items() + })) diff --git a/firmware/coins.c b/firmware/coins.c index 0618c60dd..1600f9acb 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -20,15 +20,8 @@ #include #include "coins.h" #include "address.h" -#include "curves.h" #include "ecdsa.h" #include "base58.h" -#include "secp256k1.h" - -// filled CoinInfo structure defined in coins.h -const CoinInfo coins[COINS_COUNT] = { -#include "coins_array.h" -}; const CoinInfo *coinByName(const char *name) { diff --git a/firmware/coins.h b/firmware/coins.h index eae9bbd61..c6a1c0b7a 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -24,7 +24,6 @@ #include #include "bip32.h" -#include "coins_count.h" #include "hasher.h" typedef struct _CoinInfo { @@ -49,7 +48,7 @@ typedef struct _CoinInfo { const curve_info *curve; } CoinInfo; -extern const CoinInfo coins[COINS_COUNT]; +#include "coin_info.h" const CoinInfo *coinByName(const char *name); const CoinInfo *coinByAddressType(uint32_t address_type);