globalvars.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2020 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.1'
  43. release_date = 'June 2020'
  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-2020'
  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. # Variables - these might be altered at runtime:
  60. user_entropy = b''
  61. dfl_hash_preset = '3'
  62. dfl_seed_len = 256
  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. use_internal_keccak_module = False
  81. # rpc:
  82. rpc_host = ''
  83. rpc_port = 0
  84. rpc_user = ''
  85. rpc_password = ''
  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. # test suite:
  97. bogus_wallet_data = ''
  98. bogus_send = False
  99. debug_utf8 = False
  100. traceback = False
  101. test_suite = False
  102. test_suite_popen_spawn = False
  103. terminal_width = 0
  104. mnemonic_entry_modes = {}
  105. color = bool(
  106. ( sys.stdout.isatty() and not os.getenv('MMGEN_TEST_SUITE_PEXPECT') ) or
  107. os.getenv('MMGEN_FORCE_COLOR')
  108. )
  109. for k in ('linux','win','msys'):
  110. if sys.platform[:len(k)] == k:
  111. platform = { 'linux':'linux', 'win':'win', 'msys':'win' }[k]
  112. break
  113. else:
  114. die(1,f'{sys.platform!r}: platform not supported by {proj_name}')
  115. if os.getenv('HOME'): # Linux or MSYS2
  116. home_dir = os.getenv('HOME')
  117. elif platform == 'win': # Windows without MSYS2 - not supported
  118. die(1,f'$HOME not set! {proj_name} for Windows must be run in MSYS2 environment')
  119. else:
  120. die(2,'$HOME is not set! Unable to determine home directory')
  121. # https://wiki.debian.org/Python:
  122. # Debian (Ubuntu) sys.prefix is '/usr' rather than '/usr/local, so add 'local'
  123. # This must match the configuration in setup.py
  124. shared_data_path = os.path.join(
  125. sys.prefix,
  126. *(['local','share'] if platform == 'linux' else ['share']),
  127. proj_name.lower()
  128. )
  129. data_dir_root,data_dir,cfg_file = None,None,None
  130. daemon_data_dir = '' # set by user
  131. # global var sets user opt:
  132. global_sets_opt = (
  133. 'minconf','usr_randchars','debug', 'quiet','tx_confs','tx_fee_adj','key_generator' )
  134. # user opt sets global var:
  135. opt_sets_global = (
  136. 'use_internal_keccak_module','subseeds','cached_balances' )
  137. # 'long' opts - opt sets global var
  138. common_opts = (
  139. 'color','no_license','testnet',
  140. 'rpc_host','rpc_port','rpc_user','rpc_password','rpc_backend','aiohttp_rpc_queue_len',
  141. 'monero_wallet_rpc_host','monero_wallet_rpc_user','monero_wallet_rpc_password',
  142. 'daemon_data_dir','force_256_color','regtest','coin','bob','alice',
  143. 'accept_defaults','token'
  144. )
  145. # opts initialized to None by opts.init() if not set by user
  146. required_opts = (
  147. 'quiet','verbose','debug','outdir','echo_passphrase','passwd_file','stdout',
  148. 'show_hash_presets','label','keep_passphrase','keep_hash_preset','yes',
  149. 'brain_params','b16','usr_randchars','coin','bob','alice','key_generator',
  150. 'hidden_incog_input_params','in_fmt','hash_preset','seed_len',
  151. )
  152. incompatible_opts = (
  153. ('help','longhelp'),
  154. ('bob','alice'),
  155. ('label','keep_label'),
  156. ('tx_id','info'),
  157. ('tx_id','terse_info'),
  158. ('batch','rescan'), # TODO: still incompatible?
  159. )
  160. cfg_file_opts = (
  161. 'color','debug','hash_preset','http_timeout','no_license','rpc_host','rpc_port',
  162. 'quiet','tx_fee_adj','usr_randchars','testnet','rpc_user','rpc_password',
  163. 'monero_wallet_rpc_host','monero_wallet_rpc_user','monero_wallet_rpc_password',
  164. 'daemon_data_dir','force_256_color','regtest','subseeds','mnemonic_entry_modes',
  165. 'btc_max_tx_fee','ltc_max_tx_fee','bch_max_tx_fee','eth_max_tx_fee',
  166. 'eth_mainnet_chain_name','eth_testnet_chain_name',
  167. 'max_tx_file_size','max_input_size'
  168. )
  169. # Supported environmental vars
  170. # The corresponding vars (lowercase, minus 'mmgen_') must be initialized in g
  171. # 'DISABLE_' env vars disable the corresponding var in g
  172. env_opts = (
  173. 'MMGEN_DEBUG_ALL', # special: there is no g.debug_all var
  174. 'MMGEN_TEST_SUITE',
  175. 'MMGEN_TEST_SUITE_POPEN_SPAWN',
  176. 'MMGEN_TERMINAL_WIDTH',
  177. 'MMGEN_BOGUS_WALLET_DATA',
  178. 'MMGEN_BOGUS_SEND',
  179. 'MMGEN_DEBUG',
  180. 'MMGEN_DEBUG_OPTS',
  181. 'MMGEN_DEBUG_RPC',
  182. 'MMGEN_DEBUG_ADDRLIST',
  183. 'MMGEN_DEBUG_UTF8',
  184. 'MMGEN_DEBUG_SUBSEED',
  185. 'MMGEN_QUIET',
  186. 'MMGEN_FORCE_256_COLOR',
  187. 'MMGEN_MIN_URANDCHARS',
  188. 'MMGEN_NO_LICENSE',
  189. 'MMGEN_RPC_HOST',
  190. 'MMGEN_RPC_FAIL_ON_COMMAND',
  191. 'MMGEN_TESTNET',
  192. 'MMGEN_REGTEST',
  193. 'MMGEN_TRACEBACK',
  194. 'MMGEN_RPC_BACKEND',
  195. 'MMGEN_USE_STANDALONE_SCRYPT_MODULE',
  196. 'MMGEN_DISABLE_COLOR',
  197. 'MMGEN_DISABLE_MSWIN_PW_WARNING',
  198. )
  199. infile_opts = (
  200. 'keys_from_file',
  201. 'mmgen_keys_from_file',
  202. 'passwd_file',
  203. 'keysforaddrs',
  204. 'comment_file',
  205. 'contract_data',
  206. )
  207. # Auto-typechecked and auto-set opts. These have no corresponding value in g.
  208. # First value in list is the default
  209. ov = namedtuple('autoset_opt_info',['type','choices'])
  210. autoset_opts = {
  211. 'fee_estimate_mode': ov('nocase_pfx', ['conservative','economical']),
  212. 'rpc_backend': ov('nocase_pfx', ['auto','httplib','curl','aiohttp','requests']),
  213. }
  214. if platform == 'win':
  215. autoset_opts['rpc_backend'].choices.remove('aiohttp')
  216. _skip_type_check = ('stdout','stderr')
  217. auto_typeset_opts = {
  218. 'seed_len': int,
  219. }
  220. min_screen_width = 80
  221. minconf = 1
  222. max_tx_file_size = 100000
  223. max_input_size = 1024 * 1024
  224. passwd_max_tries = 5
  225. max_urandchars = 80
  226. min_urandchars = 10
  227. seed_lens = 128,192,256
  228. scramble_hash_rounds = 10
  229. subseeds = 100
  230. mmenc_ext = 'mmenc'
  231. salt_len = 16
  232. aesctr_iv_len = 16
  233. aesctr_dfl_iv = int.to_bytes(1,aesctr_iv_len,'big')
  234. hincog_chk_len = 8
  235. key_generators = ('python-ecdsa','libsecp256k1') # '1','2'
  236. key_generator = 2 # libsecp256k1 is default
  237. force_standalone_scrypt_module = False
  238. # Scrypt params: 'id_num': [N, p, r] (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. hash_presets = {
  242. '1': [12, 8, 1],
  243. '2': [13, 8, 4],
  244. '3': [14, 8, 8],
  245. '4': [15, 8, 12],
  246. '5': [16, 8, 16],
  247. '6': [17, 8, 20],
  248. '7': [18, 8, 24],
  249. }
  250. if os.getenv('MMGEN_TEST_SUITE'):
  251. err_disp_timeout = 0.1
  252. short_disp_timeout = 0.1
  253. if os.getenv('MMGEN_TEST_SUITE_POPEN_SPAWN'):
  254. stdin_tty = True
  255. if prog_name == 'unit_tests.py':
  256. _set_ok += ('debug_subseed',)
  257. _reset_ok += ('force_standalone_scrypt_module','session')
  258. if os.getenv('MMGEN_DEBUG_ALL'):
  259. for name in env_opts:
  260. if name[:11] == 'MMGEN_DEBUG':
  261. os.environ[name] = '1'
  262. g = GlobalContext()