globalvars.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2022 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. _autolock = False
  39. _set_ok = ('user_entropy','session')
  40. _reset_ok = ('stdout','stderr','accept_defaults')
  41. _use_class_attr = True
  42. # Constants:
  43. proj_name = 'MMGen'
  44. proj_url = 'https://github.com/mmgen/mmgen'
  45. prog_name = os.path.basename(sys.argv[0])
  46. author = 'The MMGen Project'
  47. email = '<mmgen@tuta.io>'
  48. Cdates = '2013-2022'
  49. try:
  50. from importlib.resources import files # Python 3.9
  51. except ImportError:
  52. from importlib_resources import files
  53. version = files('mmgen').joinpath('data','version').read_text().strip()
  54. release_date = files('mmgen').joinpath('data','release_date').read_text().strip()
  55. max_int = 0xffffffff
  56. stdin_tty = sys.stdin.isatty()
  57. stdout = sys.stdout
  58. stderr = sys.stderr
  59. http_timeout = 60
  60. err_disp_timeout = 0.7
  61. short_disp_timeout = 0.3
  62. min_time_precision = 18
  63. dfl_seed_len = 256
  64. # Variables - these might be altered at runtime:
  65. user_entropy = b''
  66. dfl_hash_preset = '3'
  67. usr_randchars = 30
  68. tx_fee_adj = Decimal('1.0')
  69. tx_confs = 3
  70. # Constant vars - some of these might be overridden in opts.py, but they don't change thereafter
  71. coin = ''
  72. token = ''
  73. debug = False
  74. debug_opts = False
  75. debug_rpc = False
  76. debug_addrlist = False
  77. debug_subseed = False
  78. quiet = False
  79. no_license = False
  80. force_256_color = False
  81. testnet = False
  82. regtest = False
  83. accept_defaults = False
  84. # rpc:
  85. rpc_host = ''
  86. rpc_port = 0
  87. rpc_user = ''
  88. rpc_password = ''
  89. ignore_daemon_version = False
  90. monero_wallet_rpc_host = 'localhost'
  91. monero_wallet_rpc_user = 'monero'
  92. monero_wallet_rpc_password = ''
  93. aiohttp_rpc_queue_len = 16
  94. session = None
  95. cached_balances = False
  96. # regtest:
  97. bob = False
  98. alice = False
  99. # miscellaneous features:
  100. use_internal_keccak_module = False
  101. enable_erigon = False
  102. # test suite:
  103. bogus_send = False
  104. debug_utf8 = False
  105. traceback = False
  106. test_suite = False
  107. test_suite_deterministic = False
  108. test_suite_popen_spawn = False
  109. terminal_width = 0
  110. mnemonic_entry_modes = {}
  111. color = bool(
  112. ( sys.stdout.isatty() and not os.getenv('MMGEN_TEST_SUITE_PEXPECT') ) or
  113. os.getenv('MMGEN_FORCE_COLOR')
  114. )
  115. for k in ('linux','win','msys'):
  116. if sys.platform.startswith(k):
  117. platform = { 'linux':'linux', 'win':'win', 'msys':'win' }[k]
  118. break
  119. else:
  120. die(1,f'{sys.platform!r}: platform not supported by {proj_name}')
  121. if os.getenv('HOME'): # Linux or MSYS2
  122. home_dir = os.getenv('HOME')
  123. elif platform == 'win': # Windows without MSYS2 - not supported
  124. die(1,f'$HOME not set! {proj_name} for Windows must be run in MSYS2 environment')
  125. else:
  126. die(2,'$HOME is not set! Unable to determine home directory')
  127. data_dir_root,data_dir,cfg_file = None,None,None
  128. daemon_data_dir = '' # set by user
  129. daemon_id = ''
  130. # global var sets user opt:
  131. global_sets_opt = (
  132. 'use_internal_keccak_module',
  133. 'minconf','usr_randchars','debug','quiet','tx_confs','tx_fee_adj' )
  134. # user opt sets global var:
  135. opt_sets_global = ( 'subseeds','cached_balances' )
  136. # 'long' opts - opt sets global var
  137. common_opts = (
  138. 'color','no_license','testnet',
  139. 'rpc_host','rpc_port','rpc_user','rpc_password','rpc_backend','aiohttp_rpc_queue_len',
  140. 'monero_wallet_rpc_host','monero_wallet_rpc_user','monero_wallet_rpc_password',
  141. 'daemon_data_dir','force_256_color','regtest','coin','bob','alice',
  142. 'accept_defaults','token','ignore_daemon_version','daemon_id','http_timeout',
  143. )
  144. # opts initialized to None by opts.init() if not set by user
  145. required_opts = (
  146. 'quiet','verbose','debug','outdir','echo_passphrase','passwd_file','stdout',
  147. 'show_hash_presets','label','keep_passphrase','keep_hash_preset','yes',
  148. 'brain_params','b16','usr_randchars','coin','bob','alice',
  149. 'hidden_incog_input_params','in_fmt','hash_preset','seed_len',
  150. )
  151. incompatible_opts = (
  152. ('help','longhelp'),
  153. ('bob','alice'),
  154. ('label','keep_label'),
  155. ('tx_id','info'),
  156. ('tx_id','terse_info'),
  157. ('batch','rescan'), # TODO: still incompatible?
  158. )
  159. cfg_file_opts = (
  160. 'color','debug','hash_preset','http_timeout','no_license','rpc_host','rpc_port',
  161. 'quiet','tx_fee_adj','usr_randchars','testnet','rpc_user','rpc_password',
  162. 'monero_wallet_rpc_host','monero_wallet_rpc_user','monero_wallet_rpc_password',
  163. 'daemon_data_dir','force_256_color','regtest','subseeds','mnemonic_entry_modes',
  164. 'btc_max_tx_fee','ltc_max_tx_fee','bch_max_tx_fee','eth_max_tx_fee',
  165. 'btc_ignore_daemon_version','bch_ignore_daemon_version','ltc_ignore_daemon_version',
  166. 'eth_ignore_daemon_version','etc_ignore_daemon_version',
  167. 'eth_mainnet_chain_names','eth_testnet_chain_names',
  168. 'max_tx_file_size','max_input_size'
  169. )
  170. # Supported environmental vars
  171. # The corresponding vars (lowercase, minus 'mmgen_') must be initialized in g
  172. # 'DISABLE_' env vars disable the corresponding var in g
  173. env_opts = (
  174. 'MMGEN_DEBUG_ALL', # special: there is no g.debug_all var
  175. 'MMGEN_TEST_SUITE',
  176. 'MMGEN_TEST_SUITE_DETERMINISTIC',
  177. 'MMGEN_TEST_SUITE_POPEN_SPAWN',
  178. 'MMGEN_TERMINAL_WIDTH',
  179. 'MMGEN_BOGUS_SEND',
  180. 'MMGEN_DEBUG',
  181. 'MMGEN_DEBUG_OPTS',
  182. 'MMGEN_DEBUG_RPC',
  183. 'MMGEN_DEBUG_ADDRLIST',
  184. 'MMGEN_DEBUG_UTF8',
  185. 'MMGEN_DEBUG_SUBSEED',
  186. 'MMGEN_QUIET',
  187. 'MMGEN_FORCE_256_COLOR',
  188. 'MMGEN_MIN_URANDCHARS',
  189. 'MMGEN_NO_LICENSE',
  190. 'MMGEN_RPC_HOST',
  191. 'MMGEN_RPC_FAIL_ON_COMMAND',
  192. 'MMGEN_TESTNET',
  193. 'MMGEN_REGTEST',
  194. 'MMGEN_TRACEBACK',
  195. 'MMGEN_RPC_BACKEND',
  196. 'MMGEN_IGNORE_DAEMON_VERSION',
  197. 'MMGEN_USE_STANDALONE_SCRYPT_MODULE',
  198. 'MMGEN_ENABLE_ERIGON',
  199. 'MMGEN_DISABLE_COLOR',
  200. 'MMGEN_DISABLE_MSWIN_PW_WARNING',
  201. )
  202. infile_opts = (
  203. 'keys_from_file',
  204. 'mmgen_keys_from_file',
  205. 'passwd_file',
  206. 'keysforaddrs',
  207. 'comment_file',
  208. 'contract_data',
  209. )
  210. # Auto-typechecked and auto-set opts. These have no corresponding value in g.
  211. # First value in list is the default
  212. ov = namedtuple('autoset_opt_info',['type','choices'])
  213. autoset_opts = {
  214. 'fee_estimate_mode': ov('nocase_pfx', ['conservative','economical']),
  215. 'rpc_backend': ov('nocase_pfx', ['auto','httplib','curl','aiohttp','requests']),
  216. }
  217. if platform == 'win':
  218. autoset_opts['rpc_backend'].choices.remove('aiohttp')
  219. _skip_type_check = ('stdout','stderr')
  220. auto_typeset_opts = {
  221. 'seed_len': int,
  222. }
  223. min_screen_width = 80
  224. minconf = 1
  225. max_tx_file_size = 100000
  226. max_input_size = 1024 * 1024
  227. passwd_max_tries = 5
  228. max_urandchars = 80
  229. min_urandchars = 10
  230. seed_lens = 128,192,256
  231. scramble_hash_rounds = 10
  232. subseeds = 100
  233. salt_len = 16
  234. aesctr_iv_len = 16
  235. aesctr_dfl_iv = int.to_bytes(1,aesctr_iv_len,'big')
  236. hincog_chk_len = 8
  237. force_standalone_scrypt_module = False
  238. # Scrypt params: 'id_num': [N, r, p] (N is an exponent of two)
  239. # NB: hashlib.scrypt in Python (>=v3.6) supports max N value of 14. This means that
  240. # for hash presets > 3 the standalone scrypt library must be used!
  241. _hp = namedtuple('scrypt_preset',['N','r','p'])
  242. hash_presets = {
  243. '1': _hp(12, 8, 1),
  244. '2': _hp(13, 8, 4),
  245. '3': _hp(14, 8, 8),
  246. '4': _hp(15, 8, 12),
  247. '5': _hp(16, 8, 16),
  248. '6': _hp(17, 8, 20),
  249. '7': _hp(18, 8, 24),
  250. }
  251. if os.getenv('MMGEN_TEST_SUITE'):
  252. err_disp_timeout = 0.1
  253. short_disp_timeout = 0.1
  254. if os.getenv('MMGEN_TEST_SUITE_POPEN_SPAWN'):
  255. stdin_tty = True
  256. if prog_name == 'unit_tests.py':
  257. _set_ok += ('debug_subseed',)
  258. _reset_ok += ('force_standalone_scrypt_module','session')
  259. if os.getenv('MMGEN_DEBUG_ALL'):
  260. for name in env_opts:
  261. if name[:11] == 'MMGEN_DEBUG':
  262. os.environ[name] = '1'
  263. g = GlobalContext()