__init__.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2023 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. help: help notes for MMGen suite commands
  20. """
  21. from ..cfg import gc
  22. def help_notes_func(proto,cfg,k):
  23. def fee_spec_letters(use_quotes=False):
  24. cu = proto.coin_amt.units
  25. sep,conj = ((',',' or '),("','","' or '"))[use_quotes]
  26. return sep.join(u[0] for u in cu[:-1]) + ('',conj)[len(cu)>1] + cu[-1][0]
  27. def fee_spec_names():
  28. cu = proto.coin_amt.units
  29. return ', '.join(cu[:-1]) + ('',' and ')[len(cu)>1] + cu[-1] + ('',',\nrespectively')[len(cu)>1]
  30. def coind_exec():
  31. from ..daemon import CoinDaemon
  32. return (
  33. CoinDaemon(cfg,proto.coin).exec_fn if proto.coin in CoinDaemon.coins else 'bitcoind' )
  34. class help_notes:
  35. def MasterShareIdx():
  36. from ..seedsplit import MasterShareIdx
  37. return MasterShareIdx
  38. def test_py_log_file():
  39. from test.test_py_d.common import log_file
  40. return log_file
  41. def tool_help():
  42. from ..tool.help import main_help
  43. return main_help()
  44. def dfl_subseeds():
  45. from ..subseed import SubSeedList
  46. return str(SubSeedList.dfl_len)
  47. def dfl_seed_len():
  48. from ..seed import Seed
  49. return str(Seed.dfl_len)
  50. def password_formats():
  51. from ..passwdlist import PasswordList
  52. pwi_fs = '{:8} {:1} {:26} {:<7} {:<7} {}'
  53. return '\n '.join(
  54. [pwi_fs.format('Code','','Description','Min Len','Max Len','Default Len')] +
  55. [pwi_fs.format(k,'-',v.desc,v.min_len,v.max_len,v.dfl_len) for k,v in PasswordList.pw_info.items()]
  56. )
  57. def dfl_mmtype():
  58. from ..addr import MMGenAddrType
  59. return "'{}' or '{}'".format(
  60. proto.dfl_mmtype,
  61. MMGenAddrType.mmtypes[proto.dfl_mmtype].name )
  62. def address_types():
  63. from ..addr import MMGenAddrType
  64. return '\n '.join([
  65. "'{}','{:<12} - {}".format( k, v.name+"'", v.desc )
  66. for k,v in MMGenAddrType.mmtypes.items()
  67. ])
  68. def fmt_codes():
  69. from ..wallet import format_fmt_codes
  70. return '\n '.join( format_fmt_codes().splitlines() )
  71. def coin_id():
  72. return proto.coin_id
  73. def keygen_backends():
  74. from ..keygen import get_backends
  75. from ..addr import MMGenAddrType
  76. backends = get_backends(
  77. MMGenAddrType(proto,cfg.type or proto.dfl_mmtype).pubkey_type
  78. )
  79. return ' '.join( f'{n}:{k}{" [default]" if n==1 else ""}' for n,k in enumerate(backends,1) )
  80. def coind_exec():
  81. return coind_exec()
  82. def coin_daemon_network_ids():
  83. from ..daemon import CoinDaemon
  84. from ..util import fmt_list
  85. return fmt_list(CoinDaemon.get_network_ids(cfg),fmt='bare')
  86. def rel_fee_desc():
  87. from ..tx import BaseTX
  88. return BaseTX(cfg=cfg,proto=proto).rel_fee_desc
  89. def fee_spec_letters():
  90. return fee_spec_letters()
  91. def fee():
  92. from ..tx import BaseTX
  93. return """
  94. FEE SPECIFICATION
  95. Transaction fees, both on the command line and at the interactive prompt, may
  96. be specified as either absolute {c} amounts, using a plain decimal number, or
  97. as {r}, using an integer followed by '{l}', for {u}.
  98. """.format(
  99. c = proto.coin,
  100. r = BaseTX(cfg=cfg,proto=proto).rel_fee_desc,
  101. l = fee_spec_letters(use_quotes=True),
  102. u = fee_spec_names() )
  103. def passwd():
  104. return """
  105. PASSPHRASE NOTE:
  106. For passphrases all combinations of whitespace are equal, and leading and
  107. trailing space are ignored. This permits reading passphrase or brainwallet
  108. data from a multi-line file with free spacing and indentation.
  109. """.strip()
  110. def brainwallet():
  111. return """
  112. BRAINWALLET NOTE:
  113. To thwart dictionary attacks, it's recommended to use a strong hash preset
  114. with brainwallets. For a brainwallet passphrase to generate the correct
  115. seed, the same seed length and hash preset parameters must always be used.
  116. """.strip()
  117. def txcreate_examples():
  118. mmtype = 'S' if 'segwit' in proto.caps else 'C'
  119. from ..tool.coin import tool_cmd
  120. t = tool_cmd(cfg,mmtype=mmtype)
  121. sample_addr = t.privhex2addr('bead'*16)
  122. return f"""
  123. EXAMPLES:
  124. Send 0.123 {proto.coin} to an external {proto.name} address, returning the change to a
  125. specific MMGen address in the tracking wallet:
  126. $ {gc.prog_name} {sample_addr},0.123 01ABCDEF:{mmtype}:7
  127. Same as above, but select the change address automatically:
  128. $ {gc.prog_name} {sample_addr},0.123 01ABCDEF:{mmtype}
  129. Same as above, but select the change address automatically by address type:
  130. $ {gc.prog_name} {sample_addr},0.123 {mmtype}
  131. Same as above, but reduce verbosity and specify fee of 20 satoshis
  132. per byte:
  133. $ {gc.prog_name} -q -f 20s {sample_addr},0.123 {mmtype}
  134. Send entire balance of selected inputs minus fee to an external {proto.name}
  135. address:
  136. $ {gc.prog_name} {sample_addr}
  137. Send entire balance of selected inputs minus fee to first unused wallet
  138. address of specified type:
  139. $ {gc.prog_name} {mmtype}
  140. """
  141. def txcreate():
  142. return f"""
  143. The transaction’s outputs are listed on the command line, while its inputs
  144. are chosen from a list of the wallet’s unspent outputs via an interactive
  145. menu. Alternatively, inputs may be specified using the --inputs option.
  146. All addresses on the command line can be either {proto.name} addresses or MMGen
  147. IDs in the form <seed ID>:<address type letter>:<index>.
  148. Outputs are specified in the form <address>,<amount>, with the change output
  149. specified by address only. Alternatively, the change output may be an
  150. addrlist ID in the form <seed ID>:<address type letter>, in which case the
  151. first unused address in the tracking wallet matching the requested ID will
  152. be automatically selected as the change output.
  153. If the transaction fee is not specified on the command line (see FEE
  154. SPECIFICATION below), it will be calculated dynamically using network fee
  155. estimation for the default (or user-specified) number of confirmations.
  156. If network fee estimation fails, the user will be prompted for a fee.
  157. Network-estimated fees will be multiplied by the value of --fee-adjust, if
  158. specified.
  159. To send the value of all inputs (minus TX fee) to a single output, specify
  160. a single address with no amount on the command line. Alternatively, an
  161. addrlist ID may be specified, and the address will be chosen automatically
  162. as described above for the change output.
  163. """
  164. def txsign():
  165. from ..proto.btc.params import mainnet
  166. return """
  167. Transactions may contain both {pnm} or non-{pnm} input addresses.
  168. To sign non-{pnm} inputs, a {wd}flat key list is used
  169. as the key source ('--keys-from-file' option).
  170. To sign {pnm} inputs, key data is generated from a seed as with the
  171. {pnl}-addrgen and {pnl}-keygen commands. Alternatively, a key-address file
  172. may be used (--mmgen-keys-from-file option).
  173. Multiple wallets or other seed files can be listed on the command line in
  174. any order. If the seeds required to sign the transaction's inputs are not
  175. found in these files (or in the default wallet), the user will be prompted
  176. for seed data interactively.
  177. To prevent an attacker from crafting transactions with bogus {pnm}-to-{pnu}
  178. address mappings, all outputs to {pnm} addresses are verified with a seed
  179. source. Therefore, seed files or a key-address file for all {pnm} outputs
  180. must also be supplied on the command line if the data can't be found in the
  181. default wallet.
  182. """.format(
  183. wd = (f'{coind_exec()} wallet dump or ' if isinstance(proto,mainnet) else ''),
  184. pnm = gc.proj_name,
  185. pnu = proto.name,
  186. pnl = gc.proj_name.lower() )
  187. def subwallet():
  188. from ..subseed import SubSeedIdxRange
  189. return f"""
  190. SUBWALLETS:
  191. Subwallets (subseeds) are specified by a "Subseed Index" consisting of:
  192. a) an integer in the range 1-{SubSeedIdxRange.max_idx}, plus
  193. b) an optional single letter, 'L' or 'S'
  194. The letter designates the length of the subseed. If omitted, 'L' is assumed.
  195. Long ('L') subseeds are the same length as their parent wallet's seed
  196. (typically 256 bits), while short ('S') subseeds are always 128-bit.
  197. The long and short subseeds for a given index are derived independently,
  198. so both may be used.
  199. MMGen has no notion of "depth", and to an outside observer subwallets are
  200. identical to ordinary wallets. This is a feature rather than a bug, as it
  201. denies an attacker any way of knowing whether a given wallet has a parent.
  202. Since subwallets are just wallets, they may be used to generate other
  203. subwallets, leading to hierarchies of arbitrary depth. However, this is
  204. inadvisable in practice for two reasons: Firstly, it creates accounting
  205. complexity, requiring the user to independently keep track of a derivation
  206. tree. More importantly, however, it leads to the danger of Seed ID
  207. collisions between subseeds at different levels of the hierarchy, as
  208. MMGen checks and avoids ID collisions only among sibling subseeds.
  209. An exception to this caveat would be a multi-user setup where sibling
  210. subwallets are distributed to different users as their default wallets.
  211. Since the subseeds derived from these subwallets are private to each user,
  212. Seed ID collisions among them doesn't present a problem.
  213. A safe rule of thumb, therefore, is for *each user* to derive all of his/her
  214. subwallets from a single parent. This leaves each user with a total of two
  215. million subwallets, which should be enough for most practical purposes.
  216. """.strip()
  217. return getattr(help_notes,k)()