New 'mmgen-walletconv' utility converts to and from all available MMGen wallet
formats, thus obsoleting much of the functionality in '-walletgen' and '-walletchk'. This is the first script to utilize the new OO wallet code in 'seed.py'. New tests in the 'test.py' suite. new file: mmgen-walletconv new file: mmgen/main_walletconv.py modified: mmgen/seed.py modified: test/test.py
This commit is contained in:
parent
1c1659add0
commit
03b1b4b00e
41 changed files with 1728 additions and 1090 deletions
25
mmgen-walletconv
Executable file
25
mmgen-walletconv
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# Copyright (C)2013-2015 Philemon <mmgen-py@yandex.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
mmgen-walletconv: Convert an MMGen deterministic wallet from one format
|
||||
to another
|
||||
"""
|
||||
|
||||
from mmgen.main import launch
|
||||
launch("walletconv")
|
||||
|
|
@ -224,6 +224,13 @@ class AddrInfoList(MMGenObject):
|
|||
if sid in self.data:
|
||||
return self.data[sid]
|
||||
|
||||
def mmaddr2btcaddr(self,mmaddr):
|
||||
btcaddr = ""
|
||||
sid,idx = mmaddr.split(":")
|
||||
if sid in self.seed_ids():
|
||||
btcaddr = self.addrinfo(sid).btcaddr(int(idx))
|
||||
return btcaddr
|
||||
|
||||
def add_wallet_data(self,c):
|
||||
vmsg_r("Getting account data from wallet...")
|
||||
data,accts,i = {},c.listaccounts(minconf=0,includeWatchonly=True),0
|
||||
|
|
@ -291,10 +298,12 @@ class AddrInfo(MMGenObject):
|
|||
self.seed_id = seed_id
|
||||
self.addrdata = addrdata
|
||||
self.num_addrs = len(addrdata)
|
||||
if self.source in ("wallet","txsign") or \
|
||||
(self.source == "addrgen" and opt.gen_what == "k"):
|
||||
if self.source in ("wallet","txsign"):
|
||||
self.checksum = None
|
||||
self.idxs_fmt = None
|
||||
elif self.source == "addrgen" and opt.gen_what == "k":
|
||||
self.checksum = None
|
||||
self.fmt_addr_idxs()
|
||||
else: # self.source in addrfile, addrgen
|
||||
self.make_addrdata_chksum()
|
||||
self.fmt_addr_idxs()
|
||||
|
|
@ -383,10 +392,11 @@ class AddrInfo(MMGenObject):
|
|||
out = []
|
||||
from mmgen.addr import addrmsgs
|
||||
out.append(addrmsgs['addrfile_header'] + "\n")
|
||||
w = "Key-address" if status[1] else "Address"
|
||||
out.append("# {} data checksum for {}[{}]: {}".format(
|
||||
w, self.seed_id, self.idxs_fmt, self.checksum))
|
||||
out.append("# Record this value to a secure location\n")
|
||||
if self.checksum:
|
||||
w = "Key-address" if status[1] else "Address"
|
||||
out.append("# {} data checksum for {}[{}]: {}".format(
|
||||
w, self.seed_id, self.idxs_fmt, self.checksum))
|
||||
out.append("# Record this value to a secure location\n")
|
||||
out.append("%s {" % self.seed_id)
|
||||
|
||||
# Body
|
||||
|
|
@ -409,7 +419,7 @@ class AddrInfo(MMGenObject):
|
|||
|
||||
out.append("}")
|
||||
|
||||
return "\n".join([l.rstrip() for l in out])
|
||||
return "\n".join([l.rstrip() for l in out]) + "\n"
|
||||
|
||||
|
||||
def fmt_addr_idxs(self):
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
crypto.py: Cryptographic and related routines for the 'mmgen-tool' utility
|
||||
crypto.py: Cryptographic and related routines for the MMGen suite
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
|
@ -58,7 +58,7 @@ to exit and re-run the program with the '--old-incog-fmt' option.
|
|||
}
|
||||
|
||||
def encrypt_seed(seed, key):
|
||||
return encrypt_data(seed, key, iv=1, what="seed")
|
||||
return encrypt_data(seed, key, iv=1, desc="seed")
|
||||
|
||||
|
||||
def decrypt_seed(enc_seed, key, seed_id, key_id):
|
||||
|
|
@ -66,21 +66,21 @@ def decrypt_seed(enc_seed, key, seed_id, key_id):
|
|||
vmsg_r("Checking key...")
|
||||
chk1 = make_chksum_8(key)
|
||||
if key_id:
|
||||
if not compare_chksums(key_id,"key id",chk1,"computed",die=False):
|
||||
if not compare_chksums(key_id,"key ID",chk1,"computed"):
|
||||
msg("Incorrect passphrase")
|
||||
return False
|
||||
|
||||
dec_seed = decrypt_data(enc_seed, key, iv=1, what="seed")
|
||||
dec_seed = decrypt_data(enc_seed, key, iv=1, desc="seed")
|
||||
|
||||
chk2 = make_chksum_8(dec_seed)
|
||||
|
||||
if seed_id:
|
||||
if compare_chksums(seed_id,"seed id",chk2,"decrypted seed",die=False):
|
||||
if compare_chksums(seed_id,"seed ID",chk2,"decrypted seed"):
|
||||
qmsg("Passphrase is OK")
|
||||
else:
|
||||
if not opt.debug:
|
||||
msg_r("Checking key ID...")
|
||||
if compare_chksums(key_id,"key id",chk1,"computed",die=False):
|
||||
if compare_chksums(key_id,"key ID",chk1,"computed"):
|
||||
msg("Key ID is correct but decryption of seed failed")
|
||||
else:
|
||||
msg("Incorrect passphrase")
|
||||
|
|
@ -90,29 +90,25 @@ def decrypt_seed(enc_seed, key, seed_id, key_id):
|
|||
# else:
|
||||
# qmsg("Generated IDs (Seed/Key): %s/%s" % (chk2,chk1))
|
||||
|
||||
if opt.debug: Msg("Decrypted seed: %s" % hexlify(dec_seed))
|
||||
dmsg("Decrypted seed: %s" % hexlify(dec_seed))
|
||||
|
||||
vmsg("OK")
|
||||
return dec_seed
|
||||
|
||||
|
||||
def encrypt_data(data, key, iv=1, what="data", verify=True):
|
||||
"""
|
||||
Encrypt arbitrary data using AES256 in counter mode
|
||||
"""
|
||||
def encrypt_data(data, key, iv=1, desc="data", verify=True):
|
||||
|
||||
# 192-bit seed is 24 bytes -> not multiple of 16. Must use MODE_CTR
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util import Counter
|
||||
|
||||
vmsg("Encrypting %s" % what)
|
||||
vmsg("Encrypting %s" % desc)
|
||||
|
||||
c = AES.new(key, AES.MODE_CTR,
|
||||
counter=Counter.new(g.aesctr_iv_len*8,initial_value=iv))
|
||||
enc_data = c.encrypt(data)
|
||||
|
||||
if verify:
|
||||
vmsg_r("Performing a test decryption of the %s..." % what)
|
||||
vmsg_r("Performing a test decryption of the %s..." % desc)
|
||||
|
||||
c = AES.new(key, AES.MODE_CTR,
|
||||
counter=Counter.new(g.aesctr_iv_len*8,initial_value=iv))
|
||||
|
|
@ -120,15 +116,15 @@ def encrypt_data(data, key, iv=1, what="data", verify=True):
|
|||
|
||||
if dec_data == data: vmsg("done")
|
||||
else:
|
||||
msg("ERROR.\nDecrypted %s doesn't match original %s" % (what,what))
|
||||
msg("ERROR.\nDecrypted %s doesn't match original %s" % (desc,desc))
|
||||
sys.exit(2)
|
||||
|
||||
return enc_data
|
||||
|
||||
|
||||
def decrypt_data(enc_data, key, iv=1, what="data"):
|
||||
def decrypt_data(enc_data, key, iv=1, desc="data"):
|
||||
|
||||
vmsg_r("Decrypting %s with key..." % what)
|
||||
vmsg_r("Decrypting %s with key..." % desc)
|
||||
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util import Counter
|
||||
|
|
@ -151,18 +147,18 @@ def scrypt_hash_passphrase(passwd, salt, hash_preset, buflen=32):
|
|||
|
||||
|
||||
def make_key(passwd,salt,hash_preset,
|
||||
what="encryption key",from_what="passphrase",verbose=False):
|
||||
desc="encryption key",from_what="passphrase",verbose=False):
|
||||
|
||||
if from_what: what += " from "
|
||||
if from_what: desc += " from "
|
||||
if opt.verbose or verbose:
|
||||
msg_r("Generating %s%s..." % (what,from_what))
|
||||
msg_r("Generating %s%s..." % (desc,from_what))
|
||||
key = scrypt_hash_passphrase(passwd, salt, hash_preset)
|
||||
if opt.verbose or verbose: msg("done")
|
||||
if opt.debug: Msg("Key: %s" % hexlify(key))
|
||||
dmsg("Key: %s" % hexlify(key))
|
||||
return key
|
||||
|
||||
|
||||
def get_random_data_from_user(uchars):
|
||||
def _get_random_data_from_user(uchars):
|
||||
|
||||
if opt.quiet: msg("Enter %s random symbols" % uchars)
|
||||
else: msg(crmsg['usr_rand_notice'] % uchars)
|
||||
|
|
@ -189,8 +185,7 @@ def get_random_data_from_user(uchars):
|
|||
|
||||
fmt_time_data = ["{:.22f}".format(i) for i in time_data]
|
||||
|
||||
if opt.debug:
|
||||
msg("\nUser input:\n%s\nKeystroke time intervals:\n%s\n" %
|
||||
dmsg("\nUser input:\n%s\nKeystroke time intervals:\n%s\n" %
|
||||
(key_data,"\n".join(fmt_time_data)))
|
||||
|
||||
prompt = "User random data successfully acquired. Press ENTER to continue"
|
||||
|
|
@ -202,23 +197,23 @@ def get_random_data_from_user(uchars):
|
|||
def get_random(length):
|
||||
from Crypto import Random
|
||||
os_rand = Random.new().read(length)
|
||||
if g.use_urandchars:
|
||||
if g.use_urandchars and opt.usr_randchars:
|
||||
from_what = "OS random data"
|
||||
if not g.user_entropy:
|
||||
g.user_entropy = \
|
||||
sha256(get_random_data_from_user(opt.usr_randchars)).digest()
|
||||
sha256(_get_random_data_from_user(opt.usr_randchars)).digest()
|
||||
from_what += " plus user-supplied entropy"
|
||||
else:
|
||||
from_what += " plus saved user-supplied entropy"
|
||||
key = make_key(g.user_entropy, "", '2', from_what=from_what, verbose=True)
|
||||
return encrypt_data(os_rand,key,what="random data",verify=False)
|
||||
return encrypt_data(os_rand,key,desc="random data",verify=False)
|
||||
else:
|
||||
return os_rand
|
||||
|
||||
|
||||
def get_seed_from_wallet(
|
||||
infile,
|
||||
prompt_info="{pnm} wallet".format(pnm=g.proj_name),
|
||||
desc="{pnm} wallet".format(pnm=g.proj_name),
|
||||
silent=False
|
||||
):
|
||||
|
||||
|
|
@ -228,7 +223,7 @@ def get_seed_from_wallet(
|
|||
if opt.debug: display_control_data(*wdata)
|
||||
|
||||
padd = " "+infile if opt.quiet else ""
|
||||
passwd = get_mmgen_passphrase(prompt_info+padd)
|
||||
passwd = get_mmgen_passphrase(desc+padd)
|
||||
|
||||
key = make_key(passwd, salt, hash_preset)
|
||||
|
||||
|
|
@ -270,17 +265,17 @@ def confirm_old_format():
|
|||
|
||||
def get_seed_from_incog_wallet(
|
||||
infile,
|
||||
prompt_info="{pnm} incognito wallet".format(pnm=g.proj_name),
|
||||
desc="{pnm} incognito wallet".format(pnm=g.proj_name),
|
||||
silent=False,
|
||||
hex_input=False
|
||||
):
|
||||
|
||||
what = "incognito wallet data"
|
||||
desc = "incognito wallet data"
|
||||
|
||||
if opt.from_incog_hidden:
|
||||
d = get_hidden_incog_data()
|
||||
else:
|
||||
d = get_data_from_file(infile,what)
|
||||
d = get_data_from_file(infile,desc)
|
||||
if hex_input:
|
||||
try:
|
||||
d = unhexlify("".join(d.split()).strip())
|
||||
|
|
@ -310,10 +305,13 @@ def get_seed_from_incog_wallet(
|
|||
else 'incog_iv_id'])
|
||||
|
||||
while True:
|
||||
passwd = get_mmgen_passphrase(prompt_info+" "+incog_id)
|
||||
passwd = get_mmgen_passphrase(desc+" "+incog_id)
|
||||
|
||||
qmsg("Configured hash presets: %s" % " ".join(sorted(g.hash_presets)))
|
||||
hp = get_hash_preset_from_user(what="incog wallet")
|
||||
if 'hash_preset' in opt.set_by_user:
|
||||
hp = opt.hash_preset
|
||||
else:
|
||||
hp = get_hash_preset_from_user(desc="incog wallet")
|
||||
|
||||
# IV is used BOTH to initialize counter and to salt password!
|
||||
key = make_key(passwd, iv, hp, "wrapper key")
|
||||
|
|
@ -399,7 +397,7 @@ def _get_seed(infile,silent=False,seed_id=""):
|
|||
msg("Invalid %s file '%s'" % (source,infile))
|
||||
sys.exit(2)
|
||||
|
||||
if opt.debug: Msg("Seed: %s" % hexlify(seed))
|
||||
dmsg("Seed: %s" % hexlify(seed))
|
||||
|
||||
return seed
|
||||
|
||||
|
|
@ -415,9 +413,9 @@ def get_seed_retry(infile,seed_id=""):
|
|||
|
||||
def _get_seed_from_brain_passphrase(words,silent=False):
|
||||
bp = " ".join(words)
|
||||
if opt.debug: Msg("Sanitized brain passphrase: %s" % bp)
|
||||
dmsg("Sanitized brain passphrase: %s" % bp)
|
||||
seed_len,hash_preset = get_from_brain_opt_params()
|
||||
if opt.debug: Msg("Brainwallet l = %s, p = %s" % (seed_len,hash_preset))
|
||||
dmsg("Brainwallet l = %s, p = %s" % (seed_len,hash_preset))
|
||||
vmsg_r("Hashing brainwallet data. Please wait...")
|
||||
# Use buflen arg of scrypt.hash() to get seed of desired length
|
||||
seed = scrypt_hash_passphrase(bp, "", hash_preset, buflen=seed_len/8)
|
||||
|
|
@ -432,31 +430,31 @@ def _get_seed_from_brain_passphrase(words,silent=False):
|
|||
# Vars for mmgen_*crypt functions only
|
||||
salt_len,sha256_len,nonce_len = 32,32,32
|
||||
|
||||
def mmgen_encrypt(data,what="data",hash_preset=''):
|
||||
def mmgen_encrypt(data,desc="data",hash_preset=''):
|
||||
salt,iv,nonce = get_random(salt_len),\
|
||||
get_random(g.aesctr_iv_len), \
|
||||
get_random(nonce_len)
|
||||
hp = hash_preset or get_hash_preset_from_user('3',what)
|
||||
hp = hash_preset or get_hash_preset_from_user('3',desc)
|
||||
m = "default" if hp == '3' else "user-requested"
|
||||
vmsg("Encrypting %s" % what)
|
||||
vmsg("Encrypting %s" % desc)
|
||||
qmsg("Using %s hash preset of '%s'" % (m,hp))
|
||||
passwd = get_new_passphrase(what, {})
|
||||
passwd = get_new_passphrase(desc, {})
|
||||
key = make_key(passwd, salt, hp)
|
||||
enc_d = encrypt_data(sha256(nonce+data).digest() + nonce + data, key,
|
||||
int(hexlify(iv),16), what=what)
|
||||
int(hexlify(iv),16), desc=desc)
|
||||
return salt+iv+enc_d
|
||||
|
||||
|
||||
def mmgen_decrypt(data,what="data",hash_preset=""):
|
||||
def mmgen_decrypt(data,desc="data",hash_preset=""):
|
||||
dstart = salt_len + g.aesctr_iv_len
|
||||
salt,iv,enc_d = data[:salt_len],data[salt_len:dstart],data[dstart:]
|
||||
vmsg("Preparing to decrypt %s" % what)
|
||||
hp = hash_preset or get_hash_preset_from_user('3',what)
|
||||
vmsg("Preparing to decrypt %s" % desc)
|
||||
hp = hash_preset or get_hash_preset_from_user('3',desc)
|
||||
m = "default" if hp == '3' else "user-requested"
|
||||
qmsg("Using %s hash preset of '%s'" % (m,hp))
|
||||
passwd = get_mmgen_passphrase(what)
|
||||
passwd = get_mmgen_passphrase(desc)
|
||||
key = make_key(passwd, salt, hp)
|
||||
dec_d = decrypt_data(enc_d, key, int(hexlify(iv),16), what)
|
||||
dec_d = decrypt_data(enc_d, key, int(hexlify(iv),16), desc)
|
||||
if dec_d[:sha256_len] == sha256(dec_d[sha256_len:]).digest():
|
||||
vmsg("OK")
|
||||
return dec_d[sha256_len+nonce_len:]
|
||||
|
|
@ -464,8 +462,8 @@ def mmgen_decrypt(data,what="data",hash_preset=""):
|
|||
msg("Incorrect passphrase or hash preset")
|
||||
return False
|
||||
|
||||
def mmgen_decrypt_retry(d,what="data"):
|
||||
def mmgen_decrypt_retry(d,desc="data"):
|
||||
while True:
|
||||
d_dec = mmgen_decrypt(d,what)
|
||||
d_dec = mmgen_decrypt(d,desc)
|
||||
if d_dec: return d_dec
|
||||
msg("Trying again...")
|
||||
|
|
|
|||
|
|
@ -20,66 +20,25 @@
|
|||
filename.py: Filename class and methods for the MMGen suite
|
||||
"""
|
||||
import sys,os
|
||||
import mmgen.opt as opt
|
||||
from mmgen.obj import *
|
||||
import mmgen.globalvars as g
|
||||
from mmgen.util import msg,fmt_code_to_sstype
|
||||
from mmgen.util import die,get_extension,check_infile
|
||||
|
||||
class Filename(MMGenObject):
|
||||
|
||||
exts = {
|
||||
'seed': {
|
||||
"mmdat": "Wallet",
|
||||
"mmseed": "SeedFile",
|
||||
"mmwords": "Mnemonic",
|
||||
"mmbrain": "Brainwallet",
|
||||
"mmincog": "IncogWallet",
|
||||
"mmincox": "IncogWalletHex",
|
||||
},
|
||||
'tx': {
|
||||
"raw": "RawTX",
|
||||
"sig": "SigTX",
|
||||
},
|
||||
'addr': {
|
||||
"addrs": "AddrInfo",
|
||||
"keys": "KeyInfo",
|
||||
"akeys": "KeyAddrInfo",
|
||||
"akeys.mmenc": "KeyAddrInfoEnc",
|
||||
},
|
||||
'other': {
|
||||
"chk": "AddrInfoChecksum",
|
||||
"mmenc": "MMEncInfo",
|
||||
},
|
||||
}
|
||||
|
||||
ftypes = {
|
||||
'seed': {
|
||||
"hincog": "IncogWalletHidden",
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self,fn,ftype=""):
|
||||
def __init__(self,fn,ftype=None):
|
||||
self.name = fn
|
||||
self.dirname = os.path.dirname(fn)
|
||||
self.basename = os.path.basename(fn)
|
||||
self.ext = None
|
||||
self.ftype = ftype
|
||||
|
||||
def mf1(k): return k == ftype
|
||||
def mf2(k): return '.'+k == fn[-len('.'+k):]
|
||||
# This should be done before license msg instead
|
||||
# check_infile(fn)
|
||||
|
||||
# find file info for ftype or extension
|
||||
e,attr,have_match = (self.ftypes,"ftype",mf1) if ftype else \
|
||||
(self.exts,"ext",mf2)
|
||||
|
||||
for k in e:
|
||||
for j in e[k]:
|
||||
if have_match(j):
|
||||
setattr(self,attr,j)
|
||||
self.fclass = k
|
||||
self.sstype = e[k][j]
|
||||
|
||||
if not hasattr(self,attr):
|
||||
die(2,"Unrecognized %s for file '%s'" % (attr,fn))
|
||||
if not ftype:
|
||||
self.ext = get_extension(fn)
|
||||
if not (self.ext):
|
||||
die(2,"Unrecognized extension '.%s' for file '%s'" % (self.ext,fn))
|
||||
|
||||
# TODO: Check for Windows
|
||||
import stat
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ version = '0.8.0'
|
|||
|
||||
required_opts = [
|
||||
"quiet","verbose","debug","outdir","echo_passphrase","passwd_file",
|
||||
"usr_randchars","stdout","show_hash_presets"
|
||||
"usr_randchars","stdout","show_hash_presets","label",
|
||||
"keep_passphrase","keep_hash_preset"
|
||||
]
|
||||
min_screen_width = 80
|
||||
|
||||
|
|
@ -119,16 +120,3 @@ addr_label_symbols = wallet_label_symbols = printable_nonl
|
|||
max_addr_label_len = 32
|
||||
max_wallet_label_len = 48
|
||||
max_tx_comment_len = 72 # Comment is b58 encoded, so can permit all UTF-8
|
||||
|
||||
wallet_fmt_codes = (
|
||||
( "Wallet", "wallet", "w" ),
|
||||
( "SeedFile", "mmseed","seed", "s" ),
|
||||
( "Mnemonic", "mmwords","words","mnemonic","mnem","m" ),
|
||||
( "Brainwallet", "mmbrain","brainwallet","brain","bw","b" ),
|
||||
( "IncogWallet", "mmincog","incog","i" ),
|
||||
( "IncogWalletHex", "mmincox","incog_hex","ix" ),
|
||||
( "IncogWalletHidden", "incog_hidden","ih" ),
|
||||
)
|
||||
#addr_label_punc = ".","_",",","-"," ","(",")"
|
||||
#addr_label_symbols = tuple(ascii_letters + digits) + addr_label_punc
|
||||
#wallet_label_punc = addr_label_punc
|
||||
|
|
|
|||
|
|
@ -19,18 +19,16 @@
|
|||
"""
|
||||
license.py: Text of GPLv3
|
||||
"""
|
||||
|
||||
import mmgen.globalvars as g
|
||||
|
||||
gpl = {
|
||||
'warning': """
|
||||
warning = """
|
||||
{pnm} Copyright (C) {g.Cdates} by {g.author} {g.email}. This
|
||||
program comes with ABSOLUTELY NO WARRANTY. This is free software, and
|
||||
you are welcome to redistribute it under certain conditions.
|
||||
""".format(g=g,pnm=g.proj_name),
|
||||
'prompt': """
|
||||
Press 'w' for conditions and warranty info, or 'c' to continue:
|
||||
""",
|
||||
'conditions': """
|
||||
""".format(g=g,pnm=g.proj_name)
|
||||
|
||||
conditions = """
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
|
@ -581,4 +579,3 @@ an absolute waiver of all civil liability in connection with the
|
|||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
"""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ def launch(what):
|
|||
def launch_txsend(): import mmgen.main_txsend
|
||||
def launch_txsign(): import mmgen.main_txsign
|
||||
def launch_walletchk(): import mmgen.main_walletchk
|
||||
def launch_walletconv(): import mmgen.main_walletconv
|
||||
def launch_walletgen(): import mmgen.main_walletgen
|
||||
|
||||
try: import termios
|
||||
|
|
|
|||
|
|
@ -161,8 +161,8 @@ if opt.stdout or not sys.stdout.isatty():
|
|||
if enc_ext and sys.stdout.isatty():
|
||||
msg("Cannot write encrypted data to screen. Exiting")
|
||||
sys.exit(2)
|
||||
write_to_stdout(addrdata_str,what,
|
||||
(what=="keys"and not opt.quiet and sys.stdout.isatty()))
|
||||
write_to_stdout(addrdata_str,what,ask_terminal=(what=="keys"
|
||||
and not opt.quiet and sys.stdout.isatty()))
|
||||
else:
|
||||
outfile = "%s.%s%s" % (outfile_base, (
|
||||
g.keyaddrfile_ext if "ka" in opt.gen_what else (
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ if len(cmd_args) == 1:
|
|||
ai = AddrInfo(infile,has_keys=opt.keyaddr_file)
|
||||
else:
|
||||
msg("""
|
||||
"You must specify an mmgen address file (or a list of non-{pnm} addresses
|
||||
You must specify an {pnm} address file (or a list of non-{pnm} addresses
|
||||
with the '--addrlist' option)
|
||||
""".strip().format(pnm=g.proj_name))
|
||||
sys.exit(1)
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ seed_id,key_id = metadata[:2]
|
|||
|
||||
# Repeat on incorrect pw entry
|
||||
while True:
|
||||
p = "{pnm} wallet".format(pnm=g.proj_name)
|
||||
passwd = get_mmgen_passphrase(p,not opt.keep_old_passphrase)
|
||||
desc = "{pnm} wallet".format(pnm=g.proj_name)
|
||||
passwd = get_mmgen_passphrase(desc,not opt.keep_old_passphrase)
|
||||
key = make_key(passwd, salt, hash_preset)
|
||||
seed = decrypt_seed(enc_seed, key, seed_id, key_id)
|
||||
if seed: break
|
||||
|
|
|
|||
|
|
@ -180,8 +180,8 @@ class AES(object):
|
|||
def rotate(self, word):
|
||||
""" Rijndael's key schedule rotate operation.
|
||||
|
||||
Rotate a word eight bits to the left: eg, rotate(1d2c3a4f) == 2c3a4f1d
|
||||
Word is an char list of size 4 (32 bits overall).
|
||||
Rotate a word eight bits to the left: eg, rotate(1d2c3a4f) == 2c3a4f1d
|
||||
Word is an char list of size 4 (32 bits overall).
|
||||
"""
|
||||
return word[1:] + word[:1]
|
||||
|
||||
|
|
@ -230,10 +230,10 @@ class AES(object):
|
|||
def expandKey(self, key, size, expandedKeySize):
|
||||
"""Rijndael's key expansion.
|
||||
|
||||
Expands an 128,192,256 key into an 176,208,240 bytes key
|
||||
Expands an 128,192,256 key into an 176,208,240 bytes key
|
||||
|
||||
expandedKey is a char list of large enough size,
|
||||
key is the non-expanded key.
|
||||
expandedKey is a char list of large enough size,
|
||||
key is the non-expanded key.
|
||||
"""
|
||||
# current expanded keySize, in bytes
|
||||
currentSize = 0
|
||||
|
|
@ -276,8 +276,8 @@ class AES(object):
|
|||
|
||||
def createRoundKey(self, expandedKey, roundKeyPointer):
|
||||
"""Create a round key.
|
||||
Creates a round key from the given expanded key and the
|
||||
position within the expanded key.
|
||||
Creates a round key from the given expanded key and the
|
||||
position within the expanded key.
|
||||
"""
|
||||
roundKey = [0] * 16
|
||||
for i in range(4):
|
||||
|
|
@ -1183,8 +1183,8 @@ def parse_BlockLocator(vds):
|
|||
return d
|
||||
|
||||
def deserialize_BlockLocator(d):
|
||||
result = "Block Locator top: "+d['hashes'][0][::-1].encode('hex_codec')
|
||||
return result
|
||||
result = "Block Locator top: "+d['hashes'][0][::-1].encode('hex_codec')
|
||||
return result
|
||||
|
||||
def parse_setting(setting, vds):
|
||||
if setting[0] == "f": # flag (boolean) settings
|
||||
|
|
@ -1404,11 +1404,11 @@ def parse_wallet(db, item_callback):
|
|||
|
||||
def update_wallet(db, type, data):
|
||||
"""Write a single item to the wallet.
|
||||
db must be open with writable=True.
|
||||
type and data are the type code and data dictionary as parse_wallet would
|
||||
give to item_callback.
|
||||
data's __key__, __value__ and __type__ are ignored; only the primary data
|
||||
fields are used.
|
||||
db must be open with writable=True.
|
||||
type and data are the type code and data dictionary as parse_wallet would
|
||||
give to item_callback.
|
||||
data's __key__, __value__ and __type__ are ignored; only the primary data
|
||||
fields are used.
|
||||
"""
|
||||
d = data
|
||||
kds = BCDataStream()
|
||||
|
|
@ -1656,8 +1656,8 @@ elif opt.keysforaddrs:
|
|||
msg("Warning: not all requested keys found")
|
||||
|
||||
len_arg = "%s" % len(wallet_addrs) \
|
||||
if len(data) == len(wallet_addrs) or ext == "json" \
|
||||
else "%s:%s" % (len(data),len(wallet_addrs))
|
||||
if len(data) == len(wallet_addrs) or ext == "json" \
|
||||
else "%s:%s" % (len(data),len(wallet_addrs))
|
||||
|
||||
from mmgen.util import make_chksum_8,write_to_file,write_to_stdout
|
||||
wallet_id = make_chksum_8(str(sorted(wallet_addrs)))
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ from decimal import Decimal
|
|||
|
||||
import mmgen.globalvars as g
|
||||
import mmgen.opt as opt
|
||||
from mmgen.util import dmsg
|
||||
from mmgen.tx import *
|
||||
|
||||
pnm = g.proj_name
|
||||
|
|
@ -196,9 +197,9 @@ Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen
|
|||
i.addr = "%s%s %s" % (
|
||||
i.address[:btaddr_w-len(dots)],
|
||||
dots, (
|
||||
("{:<{w}} ".format(i.mmid,w=mmid_w) if i.mmid else "")
|
||||
+ i.comment)[:acct_w]
|
||||
)
|
||||
("{:<{w}} ".format(i.mmid,w=mmid_w) if i.mmid else "")
|
||||
+ i.comment)[:acct_w]
|
||||
)
|
||||
else:
|
||||
i.addr = i.address
|
||||
|
||||
|
|
@ -294,16 +295,13 @@ def mmaddr2btcaddr_unspent(unspent,mmaddr):
|
|||
|
||||
|
||||
def mmaddr2btcaddr(c,mmaddr,ail_w,ail_f):
|
||||
# assume mmaddr has already been checked
|
||||
sid,idx = mmaddr.split(":")
|
||||
btcaddr = ""
|
||||
|
||||
if sid in ail_w.seed_ids():
|
||||
btcaddr = ail_w.addrinfo(sid).btcaddr(int(idx))
|
||||
# assume mmaddr has already been checked
|
||||
btcaddr = ail_w.mmaddr2btcaddr(mmaddr)
|
||||
|
||||
if not btcaddr:
|
||||
if ail_f and sid in ail_f.seed_ids():
|
||||
btcaddr = ail_f.addrinfo(sid).btcaddr(int(idx))
|
||||
if ail_f:
|
||||
btcaddr = ail_f.mmaddr2btcaddr(mmaddr)
|
||||
if btcaddr:
|
||||
msg(wmsg['addr_in_addrfile_only'].format(mmgenaddr=mmaddr))
|
||||
if not keypress_confirm("Continue anyway?"):
|
||||
|
|
@ -449,9 +447,7 @@ if change > 0: tx_out[change_addr] = float(change)
|
|||
|
||||
tx_in = [{"txid":i.txid, "vout":i.vout} for i in sel_unspent]
|
||||
|
||||
if opt.debug:
|
||||
Msg("tx_in: " + repr(tx_in))
|
||||
Msg("tx_out: " + repr(tx_out))
|
||||
dmsg("tx_in: %s\ntx_out: %s" % (repr(tx_in),repr(tx_out)))
|
||||
|
||||
if opt.comment_file:
|
||||
if keypress_confirm("Edit comment?",False):
|
||||
|
|
|
|||
|
|
@ -68,12 +68,12 @@ if keypress_confirm("Edit transaction comment?"):
|
|||
write_to_file(outfile,data,w,False,True,True)
|
||||
|
||||
warn = "Once this transaction is sent, there's no taking it back!"
|
||||
what = "broadcast this transaction to the network"
|
||||
action = "broadcast this transaction to the network"
|
||||
expect = "YES, I REALLY WANT TO DO THIS"
|
||||
|
||||
if opt.quiet: warn,expect = "","YES"
|
||||
|
||||
confirm_or_exit(warn, what, expect)
|
||||
confirm_or_exit(warn, action, expect)
|
||||
|
||||
msg("Sending transaction")
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import sys
|
|||
import mmgen.globalvars as g
|
||||
import mmgen.opt as opt
|
||||
from mmgen.tx import *
|
||||
from mmgen.util import do_license_msg
|
||||
from mmgen.util import do_license_msg,dmsg
|
||||
|
||||
pnm = g.proj_name
|
||||
pnl = pnm.lower()
|
||||
|
|
@ -150,7 +150,7 @@ def sign_transaction(c,tx_hex,tx_num_str,sig_data,keys=None):
|
|||
|
||||
if keys:
|
||||
qmsg("Passing %s key%s to bitcoind" % (len(keys),suf(keys,"k")))
|
||||
if opt.debug: Msg("Keys:\n %s" % "\n ".join(keys))
|
||||
dmsg("Keys:\n %s" % "\n ".join(keys))
|
||||
|
||||
msg_r("Signing transaction{}...".format(tx_num_str))
|
||||
from mmgen.rpc import exceptions
|
||||
|
|
@ -192,11 +192,11 @@ def sign_tx_with_bitcoind_wallet(c,tx_hex,tx_num_str,sig_data,keys):
|
|||
return sig_tx
|
||||
|
||||
|
||||
def check_maps_from_seeds(maplist,what,infiles,saved_seeds,return_keys=False):
|
||||
def check_maps_from_seeds(maplist,desc,infiles,saved_seeds,return_keys=False):
|
||||
|
||||
if not maplist: return []
|
||||
qmsg("Checking {pnm} -> BTC address mappings for {w}s (from seed(s))".format(
|
||||
pnm=pnm,w=what))
|
||||
pnm=pnm,w=desc))
|
||||
d = get_keys_for_mmgen_addrs(maplist.keys(),infiles,saved_seeds)
|
||||
# 0=mmaddr 1=addr 2=wif
|
||||
m = dict([(e[0],e[1]) for e in d])
|
||||
|
|
@ -253,9 +253,9 @@ def parse_keylist(from_file):
|
|||
|
||||
|
||||
# Check inputs and outputs maps against key-address file, deleting entries:
|
||||
def check_maps_from_kafile(imap,what,kadata,return_keys=False):
|
||||
def check_maps_from_kafile(imap,desc,kadata,return_keys=False):
|
||||
if not kadata: return []
|
||||
qmsg("Checking {pnm} -> BTC address mappings for {w}s (from key-address file)".format(pnm=pnm,w=what))
|
||||
qmsg("Checking {pnm} -> BTC address mappings for {w}s (from key-address file)".format(pnm=pnm,w=desc))
|
||||
ret = []
|
||||
for k in imap.keys():
|
||||
if k in kadata.keys():
|
||||
|
|
@ -266,9 +266,9 @@ def check_maps_from_kafile(imap,what,kadata,return_keys=False):
|
|||
kl,il = "key-address file:","tx file:"
|
||||
msg(wmsg['mm2btc_mapping_error']%(kl,k,kadata[k][0],il,k,imap[k]))
|
||||
sys.exit(2)
|
||||
if ret: vmsg("Removed %s address%s from %ss map" % (len(ret),suf(ret,"a"),what))
|
||||
if ret: vmsg("Removed %s address%s from %ss map" % (len(ret),suf(ret,"a"),desc))
|
||||
if return_keys:
|
||||
vmsg("Added %s wif key%s from %ss map" % (len(ret),suf(ret,"k"),what))
|
||||
vmsg("Added %s wif key%s from %ss map" % (len(ret),suf(ret,"k"),desc))
|
||||
return ret
|
||||
|
||||
|
||||
|
|
@ -288,7 +288,7 @@ infiles = opt.opts.init(opts_data,add_opts=["b16"])
|
|||
for l in (
|
||||
('tx_id', 'info'),
|
||||
('tx_id', 'terse_info'),
|
||||
): opt.opts.warn_incompatible_opts(l)
|
||||
): opt.opts.die_on_incompatible_opts(l)
|
||||
|
||||
if opt.from_incog_hex or opt.from_incog_hidden: opt.from_incog = True
|
||||
|
||||
|
|
|
|||
|
|
@ -95,8 +95,7 @@ def export_to_hidden_incog(incog_enc):
|
|||
outfile,offset = opt.export_incog_hidden.split(",") #Already sanity-checked
|
||||
if opt.outdir: outfile = make_full_path(opt.outdir,outfile)
|
||||
|
||||
if opt.debug:
|
||||
Msg("Incog data len %s, offset %s" % (len(incog_enc),offset))
|
||||
dmsg("Incog data len %s, offset %s" % (len(incog_enc),offset))
|
||||
check_data_fits_file_at_offset(outfile,int(offset),len(incog_enc),"write")
|
||||
|
||||
if not opt.quiet: confirm_or_exit("","alter file '%s'" % outfile)
|
||||
|
|
@ -162,7 +161,7 @@ if opt.export_mnemonic:
|
|||
|
||||
elif opt.export_seed:
|
||||
from mmgen.bitcoin import b58encode_pad
|
||||
data = split_into_columns(4,b58encode_pad(seed))
|
||||
data = split_into_cols(4,b58encode_pad(seed))
|
||||
chk = make_chksum_6(b58encode_pad(seed))
|
||||
fn = "%s.%s" % (make_chksum_8(seed).upper(), g.seed_ext)
|
||||
write_to_file_or_stdout(fn, "%s %s\n" % (chk,data), "seed data")
|
||||
|
|
|
|||
89
mmgen/main_walletconv.py
Executable file
89
mmgen/main_walletconv.py
Executable file
|
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# Copyright (C)2013-2015 Philemon <mmgen-py@yandex.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
mmgen-walletconv: Convert an MMGen deterministic wallet from one format
|
||||
to another
|
||||
"""
|
||||
|
||||
import sys
|
||||
import mmgen.globalvars as g
|
||||
import mmgen.opt as opt
|
||||
from mmgen.util import die,msg,green,do_license_msg,check_infile
|
||||
from mmgen.seed import SeedSource
|
||||
|
||||
opts_data = {
|
||||
'sets_disabled': (
|
||||
('hidden_incog_input_params', bool, 'in_fmt', 'hi'),
|
||||
('hidden_incog_output_params', bool, 'out_fmt', 'hi')
|
||||
),
|
||||
'desc': "Convert an {pnm} wallet from one format to another".format(
|
||||
pnm=g.proj_name),
|
||||
'usage':"[opts] [infile]",
|
||||
'options': """
|
||||
-h, --help Print this help message.
|
||||
-d, --outdir= d Output files to directory 'd' instead of working dir.
|
||||
-i, --in-fmt= f Convert from wallet format 'f' (see FMT CODES below).
|
||||
-o, --out-fmt= f Convert to wallet format 'f' (see FMT CODES below).
|
||||
-H, --hidden-incog-input-params=f,o Use filename 'f' and offset 'o' (comma
|
||||
separated) for hidden incognito input.
|
||||
-J, --hidden-incog-output-params=f,o Same above, but for output. If file
|
||||
'f' doesn't exist, it will be created and filled with
|
||||
random data.
|
||||
-O, --old-incog-fmt Specify old-format incognito input.
|
||||
-k, --keep-passphrase Reuse input wallet passphrase for output wallet.
|
||||
-K, --keep-hash-preset Reuse input wallet hash preset for output wallet.
|
||||
-l, --seed-len= l Specify wallet seed length of 'l' bits. This option
|
||||
is required only for brainwallet and incognito inputs
|
||||
with non-standard (< {g.seed_len}-bit) seed lengths.
|
||||
-p, --hash-preset= p Use the scrypt hash parameters defined by preset 'p'
|
||||
for password hashing (default: '{g.hash_preset}').
|
||||
-q, --quiet Produce quieter output; suppress some warnings.
|
||||
-r, --usr-randchars=n Get 'n' characters of additional randomness from user
|
||||
(min={g.min_urandchars}, max={g.max_urandchars}, default={g.usr_randchars}).
|
||||
-S, --stdout Write wallet data to stdout instead of file.
|
||||
-v, --verbose Produce more verbose output.
|
||||
|
||||
FMT CODES:
|
||||
{f}
|
||||
""".format(g=g,f="\n ".join(SeedSource.format_fmt_codes().split("\n")))
|
||||
}
|
||||
|
||||
cmd_args = opt.opts.init(opts_data)
|
||||
|
||||
if len(cmd_args) == 0 \
|
||||
and not opt.hidden_incog_input_params \
|
||||
and not opt.in_fmt:
|
||||
die(1,"An input file or input format must be specified")
|
||||
|
||||
if len(cmd_args) > 1 or (len(cmd_args) == 1 and opt.hidden_incog_input_params):
|
||||
die(1,"Only one input file may be specified")
|
||||
|
||||
if len(cmd_args) == 1:
|
||||
check_infile(cmd_args[0])
|
||||
|
||||
do_license_msg()
|
||||
|
||||
msg(green("Processing input wallet"))
|
||||
|
||||
ss_in = SeedSource(*cmd_args)
|
||||
|
||||
msg(green("Processing output wallet"))
|
||||
|
||||
ss_out = SeedSource(ss=ss_in)
|
||||
ss_out.write_to_file()
|
||||
14
mmgen/obj.py
14
mmgen/obj.py
|
|
@ -20,7 +20,7 @@
|
|||
obj.py: The MMGenObject class and methods
|
||||
"""
|
||||
import mmgen.globalvars as g
|
||||
from mmgen.util import msgrepr_exit,msgrepr
|
||||
from mmgen.util import mdie,mmsg
|
||||
|
||||
lvl = 0
|
||||
|
||||
|
|
@ -72,18 +72,18 @@ class MMGenObject(object):
|
|||
col_w = max(len(k) for k in keys)
|
||||
fs = "{}%-{}s: %s".format(indent,col_w)
|
||||
|
||||
methods = [k for k in keys if repr(getattr(self,k))[:14] == '<bound method ']
|
||||
methods = [k for k in keys if repr(getattr(self,k))[:14] == '<bound method ']
|
||||
|
||||
def f(k): return repr(getattr(self,k))[:14] == '<bound method '
|
||||
methods = filter(f,keys)
|
||||
def f(k): return repr(getattr(self,k))[:7] == '<mmgen.'
|
||||
objects = filter(f,keys)
|
||||
def f(k): return repr(getattr(self,k))[:14] == '<bound method '
|
||||
methods = filter(f,keys)
|
||||
def f(k): return repr(getattr(self,k))[:7] == '<mmgen.'
|
||||
objects = filter(f,keys)
|
||||
other = list(set(keys) - set(methods) - set(objects))
|
||||
|
||||
for k in sorted(methods) + sorted(other) + sorted(objects):
|
||||
val = getattr(self,k)
|
||||
if str(type(val))[:13] == "<class 'mmgen": # recurse into sub-objects
|
||||
out.append("\n%s%s (%s):" % (indent,k,repr(type(val))))
|
||||
out.append("\n%s%s (%s):" % (indent,k,type(val)))
|
||||
lvl += 1
|
||||
out.append(str(getattr(self,k))+"\n")
|
||||
lvl -= 1
|
||||
|
|
|
|||
145
mmgen/opts.py
145
mmgen/opts.py
|
|
@ -24,7 +24,7 @@ import sys
|
|||
import mmgen.globalvars as g
|
||||
import mmgen.share.Opts
|
||||
import opt
|
||||
from mmgen.util import msg,msgrepr_exit,msgrepr,Msg,fmt_type
|
||||
from mmgen.util import msg,msg_r,mdie,mmsg,Msg,die
|
||||
|
||||
def usage():
|
||||
Msg("USAGE: %s %s" % (g.prog_name, usage_txt))
|
||||
|
|
@ -32,17 +32,15 @@ def usage():
|
|||
|
||||
def print_version_info():
|
||||
Msg("""
|
||||
{progname_uc} version {g.version}
|
||||
{pgnm_uc} version {g.version}
|
||||
Part of the {pnm} suite, a Bitcoin cold-storage solution for the com-
|
||||
mand line. Copyright (C) {g.Cdates} {g.author} {g.email}
|
||||
""".format(pnm=g.proj_name,g=g,progname_uc=g.prog_name.upper()).strip())
|
||||
""".format(pnm=g.proj_name, g=g, pgnm_uc=g.prog_name.upper()).strip())
|
||||
|
||||
def warn_incompatible_opts(incompat_list):
|
||||
def die_on_incompatible_opts(incompat_list):
|
||||
bad = [k for k in opt.__dict__ if opt.__dict__[k] and k in incompat_list]
|
||||
if len(bad) > 1:
|
||||
msg("Mutually exclusive options: %s" % " ".join(
|
||||
["--"+b.replace("_","-") for b in bad]))
|
||||
sys.exit(1)
|
||||
die(1,"Conflicting options: %s" % ", ".join([fmt_opt(b) for b in bad]))
|
||||
|
||||
def _typeconvert_from_dfl(key):
|
||||
|
||||
|
|
@ -51,7 +49,6 @@ def _typeconvert_from_dfl(key):
|
|||
gval = g.__dict__[key]
|
||||
uval = opt.__dict__[key]
|
||||
gtype = type(gval)
|
||||
utype = type(uval)
|
||||
|
||||
try:
|
||||
opt.__dict__[key] = gtype(opt.__dict__[key])
|
||||
|
|
@ -62,16 +59,18 @@ def _typeconvert_from_dfl(key):
|
|||
'float': 'a float',
|
||||
'bool': 'a boolean value',
|
||||
}
|
||||
m = [d[k] for k in d if __builtins__[k] == gtype]
|
||||
fs = "'%s': invalid parameter for '--%s' option (not %s)"
|
||||
msg(fs % (opt.__dict__[key],opt.replace("_","-"),m))
|
||||
sys.exit(1)
|
||||
die(1, "'%s': invalid parameter for '--%s' option (not %s)" % (
|
||||
opt.__dict__[key],
|
||||
key.replace("_","-"),
|
||||
d[gtype.__name__]
|
||||
))
|
||||
|
||||
if g.debug:
|
||||
Msg("Opt overriden by user:\n %-18s: %s" % (
|
||||
key, ("%s -> %s" % (gval,uval))
|
||||
))
|
||||
|
||||
def fmt_opt(o): return "--" + o.replace("_","-")
|
||||
|
||||
def _show_hash_presets():
|
||||
fs = " {:<7} {:<6} {:<3} {}"
|
||||
|
|
@ -116,21 +115,25 @@ def init(opts_data,add_opts=[]):
|
|||
for o in [s.rstrip("=") for s in long_opts] + g.required_opts + add_opts:
|
||||
opt.__dict__[o] = uopts[o] if o in uopts else None
|
||||
|
||||
# check user-set opts without modifying them
|
||||
if not check_opts(uopts): sys.exit(1)
|
||||
|
||||
# A special case - do this here, before opt gets set from g.dfl_vars
|
||||
if opt.usr_randchars: g.use_urandchars = True
|
||||
|
||||
# If user opt is set, convert its type based on value in mmgen.globalvars
|
||||
# If unset, set it to default value in mmgen.globalvars (g):
|
||||
opt.__dict__['set_by_user'] = []
|
||||
for k in g.dfl_vars:
|
||||
if k in opt.__dict__ and opt.__dict__[k] != None:
|
||||
_typeconvert_from_dfl(k)
|
||||
else: opt.__dict__[k] = g.__dict__[k]
|
||||
opt.set_by_user.append(k)
|
||||
else:
|
||||
opt.__dict__[k] = g.__dict__[k]
|
||||
|
||||
# Check user-set opts without modifying them
|
||||
if not check_opts(uopts): sys.exit(1)
|
||||
|
||||
if opt.show_hash_presets:
|
||||
_show_hash_presets(); sys.exit(0)
|
||||
|
||||
if opt.debug: opt.verbose = True
|
||||
|
||||
if g.debug:
|
||||
|
|
@ -138,7 +141,7 @@ def init(opts_data,add_opts=[]):
|
|||
for k in opt.__dict__:
|
||||
v = opt.__dict__[k]
|
||||
if v != None and k != "opts":
|
||||
Msg(" %-18s: %-6s [%s]" % (k,v,fmt_type(v)))
|
||||
Msg(" %-18s: %-6s [%s]" % (k,v,type(v).__name__))
|
||||
Msg("### END OPTS.PY ###\n")
|
||||
|
||||
for l in (
|
||||
|
|
@ -146,7 +149,7 @@ def init(opts_data,add_opts=[]):
|
|||
('export_incog','export_incog_hex','export_incog_hidden','export_mnemonic',
|
||||
'export_seed'),
|
||||
('quiet','verbose')
|
||||
): warn_incompatible_opts(l)
|
||||
): die_on_incompatible_opts(l)
|
||||
|
||||
return args
|
||||
|
||||
|
|
@ -160,50 +163,61 @@ def show_all_opts():
|
|||
|
||||
def check_opts(usr_opts): # Returns false if any check fails
|
||||
|
||||
def opt_splits(val,sep,n,what):
|
||||
def opt_splits(val,sep,n,desc):
|
||||
sepword = "comma" if sep == "," else (
|
||||
"colon" if sep == ":" else ("'"+sep+"'"))
|
||||
try: l = val.split(sep)
|
||||
except:
|
||||
msg("'%s': invalid %s (not %s-separated list)" % (val,what,sepword))
|
||||
msg("'%s': invalid %s (not %s-separated list)" % (val,desc,sepword))
|
||||
return False
|
||||
|
||||
if len(l) == n: return True
|
||||
else:
|
||||
msg("'%s': invalid %s (%s %s-separated items required)" %
|
||||
(val,what,n,sepword))
|
||||
(val,desc,n,sepword))
|
||||
return False
|
||||
|
||||
def opt_compares(val,op,target,what):
|
||||
def opt_compares(val,op,target,desc):
|
||||
if not eval("%s %s %s" % (val, op, target)):
|
||||
msg("%s: invalid %s (not %s %s)" % (val,what,op,target))
|
||||
msg("%s: invalid %s (not %s %s)" % (val,desc,op,target))
|
||||
return False
|
||||
return True
|
||||
|
||||
def opt_is_int(val,what):
|
||||
def opt_is_int(val,desc):
|
||||
try: int(val)
|
||||
except:
|
||||
msg("'%s': invalid %s (not an integer)" % (val,what))
|
||||
msg("'%s': invalid %s (not an integer)" % (val,desc))
|
||||
return False
|
||||
return True
|
||||
|
||||
def opt_is_in_list(val,lst,what):
|
||||
def opt_is_in_list(val,lst,desc):
|
||||
if val not in lst:
|
||||
q,sep = ("'","','") if type(lst[0]) == str else ("",",")
|
||||
msg("{q}{}{q}: invalid {}\nValid options: {q}{}{q}".format(
|
||||
val,what,sep.join([str(i) for i in sorted(lst)]),q=q))
|
||||
msg("{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}".format(
|
||||
v=val,w=desc,q=q,
|
||||
o=sep.join([str(i) for i in sorted(lst)])
|
||||
))
|
||||
return False
|
||||
return True
|
||||
|
||||
def opt_unrecognized(key,val,desc):
|
||||
msg("'%s': unrecognized %s for option '%s'"
|
||||
% (val,desc,fmt_opt(key)))
|
||||
return False
|
||||
|
||||
def opt_display(key,val='',beg="For selected",end=":\n"):
|
||||
s = "%s=%s" % (fmt_opt(key),val) if val else fmt_opt(key)
|
||||
msg_r("%s option '%s'%s" % (beg,s,end))
|
||||
|
||||
global opt
|
||||
for key,val in [(k,getattr(opt,k)) for k in usr_opts]:
|
||||
|
||||
what = "parameter for '--%s' option" % key.replace("_","-")
|
||||
desc = "parameter for '%s' option" % fmt_opt(key)
|
||||
|
||||
# Check for file existence and readability
|
||||
from mmgen.util import check_infile
|
||||
if key in ('keys_from_file','mmgen_keys_from_file',
|
||||
'passwd_file','keysforaddrs','comment_file'):
|
||||
from mmgen.util import check_infile
|
||||
check_infile(val) # exits on error
|
||||
continue
|
||||
|
||||
|
|
@ -220,40 +234,83 @@ def check_opts(usr_opts): # Returns false if any check fails
|
|||
w = "character in label"
|
||||
for ch in list(val):
|
||||
if not opt_is_in_list(ch,g.wallet_label_symbols,w): return False
|
||||
# NEW
|
||||
elif key in ('in_fmt','out_fmt'):
|
||||
from mmgen.seed import SeedSource,IncogWallet,Brainwallet,IncogWalletHidden
|
||||
sstype = SeedSource.fmt_code_to_sstype(val)
|
||||
if not sstype:
|
||||
return opt_unrecognized(key,val,"format code")
|
||||
if key == 'out_fmt':
|
||||
p = 'hidden_incog_output_params'
|
||||
if sstype == IncogWalletHidden and not getattr(opt,p):
|
||||
die(1,"Hidden incog format output requested. You must supply"
|
||||
+ " a file and offset with the '%s' option" % fmt_opt(p))
|
||||
if issubclass(sstype,IncogWallet) and opt.old_incog_fmt:
|
||||
opt_display(key,val,beg="Selected",end=" ")
|
||||
opt_display('old_incog_fmt',beg="conflicts with",end=":\n")
|
||||
die(1,"Export to old incog wallet format unsupported")
|
||||
elif issubclass(sstype,Brainwallet):
|
||||
die(1,"Output to brainwallet format unsupported")
|
||||
elif key in ('hidden_incog_input_params','hidden_incog_output_params'):
|
||||
if key == 'hidden_incog_input_params':
|
||||
check_infile(val.split(",")[0])
|
||||
key2 = 'in_fmt'
|
||||
else:
|
||||
key2 = 'out_fmt'
|
||||
if hasattr(opt,key2):
|
||||
val2 = getattr(opt,key2)
|
||||
from mmgen.seed import IncogWalletHidden
|
||||
if val2 and val2 not in IncogWalletHidden.fmt_codes:
|
||||
die(1,
|
||||
"Option conflict:\n %s, with\n %s=%s" % (
|
||||
fmt_opt(key),fmt_opt(key2),val2
|
||||
))
|
||||
|
||||
# begin OLD, deprecated
|
||||
elif key == 'hidden_incog_params':
|
||||
from mmgen.util import check_outfile
|
||||
if not opt_splits(val,",",2,desc): return False
|
||||
outfile,offset = val.split(",")
|
||||
check_outfile(outfile)
|
||||
w = "offset " + desc
|
||||
if not opt_is_int(offset,w): return False
|
||||
if not opt_compares(offset,">=",0,desc): return False
|
||||
elif key == 'export_incog_hidden' or key == 'from_incog_hidden':
|
||||
if key == 'from_incog_hidden':
|
||||
if not opt_splits(val,",",3,what): return False
|
||||
if not opt_splits(val,",",3,desc): return False
|
||||
infile,offset,seed_len = val.split(",")
|
||||
from mmgen.util import check_infile
|
||||
check_infile(infile)
|
||||
w = "seed length " + what
|
||||
w = "seed length " + desc
|
||||
if not opt_is_int(seed_len,w): return False
|
||||
if not opt_is_in_list(int(seed_len),g.seed_lens,w): return False
|
||||
else:
|
||||
from mmgen.util import check_outfile
|
||||
if not opt_splits(val,",",2,what): return False
|
||||
if not opt_splits(val,",",2,desc): return False
|
||||
outfile,offset = val.split(",")
|
||||
check_outfile(outfile)
|
||||
w = "offset " + what
|
||||
w = "offset " + desc
|
||||
if not opt_is_int(offset,w): return False
|
||||
if not opt_compares(offset,">=",0,what): return False
|
||||
if not opt_compares(offset,">=",0,desc): return False
|
||||
elif key == 'from_brain':
|
||||
if not opt_splits(val,",",2,what): return False
|
||||
if not opt_splits(val,",",2,desc): return False
|
||||
l,p = val.split(",")
|
||||
w = "seed length " + what
|
||||
w = "seed length " + desc
|
||||
if not opt_is_int(l,w): return False
|
||||
if not opt_is_in_list(int(l),g.seed_lens,w): return False
|
||||
w = "hash preset " + what
|
||||
w = "hash preset " + desc
|
||||
if not opt_is_in_list(p,g.hash_presets.keys(),w): return False
|
||||
# end OLD
|
||||
elif key == 'seed_len':
|
||||
if not opt_is_int(val,what): return False
|
||||
if not opt_is_in_list(int(val),g.seed_lens,what): return False
|
||||
if not opt_is_int(val,desc): return False
|
||||
if not opt_is_in_list(int(val),g.seed_lens,desc): return False
|
||||
elif key == 'hash_preset':
|
||||
if not opt_is_in_list(val,g.hash_presets.keys(),what): return False
|
||||
if not opt_is_in_list(val,g.hash_presets.keys(),desc): return False
|
||||
elif key == 'usr_randchars':
|
||||
if not opt_is_int(val,what): return False
|
||||
if not opt_compares(val,">=",g.min_urandchars,what): return False
|
||||
if not opt_compares(val,"<=",g.max_urandchars,what): return False
|
||||
if val == 0: continue
|
||||
if not opt_is_int(val,desc): return False
|
||||
if not opt_compares(val,">=",g.min_urandchars,desc): return False
|
||||
if not opt_compares(val,"<=",g.max_urandchars,desc): return False
|
||||
else:
|
||||
if g.debug: Msg("check_opts(): No test for opt '%s'" % key)
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ bitcoin-python - Easy-to-use Bitcoin API client
|
|||
|
||||
|
||||
def connect_to_local(filename=None):
|
||||
"""
|
||||
"""
|
||||
Connect to default bitcoin instance owned by this user, on this machine.
|
||||
|
||||
Returns a :class:`~mmgen.rpc.connection.BitcoinConnection` object.
|
||||
|
|
@ -31,24 +31,23 @@ def connect_to_local(filename=None):
|
|||
Arguments:
|
||||
|
||||
- `filename`: Path to a configuration file in a non-standard location (optional)
|
||||
"""
|
||||
from mmgen.rpc.connection import BitcoinConnection
|
||||
from mmgen.rpc.config import read_default_config
|
||||
"""
|
||||
from mmgen.rpc.connection import BitcoinConnection
|
||||
from mmgen.rpc.config import read_default_config
|
||||
|
||||
cfg = read_default_config(filename)
|
||||
port = int(cfg.get('rpcport', '18332' if cfg.get('testnet') else '8332'))
|
||||
rcpuser = cfg.get('rpcuser', '')
|
||||
cfg = read_default_config(filename)
|
||||
port = int(cfg.get('rpcport', '18332' if cfg.get('testnet') else '8332'))
|
||||
rcpuser = cfg.get('rpcuser', '')
|
||||
|
||||
return BitcoinConnection(rcpuser, cfg['rpcpassword'], 'localhost', port)
|
||||
return BitcoinConnection(rcpuser, cfg['rpcpassword'], 'localhost', port)
|
||||
|
||||
|
||||
def connect_to_remote(user, password, host='localhost', port=8332,
|
||||
use_https=False):
|
||||
"""
|
||||
def connect_to_remote(user,password,host='localhost',port=8332,use_https=False):
|
||||
"""
|
||||
Connect to remote or alternative local bitcoin client instance.
|
||||
|
||||
Returns a :class:`~mmgen.rpc.connection.BitcoinConnection` object.
|
||||
"""
|
||||
from mmgen.rpc.connection import BitcoinConnection
|
||||
"""
|
||||
from mmgen.rpc.connection import BitcoinConnection
|
||||
|
||||
return BitcoinConnection(user, password, host, port, use_https)
|
||||
return BitcoinConnection(user, password, host, port, use_https)
|
||||
|
|
|
|||
|
|
@ -23,53 +23,53 @@ Utilities for reading bitcoin configuration files.
|
|||
|
||||
|
||||
def read_config_file(filename):
|
||||
"""
|
||||
"""
|
||||
Read a simple ``'='``-delimited config file.
|
||||
Raises :const:`IOError` if unable to open file, or :const:`ValueError`
|
||||
if an parse error occurs.
|
||||
"""
|
||||
f = open(filename)
|
||||
try:
|
||||
cfg = {}
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#"):
|
||||
try:
|
||||
(key, value) = line.split('=', 1)
|
||||
cfg[key] = value
|
||||
except ValueError:
|
||||
pass # Happens when line has no '=', ignore
|
||||
finally:
|
||||
f.close()
|
||||
return cfg
|
||||
"""
|
||||
f = open(filename)
|
||||
try:
|
||||
cfg = {}
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#"):
|
||||
try:
|
||||
(key, value) = line.split('=', 1)
|
||||
cfg[key] = value
|
||||
except ValueError:
|
||||
pass # Happens when line has no '=', ignore
|
||||
finally:
|
||||
f.close()
|
||||
return cfg
|
||||
|
||||
|
||||
def read_default_config(filename=None):
|
||||
"""
|
||||
"""
|
||||
Read bitcoin default configuration from the current user's home directory.
|
||||
|
||||
Arguments:
|
||||
|
||||
- `filename`: Path to a configuration file in a non-standard location (optional)
|
||||
"""
|
||||
if filename is None:
|
||||
import os
|
||||
import platform
|
||||
home = os.getenv("HOME")
|
||||
if not home:
|
||||
raise IOError("Home directory not defined, don't know where to look for config file")
|
||||
"""
|
||||
if filename is None:
|
||||
import os
|
||||
import platform
|
||||
home = os.getenv("HOME")
|
||||
if not home:
|
||||
raise IOError("Home directory not defined, don't know where to look for config file")
|
||||
|
||||
if platform.system() == "Darwin":
|
||||
location = 'Library/Application Support/Bitcoin/bitcoin.conf'
|
||||
else:
|
||||
location = '.bitcoin/bitcoin.conf'
|
||||
filename = os.path.join(home, location)
|
||||
if platform.system() == "Darwin":
|
||||
location = 'Library/Application Support/Bitcoin/bitcoin.conf'
|
||||
else:
|
||||
location = '.bitcoin/bitcoin.conf'
|
||||
filename = os.path.join(home, location)
|
||||
|
||||
elif filename.startswith("~"):
|
||||
import os
|
||||
filename = os.path.expanduser(filename)
|
||||
elif filename.startswith("~"):
|
||||
import os
|
||||
filename = os.path.expanduser(filename)
|
||||
|
||||
try:
|
||||
return read_config_file(filename)
|
||||
except (IOError, ValueError):
|
||||
pass # Cannot read config file, ignore
|
||||
try:
|
||||
return read_config_file(filename)
|
||||
except (IOError, ValueError):
|
||||
pass # Cannot read config file, ignore
|
||||
|
|
|
|||
|
|
@ -32,21 +32,21 @@ from mmgen.rpc.data import (ServerInfo, AccountInfo, AddressInfo, TransactionInf
|
|||
|
||||
class BitcoinConnection(object):
|
||||
"""
|
||||
A BitcoinConnection object defines a connection to a bitcoin server.
|
||||
It is a thin wrapper around a JSON-RPC API connection.
|
||||
A BitcoinConnection object defines a connection to a bitcoin server.
|
||||
It is a thin wrapper around a JSON-RPC API connection.
|
||||
|
||||
Up-to-date for SVN revision 198.
|
||||
Up-to-date for SVN revision 198.
|
||||
|
||||
Arguments to constructor:
|
||||
Arguments to constructor:
|
||||
|
||||
- *user* -- Authenticate as user.
|
||||
- *password* -- Authentication password.
|
||||
- *host* -- Bitcoin JSON-RPC host.
|
||||
- *port* -- Bitcoin JSON-RPC port.
|
||||
- *user* -- Authenticate as user.
|
||||
- *password* -- Authentication password.
|
||||
- *host* -- Bitcoin JSON-RPC host.
|
||||
- *port* -- Bitcoin JSON-RPC port.
|
||||
"""
|
||||
def __init__(self, user, password, host='localhost', port=8332, use_https=False):
|
||||
"""
|
||||
Create a new bitcoin server connection.
|
||||
Create a new bitcoin server connection.
|
||||
"""
|
||||
url = 'http{s}://{user}:{password}@{host}:{port}/'.format(
|
||||
s='s' if use_https else '',
|
||||
|
|
@ -59,8 +59,6 @@ class BitcoinConnection(object):
|
|||
|
||||
# importaddress <address> [label] [rescan=true]
|
||||
def importaddress(self,address,label=None,rescan=True):
|
||||
"""
|
||||
"""
|
||||
try:
|
||||
# return self.proxy.badmethod(address,label) # DEBUG
|
||||
return self.proxy.importaddress(address,label,rescan)
|
||||
|
|
@ -78,8 +76,6 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
# sendrawtransaction <hex string> [allowhighfees=false]
|
||||
def sendrawtransaction(self,tx):
|
||||
"""
|
||||
"""
|
||||
try:
|
||||
return self.proxy.sendrawtransaction(tx)
|
||||
except JSONRPCException as e:
|
||||
|
|
@ -87,7 +83,7 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def stop(self):
|
||||
"""
|
||||
Stop bitcoin server.
|
||||
Stop bitcoin server.
|
||||
"""
|
||||
try:
|
||||
self.proxy.stop()
|
||||
|
|
@ -96,7 +92,7 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getblock(self, hash):
|
||||
"""
|
||||
Returns information about the given block hash.
|
||||
Returns information about the given block hash.
|
||||
"""
|
||||
try:
|
||||
return self.proxy.getblock(hash)
|
||||
|
|
@ -105,7 +101,7 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getblockcount(self):
|
||||
"""
|
||||
Returns the number of blocks in the longest block chain.
|
||||
Returns the number of blocks in the longest block chain.
|
||||
"""
|
||||
try:
|
||||
return self.proxy.getblockcount()
|
||||
|
|
@ -114,9 +110,9 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getblockhash(self, index):
|
||||
"""
|
||||
Returns hash of block in best-block-chain at index.
|
||||
Returns hash of block in best-block-chain at index.
|
||||
|
||||
:param index: index ob the block
|
||||
:param index: index ob the block
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -126,14 +122,14 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getblocknumber(self):
|
||||
"""
|
||||
Returns the block number of the latest block in the longest block chain.
|
||||
Deprecated. Use getblockcount instead.
|
||||
Returns the block number of the latest block in the longest block chain.
|
||||
Deprecated. Use getblockcount instead.
|
||||
"""
|
||||
return self.getblockcount()
|
||||
|
||||
def getconnectioncount(self):
|
||||
"""
|
||||
Returns the number of connections to other nodes.
|
||||
Returns the number of connections to other nodes.
|
||||
"""
|
||||
try:
|
||||
return self.proxy.getconnectioncount()
|
||||
|
|
@ -142,7 +138,7 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getdifficulty(self):
|
||||
"""
|
||||
Returns the proof-of-work difficulty as a multiple of the minimum difficulty.
|
||||
Returns the proof-of-work difficulty as a multiple of the minimum difficulty.
|
||||
"""
|
||||
try:
|
||||
return self.proxy.getdifficulty()
|
||||
|
|
@ -151,8 +147,8 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getgenerate(self):
|
||||
"""
|
||||
Returns :const:`True` or :const:`False`, depending on whether
|
||||
generation is enabled.
|
||||
Returns :const:`True` or :const:`False`, depending on whether
|
||||
generation is enabled.
|
||||
"""
|
||||
try:
|
||||
return self.proxy.getgenerate()
|
||||
|
|
@ -161,14 +157,14 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def setgenerate(self, generate, genproclimit=None):
|
||||
"""
|
||||
Enable or disable generation (mining) of coins.
|
||||
Enable or disable generation (mining) of coins.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *generate* -- is :const:`True` or :const:`False` to turn generation
|
||||
on or off.
|
||||
- *genproclimit* -- Number of processors that are used for generation,
|
||||
-1 is unlimited.
|
||||
- *generate* -- is :const:`True` or :const:`False` to turn generation
|
||||
on or off.
|
||||
- *genproclimit* -- Number of processors that are used for generation,
|
||||
-1 is unlimited.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -181,7 +177,7 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def gethashespersec(self):
|
||||
"""
|
||||
Returns a recent hashes per second performance measurement while generating.
|
||||
Returns a recent hashes per second performance measurement while generating.
|
||||
"""
|
||||
try:
|
||||
return self.proxy.gethashespersec()
|
||||
|
|
@ -190,8 +186,8 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getinfo(self):
|
||||
"""
|
||||
Returns an :class:`~mmgen.rpc.data.ServerInfo` object containing
|
||||
various state info.
|
||||
Returns an :class:`~mmgen.rpc.data.ServerInfo` object containing
|
||||
various state info.
|
||||
"""
|
||||
try:
|
||||
return ServerInfo(**self.proxy.getinfo())
|
||||
|
|
@ -200,8 +196,8 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getmininginfo(self):
|
||||
"""
|
||||
Returns an :class:`~mmgen.rpc.data.MiningInfo` object containing various
|
||||
mining state info.
|
||||
Returns an :class:`~mmgen.rpc.data.MiningInfo` object containing various
|
||||
mining state info.
|
||||
"""
|
||||
try:
|
||||
return MiningInfo(**self.proxy.getmininginfo())
|
||||
|
|
@ -210,13 +206,13 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getnewaddress(self, account=None):
|
||||
"""
|
||||
Returns a new bitcoin address for receiving payments.
|
||||
Returns a new bitcoin address for receiving payments.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *account* -- If account is specified (recommended), it is added to the
|
||||
address book so that payments received with the address will be
|
||||
credited to it.
|
||||
- *account* -- If account is specified (recommended), it is added to the
|
||||
address book so that payments received with the address will be
|
||||
credited to it.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -229,11 +225,11 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getaccountaddress(self, account):
|
||||
"""
|
||||
Returns the current bitcoin address for receiving payments to an account.
|
||||
Returns the current bitcoin address for receiving payments to an account.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *account* -- Account for which the address should be returned.
|
||||
- *account* -- Account for which the address should be returned.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -243,12 +239,12 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def setaccount(self, bitcoinaddress, account):
|
||||
"""
|
||||
Sets the account associated with the given address.
|
||||
Sets the account associated with the given address.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *bitcoinaddress* -- Bitcoin address to associate.
|
||||
- *account* -- Account to associate the address to.
|
||||
- *bitcoinaddress* -- Bitcoin address to associate.
|
||||
- *account* -- Account to associate the address to.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -258,11 +254,11 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getaccount(self, bitcoinaddress):
|
||||
"""
|
||||
Returns the account associated with the given address.
|
||||
Returns the account associated with the given address.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *bitcoinaddress* -- Bitcoin address to get account for.
|
||||
- *bitcoinaddress* -- Bitcoin address to get account for.
|
||||
"""
|
||||
try:
|
||||
return self.proxy.getaccount(bitcoinaddress)
|
||||
|
|
@ -271,11 +267,11 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getaddressesbyaccount(self, account):
|
||||
"""
|
||||
Returns the list of addresses for the given account.
|
||||
Returns the list of addresses for the given account.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *account* -- Account to get list of addresses for.
|
||||
- *account* -- Account to get list of addresses for.
|
||||
"""
|
||||
try:
|
||||
return self.proxy.getaddressesbyaccount(account)
|
||||
|
|
@ -284,16 +280,16 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def sendtoaddress(self, bitcoinaddress, amount, comment=None, comment_to=None):
|
||||
"""
|
||||
Sends *amount* from the server's available balance to *bitcoinaddress*.
|
||||
Sends *amount* from the server's available balance to *bitcoinaddress*.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *bitcoinaddress* -- Bitcoin address to send to.
|
||||
- *amount* -- Amount to send (float, rounded to the nearest 0.01).
|
||||
- *minconf* -- Minimum number of confirmations required for transferred
|
||||
balance.
|
||||
- *comment* -- Comment for transaction.
|
||||
- *comment_to* -- Comment for to-address.
|
||||
- *bitcoinaddress* -- Bitcoin address to send to.
|
||||
- *amount* -- Amount to send (float, rounded to the nearest 0.01).
|
||||
- *minconf* -- Minimum number of confirmations required for transferred
|
||||
balance.
|
||||
- *comment* -- Comment for transaction.
|
||||
- *comment_to* -- Comment for to-address.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -308,14 +304,14 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getreceivedbyaddress(self, bitcoinaddress, minconf=1):
|
||||
"""
|
||||
Returns the total amount received by a bitcoin address in transactions
|
||||
with at least a certain number of confirmations.
|
||||
Returns the total amount received by a bitcoin address in transactions
|
||||
with at least a certain number of confirmations.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *bitcoinaddress* -- Address to query for total amount.
|
||||
- *bitcoinaddress* -- Address to query for total amount.
|
||||
|
||||
- *minconf* -- Number of confirmations to require, defaults to 1.
|
||||
- *minconf* -- Number of confirmations to require, defaults to 1.
|
||||
"""
|
||||
try:
|
||||
return self.proxy.getreceivedbyaddress(bitcoinaddress, minconf)
|
||||
|
|
@ -324,13 +320,13 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getreceivedbyaccount(self, account, minconf=1):
|
||||
"""
|
||||
Returns the total amount received by addresses with an account in
|
||||
transactions with at least a certain number of confirmations.
|
||||
Returns the total amount received by addresses with an account in
|
||||
transactions with at least a certain number of confirmations.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *account* -- Account to query for total amount.
|
||||
- *minconf* -- Number of confirmations to require, defaults to 1.
|
||||
- *account* -- Account to query for total amount.
|
||||
- *minconf* -- Number of confirmations to require, defaults to 1.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -340,11 +336,11 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def gettransaction(self, txid):
|
||||
"""
|
||||
Get detailed information about transaction
|
||||
Get detailed information about transaction
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *txid* -- Transactiond id for which the info should be returned
|
||||
- *txid* -- Transactiond id for which the info should be returned
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -354,12 +350,12 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def getrawtransaction(self, txid, verbose=True):
|
||||
"""
|
||||
Get transaction raw info
|
||||
Get transaction raw info
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *txid* -- Transactiond id for which the info should be returned.
|
||||
- *verbose* -- If False, return only the "hex" of the transaction.
|
||||
- *txid* -- Transactiond id for which the info should be returned.
|
||||
- *verbose* -- If False, return only the "hex" of the transaction.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -371,24 +367,24 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def createrawtransaction(self, inputs, outputs):
|
||||
"""
|
||||
Creates a raw transaction spending given inputs
|
||||
(a list of dictionaries, each containing a transaction id and an output
|
||||
number), sending to given address(es).
|
||||
Creates a raw transaction spending given inputs
|
||||
(a list of dictionaries, each containing a transaction id and an output
|
||||
number), sending to given address(es).
|
||||
|
||||
Returns hex-encoded raw transaction.
|
||||
Returns hex-encoded raw transaction.
|
||||
|
||||
Example usage:
|
||||
>>> conn.createrawtransaction(
|
||||
[{"txid": "a9d4599e15b53f3eb531608ddb31f48c695c3d0b3538a6bda871e8b34f2f430c",
|
||||
"vout": 0}],
|
||||
{"mkZBYBiq6DNoQEKakpMJegyDbw2YiNQnHT":50})
|
||||
Example usage:
|
||||
>>> conn.createrawtransaction(
|
||||
[{"txid": "a9d4599e15b53f3eb531608ddb31f48c695c3d0b3538a6bda871e8b34f2f430c",
|
||||
"vout": 0}],
|
||||
{"mkZBYBiq6DNoQEKakpMJegyDbw2YiNQnHT":50})
|
||||
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *inputs* -- A list of {"txid": txid, "vout": n} dictionaries.
|
||||
- *outputs* -- A dictionary mapping (public) addresses to the amount
|
||||
they are to be paid.
|
||||
- *inputs* -- A list of {"txid": txid, "vout": n} dictionaries.
|
||||
- *outputs* -- A dictionary mapping (public) addresses to the amount
|
||||
they are to be paid.
|
||||
"""
|
||||
try:
|
||||
return self.proxy.createrawtransaction(inputs, outputs)
|
||||
|
|
@ -397,22 +393,22 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def signrawtransaction(self, hexstring, previous_transactions=None, private_keys=None):
|
||||
"""
|
||||
Sign inputs for raw transaction (serialized, hex-encoded).
|
||||
Sign inputs for raw transaction (serialized, hex-encoded).
|
||||
|
||||
Returns a dictionary with the keys:
|
||||
"hex": raw transaction with signature(s) (hex-encoded string)
|
||||
"complete": 1 if transaction has a complete set of signature(s), 0 if not
|
||||
Returns a dictionary with the keys:
|
||||
"hex": raw transaction with signature(s) (hex-encoded string)
|
||||
"complete": 1 if transaction has a complete set of signature(s), 0 if not
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *hexstring* -- A hex string of the transaction to sign.
|
||||
- *previous_transactions* -- A (possibly empty) list of dictionaries of
|
||||
the form:
|
||||
{"txid": txid, "vout": n, "scriptPubKey": hex, "redeemScript": hex},
|
||||
representing previous transaction outputs that this transaction depends
|
||||
on but may not yet be in the block chain.
|
||||
- *private_keys* -- A (possibly empty) list of base58-encoded private
|
||||
keys that, if given, will be the only keys used to sign the transaction.
|
||||
- *hexstring* -- A hex string of the transaction to sign.
|
||||
- *previous_transactions* -- A (possibly empty) list of dictionaries of
|
||||
the form:
|
||||
{"txid": txid, "vout": n, "scriptPubKey": hex, "redeemScript": hex},
|
||||
representing previous transaction outputs that this transaction depends
|
||||
on but may not yet be in the block chain.
|
||||
- *private_keys* -- A (possibly empty) list of base58-encoded private
|
||||
keys that, if given, will be the only keys used to sign the transaction.
|
||||
"""
|
||||
try:
|
||||
return dict(self.proxy.signrawtransaction(hexstring,
|
||||
|
|
@ -422,11 +418,11 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def decoderawtransaction(self, hexstring):
|
||||
"""
|
||||
Produces a human-readable JSON object for a raw transaction.
|
||||
Produces a human-readable JSON object for a raw transaction.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *hexstring* -- A hex string of the transaction to be decoded.
|
||||
- *hexstring* -- A hex string of the transaction to be decoded.
|
||||
"""
|
||||
try:
|
||||
return dict(self.proxy.decoderawtransaction(hexstring))
|
||||
|
|
@ -443,16 +439,16 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def listreceivedbyaddress(self, minconf=1, includeempty=False):
|
||||
"""
|
||||
Returns a list of addresses.
|
||||
Returns a list of addresses.
|
||||
|
||||
Each address is represented with a
|
||||
:class:`~mmgen.rpc.data.AddressInfo` object.
|
||||
Each address is represented with a
|
||||
:class:`~mmgen.rpc.data.AddressInfo` object.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *minconf* -- Minimum number of confirmations before payments are included.
|
||||
- *includeempty* -- Whether to include addresses that haven't received
|
||||
any payments.
|
||||
- *minconf* -- Minimum number of confirmations before payments are included.
|
||||
- *includeempty* -- Whether to include addresses that haven't received
|
||||
any payments.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -463,12 +459,12 @@ ERROR: 'importaddress' not found. Does your bitcoind support watch-only addrs?
|
|||
|
||||
def listaccounts(self, minconf=1, includeWatchonly=False, as_dict=False):
|
||||
"""
|
||||
Returns a list of account names.
|
||||
Returns a list of account names.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *minconf* -- Minimum number of confirmations before payments are included.
|
||||
- *as_dict* -- Returns a dictionary of account names, with their balance as values.
|
||||
- *minconf* -- Minimum number of confirmations before payments are included.
|
||||
- *as_dict* -- Returns a dictionary of account names, with their balance as values.
|
||||
"""
|
||||
try:
|
||||
if as_dict:
|
||||
|
|
@ -488,15 +484,15 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
|
||||
def listreceivedbyaccount(self, minconf=1, includeempty=False):
|
||||
"""
|
||||
Returns a list of accounts.
|
||||
Returns a list of accounts.
|
||||
|
||||
Each account is represented with a :class:`~mmgen.rpc.data.AccountInfo` object.
|
||||
Each account is represented with a :class:`~mmgen.rpc.data.AccountInfo` object.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *minconf* -- Minimum number of confirmations before payments are included.
|
||||
- *minconf* -- Minimum number of confirmations before payments are included.
|
||||
|
||||
- *includeempty* -- Whether to include addresses that haven't received any payments.
|
||||
- *includeempty* -- Whether to include addresses that haven't received any payments.
|
||||
"""
|
||||
try:
|
||||
return [AccountInfo(**x) for x in
|
||||
|
|
@ -506,17 +502,17 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
|
||||
def listtransactions(self, account=None, count=10, from_=0, address=None):
|
||||
"""
|
||||
Returns a list of the last transactions for an account.
|
||||
Returns a list of the last transactions for an account.
|
||||
|
||||
Each transaction is represented with a :class:`~mmgen.rpc.data.TransactionInfo` object.
|
||||
Each transaction is represented with a :class:`~mmgen.rpc.data.TransactionInfo` object.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *account* -- Account to list transactions from. Return transactions from
|
||||
all accounts if None.
|
||||
- *count* -- Number of transactions to return.
|
||||
- *from_* -- Skip the first <from_> transactions.
|
||||
- *address* -- Receive address to consider
|
||||
- *account* -- Account to list transactions from. Return transactions from
|
||||
all accounts if None.
|
||||
- *count* -- Number of transactions to return.
|
||||
- *from_* -- Skip the first <from_> transactions.
|
||||
- *address* -- Receive address to consider
|
||||
"""
|
||||
accounts = [account] if account is not None else self.listaccounts(as_dict=True).iterkeys()
|
||||
try:
|
||||
|
|
@ -528,11 +524,11 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
|
||||
def backupwallet(self, destination):
|
||||
"""
|
||||
Safely copies ``wallet.dat`` to *destination*, which can be a directory or a path
|
||||
with filename.
|
||||
Safely copies ``wallet.dat`` to *destination*, which can be a directory or a path
|
||||
with filename.
|
||||
|
||||
Arguments:
|
||||
- *destination* -- directory or path with filename to backup wallet to.
|
||||
Arguments:
|
||||
- *destination* -- directory or path with filename to backup wallet to.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -542,14 +538,14 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
|
||||
def validateaddress(self, validateaddress):
|
||||
"""
|
||||
Validate a bitcoin address and return information for it.
|
||||
Validate a bitcoin address and return information for it.
|
||||
|
||||
The information is represented by a :class:`~mmgen.rpc.data.AddressValidation` object.
|
||||
The information is represented by a :class:`~mmgen.rpc.data.AddressValidation` object.
|
||||
|
||||
Arguments: -- Address to validate.
|
||||
Arguments: -- Address to validate.
|
||||
|
||||
|
||||
- *validateaddress*
|
||||
- *validateaddress*
|
||||
"""
|
||||
try:
|
||||
return AddressValidation(**self.proxy.validateaddress(validateaddress))
|
||||
|
|
@ -558,11 +554,11 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
|
||||
def getbalance(self, account=None, minconf=None):
|
||||
"""
|
||||
Get the current balance, either for an account or the total server balance.
|
||||
Get the current balance, either for an account or the total server balance.
|
||||
|
||||
Arguments:
|
||||
- *account* -- If this parameter is specified, returns the balance in the account.
|
||||
- *minconf* -- Minimum number of confirmations required for transferred balance.
|
||||
Arguments:
|
||||
- *account* -- If this parameter is specified, returns the balance in the account.
|
||||
- *minconf* -- Minimum number of confirmations required for transferred balance.
|
||||
|
||||
"""
|
||||
args = []
|
||||
|
|
@ -577,15 +573,15 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
|
||||
def move(self, fromaccount, toaccount, amount, minconf=1, comment=None):
|
||||
"""
|
||||
Move from one account in your wallet to another.
|
||||
Move from one account in your wallet to another.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *fromaccount* -- Source account name.
|
||||
- *toaccount* -- Destination account name.
|
||||
- *amount* -- Amount to transfer.
|
||||
- *minconf* -- Minimum number of confirmations required for transferred balance.
|
||||
- *comment* -- Comment to add to transaction log.
|
||||
- *fromaccount* -- Source account name.
|
||||
- *toaccount* -- Destination account name.
|
||||
- *amount* -- Amount to transfer.
|
||||
- *minconf* -- Minimum number of confirmations required for transferred balance.
|
||||
- *comment* -- Comment to add to transaction log.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -599,19 +595,19 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
def sendfrom(self, fromaccount, tobitcoinaddress, amount, minconf=1, comment=None,
|
||||
comment_to=None):
|
||||
"""
|
||||
Sends amount from account's balance to bitcoinaddress. This method will fail
|
||||
if there is less than amount bitcoins with minconf confirmations in the account's
|
||||
balance (unless account is the empty-string-named default account; it
|
||||
behaves like the sendtoaddress method). Returns transaction ID on success.
|
||||
Sends amount from account's balance to bitcoinaddress. This method will fail
|
||||
if there is less than amount bitcoins with minconf confirmations in the account's
|
||||
balance (unless account is the empty-string-named default account; it
|
||||
behaves like the sendtoaddress method). Returns transaction ID on success.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *fromaccount* -- Account to send from.
|
||||
- *tobitcoinaddress* -- Bitcoin address to send to.
|
||||
- *amount* -- Amount to send (float, rounded to the nearest 0.01).
|
||||
- *minconf* -- Minimum number of confirmations required for transferred balance.
|
||||
- *comment* -- Comment for transaction.
|
||||
- *comment_to* -- Comment for to-address.
|
||||
- *fromaccount* -- Account to send from.
|
||||
- *tobitcoinaddress* -- Bitcoin address to send to.
|
||||
- *amount* -- Amount to send (float, rounded to the nearest 0.01).
|
||||
- *minconf* -- Minimum number of confirmations required for transferred balance.
|
||||
- *comment* -- Comment for transaction.
|
||||
- *comment_to* -- Comment for to-address.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -626,20 +622,20 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
|
||||
def sendmany(self, fromaccount, todict, minconf=1, comment=None):
|
||||
"""
|
||||
Sends specified amounts from account's balance to bitcoinaddresses.
|
||||
This method will fail if there is less than total amount bitcoins with
|
||||
minconf confirmations in the account's balance (unless account is the
|
||||
empty-string-named default account; Returns transaction ID on
|
||||
success.
|
||||
Sends specified amounts from account's balance to bitcoinaddresses.
|
||||
This method will fail if there is less than total amount bitcoins with
|
||||
minconf confirmations in the account's balance (unless account is the
|
||||
empty-string-named default account; Returns transaction ID on
|
||||
success.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *fromaccount* -- Account to send from.
|
||||
- *todict* -- Dictionary with Bitcoin addresses as keys and amounts as
|
||||
values.
|
||||
- *minconf* -- Minimum number of confirmations required for transferred
|
||||
balance.
|
||||
- *comment* -- Comment for transaction.
|
||||
- *fromaccount* -- Account to send from.
|
||||
- *todict* -- Dictionary with Bitcoin addresses as keys and amounts as
|
||||
values.
|
||||
- *minconf* -- Minimum number of confirmations required for transferred
|
||||
balance.
|
||||
- *comment* -- Comment for transaction.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -652,15 +648,15 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
|
||||
def verifymessage(self, bitcoinaddress, signature, message):
|
||||
"""
|
||||
Verifies a signature given the bitcoinaddress used to sign,
|
||||
the signature itself, and the message that was signed.
|
||||
Returns :const:`True` if the signature is valid, and :const:`False` if it is invalid.
|
||||
Verifies a signature given the bitcoinaddress used to sign,
|
||||
the signature itself, and the message that was signed.
|
||||
Returns :const:`True` if the signature is valid, and :const:`False` if it is invalid.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *bitcoinaddress* -- the bitcoinaddress used to sign the message
|
||||
- *signature* -- the signature to be verified
|
||||
- *message* -- the message that was originally signed
|
||||
- *bitcoinaddress* -- the bitcoinaddress used to sign the message
|
||||
- *signature* -- the signature to be verified
|
||||
- *message* -- the message that was originally signed
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -670,15 +666,15 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
|
||||
def getwork(self, data=None):
|
||||
"""
|
||||
Get work for remote mining, or submit result.
|
||||
If data is specified, the server tries to solve the block
|
||||
using the provided data and returns :const:`True` if it was successful.
|
||||
If not, the function returns formatted hash data (:class:`~mmgen.rpc.data.WorkItem`)
|
||||
to work on.
|
||||
Get work for remote mining, or submit result.
|
||||
If data is specified, the server tries to solve the block
|
||||
using the provided data and returns :const:`True` if it was successful.
|
||||
If not, the function returns formatted hash data (:class:`~mmgen.rpc.data.WorkItem`)
|
||||
to work on.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *data* -- Result from remote mining.
|
||||
- *data* -- Result from remote mining.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
@ -692,13 +688,13 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
|
||||
def listunspent(self, minconf=1, maxconf=999999):
|
||||
"""
|
||||
Returns a list of unspent transaction inputs in the wallet.
|
||||
Returns a list of unspent transaction inputs in the wallet.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *minconf* -- Minimum number of confirmations required to be listed.
|
||||
- *minconf* -- Minimum number of confirmations required to be listed.
|
||||
|
||||
- *maxconf* -- Maximal number of confirmations allowed to be listed.
|
||||
- *maxconf* -- Maximal number of confirmations allowed to be listed.
|
||||
|
||||
|
||||
"""
|
||||
|
|
@ -717,15 +713,15 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
|
||||
def walletpassphrase(self, passphrase, timeout, dont_raise=False):
|
||||
"""
|
||||
Stores the wallet decryption key in memory for <timeout> seconds.
|
||||
Stores the wallet decryption key in memory for <timeout> seconds.
|
||||
|
||||
- *passphrase* -- The wallet passphrase.
|
||||
- *passphrase* -- The wallet passphrase.
|
||||
|
||||
- *timeout* -- Time in seconds to keep the wallet unlocked
|
||||
(by keeping the passphrase in memory).
|
||||
- *timeout* -- Time in seconds to keep the wallet unlocked
|
||||
(by keeping the passphrase in memory).
|
||||
|
||||
- *dont_raise* -- instead of raising `~mmgen.rpc.exceptions.WalletPassphraseIncorrect`
|
||||
return False.
|
||||
- *dont_raise* -- instead of raising `~mmgen.rpc.exceptions.WalletPassphraseIncorrect`
|
||||
return False.
|
||||
"""
|
||||
try:
|
||||
self.proxy.walletpassphrase(passphrase, timeout)
|
||||
|
|
@ -741,10 +737,10 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
|
||||
def walletlock(self):
|
||||
"""
|
||||
Removes the wallet encryption key from memory, locking the wallet.
|
||||
After calling this method, you will need to call walletpassphrase
|
||||
again before being able to call any methods which require the wallet
|
||||
to be unlocked.
|
||||
Removes the wallet encryption key from memory, locking the wallet.
|
||||
After calling this method, you will need to call walletpassphrase
|
||||
again before being able to call any methods which require the wallet
|
||||
to be unlocked.
|
||||
"""
|
||||
try:
|
||||
return self.proxy.walletlock()
|
||||
|
|
@ -753,12 +749,12 @@ ERROR: 'listaccounts' failed. Does your bitcoind support watch-only addresses?
|
|||
|
||||
def walletpassphrasechange(self, oldpassphrase, newpassphrase, dont_raise=False):
|
||||
"""
|
||||
Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.
|
||||
Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.
|
||||
|
||||
Arguments:
|
||||
Arguments:
|
||||
|
||||
- *dont_raise* -- instead of raising
|
||||
`~mmgen.rpc.exceptions.WalletPassphraseIncorrect` return False.
|
||||
- *dont_raise* -- instead of raising
|
||||
`~mmgen.rpc.exceptions.WalletPassphraseIncorrect` return False.
|
||||
"""
|
||||
try:
|
||||
self.proxy.walletpassphrasechange(oldpassphrase, newpassphrase)
|
||||
|
|
|
|||
|
|
@ -23,181 +23,181 @@ Exception definitions.
|
|||
|
||||
|
||||
class BitcoinException(Exception):
|
||||
"""
|
||||
"""
|
||||
Base class for exceptions received from Bitcoin server.
|
||||
|
||||
- *code* -- Error code from ``bitcoind``.
|
||||
"""
|
||||
# Standard JSON-RPC 2.0 errors
|
||||
INVALID_REQUEST = -32600,
|
||||
METHOD_NOT_FOUND = -32601,
|
||||
INVALID_PARAMS = -32602,
|
||||
INTERNAL_ERROR = -32603,
|
||||
PARSE_ERROR = -32700,
|
||||
"""
|
||||
# Standard JSON-RPC 2.0 errors
|
||||
INVALID_REQUEST = -32600,
|
||||
METHOD_NOT_FOUND = -32601,
|
||||
INVALID_PARAMS = -32602,
|
||||
INTERNAL_ERROR = -32603,
|
||||
PARSE_ERROR = -32700,
|
||||
|
||||
# General application defined errors
|
||||
MISC_ERROR = -1 # std::exception thrown in command handling
|
||||
FORBIDDEN_BY_SAFE_MODE = -2 # Server is in safe mode, and command is not allowed in safe mode
|
||||
TYPE_ERROR = -3 # Unexpected type was passed as parameter
|
||||
INVALID_ADDRESS_OR_KEY = -5 # Invalid address or key
|
||||
OUT_OF_MEMORY = -7 # Ran out of memory during operation
|
||||
INVALID_PARAMETER = -8 # Invalid, missing or duplicate parameter
|
||||
DATABASE_ERROR = -20 # Database error
|
||||
DESERIALIZATION_ERROR = -22 # Error parsing or validating structure in raw format
|
||||
# General application defined errors
|
||||
MISC_ERROR = -1 # std::exception thrown in command handling
|
||||
FORBIDDEN_BY_SAFE_MODE = -2 # Server is in safe mode, and command is not allowed in safe mode
|
||||
TYPE_ERROR = -3 # Unexpected type was passed as parameter
|
||||
INVALID_ADDRESS_OR_KEY = -5 # Invalid address or key
|
||||
OUT_OF_MEMORY = -7 # Ran out of memory during operation
|
||||
INVALID_PARAMETER = -8 # Invalid, missing or duplicate parameter
|
||||
DATABASE_ERROR = -20 # Database error
|
||||
DESERIALIZATION_ERROR = -22 # Error parsing or validating structure in raw format
|
||||
|
||||
# P2P client errors
|
||||
CLIENT_NOT_CONNECTED = -9 # Bitcoin is not connected
|
||||
CLIENT_IN_INITIAL_DOWNLOAD = -10 # Still downloading initial blocks
|
||||
# P2P client errors
|
||||
CLIENT_NOT_CONNECTED = -9 # Bitcoin is not connected
|
||||
CLIENT_IN_INITIAL_DOWNLOAD = -10 # Still downloading initial blocks
|
||||
|
||||
# Wallet errors
|
||||
WALLET_ERROR = -4 # Unspecified problem with wallet (key not found etc.)
|
||||
WALLET_INSUFFICIENT_FUNDS = -6 # Not enough funds in wallet or account
|
||||
WALLET_INVALID_ACCOUNT_NAME = -11 # Invalid account name
|
||||
WALLET_KEYPOOL_RAN_OUT = -12 # Keypool ran out, call keypoolrefill first
|
||||
WALLET_UNLOCK_NEEDED = -13 # Enter the wallet passphrase with walletpassphrase first
|
||||
WALLET_PASSPHRASE_INCORRECT = -14 # The wallet passphrase entered was incorrect
|
||||
WALLET_WRONG_ENC_STATE = -15 # Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
|
||||
WALLET_ENCRYPTION_FAILED = -16 # Failed to encrypt the wallet
|
||||
WALLET_ALREADY_UNLOCKED = -17 # Wallet is already unlocked
|
||||
# Wallet errors
|
||||
WALLET_ERROR = -4 # Unspecified problem with wallet (key not found etc.)
|
||||
WALLET_INSUFFICIENT_FUNDS = -6 # Not enough funds in wallet or account
|
||||
WALLET_INVALID_ACCOUNT_NAME = -11 # Invalid account name
|
||||
WALLET_KEYPOOL_RAN_OUT = -12 # Keypool ran out, call keypoolrefill first
|
||||
WALLET_UNLOCK_NEEDED = -13 # Enter the wallet passphrase with walletpassphrase first
|
||||
WALLET_PASSPHRASE_INCORRECT = -14 # The wallet passphrase entered was incorrect
|
||||
WALLET_WRONG_ENC_STATE = -15 # Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
|
||||
WALLET_ENCRYPTION_FAILED = -16 # Failed to encrypt the wallet
|
||||
WALLET_ALREADY_UNLOCKED = -17 # Wallet is already unlocked
|
||||
|
||||
def __init__(self, error):
|
||||
Exception.__init__(self, error['message'])
|
||||
self.code = error['code']
|
||||
def __init__(self, error):
|
||||
Exception.__init__(self, error['message'])
|
||||
self.code = error['code']
|
||||
|
||||
|
||||
##### General application defined errors
|
||||
class SafeMode(BitcoinException):
|
||||
"""
|
||||
"""
|
||||
Operation denied in safe mode (run ``bitcoind`` with ``-disablesafemode``).
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
class JSONTypeError(BitcoinException):
|
||||
"""
|
||||
"""
|
||||
Unexpected type was passed as parameter
|
||||
"""
|
||||
"""
|
||||
InvalidAmount = JSONTypeError # Backwards compatibility
|
||||
|
||||
|
||||
class InvalidAddressOrKey(BitcoinException):
|
||||
"""
|
||||
"""
|
||||
Invalid address or key.
|
||||
"""
|
||||
"""
|
||||
InvalidTransactionID = InvalidAddressOrKey # Backwards compatibility
|
||||
|
||||
|
||||
class OutOfMemory(BitcoinException):
|
||||
"""
|
||||
"""
|
||||
Out of memory during operation.
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
class InvalidParameter(BitcoinException):
|
||||
"""
|
||||
"""
|
||||
Invalid parameter provided to RPC call.
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
##### Client errors
|
||||
class ClientException(BitcoinException):
|
||||
"""
|
||||
"""
|
||||
P2P network error.
|
||||
This exception is never raised but functions as a superclass
|
||||
for other P2P client exceptions.
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
class NotConnected(ClientException):
|
||||
"""
|
||||
"""
|
||||
Not connected to any peers.
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
class DownloadingBlocks(ClientException):
|
||||
"""
|
||||
"""
|
||||
Client is still downloading blocks.
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
##### Wallet errors
|
||||
class WalletError(BitcoinException):
|
||||
"""
|
||||
"""
|
||||
Unspecified problem with wallet (key not found etc.)
|
||||
"""
|
||||
"""
|
||||
SendError = WalletError # Backwards compatibility
|
||||
|
||||
class InsufficientFunds(WalletError):
|
||||
"""
|
||||
"""
|
||||
Insufficient funds to complete transaction in wallet or account
|
||||
"""
|
||||
"""
|
||||
|
||||
class InvalidAccountName(WalletError):
|
||||
"""
|
||||
"""
|
||||
Invalid account name
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
class KeypoolRanOut(WalletError):
|
||||
"""
|
||||
"""
|
||||
Keypool ran out, call keypoolrefill first
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
class WalletUnlockNeeded(WalletError):
|
||||
"""
|
||||
"""
|
||||
Enter the wallet passphrase with walletpassphrase first
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
class WalletPassphraseIncorrect(WalletError):
|
||||
"""
|
||||
"""
|
||||
The wallet passphrase entered was incorrect
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
class WalletWrongEncState(WalletError):
|
||||
"""
|
||||
"""
|
||||
Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
class WalletEncryptionFailed(WalletError):
|
||||
"""
|
||||
"""
|
||||
Failed to encrypt the wallet
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
class WalletAlreadyUnlocked(WalletError):
|
||||
"""
|
||||
"""
|
||||
Wallet is already unlocked
|
||||
"""
|
||||
"""
|
||||
|
||||
|
||||
# For convenience, we define more specific exception classes
|
||||
# for the more common errors.
|
||||
_exception_map = {
|
||||
BitcoinException.FORBIDDEN_BY_SAFE_MODE: SafeMode,
|
||||
BitcoinException.TYPE_ERROR: JSONTypeError,
|
||||
BitcoinException.WALLET_ERROR: WalletError,
|
||||
BitcoinException.INVALID_ADDRESS_OR_KEY: InvalidAddressOrKey,
|
||||
BitcoinException.WALLET_INSUFFICIENT_FUNDS: InsufficientFunds,
|
||||
BitcoinException.OUT_OF_MEMORY: OutOfMemory,
|
||||
BitcoinException.INVALID_PARAMETER: InvalidParameter,
|
||||
BitcoinException.CLIENT_NOT_CONNECTED: NotConnected,
|
||||
BitcoinException.CLIENT_IN_INITIAL_DOWNLOAD: DownloadingBlocks,
|
||||
BitcoinException.WALLET_INSUFFICIENT_FUNDS: InsufficientFunds,
|
||||
BitcoinException.WALLET_INVALID_ACCOUNT_NAME: InvalidAccountName,
|
||||
BitcoinException.WALLET_KEYPOOL_RAN_OUT: KeypoolRanOut,
|
||||
BitcoinException.WALLET_UNLOCK_NEEDED: WalletUnlockNeeded,
|
||||
BitcoinException.WALLET_PASSPHRASE_INCORRECT: WalletPassphraseIncorrect,
|
||||
BitcoinException.WALLET_WRONG_ENC_STATE: WalletWrongEncState,
|
||||
BitcoinException.WALLET_ENCRYPTION_FAILED: WalletEncryptionFailed,
|
||||
BitcoinException.WALLET_ALREADY_UNLOCKED: WalletAlreadyUnlocked,
|
||||
BitcoinException.FORBIDDEN_BY_SAFE_MODE: SafeMode,
|
||||
BitcoinException.TYPE_ERROR: JSONTypeError,
|
||||
BitcoinException.WALLET_ERROR: WalletError,
|
||||
BitcoinException.INVALID_ADDRESS_OR_KEY: InvalidAddressOrKey,
|
||||
BitcoinException.WALLET_INSUFFICIENT_FUNDS: InsufficientFunds,
|
||||
BitcoinException.OUT_OF_MEMORY: OutOfMemory,
|
||||
BitcoinException.INVALID_PARAMETER: InvalidParameter,
|
||||
BitcoinException.CLIENT_NOT_CONNECTED: NotConnected,
|
||||
BitcoinException.CLIENT_IN_INITIAL_DOWNLOAD: DownloadingBlocks,
|
||||
BitcoinException.WALLET_INSUFFICIENT_FUNDS: InsufficientFunds,
|
||||
BitcoinException.WALLET_INVALID_ACCOUNT_NAME: InvalidAccountName,
|
||||
BitcoinException.WALLET_KEYPOOL_RAN_OUT: KeypoolRanOut,
|
||||
BitcoinException.WALLET_UNLOCK_NEEDED: WalletUnlockNeeded,
|
||||
BitcoinException.WALLET_PASSPHRASE_INCORRECT: WalletPassphraseIncorrect,
|
||||
BitcoinException.WALLET_WRONG_ENC_STATE: WalletWrongEncState,
|
||||
BitcoinException.WALLET_ENCRYPTION_FAILED: WalletEncryptionFailed,
|
||||
BitcoinException.WALLET_ALREADY_UNLOCKED: WalletAlreadyUnlocked,
|
||||
}
|
||||
|
||||
|
||||
def _wrap_exception(error):
|
||||
"""
|
||||
"""
|
||||
Convert a JSON error object to a more specific Bitcoin exception.
|
||||
"""
|
||||
return _exception_map.get(error['code'], BitcoinException)(error)
|
||||
"""
|
||||
return _exception_map.get(error['code'], BitcoinException)(error)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
ServiceProxy class:
|
||||
|
||||
- HTTP connections persist for the life of the AuthServiceProxy object
|
||||
(if server supports HTTP/1.1)
|
||||
(if server supports HTTP/1.1)
|
||||
- sends protocol 'version', per JSON-RPC 1.1
|
||||
- sends proper, incrementing 'id'
|
||||
- sends Basic HTTP authentication headers
|
||||
|
|
|
|||
|
|
@ -22,28 +22,28 @@ from copy import copy
|
|||
|
||||
|
||||
class DStruct(object):
|
||||
"""
|
||||
"""
|
||||
Simple dynamic structure, like :const:`collections.namedtuple` but more flexible
|
||||
(and less memory-efficient)
|
||||
"""
|
||||
# Default arguments. Defaults are *shallow copied*, to allow defaults such as [].
|
||||
_fields = []
|
||||
_defaults = {}
|
||||
"""
|
||||
# Default arguments. Defaults are *shallow copied*, to allow defaults such as [].
|
||||
_fields = []
|
||||
_defaults = {}
|
||||
|
||||
def __init__(self, *args_t, **args_d):
|
||||
# order
|
||||
if len(args_t) > len(self._fields):
|
||||
raise TypeError("Number of arguments is larger than of predefined fields")
|
||||
# Copy default values
|
||||
for (k, v) in self._defaults.iteritems():
|
||||
self.__dict__[k] = copy(v)
|
||||
# Set pass by value arguments
|
||||
self.__dict__.update(zip(self._fields, args_t))
|
||||
# dict
|
||||
self.__dict__.update(args_d)
|
||||
def __init__(self, *args_t, **args_d):
|
||||
# order
|
||||
if len(args_t) > len(self._fields):
|
||||
raise TypeError("Number of arguments is larger than of predefined fields")
|
||||
# Copy default values
|
||||
for (k, v) in self._defaults.iteritems():
|
||||
self.__dict__[k] = copy(v)
|
||||
# Set pass by value arguments
|
||||
self.__dict__.update(zip(self._fields, args_t))
|
||||
# dict
|
||||
self.__dict__.update(args_d)
|
||||
|
||||
def __repr__(self):
|
||||
return '{module}.{classname}({slots})'.format(
|
||||
module=self.__class__.__module__, classname=self.__class__.__name__,
|
||||
slots=", ".join('{k}={v!r}'.format(k=k, v=v) for k, v in
|
||||
self.__dict__.iteritems()))
|
||||
def __repr__(self):
|
||||
return '{module}.{classname}({slots})'.format(
|
||||
module=self.__class__.__module__, classname=self.__class__.__name__,
|
||||
slots=", ".join('{k}={v!r}'.format(k=k, v=v) for k, v in
|
||||
self.__dict__.iteritems()))
|
||||
|
|
|
|||
713
mmgen/seed.py
713
mmgen/seed.py
File diff suppressed because it is too large
Load diff
|
|
@ -62,6 +62,21 @@ def process_opts(argv,opts_data,short_opts,long_opts):
|
|||
opt[1:]+":")][:-1].replace("-","_")] = arg
|
||||
else: assert False, "Invalid option"
|
||||
|
||||
if 'sets' in opts_data:
|
||||
for o_in,v_in,o_out,v_out in opts_data['sets']:
|
||||
if o_in in opts:
|
||||
v = opts[o_in]
|
||||
if (v and v_in == bool) or v == v_in:
|
||||
if o_out in opts and opts[o_out] != v_out:
|
||||
sys.stderr.write(
|
||||
"Option conflict:\n --%s=%s, with\n --%s=%s\n" % (
|
||||
o_out.replace("_","-"),opts[o_out],
|
||||
o_in.replace("_","-"),opts[o_in]
|
||||
))
|
||||
sys.exit(1)
|
||||
else:
|
||||
opts[o_out] = v_out
|
||||
|
||||
return opts,args
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -77,14 +77,14 @@ def ok_or_die(val,chk_func,s,skip_ok=False):
|
|||
try: ret = chk_func(val)
|
||||
except: ret = False
|
||||
if ret:
|
||||
if not skip_ok: ok()
|
||||
if not skip_ok: ok()
|
||||
else:
|
||||
msg(red("Returned value '%s' is not a %s" % (val,s)))
|
||||
sys.exit(3)
|
||||
|
||||
def cmp_or_die(s,t,skip_ok=False):
|
||||
if s == t:
|
||||
if not skip_ok: ok()
|
||||
if not skip_ok: ok()
|
||||
else:
|
||||
sys.stderr.write(red(
|
||||
"ERROR: recoded data:\n%s\ndiffers from original data:\n%s\n" %
|
||||
|
|
|
|||
|
|
@ -439,19 +439,17 @@ def add_label(mmaddr,label,remove=False):
|
|||
check_addr_label(label) # Exits on failure
|
||||
|
||||
c = connect_to_bitcoind()
|
||||
from mmgen.addr import AddrInfoList
|
||||
ail = AddrInfoList(bitcoind_connection=c)
|
||||
|
||||
btcaddr = ""
|
||||
sid,idx = mmaddr.split(":")
|
||||
if sid in ail.seed_ids():
|
||||
btcaddr = ail.addrinfo(sid).btcaddr(int(idx))
|
||||
from mmgen.addr import AddrInfoList
|
||||
btcaddr = AddrInfoList(bitcoind_connection=c).mmaddr2btcaddr(mmaddr)
|
||||
|
||||
if not btcaddr:
|
||||
die(1,"{pnm} address {a} not found in tracking wallet".format(
|
||||
pnm=pnm,a=mmaddr))
|
||||
|
||||
try:
|
||||
c.importaddress(btcaddr," ".join((mmaddr,label)),rescan=False)
|
||||
l = " " + label if label else ""
|
||||
c.importaddress(btcaddr,mmaddr+l,rescan=False)
|
||||
except:
|
||||
die(1,"Unable to add label")
|
||||
|
||||
|
|
@ -508,7 +506,7 @@ def encrypt(infile,outfile="",hash_preset=""):
|
|||
data = get_data_from_file(infile,"data for encryption")
|
||||
enc_d = mmgen_encrypt(data,"user data",hash_preset)
|
||||
if outfile == '-':
|
||||
write_to_stdout(enc_d,"encrypted data",confirm=True)
|
||||
write_to_stdout(enc_d,"encrypted data")
|
||||
else:
|
||||
if not outfile:
|
||||
outfile = os.path.basename(infile) + "." + g.mmenc_ext
|
||||
|
|
@ -522,7 +520,7 @@ def decrypt(infile,outfile="",hash_preset=""):
|
|||
if dec_d: break
|
||||
msg("Trying again...")
|
||||
if outfile == '-':
|
||||
write_to_stdout(dec_d,"decrypted data",confirm=not opt.quiet)
|
||||
write_to_stdout(dec_d,"decrypted data",ask_terminal=not opt.quiet)
|
||||
else:
|
||||
if not outfile:
|
||||
outfile = os.path.basename(infile)
|
||||
|
|
|
|||
|
|
@ -46,8 +46,7 @@ def normalize_btc_amt(amt):
|
|||
msg("%s: Invalid amount" % amt)
|
||||
return False
|
||||
|
||||
if opt.debug:
|
||||
Msg("Decimal(amt): %s\nAs tuple: %s" % (amt,repr(ret.as_tuple())))
|
||||
dmsg("Decimal(amt): %s\nAs tuple: %s" % (amt,repr(ret.as_tuple())))
|
||||
|
||||
if ret.as_tuple()[-1] < -8:
|
||||
msg("%s: Too many decimal places in amount" % amt)
|
||||
|
|
|
|||
273
mmgen/util.py
273
mmgen/util.py
|
|
@ -42,10 +42,10 @@ def msg_r(s): sys.stderr.write(s)
|
|||
def Msg(s): sys.stdout.write(s + "\n")
|
||||
def Msg_r(s): sys.stdout.write(s)
|
||||
def msgred(s): sys.stderr.write(red(s+"\n"))
|
||||
def msgrepr(*args):
|
||||
def mmsg(*args):
|
||||
for d in args:
|
||||
sys.stdout.write(repr(d)+"\n")
|
||||
def msgrepr_exit(*args):
|
||||
def mdie(*args):
|
||||
for d in args:
|
||||
sys.stdout.write(repr(d)+"\n")
|
||||
sys.exit()
|
||||
|
|
@ -55,20 +55,8 @@ def die(ev,s):
|
|||
def Die(ev,s):
|
||||
sys.stdout.write(s+"\n"); sys.exit(ev)
|
||||
|
||||
def fmt_type(x): return "%s" % str(type(x)).split("'")[1]
|
||||
|
||||
import opt
|
||||
|
||||
def fmt_code_to_sstype(fmt_code):
|
||||
for e in g.wallet_fmt_codes:
|
||||
if fmt_code in e: return e[0]
|
||||
die(2,"'%s': unrecognized format code" % fmt_code)
|
||||
|
||||
def format_fmt_codes():
|
||||
return "".join(
|
||||
["%-20s " % (e[0]+":") + ",".join(e[1:]) + "\n"
|
||||
for e in g.wallet_fmt_codes])
|
||||
|
||||
def qmsg(s,alt=False):
|
||||
if opt.quiet:
|
||||
if alt != False: sys.stderr.write(alt + "\n")
|
||||
|
|
@ -87,7 +75,10 @@ def Vmsg(s):
|
|||
def Vmsg_r(s):
|
||||
if opt.verbose: sys.stdout.write(s)
|
||||
|
||||
def suf(arg,what):
|
||||
def dmsg(s):
|
||||
if opt.debug: sys.stdout.write(s + "\n")
|
||||
|
||||
def suf(arg,suf_type):
|
||||
t = type(arg)
|
||||
if t == int:
|
||||
n = arg
|
||||
|
|
@ -97,9 +88,9 @@ def suf(arg,what):
|
|||
msg("%s: invalid parameter" % arg)
|
||||
return ""
|
||||
|
||||
if what in "a":
|
||||
if suf_type in ("a","es"):
|
||||
return "" if n == 1 else "es"
|
||||
if what in "k":
|
||||
if suf_type in ("k","s"):
|
||||
return "" if n == 1 else "s"
|
||||
|
||||
def get_extension(f):
|
||||
|
|
@ -125,10 +116,14 @@ def splitN(s,n,sep=None): # always return an n-element list
|
|||
def split2(s,sep=None): return splitN(s,2,sep) # always return a 2-element list
|
||||
def split3(s,sep=None): return splitN(s,3,sep) # always return a 3-element list
|
||||
|
||||
def split_into_columns(col_wid,s):
|
||||
def split_into_cols(col_wid,s):
|
||||
return " ".join([s[col_wid*i:col_wid*(i+1)]
|
||||
for i in range(len(s)/col_wid+1)]).rstrip()
|
||||
|
||||
def capfirst(s):
|
||||
if len(s) == 0: return s
|
||||
return s[0].upper() + (s[1:] if len(s) > 1 else "")
|
||||
|
||||
def make_timestamp():
|
||||
tv = time.gmtime(time.time())[:6]
|
||||
return "{:04d}{:02d}{:02d}_{:02d}{:02d}{:02d}".format(*tv)
|
||||
|
|
@ -166,6 +161,13 @@ def is_utf8(s):
|
|||
def match_ext(addr,ext):
|
||||
return addr.split(".")[-1] == ext
|
||||
|
||||
def file_exists(f):
|
||||
try:
|
||||
os.stat(f)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
import opt as opt
|
||||
|
||||
def get_from_brain_opt_params():
|
||||
|
|
@ -186,7 +188,11 @@ def pretty_hexdump(data,gw=2,cols=8,line_nums=False):
|
|||
def decode_pretty_hexdump(data):
|
||||
from string import hexdigits
|
||||
lines = [re.sub('^['+hexdigits+']+:\s+','',l) for l in data.split("\n")]
|
||||
return unhexlify("".join(("".join(lines).split())))
|
||||
try:
|
||||
return unhexlify("".join(("".join(lines).split())))
|
||||
except:
|
||||
msg("Data not in hexdump format")
|
||||
return False
|
||||
|
||||
def get_hash_params(hash_preset):
|
||||
if hash_preset in g.hash_presets:
|
||||
|
|
@ -195,22 +201,25 @@ def get_hash_params(hash_preset):
|
|||
msg("%s: invalid 'hash_preset' value" % hash_preset)
|
||||
sys.exit(3)
|
||||
|
||||
def compare_chksums(chk1, desc1, chk2, desc2, die=True):
|
||||
def compare_chksums(chk1, desc1, chk2, desc2, hdr="", die_on_fail=False):
|
||||
|
||||
if not chk1 == chk2:
|
||||
if die:
|
||||
die(3,"Checksum error: %s checksum (%s) doesn't match %s checksum (%s)"
|
||||
% (desc2,chk2,desc1,chk1))
|
||||
else: return False
|
||||
m = "%s ERROR: %s checksum (%s) doesn't match %s checksum (%s)"\
|
||||
% ((hdr+":\n " if hdr else "CHECKSUM"),desc2,chk2,desc1,chk1)
|
||||
if die_on_fail:
|
||||
die(3,m)
|
||||
else:
|
||||
msg(m)
|
||||
return False
|
||||
|
||||
vmsg("%s checksum OK (%s)" % (desc1.capitalize(),chk1))
|
||||
vmsg("%s checksum OK (%s)" % (capfirst(desc1),chk1))
|
||||
return True
|
||||
|
||||
def compare_or_die(val1, desc1, val2, desc2):
|
||||
def compare_or_die(val1, desc1, val2, desc2, e="Error"):
|
||||
if cmp(val1,val2):
|
||||
die(3,"Error: %s (%s) doesn't match %s (%s)"
|
||||
% (desc2,val2,desc1,val1))
|
||||
vmsg("%s OK (%s)" % (desc2.capitalize(),val2))
|
||||
die(3,"%s: %s (%s) doesn't match %s (%s)"
|
||||
% (e,desc2,val2,desc1,val1))
|
||||
dmsg("%s OK (%s)" % (capfirst(desc2),val2))
|
||||
return True
|
||||
|
||||
def get_default_wordlist():
|
||||
|
|
@ -224,8 +233,8 @@ def open_file_or_exit(filename,mode):
|
|||
try:
|
||||
f = open(filename, mode)
|
||||
except:
|
||||
what = "reading" if 'r' in mode else "writing"
|
||||
msg("Unable to open file '%s' for %s" % (filename,what))
|
||||
op = "reading" if 'r' in mode else "writing"
|
||||
msg("Unable to open file '%s' for %s" % (filename,op))
|
||||
sys.exit(2)
|
||||
return f
|
||||
|
||||
|
|
@ -307,9 +316,9 @@ def parse_addr_idxs(arg,sep=","):
|
|||
return sorted(set(ret))
|
||||
|
||||
|
||||
def get_new_passphrase(what,passchg=False):
|
||||
def get_new_passphrase(desc,passchg=False):
|
||||
|
||||
w = "{}passphrase for {}".format("new " if passchg else "", what)
|
||||
w = "{}passphrase for {}".format("new " if passchg else "", desc)
|
||||
if opt.passwd_file:
|
||||
pw = " ".join(_get_words_from_file(opt.passwd_file,w))
|
||||
elif opt.echo_passphrase:
|
||||
|
|
@ -318,7 +327,7 @@ def get_new_passphrase(what,passchg=False):
|
|||
for i in range(g.passwd_max_tries):
|
||||
pw = " ".join(_get_words_from_user("Enter {}: ".format(w)))
|
||||
pw2 = " ".join(_get_words_from_user("Repeat passphrase: "))
|
||||
if opt.debug: Msg("Passphrases: [%s] [%s]" % (pw,pw2))
|
||||
dmsg("Passphrases: [%s] [%s]" % (pw,pw2))
|
||||
if pw == pw2:
|
||||
vmsg("Passphrases match"); break
|
||||
else: msg("Passphrases do not match. Try again.")
|
||||
|
|
@ -332,27 +341,21 @@ def get_new_passphrase(what,passchg=False):
|
|||
|
||||
|
||||
def confirm_or_exit(message, question, expect="YES"):
|
||||
if not confirm_or_false(message, question, expect):
|
||||
msg("Exiting at user request")
|
||||
sys.exit(2)
|
||||
|
||||
def confirm_or_false(message, question, expect="YES"):
|
||||
|
||||
m = message.strip()
|
||||
if m: msg(m)
|
||||
|
||||
conf_msg = "Type uppercase '%s' to confirm: " % expect
|
||||
a = question+" " if question[0].isupper() else \
|
||||
"Are you sure you want to %s?\n" % question
|
||||
b = "Type uppercase '%s' to confirm: " % expect
|
||||
|
||||
p = question+" "+conf_msg if question[0].isupper() else \
|
||||
"Are you sure you want to %s?\n%s" % (question,conf_msg)
|
||||
|
||||
vmsg("")
|
||||
return my_raw_input(p).strip() == expect
|
||||
if my_raw_input(a+b).strip() != expect:
|
||||
die(2,"Exiting at user request")
|
||||
|
||||
|
||||
def write_to_stdout(data, what, confirm=True):
|
||||
if sys.stdout.isatty() and confirm:
|
||||
confirm_or_exit("",'output {} to screen'.format(what))
|
||||
def write_to_stdout(data, desc, ask_terminal=True):
|
||||
if sys.stdout.isatty() and ask_terminal:
|
||||
confirm_or_exit("",'output {} to screen'.format(desc))
|
||||
elif not sys.stdout.isatty():
|
||||
try:
|
||||
of = os.readlink("/proc/%d/fd/1" % os.getpid())
|
||||
|
|
@ -363,8 +366,83 @@ def write_to_stdout(data, what, confirm=True):
|
|||
msg("Redirecting output to file")
|
||||
sys.stdout.write(data)
|
||||
|
||||
# New function
|
||||
def write_data_to_file(
|
||||
outfile,
|
||||
data,
|
||||
desc="data",
|
||||
ask_write=False,
|
||||
ask_write_prompt="",
|
||||
ask_write_default_yes=False,
|
||||
ask_overwrite=True,
|
||||
ask_tty=True,
|
||||
no_tty=False,
|
||||
silent=False
|
||||
):
|
||||
if opt.stdout or not sys.stdout.isatty():
|
||||
qmsg("Output to STDOUT requested")
|
||||
write_ok = False
|
||||
if sys.stdout.isatty():
|
||||
if no_tty:
|
||||
die(2,"Printing %s to screen is not allowed" % desc)
|
||||
if ask_tty:
|
||||
confirm_or_exit("",'output %s to screen' % desc)
|
||||
else:
|
||||
try: of = os.readlink("/proc/%d/fd/1" % os.getpid()) # Linux
|
||||
except: of = None # Windows
|
||||
|
||||
def write_to_file(outfile,data,what="data",confirm_overwrite=False,verbose=False,exit_on_error=True,silent=False):
|
||||
if of:
|
||||
if of[:5] == "pipe:":
|
||||
if no_tty:
|
||||
die(2,"Writing %s to pipe is not allowed" % desc)
|
||||
if ask_tty:
|
||||
confirm_or_exit("",'output %s to pipe' % desc)
|
||||
msg("")
|
||||
of2,pd = os.path.relpath(of),os.path.pardir
|
||||
msg("Redirecting output to file '%s'" %
|
||||
(of if of2[:len(pd)] == pd else of2))
|
||||
else:
|
||||
msg("Redirecting output to file")
|
||||
|
||||
sys.stdout.write(data)
|
||||
else:
|
||||
if opt.outdir: outfile = make_full_path(opt.outdir,outfile)
|
||||
|
||||
if ask_write:
|
||||
if not keypress_confirm(ask_write_prompt,
|
||||
default_yes=ask_write_default_yes):
|
||||
die(1,"Exiting at user request")
|
||||
|
||||
hush = False
|
||||
if file_exists(outfile):
|
||||
if ask_overwrite:
|
||||
q = "File '%s' already exists\nOverwrite?" % outfile
|
||||
confirm_or_exit("",q)
|
||||
if not silent: msg("Overwriting file '%s'" % outfile)
|
||||
hush = True
|
||||
|
||||
f = open_file_or_exit(outfile,'wb')
|
||||
try:
|
||||
f.write(data)
|
||||
except:
|
||||
if not silent: msg("Failed to write %s to file '%s'" % (desc,outfile))
|
||||
sys.exit(2)
|
||||
f.close
|
||||
|
||||
if not hush:
|
||||
msg("%s written to file '%s'" % (capfirst(desc),outfile))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def write_to_file(
|
||||
outfile,
|
||||
data,
|
||||
desc="data",
|
||||
confirm_overwrite=False,
|
||||
verbose=False,
|
||||
silent=False
|
||||
):
|
||||
|
||||
if opt.outdir: outfile = make_full_path(opt.outdir,outfile)
|
||||
|
||||
|
|
@ -373,12 +451,7 @@ def write_to_file(outfile,data,what="data",confirm_overwrite=False,verbose=False
|
|||
else:
|
||||
if confirm_overwrite:
|
||||
q = "File '%s' already exists\nOverwrite?" % outfile
|
||||
if exit_on_error:
|
||||
confirm_or_exit("",q)
|
||||
else:
|
||||
if not confirm_or_false("",q):
|
||||
msg("Not overwriting file at user request")
|
||||
return False
|
||||
confirm_or_exit("",q)
|
||||
else:
|
||||
if not silent: msg("Overwriting file '%s'" % outfile)
|
||||
|
||||
|
|
@ -386,20 +459,20 @@ def write_to_file(outfile,data,what="data",confirm_overwrite=False,verbose=False
|
|||
try:
|
||||
f.write(data)
|
||||
except:
|
||||
if not silent: msg("Failed to write %s to file '%s'" % (what,outfile))
|
||||
if not silent: msg("Failed to write %s to file '%s'" % (desc,outfile))
|
||||
sys.exit(2)
|
||||
f.close
|
||||
|
||||
if verbose: msg("%s written to file '%s'" % (what.capitalize(),outfile))
|
||||
if verbose: msg("%s written to file '%s'" % (capfirst(desc),outfile))
|
||||
return True
|
||||
|
||||
|
||||
def write_to_file_or_stdout(outfile, data, what="data"):
|
||||
def write_to_file_or_stdout(outfile, data, desc="data"):
|
||||
|
||||
if opt.stdout or not sys.stdout.isatty():
|
||||
write_to_stdout(data, what, confirm=True)
|
||||
write_to_stdout(data, desc)
|
||||
else:
|
||||
write_to_file(outfile,data,what,not opt.quiet,True)
|
||||
write_to_file(outfile,data,desc,not opt.quiet,True)
|
||||
|
||||
|
||||
from mmgen.bitcoin import b58decode_pad,b58encode_pad
|
||||
|
|
@ -437,7 +510,7 @@ def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed):
|
|||
seed_len = str(len(seed)*8)
|
||||
pw_status = "NE" if len(passwd) else "E"
|
||||
hash_preset = opt.hash_preset
|
||||
label = opt.label if opt.label else "No Label"
|
||||
label = opt.label or "No Label"
|
||||
metadata = seed_id.lower(),key_id.lower(),seed_len,\
|
||||
pw_status,make_timestamp()
|
||||
sf = b58encode_pad(salt)
|
||||
|
|
@ -447,8 +520,8 @@ def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed):
|
|||
label,
|
||||
"{} {} {} {} {}".format(*metadata),
|
||||
"{}: {} {} {}".format(hash_preset,*get_hash_params(hash_preset)),
|
||||
"{} {}".format(make_chksum_6(sf), split_into_columns(4,sf)),
|
||||
"{} {}".format(make_chksum_6(esf), split_into_columns(4,esf))
|
||||
"{} {}".format(make_chksum_6(sf), split_into_cols(4,sf)),
|
||||
"{} {}".format(make_chksum_6(esf), split_into_cols(4,esf))
|
||||
)
|
||||
|
||||
chk = make_chksum_6(" ".join(lines))
|
||||
|
|
@ -465,18 +538,18 @@ def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed):
|
|||
def _check_mmseed_format(words):
|
||||
|
||||
valid = False
|
||||
what = "%s data" % g.seed_ext
|
||||
desc = "%s data" % g.seed_ext
|
||||
try:
|
||||
chklen = len(words[0])
|
||||
except:
|
||||
return False
|
||||
|
||||
if len(words) < 3 or len(words) > 12:
|
||||
msg("Invalid data length (%s) in %s" % (len(words),what))
|
||||
msg("Invalid data length (%s) in %s" % (len(words),desc))
|
||||
elif not is_hexstring(words[0]):
|
||||
msg("Invalid format of checksum '%s' in %s"%(words[0], what))
|
||||
msg("Invalid format of checksum '%s' in %s"%(words[0], desc))
|
||||
elif chklen != 6:
|
||||
msg("Incorrect length of checksum (%s) in %s" % (chklen,what))
|
||||
msg("Incorrect length of checksum (%s) in %s" % (chklen,desc))
|
||||
else: valid = True
|
||||
|
||||
return valid
|
||||
|
|
@ -484,19 +557,19 @@ def _check_mmseed_format(words):
|
|||
|
||||
def _check_wallet_format(infile, lines):
|
||||
|
||||
what = "wallet file '%s'" % infile
|
||||
desc = "wallet file '%s'" % infile
|
||||
valid = False
|
||||
chklen = len(lines[0])
|
||||
if len(lines) != 6:
|
||||
vmsg("Invalid number of lines (%s) in %s" % (len(lines),what))
|
||||
vmsg("Invalid number of lines (%s) in %s" % (len(lines),desc))
|
||||
elif chklen != 6:
|
||||
vmsg("Incorrect length of Master checksum (%s) in %s" % (chklen,what))
|
||||
vmsg("Incorrect length of Master checksum (%s) in %s" % (chklen,desc))
|
||||
elif not is_hexstring(lines[0]):
|
||||
vmsg("Invalid format of Master checksum '%s' in %s"%(lines[0], what))
|
||||
vmsg("Invalid format of Master checksum '%s' in %s"%(lines[0], desc))
|
||||
else: valid = True
|
||||
|
||||
if valid == False:
|
||||
msg("Invalid %s" % what)
|
||||
msg("Invalid %s" % desc)
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
|
|
@ -506,8 +579,7 @@ def _check_chksum_6(chk,val,desc,infile):
|
|||
msg("%s checksum incorrect in file '%s'!" % (desc,infile))
|
||||
msg("Checksum: %s. Computed value: %s" % (chk,comp_chk))
|
||||
sys.exit(2)
|
||||
elif opt.debug:
|
||||
Msg("%s checksum passed: %s" % (desc.capitalize(),chk))
|
||||
dmsg("%s checksum passed: %s" % (capfirst(desc),chk))
|
||||
|
||||
|
||||
def get_data_from_wallet(infile,silent=False):
|
||||
|
|
@ -557,23 +629,23 @@ def get_data_from_wallet(infile,silent=False):
|
|||
def _get_words_from_user(prompt):
|
||||
# split() also strips
|
||||
words = my_raw_input(prompt, echo=opt.echo_passphrase).split()
|
||||
if opt.debug: Msg("Sanitized input: [%s]" % " ".join(words))
|
||||
dmsg("Sanitized input: [%s]" % " ".join(words))
|
||||
return words
|
||||
|
||||
|
||||
def _get_words_from_file(infile,what):
|
||||
qmsg("Getting %s from file '%s'" % (what,infile))
|
||||
def _get_words_from_file(infile,desc):
|
||||
qmsg("Getting %s from file '%s'" % (desc,infile))
|
||||
f = open_file_or_exit(infile, 'r')
|
||||
# split() also strips
|
||||
words = f.read().split()
|
||||
f.close()
|
||||
if opt.debug: Msg("Sanitized input: [%s]" % " ".join(words))
|
||||
dmsg("Sanitized input: [%s]" % " ".join(words))
|
||||
return words
|
||||
|
||||
|
||||
def get_words(infile,what,prompt):
|
||||
def get_words(infile,desc,prompt):
|
||||
if infile:
|
||||
return _get_words_from_file(infile,what)
|
||||
return _get_words_from_file(infile,desc)
|
||||
else:
|
||||
return _get_words_from_user(prompt)
|
||||
|
||||
|
|
@ -586,24 +658,24 @@ def remove_comments(lines):
|
|||
if i: ret.append(i)
|
||||
return ret
|
||||
|
||||
def get_lines_from_file(infile,what="",trim_comments=False):
|
||||
if what != "":
|
||||
qmsg("Getting %s from file '%s'" % (what,infile))
|
||||
def get_lines_from_file(infile,desc="",trim_comments=False):
|
||||
if desc != "":
|
||||
qmsg("Getting %s from file '%s'" % (desc,infile))
|
||||
f = open_file_or_exit(infile,'r')
|
||||
lines = f.read().splitlines()
|
||||
f.close()
|
||||
return remove_comments(lines) if trim_comments else lines
|
||||
|
||||
|
||||
def get_data_from_user(what="data",silent=False):
|
||||
data = my_raw_input("Enter %s: " % what, echo=opt.echo_passphrase)
|
||||
if opt.debug: Msg("User input: [%s]" % data)
|
||||
def get_data_from_user(desc="data",silent=False):
|
||||
data = my_raw_input("Enter %s: " % desc, echo=opt.echo_passphrase)
|
||||
dmsg("User input: [%s]" % data)
|
||||
return data
|
||||
|
||||
def get_data_from_file(infile,what="data",dash=False,silent=False):
|
||||
def get_data_from_file(infile,desc="data",dash=False,silent=False):
|
||||
if dash and infile == "-": return sys.stdin.read()
|
||||
if not silent:
|
||||
qmsg("Getting %s from file '%s'" % (what,infile))
|
||||
qmsg("Getting %s from file '%s'" % (desc,infile))
|
||||
f = open_file_or_exit(infile,'rb')
|
||||
data = f.read()
|
||||
f.close()
|
||||
|
|
@ -622,7 +694,7 @@ def get_seed_from_seed_data(words):
|
|||
chk = make_chksum_6(seed_b58)
|
||||
vmsg_r("Validating %s checksum..." % g.seed_ext)
|
||||
|
||||
if compare_chksums(chk, "seed", stored_chk, "input",die=False):
|
||||
if compare_chksums(chk, "seed", stored_chk, "input"):
|
||||
seed = b58decode_pad(seed_b58)
|
||||
if seed == False:
|
||||
msg("Invalid b58 number: %s" % val)
|
||||
|
|
@ -645,9 +717,8 @@ def mark_passwd_file_as_used():
|
|||
passwd_file_used = True
|
||||
|
||||
|
||||
def get_mmgen_passphrase(prompt_info,passchg=False):
|
||||
prompt = "Enter {}passphrase for {}: ".format(
|
||||
"old " if passchg else "",prompt_info)
|
||||
def get_mmgen_passphrase(desc,passchg=False):
|
||||
prompt ="Enter {}passphrase for {}: ".format("old " if passchg else "",desc)
|
||||
if opt.passwd_file:
|
||||
mark_passwd_file_as_used()
|
||||
return " ".join(_get_words_from_file(opt.passwd_file,"passphrase"))
|
||||
|
|
@ -674,17 +745,18 @@ def check_data_fits_file_at_offset(fname,offset,dlen,action):
|
|||
fsize = os.stat(fname).st_size
|
||||
|
||||
if fsize < offset + dlen:
|
||||
m = "Destination" if action == "write" else "Input"
|
||||
msg(
|
||||
"Destination file has length %s, too short to %s %s bytes of data at offset %s"
|
||||
% (fsize,action,dlen,offset))
|
||||
"%s file has length %s, too short to %s %s bytes of data at offset %s"
|
||||
% (m,fsize,action,dlen,offset))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
from mmgen.term import kb_hold_protect,get_char
|
||||
|
||||
def get_hash_preset_from_user(hp=g.hash_preset,what="data"):
|
||||
def get_hash_preset_from_user(hp=g.hash_preset,desc="data"):
|
||||
p = """Enter hash preset for %s,
|
||||
or hit ENTER to accept the default value ('%s'): """ % (what,hp)
|
||||
or hit ENTER to accept the default value ('%s'): """ % (desc,hp)
|
||||
while True:
|
||||
ret = my_raw_input(p)
|
||||
if ret:
|
||||
|
|
@ -751,17 +823,18 @@ def prompt_and_get_char(prompt,chars,enter_ok=False,verbose=False):
|
|||
|
||||
def do_license_msg(immed=False):
|
||||
|
||||
from mmgen.license import gpl
|
||||
import mmgen.license as gpl
|
||||
if opt.quiet or g.no_license: return
|
||||
|
||||
msg(gpl['warning'])
|
||||
prompt = "%s " % gpl['prompt'].strip()
|
||||
p = "Press 'w' for conditions and warranty info, or 'c' to continue:"
|
||||
msg(gpl.warning)
|
||||
prompt = "%s " % p.strip()
|
||||
|
||||
while True:
|
||||
reply = get_char(prompt, immed_chars="wc" if immed else "")
|
||||
if reply == 'w':
|
||||
from mmgen.term import do_pager
|
||||
do_pager(gpl['conditions'])
|
||||
do_pager(gpl.conditions)
|
||||
elif reply == 'c':
|
||||
msg(""); break
|
||||
else:
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -59,6 +59,7 @@ setup(
|
|||
'mmgen.main_txsend',
|
||||
'mmgen.main_txsign',
|
||||
'mmgen.main_walletchk',
|
||||
'mmgen.main_walletconv',
|
||||
'mmgen.main_walletgen',
|
||||
|
||||
'mmgen.share.__init__',
|
||||
|
|
@ -83,6 +84,7 @@ setup(
|
|||
'mmgen-addrimport',
|
||||
'mmgen-passchg',
|
||||
'mmgen-walletchk',
|
||||
'mmgen-walletconv',
|
||||
'mmgen-walletgen',
|
||||
'mmgen-txcreate',
|
||||
'mmgen-txsign',
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ sys.path.__setitem__(0,os.path.abspath(os.curdir))
|
|||
from binascii import hexlify
|
||||
|
||||
import mmgen.opt as opt
|
||||
import mmgen.config as g
|
||||
from mmgen.util import msg,msg_r,msgrepr,msgrepr_exit,red,green
|
||||
import mmgen.globalvars as g
|
||||
from mmgen.util import msg,msg_r,mmsg,mdie,red,green,vmsg
|
||||
from mmgen.bitcoin import hextowif,privnum2addr
|
||||
|
||||
rounds = 100
|
||||
|
|
@ -23,6 +23,7 @@ opts_data = {
|
|||
-h, --help Print this help message
|
||||
-s, --system Test scripts and modules installed on system rather than
|
||||
those in the repo root
|
||||
-v, --verbose Produce more verbose output
|
||||
""",
|
||||
'notes': """
|
||||
|
||||
|
|
@ -63,6 +64,7 @@ for i in range(1,rounds+1):
|
|||
sec = hexlify(os.urandom(32))
|
||||
wif = hextowif(sec)
|
||||
a = privnum2addr(int(sec,16))
|
||||
vmsg("\nkey: %s\naddr: %s\n" % (wif,a))
|
||||
b = check_output(["keyconv", wif]).split()[1]
|
||||
if a != b:
|
||||
msg_r(red("\nERROR: Addresses do not match!"))
|
||||
|
|
@ -74,4 +76,4 @@ for i in range(1,rounds+1):
|
|||
""".format(sec,wif,a,b,pnm=g.proj_name).rstrip())
|
||||
sys.exit(3)
|
||||
|
||||
msg(green("\nOK"))
|
||||
msg(green("%sOK" % ("" if opt.verbose else "\n")))
|
||||
|
|
|
|||
2
test/ref/1378FC64-2907DE97-F980D21F[192,1].mmincog
Normal file
2
test/ref/1378FC64-2907DE97-F980D21F[192,1].mmincog
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
H@&оRLrT.╝у%╛е7© ычeчЬа╧:x%ё5┐НoЫ*ю!вИ д
|
||||
Мё0╬sЪ│ХёR%┤Pьг
|
||||
4
test/ref/1378FC64-4DCB5174-872806A7[192,1].mmincox
Normal file
4
test/ref/1378FC64-4DCB5174-872806A7[192,1].mmincox
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
8e7a aa61 cf9d acba 10ec cda2 a54c a64e
|
||||
ee54 970a ebdc f44d 53d2 c005 46ea 1ab3
|
||||
d940 0d78 6050 16a8 4ef6 e228 661a 803a
|
||||
38ea 6874 189f b022 db94 3e11 051b 0302
|
||||
5
test/ref/98831F3A-1630A9F2-870376A9[256,1].mmincox
Normal file
5
test/ref/98831F3A-1630A9F2-870376A9[256,1].mmincox
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
078b 15e6 42c1 8447 d5a4 f03c b3ae aab9
|
||||
7d79 2640 c307 bf2a 78a6 847b 44f2 6d96
|
||||
7d9b 44ac 193c a47a 9a12 6e60 9f8f fe96
|
||||
720b 0682 01d8 7da4 9eea be67 60c6 cbcf
|
||||
d522 5a97 8bc2 5554
|
||||
1
test/ref/98831F3A-5482381C-18460FB1[256,1].mmincog
Normal file
1
test/ref/98831F3A-5482381C-18460FB1[256,1].mmincog
Normal file
|
|
@ -0,0 +1 @@
|
|||
▒╧и7м8╩≈vЮЛP 0,Ъ%▐║F╖║ДБNИ`зtсЛ╫$╟@≥pk%┘рL}нЯQГА▄≥p/╨=З╘-rО~GОС9
|
||||
4
test/ref/FE3C6545-BC4BE3F2-32586837[128,1].mmincox
Normal file
4
test/ref/FE3C6545-BC4BE3F2-32586837[128,1].mmincox
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
80f5 2531 04ab 4de4 11fd ccb8 aae4 26ed
|
||||
2520 8218 e5e1 8744 d367 9e9d 3491 ff8e
|
||||
f83e 523b 36f7 dbe5 3c92 aeca c935 15fa
|
||||
1bc5 2c54 0e4c 0825
|
||||
BIN
test/ref/FE3C6545-E29303EA-5E229E30[128,1].mmincog
Normal file
BIN
test/ref/FE3C6545-E29303EA-5E229E30[128,1].mmincog
Normal file
Binary file not shown.
BIN
test/ref/sample-text.mmenc
Normal file
BIN
test/ref/sample-text.mmenc
Normal file
Binary file not shown.
456
test/test.py
456
test/test.py
|
|
@ -10,7 +10,7 @@ sys.path.__setitem__(0,os.path.abspath(os.curdir))
|
|||
|
||||
import mmgen.globalvars as g
|
||||
import mmgen.opt as opt
|
||||
from mmgen.util import msgrepr,msgrepr_exit,Msg,die
|
||||
from mmgen.util import mmsg,mdie,Msg,die
|
||||
from mmgen.test import *
|
||||
|
||||
hincog_fn = "rand_data"
|
||||
|
|
@ -35,6 +35,9 @@ ref_kafile_pass = "kafile password"
|
|||
ref_kafile_hash_preset = "1"
|
||||
|
||||
ref_enc_fn = "sample-text.mmenc"
|
||||
tool_enc_passwd = "Scrypt it, don't hash it!"
|
||||
sample_text = \
|
||||
"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks\n"
|
||||
|
||||
cfgs = {
|
||||
'6': {
|
||||
|
|
@ -46,8 +49,11 @@ cfgs = {
|
|||
'keyaddrfile_chk': "CF83 32FB 8A8B 08E2 0F00 D601",
|
||||
'wpasswd': "reference password",
|
||||
'ref_wallet': "FE3C6545-D782B529[128,1].mmdat",
|
||||
'ic_wallet': "FE3C6545-161E495F-BEB7548E[128:1].incog-offset123",
|
||||
'ic_wallet_old': "FE3C6545-161E495F-9860A85B[128:1].incog-old.offset123",
|
||||
'ic_wallet': "FE3C6545-E29303EA-5E229E30[128,1].mmincog",
|
||||
'ic_wallet_hex': "FE3C6545-BC4BE3F2-32586837[128,1].mmincox",
|
||||
|
||||
'hic_wallet': "FE3C6545-161E495F-BEB7548E[128:1].incog-offset123",
|
||||
'hic_wallet_old': "FE3C6545-161E495F-9860A85B[128:1].incog-old.offset123",
|
||||
|
||||
'tmpdir': os.path.join("test","tmp6"),
|
||||
'kapasswd': "",
|
||||
|
|
@ -68,8 +74,11 @@ cfgs = {
|
|||
'keyaddrfile_chk': "9648 5132 B98E 3AD9 6FC3 C5AD",
|
||||
'wpasswd': "reference password",
|
||||
'ref_wallet': "1378FC64-6F0F9BB4[192,1].mmdat",
|
||||
'ic_wallet': "1378FC64-B55E9958-77256FC1[192:1].incog.offset123",
|
||||
'ic_wallet_old': "1378FC64-B55E9958-D85FF20C[192:1].incog-old.offset123",
|
||||
'ic_wallet': "1378FC64-2907DE97-F980D21F[192,1].mmincog",
|
||||
'ic_wallet_hex': "1378FC64-4DCB5174-872806A7[192,1].mmincox",
|
||||
|
||||
'hic_wallet': "1378FC64-B55E9958-77256FC1[192:1].incog.offset123",
|
||||
'hic_wallet_old': "1378FC64-B55E9958-D85FF20C[192:1].incog-old.offset123",
|
||||
|
||||
'tmpdir': os.path.join("test","tmp7"),
|
||||
'kapasswd': "",
|
||||
|
|
@ -97,8 +106,11 @@ cfgs = {
|
|||
|
||||
# 'ref_fake_unspent_data':"98831F3A_unspent.json",
|
||||
'ref_tx_file': "tx_FFB367[1.234].raw",
|
||||
'ic_wallet': "98831F3A-F59B07A0-559CEF19[256:1].incog.offset123",
|
||||
'ic_wallet_old': "98831F3A-F59B07A0-848535F3[256:1].incog-old.offset123",
|
||||
'ic_wallet': "98831F3A-5482381C-18460FB1[256,1].mmincog",
|
||||
'ic_wallet_hex': "98831F3A-1630A9F2-870376A9[256,1].mmincox",
|
||||
|
||||
'hic_wallet': "98831F3A-F59B07A0-559CEF19[256:1].incog.offset123",
|
||||
'hic_wallet_old': "98831F3A-F59B07A0-848535F3[256:1].incog-old.offset123",
|
||||
|
||||
'tmpdir': os.path.join("test","tmp8"),
|
||||
'kapasswd': "",
|
||||
|
|
@ -108,7 +120,6 @@ cfgs = {
|
|||
'addrs': "refaddrgen3",
|
||||
'akeys.mmenc': "refkeyaddrgen3"
|
||||
},
|
||||
|
||||
},
|
||||
'1': {
|
||||
'tmpdir': os.path.join("test","tmp1"),
|
||||
|
|
@ -133,7 +144,7 @@ cfgs = {
|
|||
'tmpdir': os.path.join("test","tmp2"),
|
||||
'wpasswd': "Hodling away",
|
||||
'addr_idx_list': "37,45,3-6,22-23", # 8 addresses
|
||||
'seed_len': 128,
|
||||
'seed_len': 128,
|
||||
'dep_generators': {
|
||||
'mmdat': "walletgen2",
|
||||
'addrs': "addrgen2",
|
||||
|
|
@ -157,7 +168,7 @@ cfgs = {
|
|||
'tmpdir': os.path.join("test","tmp4"),
|
||||
'wpasswd': "Hashrate rising",
|
||||
'addr_idx_list': "63,1004,542-544,7-9", # 8 addresses
|
||||
'seed_len': 192,
|
||||
'seed_len': 192,
|
||||
'dep_generators': {
|
||||
'mmdat': "walletgen4",
|
||||
'mmbrain': "walletgen4",
|
||||
|
|
@ -177,9 +188,6 @@ cfgs = {
|
|||
},
|
||||
'9': {
|
||||
'tmpdir': os.path.join("test","tmp9"),
|
||||
'tool_enc_passwd': "Scrypt it, don't hash it!",
|
||||
'sample_text':
|
||||
"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks\n",
|
||||
'tool_enc_infn': "tool_encrypt.in",
|
||||
# 'tool_enc_ref_infn': "tool_encrypt_ref.in",
|
||||
'dep_generators': {
|
||||
|
|
@ -191,46 +199,14 @@ cfgs = {
|
|||
},
|
||||
}
|
||||
|
||||
from copy import deepcopy
|
||||
for a,b in ('6','11'),('7','12'),('8','13'):
|
||||
cfgs[b] = deepcopy(cfgs[a])
|
||||
cfgs[b]['tmpdir'] = os.path.join("test","tmp"+b)
|
||||
|
||||
from collections import OrderedDict
|
||||
cmd_data = OrderedDict([
|
||||
# test description depends
|
||||
# Check saved reference files:
|
||||
['ref_wallet_chk1', (6,'saved reference wallet (128-bit)', [[[],6]])],
|
||||
['ref_wallet_chk2', (7,'saved reference wallet (192-bit)', [[[],7]])],
|
||||
['ref_wallet_chk3', (8,'saved reference wallet (256-bit)', [[[],8]])],
|
||||
['ref_seed_chk1', (6,'saved seed file (128-bit)', [[[],6]])],
|
||||
['ref_seed_chk2', (7,'saved seed file (192-bit)', [[[],7]])],
|
||||
['ref_seed_chk3', (8,'saved seed file (256-bit)', [[[],8]])],
|
||||
['ref_mn_chk1', (6,'saved mnemonic file (128-bit)', [[[],6]])],
|
||||
['ref_mn_chk2', (7,'saved mnemonic file (192-bit)', [[[],7]])],
|
||||
['ref_mn_chk3', (8,'saved mnemonic file (256-bit)', [[[],8]])],
|
||||
['ref_incog_chk1', (6,'saved incog reference wallet (128-bit)', [[[],6]])],
|
||||
['ref_incog_chk2', (7,'saved incog reference wallet (192-bit)', [[[],7]])],
|
||||
['ref_incog_chk3', (8,'saved incog reference wallet (256-bit)', [[[],8]])],
|
||||
['ref_brain_chk1', (6,'saved brainwallet (128-bit)', [[[],6]])],
|
||||
['ref_brain_chk2', (7,'saved brainwallet (192-bit)', [[[],7]])],
|
||||
['ref_brain_chk3', (8,'saved brainwallet (256-bit)', [[[],8]])],
|
||||
['ref_brain_chk3_spc', (8,'saved brainwallet (256-bit, non-standard spacing)', [[[],8]])],
|
||||
|
||||
['ref_addrfile_chk', (8,'saved reference address file', [[[],8]])],
|
||||
['ref_keyaddrfile_chk', (8,'saved reference key-address file', [[[],8]])],
|
||||
# Create the fake inputs:
|
||||
# ['txcreate8', (8,'transaction creation (8)', [[["addrs"],8]])],
|
||||
['ref_tx_chk', (8,'saved reference tx file', [[[],8]])],
|
||||
|
||||
['ref_tool_decrypt', (9,'decryption of saved MMGen-encrypted file', [[[],9]])],
|
||||
|
||||
# Generate new reference ('abc' brainwallet) files:
|
||||
['refwalletgen1', (6,'gen new refwallet (128-bit)', [[[],6]])],
|
||||
['refwalletgen2', (7,'gen new refwallet (192-bit)', [[[],7]])],
|
||||
['refwalletgen3', (8,'gen new refwallet (256-bit)', [[[],8]])],
|
||||
['refaddrgen1', (6,'new refwallet addr chksum (128-bit)', [[["mmdat"],6]])],
|
||||
['refaddrgen2', (7,'new refwallet addr chksum (192-bit)', [[["mmdat"],7]])],
|
||||
['refaddrgen3', (8,'new refwallet addr chksum (256-bit)', [[["mmdat"],8]])],
|
||||
['refkeyaddrgen1', (6,'new refwallet key-addr chksum (128-bit)', [[["mmdat"],6]])],
|
||||
['refkeyaddrgen2', (7,'new refwallet key-addr chksum (192-bit)', [[["mmdat"],7]])],
|
||||
['refkeyaddrgen3', (8,'new refwallet key-addr chksum (256-bit)', [[["mmdat"],8]])],
|
||||
|
||||
['walletgen', (1,'wallet generation', [[[],1]])],
|
||||
# ['walletchk', (1,'wallet check', [[["mmdat"],1]])],
|
||||
['passchg', (5,'password, label and hash preset change',[[["mmdat"],1]])],
|
||||
|
|
@ -256,13 +232,11 @@ cmd_data = OrderedDict([
|
|||
['keyaddrgen', (1,'key-address file generation', [[["mmdat"],1]])],
|
||||
['txsign_keyaddr',(1,'transaction signing with key-address file', [[["akeys.mmenc","raw"],1]])],
|
||||
|
||||
# ['walletgen2',(2,'wallet generation (2)', [])],
|
||||
['walletgen2',(2,'wallet generation (2), 128-bit seed', [])],
|
||||
['addrgen2', (2,'address generation (2)', [[["mmdat"],2]])],
|
||||
['txcreate2', (2,'transaction creation (2)', [[["addrs"],2]])],
|
||||
['txsign2', (2,'transaction signing, two transactions',[[["mmdat","raw"],1],[["mmdat","raw"],2]])],
|
||||
['export_mnemonic2', (2,'seed export to mmwords format (2)',[[["mmdat"],2]])],
|
||||
# ['export_mnemonic2', (2,'seed export to mmwords format (2), 128-bit seed (WIP)',[[["mmdat"],2]])],
|
||||
|
||||
['walletgen3',(3,'wallet generation (3)', [])],
|
||||
['addrgen3', (3,'address generation (3)', [[["mmdat"],3]])],
|
||||
|
|
@ -270,18 +244,83 @@ cmd_data = OrderedDict([
|
|||
['txsign3', (3,'tx signing with inputs and outputs from two wallets',[[["mmdat"],1],[["mmdat","raw"],3]])],
|
||||
|
||||
['walletgen4',(4,'wallet generation (4) (brainwallet)', [])],
|
||||
# ['walletgen4',(4,'wallet generation (4) (brainwallet, 192-bit seed (WIP))', [])],
|
||||
['addrgen4', (4,'address generation (4)', [[["mmdat"],4]])],
|
||||
['txcreate4', (4,'tx creation with inputs and outputs from four seed sources, plus non-MMGen inputs and outputs', [[["addrs"],1],[["addrs"],2],[["addrs"],3],[["addrs"],4]])],
|
||||
['txsign4', (4,'tx signing with inputs and outputs from incog file, mnemonic file, wallet and brainwallet, plus non-MMGen inputs and outputs', [[["mmincog"],1],[["mmwords"],2],[["mmdat"],3],[["mmbrain","raw"],4]])],
|
||||
['tool_encrypt', (9,"'mmgen-tool encrypt' (random data)", [])],
|
||||
['tool_decrypt', (9,"'mmgen-tool decrypt' (random data)",
|
||||
[[[cfgs['9']['tool_enc_infn'],
|
||||
cfgs['9']['tool_enc_infn']+".mmenc"],9]])],
|
||||
['tool_decrypt', (9,"'mmgen-tool decrypt' (random data)", [[[cfgs['9']['tool_enc_infn'],cfgs['9']['tool_enc_infn']+".mmenc"],9]])],
|
||||
# ['tool_encrypt_ref', (9,"'mmgen-tool encrypt' (reference text)", [])],
|
||||
['tool_find_incog_data', (9,"'mmgen-tool find_incog_data'", [[[hincog_fn],1],[[incog_id_fn],1]])],
|
||||
])
|
||||
|
||||
# saved reference data
|
||||
cmd_data_ref = (
|
||||
# reading
|
||||
('ref_wallet_chk', ([],'saved reference wallet')),
|
||||
('ref_seed_chk', ([],'saved seed file')),
|
||||
('ref_mn_chk', ([],'saved mnemonic file')),
|
||||
('ref_hincog_chk', ([],'saved hidden incog reference wallet')),
|
||||
('ref_brain_chk', ([],'saved brainwallet')),
|
||||
# generating new reference ('abc' brainwallet) files:
|
||||
('refwalletgen', ([],'gen new refwallet')),
|
||||
('refaddrgen', (["mmdat"],'new refwallet addr chksum')),
|
||||
('refkeyaddrgen', (["mmdat"],'new refwallet key-addr chksum'))
|
||||
)
|
||||
|
||||
# misc. saved reference data
|
||||
cmd_data_ref_other = (
|
||||
('ref_addrfile_chk', 'saved reference address file'),
|
||||
('ref_keyaddrfile_chk','saved reference key-address file'),
|
||||
# Create the fake inputs:
|
||||
# ('txcreate8', 'transaction creation (8)'),
|
||||
('ref_tx_chk', 'saved reference tx file'),
|
||||
('ref_brain_chk_spc3', 'saved brainwallet (non-standard spacing)'),
|
||||
('ref_tool_decrypt', 'decryption of saved MMGen-encrypted file'),
|
||||
)
|
||||
|
||||
# mmgen-walletconv:
|
||||
cmd_data_conv_in = ( # reading
|
||||
('ref_wallet_conv', 'conversion of saved reference wallet'),
|
||||
('ref_mn_conv', 'conversion of saved mnemonic'),
|
||||
('ref_seed_conv', 'conversion of saved seed file'),
|
||||
('ref_brain_conv', 'conversion of ref brainwallet'),
|
||||
('ref_incog_conv', 'conversion of saved incog wallet'),
|
||||
('ref_incox_conv', 'conversion of saved hex incog wallet'),
|
||||
('ref_hincog_conv', 'conversion of saved hidden incog wallet'),
|
||||
('ref_hincog_conv_old','conversion of saved hidden incog wallet (old format)')
|
||||
)
|
||||
cmd_data_conv_out = ( # writing
|
||||
('ref_wallet_conv_out', 'ref seed conversion to wallet'),
|
||||
('ref_mn_conv_out', 'ref seed conversion to mnemonic'),
|
||||
('ref_seed_conv_out', 'ref seed conversion to seed'),
|
||||
('ref_incog_conv_out', 'ref seed conversion to incog data'),
|
||||
('ref_incox_conv_out', 'ref seed conversion to hex incog data'),
|
||||
('ref_hincog_conv_out', 'ref seed conversion to hidden incog data')
|
||||
)
|
||||
|
||||
cmd_groups = OrderedDict([
|
||||
('main', cmd_data.keys()),
|
||||
('ref', [c[0]+str(i) for c in cmd_data_ref for i in (1,2,3)]),
|
||||
('ref_other', [c[0] for c in cmd_data_ref_other]),
|
||||
('conv_in', [c[0]+str(i) for c in cmd_data_conv_in for i in (1,2,3)]),
|
||||
('conv_out', [c[0]+str(i) for c in cmd_data_conv_out for i in (1,2,3)]),
|
||||
])
|
||||
|
||||
for a,b in cmd_data_ref:
|
||||
for i,j in (1,128),(2,192),(3,256):
|
||||
cmd_data[a+str(i)] = (5+i,"%s (%s-bit)" % (b[1],j),[[b[0],5+i]])
|
||||
|
||||
for a,b in cmd_data_ref_other:
|
||||
cmd_data[a] = (8,b,[[[],8]])
|
||||
|
||||
for a,b in cmd_data_conv_in:
|
||||
for i,j in (1,128),(2,192),(3,256):
|
||||
cmd_data[a+str(i)] = (10+i,"%s (%s-bit)" % (b,j),[[[],10+i]])
|
||||
|
||||
for a,b in cmd_data_conv_out:
|
||||
for i,j in (1,128),(2,192),(3,256):
|
||||
cmd_data[a+str(i)] = (10+i,"%s (%s-bit)" % (b,j),[[[],10+i]])
|
||||
|
||||
utils = {
|
||||
'check_deps': 'check dependencies for specified command',
|
||||
'clean': 'clean specified tmp dir(s) 1,2,3,4,5 or 6 (no arg = all dirs)',
|
||||
|
|
@ -296,23 +335,34 @@ for k in cfgs.keys():
|
|||
cfgs[k]['amts'][idx] = "%s.%s" % ((getrandnum(2) % mod), str(getrandnum(4))[:5])
|
||||
|
||||
meta_cmds = OrderedDict([
|
||||
['saved_ref1', (6,("ref_wallet_chk1","ref_seed_chk1","ref_mn_chk1","ref_brain_chk1","ref_incog_chk1"))],
|
||||
['saved_ref2', (7,("ref_wallet_chk2","ref_seed_chk2","ref_mn_chk2","ref_brain_chk2","ref_incog_chk2"))],
|
||||
['saved_ref3', (8,("ref_wallet_chk3","ref_seed_chk3","ref_mn_chk3","ref_brain_chk3","ref_incog_chk3","ref_brain_chk3_spc"))],
|
||||
['saved_ref_other', (8,("ref_addrfile_chk","ref_tx_chk","ref_tool_decrypt"))],
|
||||
['ref1', (6,("refwalletgen1","refaddrgen1","refkeyaddrgen1"))],
|
||||
['ref2', (7,("refwalletgen2","refaddrgen2","refkeyaddrgen2"))],
|
||||
['ref3', (8,("refwalletgen3","refaddrgen3","refkeyaddrgen3"))],
|
||||
['gen', (1,("walletgen","addrgen"))],
|
||||
['pass', (5,("passchg","walletchk_newpass"))],
|
||||
['tx', (1,("txcreate","txsign","txsend"))],
|
||||
['export', (1,[k for k in cmd_data if k[:7] == "export_" and cmd_data[k][0] == 1])],
|
||||
['gen_sp', (1,[k for k in cmd_data if k[:8] == "addrgen_" and cmd_data[k][0] == 1])],
|
||||
['online', (1,("keyaddrgen","txsign_keyaddr"))],
|
||||
['2', (2,[k for k in cmd_data if cmd_data[k][0] == 2])],
|
||||
['3', (3,[k for k in cmd_data if cmd_data[k][0] == 3])],
|
||||
['4', (4,[k for k in cmd_data if cmd_data[k][0] == 4])],
|
||||
['tool', (9,("tool_encrypt","tool_decrypt","tool_find_incog_data"))],
|
||||
['ref1', ("refwalletgen1","refaddrgen1","refkeyaddrgen1")],
|
||||
['ref2', ("refwalletgen2","refaddrgen2","refkeyaddrgen2")],
|
||||
['ref3', ("refwalletgen3","refaddrgen3","refkeyaddrgen3")],
|
||||
['gen', ("walletgen","addrgen")],
|
||||
['pass', ("passchg","walletchk_newpass")],
|
||||
['tx', ("addrimport","txcreate","txsign","txsend")],
|
||||
['export', [k for k in cmd_data if k[:7] == "export_" and cmd_data[k][0] == 1]],
|
||||
['gen_sp', [k for k in cmd_data if k[:8] == "addrgen_" and cmd_data[k][0] == 1]],
|
||||
['online', ("keyaddrgen","txsign_keyaddr")],
|
||||
['2', [k for k in cmd_data if cmd_data[k][0] == 2]],
|
||||
['3', [k for k in cmd_data if cmd_data[k][0] == 3]],
|
||||
['4', [k for k in cmd_data if cmd_data[k][0] == 4]],
|
||||
|
||||
['tool', ("tool_encrypt","tool_decrypt","tool_find_incog_data")],
|
||||
|
||||
['saved_ref1', [c[0]+"1" for c in cmd_data_ref]],
|
||||
['saved_ref2', [c[0]+"2" for c in cmd_data_ref]],
|
||||
['saved_ref3', [c[0]+"3" for c in cmd_data_ref]],
|
||||
|
||||
['saved_ref_other', [c[0] for c in cmd_data_ref_other]],
|
||||
|
||||
['saved_ref_conv_in1', [c[0]+"1" for c in cmd_data_conv_in]],
|
||||
['saved_ref_conv_in2', [c[0]+"2" for c in cmd_data_conv_in]],
|
||||
['saved_ref_conv_in3', [c[0]+"3" for c in cmd_data_conv_in]],
|
||||
|
||||
['saved_ref_conv_out1', [c[0]+"1" for c in cmd_data_conv_out]],
|
||||
['saved_ref_conv_out2', [c[0]+"2" for c in cmd_data_conv_out]],
|
||||
['saved_ref_conv_out3', [c[0]+"3" for c in cmd_data_conv_out]],
|
||||
])
|
||||
|
||||
opts_data = {
|
||||
|
|
@ -350,8 +400,6 @@ else:
|
|||
send_delay = 0
|
||||
os.environ["MMGEN_DISABLE_HOLD_PROTECT"] = "1"
|
||||
|
||||
if opt.debug: opt.verbose = True
|
||||
|
||||
if opt.exact_output:
|
||||
def msg(s): pass
|
||||
vmsg = vmsg_r = msg_r = msg
|
||||
|
|
@ -378,15 +426,22 @@ def errmsg_r(s): stderr_save.write(s)
|
|||
|
||||
if opt.list_cmds:
|
||||
fs = " {:<{w}} - {}"
|
||||
Msg("Available commands:")
|
||||
Msg("AVAILABLE COMMANDS:")
|
||||
w = max([len(i) for i in cmd_data])
|
||||
for cmd in cmd_data:
|
||||
Msg(fs.format(cmd,cmd_data[cmd][1],w=w))
|
||||
Msg("\nAvailable metacommands:")
|
||||
|
||||
w = max([len(i) for i in meta_cmds])
|
||||
Msg("\nAVAILABLE METACOMMANDS:")
|
||||
for cmd in meta_cmds:
|
||||
Msg(fs.format(cmd," + ".join(meta_cmds[cmd][1]),w=w))
|
||||
Msg("\nAvailable utilities:")
|
||||
Msg(fs.format(cmd," ".join(meta_cmds[cmd]),w=w))
|
||||
|
||||
w = max([len(i) for i in cmd_groups.keys()])
|
||||
Msg("\nAVAILABLE COMMAND GROUPS:")
|
||||
for g in cmd_groups.keys():
|
||||
Msg(fs.format(g," ".join(cmd_groups[g]),w=w))
|
||||
|
||||
Msg("\nAVAILABLE UTILITIES:")
|
||||
w = max([len(i) for i in utils])
|
||||
for cmd in sorted(utils):
|
||||
Msg(fs.format(cmd,utils[cmd],w=w))
|
||||
|
|
@ -428,7 +483,8 @@ def my_expect(p,s,t='',delay=send_delay,regex=False,nonl=False):
|
|||
else:
|
||||
if t == '':
|
||||
if not nonl: vmsg("")
|
||||
else: ret = my_send(p,t,delay,s)
|
||||
else:
|
||||
my_send(p,t,delay,s)
|
||||
return ret
|
||||
|
||||
def get_file_with_ext(ext,mydir,delete=True):
|
||||
|
|
@ -502,28 +558,32 @@ class MMGenExpect(object):
|
|||
vmsg("EOT")
|
||||
my_expect(self.p,"ENTER to continue: ",'\n')
|
||||
|
||||
def passphrase_new(self,what,passphrase):
|
||||
my_expect(self.p,("Enter passphrase for %s: " % what), passphrase+"\n")
|
||||
def passphrase_new(self,desc,passphrase):
|
||||
my_expect(self.p,("Enter passphrase for %s: " % desc), passphrase+"\n")
|
||||
my_expect(self.p,"Repeat passphrase: ", passphrase+"\n")
|
||||
|
||||
def passphrase(self,what,passphrase,pwtype=""):
|
||||
def passphrase(self,desc,passphrase,pwtype=""):
|
||||
if pwtype: pwtype += " "
|
||||
my_expect(self.p,("Enter %spassphrase for %s.*?: " % (pwtype,what)),
|
||||
my_expect(self.p,("Enter %spassphrase for %s.*?: " % (pwtype,desc)),
|
||||
passphrase+"\n",regex=True)
|
||||
|
||||
def hash_preset(self,what,preset=''):
|
||||
my_expect(self.p,("Enter hash preset for %s," % what))
|
||||
def hash_preset(self,desc,preset=''):
|
||||
my_expect(self.p,("Enter hash preset for %s," % desc))
|
||||
my_expect(self.p,("or hit ENTER .*?:"), str(preset)+"\n",regex=True)
|
||||
|
||||
def written_to_file(self,what,overwrite_unlikely=False,query="Overwrite? "):
|
||||
s1 = "%s written to file " % what
|
||||
def written_to_file(self,desc,overwrite_unlikely=False,query="Overwrite? ",oo=False):
|
||||
s1 = "%s written to file " % desc
|
||||
s2 = query + "Type uppercase 'YES' to confirm: "
|
||||
ret = my_expect(self.p,s1 if overwrite_unlikely else [s1,s2])
|
||||
if ret == 1:
|
||||
my_send(self.p,"YES\n")
|
||||
ret = my_expect(self.p,s1)
|
||||
if oo:
|
||||
outfile = self.expect_getend("Overwriting file '").rstrip("'")
|
||||
return outfile
|
||||
else:
|
||||
ret = my_expect(self.p,s1)
|
||||
outfile = self.p.readline().strip().strip("'")
|
||||
vmsg("%s file: %s" % (what,cyan(outfile.replace("'",""))))
|
||||
vmsg("%s file: %s" % (desc,cyan(outfile.replace("'",""))))
|
||||
return outfile
|
||||
|
||||
def no_overwrite(self):
|
||||
|
|
@ -679,15 +739,15 @@ def check_needs_rerun(ts,cmd,build=False,root=True,force_delete=False,dpy=False)
|
|||
|
||||
return rerun
|
||||
|
||||
def refcheck(what,chk,refchk):
|
||||
vmsg("Comparing %s '%s' to stored reference" % (what,chk))
|
||||
def refcheck(desc,chk,refchk):
|
||||
vmsg("Comparing %s '%s' to stored reference" % (desc,chk))
|
||||
if chk == refchk:
|
||||
ok()
|
||||
else:
|
||||
if not opt.verbose: errmsg("")
|
||||
errmsg(red("""
|
||||
Fatal error - %s '%s' does not match reference value '%s'. Aborting test
|
||||
""".strip() % (what,chk,refchk)))
|
||||
""".strip() % (desc,chk,refchk)))
|
||||
sys.exit(3)
|
||||
|
||||
def check_deps(cmds):
|
||||
|
|
@ -711,7 +771,7 @@ def check_deps(cmds):
|
|||
c = rebuild_list[cmd]
|
||||
m = "Rebuild" if (c[0] and c[1]) else "Build" if c[0] else "OK"
|
||||
msg("cmd {:<{w}} {}".format(cmd+":", m, w=w))
|
||||
# msgrepr(cmd,c)
|
||||
# mmsg(cmd,c)
|
||||
|
||||
|
||||
def clean(dirs=[]):
|
||||
|
|
@ -738,7 +798,7 @@ class MMGenTestSuite(object):
|
|||
def get_num_exts_for_cmd(self,cmd,dpy=False): # dpy ignored here
|
||||
num = str(cmd_data[cmd][0])
|
||||
dgl = cfgs[num]['dep_generators']
|
||||
# msgrepr(num,cmd,dgl)
|
||||
# mmsg(num,cmd,dgl)
|
||||
if cmd in dgl.values():
|
||||
exts = [k for k in dgl if dgl[k] == cmd]
|
||||
return (num,exts)
|
||||
|
|
@ -801,9 +861,9 @@ class MMGenTestSuite(object):
|
|||
t.usr_rand(10)
|
||||
t.passphrase_new("new MMGen wallet",cfg['wpasswd'])
|
||||
seed_id = t.written_to_file("Wallet").split("-")[0].split("/")[-1]
|
||||
refcheck("seed id",seed_id,cfg['seed_id'])
|
||||
refcheck("seed ID",seed_id,cfg['seed_id'])
|
||||
|
||||
refwalletgen1 = refwalletgen2 = refwalletgen3 = refwalletgen
|
||||
refwalletgen1 = refwalletgen2 = refwalletgen3 = refwalletgen
|
||||
|
||||
def passchg(self,name,walletfile):
|
||||
|
||||
|
|
@ -850,7 +910,7 @@ class MMGenTestSuite(object):
|
|||
d = " (%s-bit seed)" % cfg['seed_len']
|
||||
self.addrgen(name,walletfile,check_ref=True)
|
||||
|
||||
refaddrgen1 = refaddrgen2 = refaddrgen3 = refaddrgen
|
||||
refaddrgen1 = refaddrgen2 = refaddrgen3 = refaddrgen
|
||||
|
||||
def addrimport(self,name,addrfile):
|
||||
outfile = os.path.join(cfg['tmpdir'],"addrfile_w_comments")
|
||||
|
|
@ -1014,11 +1074,11 @@ class MMGenTestSuite(object):
|
|||
t.written_to_file("Data",query="")
|
||||
ok()
|
||||
|
||||
def addrgen_seed(self,name,walletfile,foo,what="seed data",arg="-s"):
|
||||
def addrgen_seed(self,name,walletfile,foo,desc="seed data",arg="-s"):
|
||||
t = MMGenExpect(name,"mmgen-addrgen",
|
||||
[arg,"-d",cfg['tmpdir'],walletfile,cfg['addr_idx_list']])
|
||||
t.license()
|
||||
t.expect_getend("Valid %s for seed ID " % what)
|
||||
t.expect_getend("Valid %s for seed ID " % desc)
|
||||
vmsg("Comparing generated checksum with checksum from previous address file")
|
||||
chk = t.expect_getend(r"Checksum for address data .*?: ",regex=True)
|
||||
verify_checksum_or_exit(get_addrfile_checksum(),chk)
|
||||
|
|
@ -1026,14 +1086,14 @@ class MMGenTestSuite(object):
|
|||
ok()
|
||||
|
||||
def addrgen_mnemonic(self,name,walletfile,foo):
|
||||
self.addrgen_seed(name,walletfile,foo,what="mnemonic",arg="-m")
|
||||
self.addrgen_seed(name,walletfile,foo,desc="mnemonic",arg="-m")
|
||||
|
||||
def addrgen_incog(self,name,walletfile,foo,args=["-g"]):
|
||||
t = MMGenExpect(name,"mmgen-addrgen",args+["-d",
|
||||
cfg['tmpdir'],walletfile,cfg['addr_idx_list']])
|
||||
t.license()
|
||||
t.expect_getend("Incog ID: ")
|
||||
t.passphrase("MMGen incognito wallet \w{8}", cfg['wpasswd'])
|
||||
t.passphrase("incognito wallet data \w{8}", cfg['wpasswd'])
|
||||
t.hash_preset("incog wallet",'1')
|
||||
vmsg("Comparing generated checksum with checksum from address file")
|
||||
chk = t.expect_getend(r"Checksum for address data .*?: ",regex=True)
|
||||
|
|
@ -1068,7 +1128,7 @@ class MMGenTestSuite(object):
|
|||
def refkeyaddrgen(self,name,walletfile):
|
||||
self.keyaddrgen(name,walletfile,check_ref=True)
|
||||
|
||||
refkeyaddrgen1 = refkeyaddrgen2 = refkeyaddrgen3 = refkeyaddrgen
|
||||
refkeyaddrgen1 = refkeyaddrgen2 = refkeyaddrgen3 = refkeyaddrgen
|
||||
|
||||
def txsign_keyaddr(self,name,keyaddr_file,txfile):
|
||||
t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],"-M",keyaddr_file,txfile])
|
||||
|
|
@ -1136,9 +1196,9 @@ class MMGenTestSuite(object):
|
|||
t.license()
|
||||
t.tx_view()
|
||||
|
||||
for cnum,what,app in ('1',"incognito"," incognito"),('3',"MMGen",""):
|
||||
t.expect_getend("Getting %s wallet data from file " % what)
|
||||
t.passphrase("MMGen%s wallet"%app,cfgs[cnum]['wpasswd'])
|
||||
for cnum,desc,app in ('1',"incognito","incognito"),('3',"MMGen","MMGen"):
|
||||
t.expect_getend("Getting %s wallet data from file " % desc)
|
||||
t.passphrase("%s wallet"%app,cfgs[cnum]['wpasswd'])
|
||||
if cnum == '1':
|
||||
t.hash_preset("incog wallet",'1')
|
||||
|
||||
|
|
@ -1155,7 +1215,7 @@ class MMGenTestSuite(object):
|
|||
infn = get_tmpfile_fn(cfg,tmp_fn)
|
||||
t = MMGenExpect(name,"mmgen-tool",["-d",cfg['tmpdir'],"encrypt",infn])
|
||||
t.hash_preset("user data",'1')
|
||||
t.passphrase_new("user data",cfg['tool_enc_passwd'])
|
||||
t.passphrase_new("user data",tool_enc_passwd)
|
||||
t.written_to_file("Encrypted data")
|
||||
ok()
|
||||
# Generate the reference mmenc file
|
||||
|
|
@ -1168,7 +1228,7 @@ class MMGenTestSuite(object):
|
|||
of = name + ".out"
|
||||
t = MMGenExpect(name,"mmgen-tool",
|
||||
["-d",cfg['tmpdir'],"decrypt",f2,"outfile="+of,"hash_preset=1"])
|
||||
t.passphrase("user data",cfg['tool_enc_passwd'])
|
||||
t.passphrase("user data",tool_enc_passwd)
|
||||
t.written_to_file("Decrypted data")
|
||||
d1 = read_from_file(f1)
|
||||
d2 = read_from_file(get_tmpfile_fn(cfg,of))
|
||||
|
|
@ -1182,7 +1242,127 @@ class MMGenTestSuite(object):
|
|||
o = t.expect_getend("Incog data for ID \w{8} found at offset ",regex=True)
|
||||
cmp_or_die(hincog_offset,int(o))
|
||||
|
||||
def walletconv_out(self,name,desc,out_fmt="w",uopts=[],uopts_chk=[],pw=False):
|
||||
opts = ["-d",cfg['tmpdir'],"-r10","-p1","-o",out_fmt] + uopts
|
||||
infile = os.path.join(ref_dir,cfg['seed_id']+".mmwords")
|
||||
d = "(convert)"
|
||||
t = MMGenExpect(name,"mmgen-walletconv",opts+[infile],extra_desc=d)
|
||||
t.license()
|
||||
if pw:
|
||||
t.passphrase_new("new "+desc,cfg['wpasswd'])
|
||||
t.usr_rand(10)
|
||||
if desc == "hidden incognito data":
|
||||
ret = t.expect(["Create? (Y/n): ","'YES' to confirm: "],"YES\n")
|
||||
if ret == 0:
|
||||
t.expect("Enter file size: ","1234\n")
|
||||
wf = t.written_to_file(desc[0].upper()+desc[1:],oo=True)
|
||||
ok()
|
||||
|
||||
d = "(check)"
|
||||
if desc == "hidden incognito data":
|
||||
self.keygen_chksum_chk_hincog(name,cfg['seed_id'],uopts_chk)
|
||||
# elif pw:
|
||||
# self.walletchk_chksum_chk(name,wf,cfg['seed_id'],uopts=uopts_chk)
|
||||
else:
|
||||
self.keygen_chksum_chk(name,wf,cfg['seed_id'],pw=pw)
|
||||
|
||||
def walletconv_in(self,name,infile,desc,uopts=[],pw=False,oo=False):
|
||||
opts = ["-d",cfg['tmpdir'],"-o","words","-r10"]
|
||||
if_arg = [infile] if infile else []
|
||||
d = "(convert)"
|
||||
t = MMGenExpect(name,"mmgen-walletconv",opts+uopts+if_arg,extra_desc=d)
|
||||
t.license()
|
||||
if desc == "brainwallet":
|
||||
t.expect("Enter brainwallet: ",ref_wallet_brainpass+"\n")
|
||||
if pw:
|
||||
t.passphrase(desc,cfg['wpasswd'])
|
||||
if name[:19] == "ref_hincog_conv_old":
|
||||
t.expect("Is the seed ID correct? (Y/n): ","\n")
|
||||
else:
|
||||
t.expect(["Passphrase is OK"," are correct"])
|
||||
# Output
|
||||
wf = t.written_to_file("Mnemonic data",oo=oo)
|
||||
t.close()
|
||||
ok()
|
||||
# back check of result
|
||||
d = "(check)"
|
||||
self.keygen_chksum_chk(name,wf,cfg['seed_id'])
|
||||
|
||||
# Saved reference file tests
|
||||
def ref_wallet_conv(self,name):
|
||||
wf = os.path.join(ref_dir,cfg['ref_wallet'])
|
||||
self.walletconv_in(name,wf,"MMGen wallet",pw=True,oo=True)
|
||||
|
||||
def ref_mn_conv(self,name,ext="mmwords",desc="Mnemonic data"):
|
||||
wf = os.path.join(ref_dir,cfg['seed_id']+"."+ext)
|
||||
self.walletconv_in(name,wf,desc,oo=True)
|
||||
|
||||
def ref_seed_conv(self,name):
|
||||
self.ref_mn_conv(name,ext="mmseed",desc="Seed data")
|
||||
|
||||
def ref_brain_conv(self,name):
|
||||
uopts = ["-i","b","-p","1","-l",str(cfg['seed_len'])]
|
||||
self.walletconv_in(name,None,"brainwallet",uopts,oo=True)
|
||||
|
||||
def ref_incog_conv(self,name,wfk="ic_wallet",in_fmt="i",desc="incognito data"):
|
||||
uopts = ["-i",in_fmt,"-p","1","-l",str(cfg['seed_len'])]
|
||||
wf = os.path.join(ref_dir,cfg[wfk])
|
||||
self.walletconv_in(name,wf,desc,uopts,oo=True,pw=True)
|
||||
|
||||
def ref_incox_conv(self,name):
|
||||
self.ref_incog_conv(name,in_fmt="xi",wfk="ic_wallet_hex",desc="hex incognito data")
|
||||
|
||||
def ref_hincog_conv(self,name,wfk='hic_wallet',add_uopts=[]):
|
||||
ic_f = os.path.join(ref_dir,cfg[wfk])
|
||||
uopts = ["-i","hi","-p","1","-l",str(cfg['seed_len'])] + add_uopts
|
||||
hi_opt = ["-H","%s,%s" % (ic_f,ref_wallet_incog_offset)]
|
||||
self.walletconv_in(name,None,"hidden incognito data",uopts+hi_opt,oo=True,pw=True)
|
||||
|
||||
def ref_hincog_conv_old(self,name):
|
||||
self.ref_hincog_conv(name,wfk='hic_wallet_old',add_uopts=["-O"])
|
||||
|
||||
def ref_wallet_conv_out(self,name):
|
||||
self.walletconv_out(name,"MMGen wallet","w",pw=True)
|
||||
|
||||
def ref_mn_conv_out(self,name):
|
||||
self.walletconv_out(name,"mnemonic data","mn")
|
||||
|
||||
def ref_seed_conv_out(self,name):
|
||||
self.walletconv_out(name,"seed data","seed")
|
||||
|
||||
def ref_incog_conv_out(self,name):
|
||||
self.walletconv_out(name,"incognito data",out_fmt="i",pw=True)
|
||||
|
||||
def ref_incox_conv_out(self,name):
|
||||
self.walletconv_out(name,"hex incognito data",out_fmt="xi",pw=True)
|
||||
|
||||
def ref_hincog_conv_out(self,name,extra_uopts=[]):
|
||||
ic_f = os.path.join(cfg['tmpdir'],"rand.data")
|
||||
hi_parms = "%s,%s" % (ic_f,ref_wallet_incog_offset)
|
||||
hi_parms_legacy = "%s,%s,%s"%(ic_f,ref_wallet_incog_offset,cfg['seed_len'])
|
||||
self.walletconv_out(name,
|
||||
"hidden incognito data", "hi",
|
||||
uopts=["-J",hi_parms] + extra_uopts,
|
||||
uopts_chk=["-G",hi_parms_legacy],
|
||||
pw=True
|
||||
)
|
||||
|
||||
ref_wallet_conv1 = ref_wallet_conv2 = ref_wallet_conv3 = ref_wallet_conv
|
||||
ref_mn_conv1 = ref_mn_conv2 = ref_mn_conv3 = ref_mn_conv
|
||||
ref_seed_conv1 = ref_seed_conv2 = ref_seed_conv3 = ref_seed_conv
|
||||
ref_brain_conv1 = ref_brain_conv2 = ref_brain_conv3 = ref_brain_conv
|
||||
ref_incog_conv1 = ref_incog_conv2 = ref_incog_conv3 = ref_incog_conv
|
||||
ref_incox_conv1 = ref_incox_conv2 = ref_incox_conv3 = ref_incox_conv
|
||||
ref_hincog_conv1 = ref_hincog_conv2 = ref_hincog_conv3 = ref_hincog_conv
|
||||
ref_hincog_conv_old1 = ref_hincog_conv_old2 = ref_hincog_conv_old3 = ref_hincog_conv_old
|
||||
|
||||
ref_wallet_conv_out1 = ref_wallet_conv_out2 = ref_wallet_conv_out3 = ref_wallet_conv_out
|
||||
ref_mn_conv_out1 = ref_mn_conv_out2 = ref_mn_conv_out3 = ref_mn_conv_out
|
||||
ref_seed_conv_out1 = ref_seed_conv_out2 = ref_seed_conv_out3 = ref_seed_conv_out
|
||||
ref_incog_conv_out1 = ref_incog_conv_out2 = ref_incog_conv_out3 = ref_incog_conv_out
|
||||
ref_incox_conv_out1 = ref_incox_conv_out2 = ref_incox_conv_out3 = ref_incox_conv_out
|
||||
ref_hincog_conv_out1 = ref_hincog_conv_out2 = ref_hincog_conv_out3 = ref_hincog_conv_out
|
||||
|
||||
def ref_wallet_chk(self,name):
|
||||
wf = os.path.join(ref_dir,cfg['ref_wallet'])
|
||||
self.walletchk(name,wf)
|
||||
|
|
@ -1191,8 +1371,8 @@ class MMGenTestSuite(object):
|
|||
|
||||
def ref_seed_chk(self,name,ext=g.seed_ext):
|
||||
wf = os.path.join(ref_dir,"%s.%s" % (cfg['seed_id'],ext))
|
||||
what = "seed data" if ext == g.seed_ext else "mnemonic"
|
||||
self.keygen_chksum_chk(name,wf,cfg['seed_id'],what)
|
||||
desc = "seed data" if ext == g.seed_ext else "mnemonic"
|
||||
self.keygen_chksum_chk(name,wf,cfg['seed_id'])
|
||||
|
||||
ref_seed_chk1 = ref_seed_chk2 = ref_seed_chk3 = ref_seed_chk
|
||||
|
||||
|
|
@ -1203,37 +1383,60 @@ class MMGenTestSuite(object):
|
|||
def ref_brain_chk(self,name,bw_file=ref_bw_file):
|
||||
wf = os.path.join(ref_dir,bw_file)
|
||||
arg = "-b%s,%s" % (cfg['seed_len'],ref_bw_hash_preset)
|
||||
self.keygen_chksum_chk(name,wf,cfg['ref_bw_seed_id'],"brainwallet",[arg])
|
||||
self.keygen_chksum_chk(name,wf,cfg['ref_bw_seed_id'],[arg])
|
||||
|
||||
def keygen_chksum_chk(self,name,wf,seed_id,what,args=[]):
|
||||
t = MMGenExpect(name,"mmgen-keygen", ["-q","-A"]+args+[wf,"1"])
|
||||
chk = t.expect_getend("Valid %s for seed ID " % what)
|
||||
def keygen_chksum_chk_hincog(self,name,seed_id,hincog_parm):
|
||||
t = MMGenExpect(name,"mmgen-keygen", ["-p1","-q","-S","-A"]+hincog_parm+["1"],extra_desc="(check)")
|
||||
t.passphrase("",cfg['wpasswd'])
|
||||
t.expect("Encrypt key list? (y/N): ","\n")
|
||||
t.expect("any printable ASCII symbol.\r\n")
|
||||
chk = t.readline()[:8]
|
||||
vmsg("Seed ID: %s" % cyan(chk))
|
||||
cmp_or_die(seed_id,chk)
|
||||
|
||||
def keygen_chksum_chk(self,name,wf,seed_id,args=[],pw=False):
|
||||
hp_arg = ["-p1"] if pw else []
|
||||
t = MMGenExpect(name,"mmgen-keygen", ["-q","-S","-A"]+args+hp_arg+[wf,"1"],extra_desc="(check)")
|
||||
if pw:
|
||||
t.passphrase("",cfg['wpasswd'])
|
||||
t.expect("Encrypt key list? (y/N): ","\n")
|
||||
t.expect("any printable ASCII symbol.\r\n")
|
||||
chk = t.readline()[:8]
|
||||
vmsg("Seed ID: %s" % cyan(chk))
|
||||
cmp_or_die(seed_id,chk)
|
||||
|
||||
# Use this for encrypted wallets instead of keygen_chksum_chk()
|
||||
def walletchk_chksum_chk(self,name,wf,seed_id,uopts=[]):
|
||||
t = MMGenExpect(name,"mmgen-walletchk",["-v", wf]+uopts,
|
||||
extra_desc="(check)")
|
||||
t.passphrase("",cfg['wpasswd'])
|
||||
chk = t.expect_getend("Seed ID checksum OK (")[:8]
|
||||
t.close()
|
||||
cmp_or_die(seed_id,chk)
|
||||
|
||||
ref_brain_chk1 = ref_brain_chk2 = ref_brain_chk3 = ref_brain_chk
|
||||
|
||||
def ref_brain_chk3_spc(self,name):
|
||||
def ref_brain_chk_spc3(self,name):
|
||||
self.ref_brain_chk(name,bw_file=ref_bw_file_spc)
|
||||
|
||||
def ref_incog_chk(self,name):
|
||||
for wtype,desc,earg in ('ic_wallet','',[]), \
|
||||
('ic_wallet_old','(old format)',["-o"]):
|
||||
def ref_hincog_chk(self,name):
|
||||
for wtype,desc,earg in ('hic_wallet','',[]), \
|
||||
('hic_wallet_old','(old format)',["-o"]):
|
||||
ic_arg = "%s,%s,%s" % (
|
||||
os.path.join(ref_dir,cfg[wtype]),
|
||||
ref_wallet_incog_offset,cfg['seed_len']
|
||||
)
|
||||
t = MMGenExpect(name,"mmgen-keygen",
|
||||
["-q","-A"]+earg+["-G"]+[ic_arg]+['1'],extra_desc=desc)
|
||||
t.passphrase("MMGen incognito wallet",cfg['wpasswd'])
|
||||
t.passphrase("incognito wallet",cfg['wpasswd'])
|
||||
t.hash_preset("incog wallet","1")
|
||||
if wtype == 'ic_wallet_old':
|
||||
if wtype == 'hic_wallet_old':
|
||||
t.expect("Is the seed ID correct? (Y/n): ","\n")
|
||||
chk = t.expect_getend("Valid incog data for seed ID ")
|
||||
t.close()
|
||||
cmp_or_die(cfg['seed_id'],chk)
|
||||
|
||||
ref_incog_chk1 = ref_incog_chk2 = ref_incog_chk3 = ref_incog_chk
|
||||
ref_hincog_chk1 = ref_hincog_chk2 = ref_hincog_chk3 = ref_hincog_chk
|
||||
|
||||
def ref_addrfile_chk(self,name,ftype="addr"):
|
||||
wf = os.path.join(ref_dir,cfg['ref_'+ftype+'file'])
|
||||
|
|
@ -1261,11 +1464,11 @@ class MMGenTestSuite(object):
|
|||
f = os.path.join(ref_dir,ref_enc_fn)
|
||||
t = MMGenExpect(name,"mmgen-tool",
|
||||
["-q","decrypt",f,"outfile=-","hash_preset=1"])
|
||||
t.passphrase("user data",cfg['tool_enc_passwd'])
|
||||
t.passphrase("user data",tool_enc_passwd)
|
||||
t.readline()
|
||||
import re
|
||||
o = re.sub('\r\n','\n',t.read())
|
||||
cmp_or_die(cfg['sample_text'],o)
|
||||
cmp_or_die(sample_text,o)
|
||||
|
||||
# main()
|
||||
if opt.pause:
|
||||
|
|
@ -1288,8 +1491,11 @@ try:
|
|||
globals()[arg](cmd_args[cmd_args.index(arg)+1:])
|
||||
sys.exit()
|
||||
elif arg in meta_cmds:
|
||||
for cmd in meta_cmds[arg][1]:
|
||||
check_needs_rerun(ts,cmd,build=True,force_delete=True)
|
||||
for cmd in meta_cmds[arg]:
|
||||
check_needs_rerun(ts,cmd,build=True)
|
||||
elif arg in cmd_groups.keys():
|
||||
for cmd in cmd_groups[arg]:
|
||||
check_needs_rerun(ts,cmd,build=True)
|
||||
elif arg in cmd_data:
|
||||
check_needs_rerun(ts,arg,build=True)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ os.chdir(os.path.join(pn,os.pardir))
|
|||
sys.path.__setitem__(0,os.path.abspath(os.curdir))
|
||||
|
||||
import mmgen.opt as opt
|
||||
from mmgen.util import msg,msg_r,vmsg,vmsg_r,Msg,msgrepr, msgrepr_exit
|
||||
from mmgen.util import msg,msg_r,vmsg,vmsg_r,Msg,mmsg,mdie
|
||||
from collections import OrderedDict
|
||||
|
||||
cmd_data = OrderedDict([
|
||||
|
|
@ -94,8 +94,6 @@ cmd_args = opt.opts.init(opts_data,add_opts=["exact_output"])
|
|||
|
||||
if opt.system: sys.path.pop(0)
|
||||
|
||||
if opt.debug: opt.verbose = True
|
||||
|
||||
if opt.list_cmds:
|
||||
fs = " {:<{w}} - {}"
|
||||
Msg("Available commands:")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue