globalvars.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2021 The MMGen Project <mmgen@tuta.io>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. globalvars.py: Constants and configuration options for the MMGen suite
  20. """
  21. import sys,os
  22. from decimal import Decimal
  23. from collections import namedtuple
  24. from .devtools import *
  25. from .base_obj import Lockable
  26. def die(exit_val,s=''):
  27. if s:
  28. sys.stderr.write(s+'\n')
  29. sys.exit(exit_val)
  30. class GlobalContext(Lockable):
  31. """
  32. Set global vars to default values
  33. Globals are overridden in this order:
  34. 1 - config file
  35. 2 - environmental vars
  36. 3 - command line
  37. """
  38. _set_ok = ('user_entropy','session')
  39. _reset_ok = ('stdout','stderr','accept_defaults')
  40. _use_class_attr = True
  41. # Constants:
  42. version = '0.12.199'
  43. release_date = 'February 2021'
  44. proj_name = 'MMGen'
  45. proj_url = 'https://github.com/mmgen/mmgen'
  46. prog_name = os.path.basename(sys.argv[0])
  47. author = 'The MMGen Project'
  48. email = '<mmgen@tuta.io>'
  49. Cdates = '2013-2021'
  50. keywords = 'Bitcoin, BTC, Ethereum, ETH, Monero, XMR, ERC20, cryptocurrency, wallet, BIP32, cold storage, offline, online, spending, open-source, command-line, Python, Linux, Bitcoin Core, bitcoind, hd, deterministic, hierarchical, secure, anonymous, Electrum, seed, mnemonic, brainwallet, Scrypt, utility, script, scriptable, blockchain, raw, transaction, permissionless, console, terminal, curses, ansi, color, tmux, remote, client, daemon, RPC, json, entropy, xterm, rxvt, PowerShell, MSYS, MSYS2, MinGW, MinGW64, MSWin, Armbian, Raspbian, Raspberry Pi, Orange Pi, BCash, BCH, Litecoin, LTC, altcoin, ZEC, Zcash, DASH, Dashpay, SHA256Compress, monerod, EMC, Emercoin, token, deploy, contract, gas, fee, smart contract, solidity, Parity, OpenEthereum, testnet, devmode, Kovan'
  51. max_int = 0xffffffff
  52. stdin_tty = sys.stdin.isatty()
  53. stdout = sys.stdout
  54. stderr = sys.stderr
  55. http_timeout = 60
  56. err_disp_timeout = 0.7
  57. short_disp_timeout = 0.3
  58. min_time_precision = 18
  59. dfl_seed_len = 256
  60. # Variables - these might be altered at runtime:
  61. user_entropy = b''
  62. dfl_hash_preset = '3'
  63. usr_randchars = 30
  64. tx_fee_adj = Decimal('1.0')
  65. tx_confs = 3
  66. # Constant vars - some of these might be overridden in opts.py, but they don't change thereafter
  67. coin = ''
  68. token = ''
  69. debug = False
  70. debug_opts = False
  71. debug_rpc = False
  72. debug_addrlist = False
  73. debug_subseed = False
  74. quiet = False
  75. no_license = False
  76. force_256_color = False
  77. testnet = False
  78. regtest = False
  79. accept_defaults = False
  80. # rpc:
  81. rpc_host = ''
  82. rpc_port = 0
  83. rpc_user = ''
  84. rpc_password = ''
  85. ignore_daemon_version = False
  86. monero_wallet_rpc_host = 'localhost'
  87. monero_wallet_rpc_user = 'monero'
  88. monero_wallet_rpc_password = ''
  89. rpc_fail_on_command = ''
  90. aiohttp_rpc_queue_len = 16
  91. session = None
  92. cached_balances = False
  93. # regtest:
  94. bob = False
  95. alice = False
  96. # miscellaneous features:
  97. use_internal_keccak_module = False
  98. # test suite:
  99. bogus_wallet_data = ''
  100. bogus_send = False
  101. debug_utf8 = False
  102. traceback = False
  103. test_suite = False
  104. test_suite_regtest = False
  105. test_suite_popen_spawn = False
  106. terminal_width = 0
  107. mnemonic_entry_modes = {}
  108. color = bool(
  109. ( sys.stdout.isatty() and not os.getenv('MMGEN_TEST_SUITE_PEXPECT') ) or
  110. os.getenv('MMGEN_FORCE_COLOR')
  111. )
  112. for k in ('linux','win','msys'):
  113. if sys.platform[:len(k)] == k:
  114. platform = { 'linux':'linux', 'win':'win', 'msys':'win' }[k]
  115. break
  116. else:
  117. die(1,f'{sys.platform!r}: platform not supported by {proj_name}')
  118. if os.getenv('HOME'): # Linux or MSYS2
  119. home_dir = os.getenv('HOME')
  120. elif platform == 'win': # Windows without MSYS2 - not supported
  121. die(1,f'$HOME not set! {proj_name} for Windows must be run in MSYS2 environment')
  122. else:
  123. die(2,'$HOME is not set! Unable to determine home directory')
  124. # https://wiki.debian.org/Python:
  125. # Debian (Ubuntu) sys.prefix is '/usr' rather than '/usr/local, so add 'local'
  126. # This must match the configuration in setup.py
  127. shared_data_path = os.path.join(
  128. sys.prefix,
  129. *(['local','share'] if platform == 'linux' else ['share']),
  130. proj_name.lower()
  131. )
  132. data_dir_root,data_dir,cfg_file = None,None,None
  133. daemon_data_dir = '' # set by user
  134. daemon_id = ''
  135. # global var sets user opt:
  136. global_sets_opt = (
  137. 'minconf','usr_randchars','debug', 'quiet','tx_confs','tx_fee_adj','key_generator' )
  138. # user opt sets global var:
  139. opt_sets_global = (
  140. 'use_internal_keccak_module','subseeds','cached_balances' )
  141. # 'long' opts - opt sets global var
  142. common_opts = (
  143. 'color','no_license','testnet',
  144. 'rpc_host','rpc_port','rpc_user','rpc_password','rpc_backend','aiohttp_rpc_queue_len',
  145. 'monero_wallet_rpc_host','monero_wallet_rpc_user','monero_wallet_rpc_password',
  146. 'daemon_data_dir','force_256_color','regtest','coin','bob','alice',
  147. 'accept_defaults','token','ignore_daemon_version','daemon_id','http_timeout',
  148. )
  149. # opts initialized to None by opts.init() if not set by user
  150. required_opts = (
  151. 'quiet','verbose','debug','outdir','echo_passphrase','passwd_file','stdout',
  152. 'show_hash_presets','label','keep_passphrase','keep_hash_preset','yes',
  153. 'brain_params','b16','usr_randchars','coin','bob','alice','key_generator',
  154. 'hidden_incog_input_params','in_fmt','hash_preset','seed_len',
  155. )
  156. incompatible_opts = (
  157. ('help','longhelp'),
  158. ('bob','alice'),
  159. ('label','keep_label'),
  160. ('tx_id','info'),
  161. ('tx_id','terse_info'),
  162. ('batch','rescan'), # TODO: still incompatible?
  163. )
  164. cfg_file_opts = (
  165. 'color','debug','hash_preset','http_timeout','no_license','rpc_host','rpc_port',
  166. 'quiet','tx_fee_adj','usr_randchars','testnet','rpc_user','rpc_password',
  167. 'monero_wallet_rpc_host','monero_wallet_rpc_user','monero_wallet_rpc_password',
  168. 'daemon_data_dir','force_256_color','regtest','subseeds','mnemonic_entry_modes',
  169. 'btc_max_tx_fee','ltc_max_tx_fee','bch_max_tx_fee','eth_max_tx_fee',
  170. 'btc_ignore_daemon_version','bch_ignore_daemon_version','ltc_ignore_daemon_version',
  171. 'eth_ignore_daemon_version','etc_ignore_daemon_version',
  172. 'eth_mainnet_chain_names','eth_testnet_chain_names',
  173. 'max_tx_file_size','max_input_size'
  174. )
  175. # Supported environmental vars
  176. # The corresponding vars (lowercase, minus 'mmgen_') must be initialized in g
  177. # 'DISABLE_' env vars disable the corresponding var in g
  178. env_opts = (
  179. 'MMGEN_DEBUG_ALL', # special: there is no g.debug_all var
  180. 'MMGEN_TEST_SUITE',
  181. 'MMGEN_TEST_SUITE_REGTEST',
  182. 'MMGEN_TEST_SUITE_POPEN_SPAWN',
  183. 'MMGEN_TERMINAL_WIDTH',
  184. 'MMGEN_BOGUS_WALLET_DATA',
  185. 'MMGEN_BOGUS_SEND',
  186. 'MMGEN_DEBUG',
  187. 'MMGEN_DEBUG_OPTS',
  188. 'MMGEN_DEBUG_RPC',
  189. 'MMGEN_DEBUG_ADDRLIST',
  190. 'MMGEN_DEBUG_UTF8',
  191. 'MMGEN_DEBUG_SUBSEED',
  192. 'MMGEN_QUIET',
  193. 'MMGEN_FORCE_256_COLOR',
  194. 'MMGEN_MIN_URANDCHARS',
  195. 'MMGEN_NO_LICENSE',
  196. 'MMGEN_RPC_HOST',
  197. 'MMGEN_RPC_FAIL_ON_COMMAND',
  198. 'MMGEN_TESTNET',
  199. 'MMGEN_REGTEST',
  200. 'MMGEN_TRACEBACK',
  201. 'MMGEN_RPC_BACKEND',
  202. 'MMGEN_IGNORE_DAEMON_VERSION',
  203. 'MMGEN_USE_STANDALONE_SCRYPT_MODULE',
  204. 'MMGEN_DISABLE_COLOR',
  205. 'MMGEN_DISABLE_MSWIN_PW_WARNING',
  206. )
  207. infile_opts = (
  208. 'keys_from_file',
  209. 'mmgen_keys_from_file',
  210. 'passwd_file',
  211. 'keysforaddrs',
  212. 'comment_file',
  213. 'contract_data',
  214. )
  215. # Auto-typechecked and auto-set opts. These have no corresponding value in g.
  216. # First value in list is the default
  217. ov = namedtuple('autoset_opt_info',['type','choices'])
  218. autoset_opts = {
  219. 'fee_estimate_mode': ov('nocase_pfx', ['conservative','economical']),
  220. 'rpc_backend': ov('nocase_pfx', ['auto','httplib','curl','aiohttp','requests']),
  221. }
  222. if platform == 'win':
  223. autoset_opts['rpc_backend'].choices.remove('aiohttp')
  224. _skip_type_check = ('stdout','stderr')
  225. auto_typeset_opts = {
  226. 'seed_len': int,
  227. }
  228. min_screen_width = 80
  229. minconf = 1
  230. max_tx_file_size = 100000
  231. max_input_size = 1024 * 1024
  232. passwd_max_tries = 5
  233. max_urandchars = 80
  234. min_urandchars = 10
  235. seed_lens = 128,192,256
  236. scramble_hash_rounds = 10
  237. subseeds = 100
  238. mmenc_ext = 'mmenc'
  239. salt_len = 16
  240. aesctr_iv_len = 16
  241. aesctr_dfl_iv = int.to_bytes(1,aesctr_iv_len,'big')
  242. hincog_chk_len = 8
  243. key_generators = ('python-ecdsa','libsecp256k1') # '1','2'
  244. key_generator = 2 # libsecp256k1 is default
  245. force_standalone_scrypt_module = False
  246. # Scrypt params: 'id_num': [N, p, r] (N is an exponent of two)
  247. # NB: hashlib.scrypt in Python (>=v3.6) supports max N value of 14. This means that
  248. # for hash presets > 3 the standalone scrypt library must be used!
  249. hash_presets = {
  250. '1': [12, 8, 1],
  251. '2': [13, 8, 4],
  252. '3': [14, 8, 8],
  253. '4': [15, 8, 12],
  254. '5': [16, 8, 16],
  255. '6': [17, 8, 20],
  256. '7': [18, 8, 24],
  257. }
  258. if os.getenv('MMGEN_TEST_SUITE'):
  259. err_disp_timeout = 0.1
  260. short_disp_timeout = 0.1
  261. if os.getenv('MMGEN_TEST_SUITE_POPEN_SPAWN'):
  262. stdin_tty = True
  263. if prog_name == 'unit_tests.py':
  264. _set_ok += ('debug_subseed',)
  265. _reset_ok += ('force_standalone_scrypt_module','session')
  266. if os.getenv('MMGEN_DEBUG_ALL'):
  267. for name in env_opts:
  268. if name[:11] == 'MMGEN_DEBUG':
  269. os.environ[name] = '1'
  270. g = GlobalContext()