whitespace, comments throughout (excluding tests)
This commit is contained in:
parent
1cbd1a63b9
commit
2449baed2c
36 changed files with 280 additions and 125 deletions
|
|
@ -123,7 +123,8 @@ class AddrFile(MMGenObject):
|
|||
out.append(fs.format( '', f'{p.al_id.mmtype.wif_label}: {e.sec.wif}', c ))
|
||||
for k in ('viewkey','wallet_passwd'):
|
||||
v = getattr(e,k)
|
||||
if v: out.append(fs.format( '', f'{k}: {v}', c ))
|
||||
if v:
|
||||
out.append(fs.format( '', f'{k}: {v}', c ))
|
||||
|
||||
out.append('}')
|
||||
self.fmt_data = '\n'.join([l.rstrip() for l in out]) + '\n'
|
||||
|
|
@ -270,12 +271,10 @@ class AddrFile(MMGenObject):
|
|||
|
||||
if type(p).__name__ != 'PasswordList':
|
||||
if proto.base_coin != p.proto.base_coin or proto.network != p.proto.network:
|
||||
"""
|
||||
Having caller supply protocol and checking address file protocol against it here
|
||||
allows us to catch all mismatches in one place. This behavior differs from that of
|
||||
transaction files, which determine the protocol independently, requiring the caller
|
||||
to check for protocol mismatches (e.g. mmgen.tx.completed.check_correct_chain())
|
||||
"""
|
||||
# Having caller supply protocol and checking address file protocol against it here
|
||||
# allows us to catch all mismatches in one place. This behavior differs from that of
|
||||
# transaction files, which determine the protocol independently, requiring the caller
|
||||
# to check for protocol mismatches (e.g. mmgen.tx.completed.check_correct_chain())
|
||||
raise ValueError(
|
||||
f'{p.desc} file is '
|
||||
+ f'{proto.base_coin} {proto.network} but protocol is '
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ amt: MMGen CoinAmt and related classes
|
|||
from decimal import Decimal
|
||||
from .objmethods import Hilite,InitErrors
|
||||
|
||||
class DecimalNegateResult(Decimal): pass
|
||||
class DecimalNegateResult(Decimal):
|
||||
pass
|
||||
|
||||
class CoinAmt(Decimal,Hilite,InitErrors): # abstract class
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -431,8 +431,10 @@ class Autosign:
|
|||
return False
|
||||
|
||||
def wipe_existing_key(self):
|
||||
try: self.keyfile.stat()
|
||||
except: pass
|
||||
try:
|
||||
self.keyfile.stat()
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
from .fileutil import shred_file
|
||||
msg(f"\nShredding existing key '{self.keyfile}'")
|
||||
|
|
@ -462,14 +464,20 @@ class Autosign:
|
|||
def remove_wallet_dir():
|
||||
msg(f"Deleting '{self.wallet_dir}'")
|
||||
import shutil
|
||||
try: shutil.rmtree(self.wallet_dir)
|
||||
except: pass
|
||||
try:
|
||||
shutil.rmtree(self.wallet_dir)
|
||||
except:
|
||||
pass
|
||||
|
||||
def create_wallet_dir():
|
||||
try: self.wallet_dir.mkdir(parents=True)
|
||||
except: pass
|
||||
try: self.wallet_dir.stat()
|
||||
except: die(2,f"Unable to create wallet directory '{self.wallet_dir}'")
|
||||
try:
|
||||
self.wallet_dir.mkdir(parents=True)
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
self.wallet_dir.stat()
|
||||
except:
|
||||
die(2,f"Unable to create wallet directory '{self.wallet_dir}'")
|
||||
|
||||
remove_wallet_dir()
|
||||
create_wallet_dir()
|
||||
|
|
@ -520,8 +528,10 @@ class Autosign:
|
|||
async_run(m.stop_wallet_daemon())
|
||||
|
||||
import shutil
|
||||
try: shutil.rmtree(self.xmr_outputs_dir)
|
||||
except: pass
|
||||
try:
|
||||
shutil.rmtree(self.xmr_outputs_dir)
|
||||
except:
|
||||
pass
|
||||
|
||||
self.xmr_outputs_dir.mkdir(parents=True)
|
||||
|
||||
|
|
@ -574,9 +584,12 @@ class Autosign:
|
|||
def get_insert_status(self):
|
||||
if self.cfg.no_insert_check:
|
||||
return True
|
||||
try: self.dev_disk_path.stat()
|
||||
except: return False
|
||||
else: return True
|
||||
try:
|
||||
self.dev_disk_path.stat()
|
||||
except:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
async def do_loop(self):
|
||||
if not self.cfg.stealth_led:
|
||||
|
|
|
|||
|
|
@ -767,7 +767,8 @@ def check_opts(cfg): # Raises exception if any check fails
|
|||
check_infile(fn,blkdev_ok=True)
|
||||
key2 = 'in_fmt'
|
||||
else:
|
||||
try: os.stat(fn)
|
||||
try:
|
||||
os.stat(fn)
|
||||
except:
|
||||
b = os.path.dirname(fn)
|
||||
if b:
|
||||
|
|
|
|||
|
|
@ -25,9 +25,11 @@
|
|||
q = 2**255 - 19
|
||||
|
||||
def expmod(b,e,m):
|
||||
if e == 0: return 1
|
||||
if e == 0:
|
||||
return 1
|
||||
t = expmod(b,e//2,m)**2 % m
|
||||
if e & 1: t = (t*b) % m
|
||||
if e & 1:
|
||||
t = (t*b) % m
|
||||
return t
|
||||
|
||||
# Can probably get some extra speedup here by replacing this with
|
||||
|
|
@ -81,7 +83,8 @@ def pt_unxform (pt):
|
|||
return ((x*inv(z))%q, (y*inv(z))%q)
|
||||
|
||||
def xpt_mult (pt, n):
|
||||
if n==0: return pt_xform((0,1))
|
||||
if n==0:
|
||||
return pt_xform((0,1))
|
||||
_ = xpt_double(xpt_mult(pt, n>>1))
|
||||
return xpt_add(_, pt) if n&1 else _
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,8 @@ class KeccakState(object):
|
|||
Formats the given state as hex, in natural byte order.
|
||||
"""
|
||||
rows = []
|
||||
def fmt(x): return '%016x' % x
|
||||
def fmt(x):
|
||||
return '%016x' % x
|
||||
for y in KeccakState.rangeH:
|
||||
row = []
|
||||
for x in rangeW:
|
||||
|
|
|
|||
|
|
@ -126,7 +126,15 @@ class Crypto:
|
|||
self.util.dmsg(f'Decrypted seed: {dec_seed.hex()}')
|
||||
return dec_seed
|
||||
|
||||
def encrypt_data(self,data,key,iv=aesctr_dfl_iv,desc='data',verify=True,silent=False):
|
||||
def encrypt_data(
|
||||
self,
|
||||
data,
|
||||
key,
|
||||
iv = aesctr_dfl_iv,
|
||||
desc = 'data',
|
||||
verify = True,
|
||||
silent = False ):
|
||||
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher,algorithms,modes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
if not silent:
|
||||
|
|
@ -147,7 +155,13 @@ class Crypto:
|
|||
|
||||
return enc_data
|
||||
|
||||
def decrypt_data(self,enc_data,key,iv=aesctr_dfl_iv,desc='data'):
|
||||
def decrypt_data(
|
||||
self,
|
||||
enc_data,
|
||||
key,
|
||||
iv = aesctr_dfl_iv,
|
||||
desc = 'data' ):
|
||||
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher,algorithms,modes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
self.util.vmsg_r(f'Decrypting {desc} with key...')
|
||||
|
|
@ -155,7 +169,12 @@ class Crypto:
|
|||
encryptor = c.encryptor()
|
||||
return encryptor.update(enc_data) + encryptor.finalize()
|
||||
|
||||
def scrypt_hash_passphrase(self,passwd,salt,hash_preset,buflen=32):
|
||||
def scrypt_hash_passphrase(
|
||||
self,
|
||||
passwd,
|
||||
salt,
|
||||
hash_preset,
|
||||
buflen = 32 ):
|
||||
|
||||
# Buflen arg is for brainwallets only, which use this function to generate
|
||||
# the seed directly.
|
||||
|
|
@ -198,11 +217,20 @@ class Crypto:
|
|||
|
||||
return ret
|
||||
|
||||
def make_key(self,passwd,salt,hash_preset,desc='encryption key',from_what='passphrase',verbose=False):
|
||||
def make_key(
|
||||
self,
|
||||
passwd,
|
||||
salt,
|
||||
hash_preset,
|
||||
desc = 'encryption key',
|
||||
from_what = 'passphrase',
|
||||
verbose = False ):
|
||||
|
||||
if self.cfg.verbose or verbose:
|
||||
msg_r(f"Generating {desc}{' from ' + from_what if from_what else ''}...")
|
||||
key = self.scrypt_hash_passphrase(passwd,salt,hash_preset)
|
||||
if self.cfg.verbose or verbose: msg('done')
|
||||
if self.cfg.verbose or verbose:
|
||||
msg('done')
|
||||
self.util.dmsg(f'Key: {key.hex()}')
|
||||
return key
|
||||
|
||||
|
|
|
|||
|
|
@ -120,10 +120,8 @@ class Daemon(Lockable):
|
|||
with open(self.pidfile) as fp:
|
||||
return fp.read().strip()
|
||||
elif self.platform == 'win':
|
||||
"""
|
||||
Assumes only one running instance of given daemon. If multiple daemons are running,
|
||||
the first PID in the list is returned and self.pids is set to the PID list.
|
||||
"""
|
||||
# Assumes only one running instance of given daemon. If multiple daemons are running,
|
||||
# the first PID in the list is returned and self.pids is set to the PID list.
|
||||
ss = f'{self.exec_fn}.exe'
|
||||
cp = self.run_cmd(['ps','-Wl'],silent=True)
|
||||
self.pids = ()
|
||||
|
|
|
|||
|
|
@ -185,8 +185,10 @@ def write_data_to_file(
|
|||
message = '',
|
||||
action = f'output {desc} to screen' )
|
||||
else:
|
||||
try: of = os.readlink(f'/proc/{os.getpid()}/fd/1') # Linux
|
||||
except: of = None # Windows
|
||||
try:
|
||||
of = os.readlink(f'/proc/{os.getpid()}/fd/1') # Linux
|
||||
except:
|
||||
of = None # Windows
|
||||
|
||||
if of:
|
||||
if of[:5] == 'pipe:':
|
||||
|
|
|
|||
12
mmgen/led.py
12
mmgen/led.py
|
|
@ -66,9 +66,12 @@ class LEDControl:
|
|||
for board_id,board in self.boards.items():
|
||||
if board_id == 'dummy' and not simulate:
|
||||
continue
|
||||
try: os.stat(board.status)
|
||||
except: pass
|
||||
else: break
|
||||
try:
|
||||
os.stat(board.status)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
break
|
||||
else:
|
||||
from .util import die
|
||||
die( 'NoLEDSupport', 'Control files not found! LED control not supported on this system' )
|
||||
|
|
@ -119,7 +122,8 @@ class LEDControl:
|
|||
os.unlink(db.status)
|
||||
os.unlink(db.trigger)
|
||||
|
||||
def noop(self,*args,**kwargs): pass
|
||||
def noop(self,*args,**kwargs):
|
||||
pass
|
||||
|
||||
def ev_sleep(self,secs):
|
||||
self.ev.wait(secs)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ opts_data = {
|
|||
'sets': [('yes', True, 'quiet', True)],
|
||||
'text': {
|
||||
'desc': f'Create, sign and send an {gc.proj_name} transaction',
|
||||
'usage': '[opts] [<addr,amt> ...] <change addr, addrlist ID or addr type> [addr file ...] ' +
|
||||
'usage': '[opts] [<addr,amt> ...] <change addr, addrlist ID or addr type> [addr file ...] ' +
|
||||
'[seed source ...]',
|
||||
'options': """
|
||||
-h, --help Print this help message
|
||||
|
|
|
|||
25
mmgen/obj.py
25
mmgen/obj.py
|
|
@ -74,10 +74,17 @@ class IndexedDict(dict):
|
|||
def key(self,idx):
|
||||
return self.__keylist[idx]
|
||||
|
||||
def __delitem__(self,*args): self.die('item deletion')
|
||||
def move_to_end(self,*args): self.die('item moving')
|
||||
def clear(self,*args): self.die('clearing')
|
||||
def update(self,*args): self.die('updating')
|
||||
def __delitem__(self,*args):
|
||||
self.die('item deletion')
|
||||
|
||||
def move_to_end(self,*args):
|
||||
self.die('item moving')
|
||||
|
||||
def clear(self,*args):
|
||||
self.die('clearing')
|
||||
|
||||
def update(self,*args):
|
||||
self.die('updating')
|
||||
|
||||
def die(self,desc):
|
||||
raise NotImplementedError(f'{desc} not implemented for type {type(self).__name__}')
|
||||
|
|
@ -106,10 +113,10 @@ class ImmutableAttr: # Descriptor
|
|||
assert typeconv and type(dtype) != str, 'ImmutableAttr_check3'
|
||||
|
||||
if dtype is None:
|
||||
'use instance-defined conversion function for this attribute'
|
||||
# use instance-defined conversion function for this attribute
|
||||
self.conv = lambda instance,value: getattr(instance.conv_funcs,self.name)(instance,value)
|
||||
elif typeconv:
|
||||
"convert this attribute's type"
|
||||
# convert this attribute's type
|
||||
if set_none_ok:
|
||||
self.conv = lambda instance,value: None if value is None else dtype(value)
|
||||
elif include_proto:
|
||||
|
|
@ -158,8 +165,10 @@ class ListItemAttr(ImmutableAttr):
|
|||
|
||||
def __get__(self,instance,owner):
|
||||
"return None if attribute doesn't exist"
|
||||
try: return instance.__dict__[self.name]
|
||||
except: return None
|
||||
try:
|
||||
return instance.__dict__[self.name]
|
||||
except:
|
||||
return None
|
||||
|
||||
def setattr_condition(self,instance):
|
||||
return getattr(instance,self.name) == None or self.reassign_ok
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ if 'MMGenObjectDevTools' in __builtins__: # added to builtins by devinit.init_de
|
|||
else:
|
||||
class MMGenObject:
|
||||
'placeholder - overridden when testing'
|
||||
def immutable_attr_init_check(self): pass
|
||||
def immutable_attr_init_check(self):
|
||||
pass
|
||||
|
||||
def truncate_str(s,width): # width = screen width
|
||||
wide_count = 0
|
||||
|
|
|
|||
|
|
@ -52,8 +52,10 @@ class PasswordList(AddrList):
|
|||
dfl_pw_fmt = 'b58'
|
||||
pwinfo = namedtuple('passwd_info',['min_len','max_len','dfl_len','valid_lens','desc','chk_func'])
|
||||
pw_info = {
|
||||
'b32': pwinfo(10, 42 ,24, None, 'base32 password', 'baseconv.is_b32_str'), # 32**24 < 2**128
|
||||
'b58': pwinfo(8, 36 ,20, None, 'base58 password', 'baseconv.is_b58_str'), # 58**20 < 2**128
|
||||
# 32**25 < 2**128 < 32**26
|
||||
'b32': pwinfo(10, 42 ,24, None, 'base32 password', 'baseconv.is_b32_str'),
|
||||
# 58**21 < 2**128 < 58**22
|
||||
'b58': pwinfo(8, 36 ,20, None, 'base58 password', 'baseconv.is_b58_str'),
|
||||
'bip39': pwinfo(12, 24 ,24, [12,18,24],'BIP39 mnemonic', 'bip39.is_bip39_mnemonic'),
|
||||
'xmrseed': pwinfo(25, 25, 25, [25], 'Monero new-style mnemonic','xmrseed.is_xmrseed'),
|
||||
'hex': pwinfo(32, 64 ,64, [32,48,64],'hexadecimal password', 'util.is_hex_str'),
|
||||
|
|
|
|||
|
|
@ -26,8 +26,11 @@ class mainnet(mainnet):
|
|||
max_tx_fee = '0.1'
|
||||
ignore_daemon_version = False
|
||||
|
||||
def pubhash2redeem_script(self,pubkey): raise NotImplementedError
|
||||
def pubhash2segwitaddr(self,pubkey): raise NotImplementedError
|
||||
def pubhash2redeem_script(self,pubhash):
|
||||
raise NotImplementedError
|
||||
|
||||
def pubhash2segwitaddr(self,pubhash):
|
||||
raise NotImplementedError
|
||||
|
||||
class testnet(mainnet):
|
||||
addr_ver_info = { '6f': 'p2pkh', 'c4': 'p2sh' }
|
||||
|
|
|
|||
|
|
@ -55,9 +55,7 @@ class bitcoin_core_daemon(CoinDaemon):
|
|||
def init_subclass(self):
|
||||
|
||||
if self.network == 'regtest':
|
||||
"""
|
||||
fall back on hard-coded credentials
|
||||
"""
|
||||
# fall back on hard-coded credentials:
|
||||
from .regtest import MMGenRegtest
|
||||
self.rpc_user = MMGenRegtest.rpc_user
|
||||
self.rpc_password = MMGenRegtest.rpc_password
|
||||
|
|
|
|||
|
|
@ -30,4 +30,5 @@ class coin_msg(coin_msg):
|
|||
async def do_verify(self,addr,sig,message,msghash_type):
|
||||
return await self.rpc.call( 'verifymessage', addr, sig, message )
|
||||
|
||||
class exported_sigs(coin_msg.exported_sigs,signed_online): pass
|
||||
class exported_sigs(coin_msg.exported_sigs,signed_online):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -27,8 +27,10 @@ from ...rpc import rpc_init,json_encoder
|
|||
from ...objmethods import MMGenObject
|
||||
|
||||
def create_data_dir(cfg,data_dir):
|
||||
try: os.stat(os.path.join(data_dir,'regtest'))
|
||||
except: pass
|
||||
try:
|
||||
os.stat(os.path.join(data_dir,'regtest'))
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
from ...ui import keypress_confirm
|
||||
if keypress_confirm(
|
||||
|
|
@ -38,8 +40,10 @@ def create_data_dir(cfg,data_dir):
|
|||
else:
|
||||
die()
|
||||
|
||||
try: os.makedirs(data_dir)
|
||||
except: pass
|
||||
try:
|
||||
os.makedirs(data_dir)
|
||||
except:
|
||||
pass
|
||||
|
||||
def cliargs_convert(args):
|
||||
def gen():
|
||||
|
|
@ -108,8 +112,10 @@ class MMGenRegtest(MMGenObject):
|
|||
|
||||
async def setup(self):
|
||||
|
||||
try: os.makedirs(self.d.datadir)
|
||||
except: pass
|
||||
try:
|
||||
os.makedirs(self.d.datadir)
|
||||
except:
|
||||
pass
|
||||
|
||||
if self.d.state != 'stopped':
|
||||
await self.rpc_call('stop')
|
||||
|
|
@ -243,8 +249,10 @@ class MMGenRegtest(MMGenObject):
|
|||
if self.d.state != 'stopped':
|
||||
await self.rpc_call('stop')
|
||||
|
||||
try: os.makedirs(self.d.datadir)
|
||||
except: pass
|
||||
try:
|
||||
os.makedirs(self.d.datadir)
|
||||
except:
|
||||
pass
|
||||
|
||||
create_data_dir( self.cfg, self.d.datadir )
|
||||
os.rmdir(self.d.datadir)
|
||||
|
|
|
|||
|
|
@ -91,21 +91,39 @@ class TokenCommon(MMGenObject):
|
|||
async def code(self):
|
||||
return (await self.rpc.call('eth_getCode','0x'+self.addr))[2:]
|
||||
|
||||
def create_data(self,to_addr,amt,method_sig='transfer(address,uint256)',from_addr=None):
|
||||
def create_data(
|
||||
self,
|
||||
to_addr,
|
||||
amt,
|
||||
method_sig = 'transfer(address,uint256)',
|
||||
from_addr = None):
|
||||
from_arg = from_addr.rjust(64,'0') if from_addr else ''
|
||||
to_arg = to_addr.rjust(64,'0')
|
||||
amt_arg = '{:064x}'.format( int(amt / self.base_unit) )
|
||||
return self.create_method_id(method_sig) + from_arg + to_arg + amt_arg
|
||||
|
||||
def make_tx_in( self,from_addr,to_addr,amt,start_gas,gasPrice,nonce,
|
||||
method_sig='transfer(address,uint256)',from_addr2=None):
|
||||
data = self.create_data(to_addr,amt,method_sig=method_sig,from_addr=from_addr2)
|
||||
return {'to': bytes.fromhex(self.addr),
|
||||
'startgas': start_gas.toWei(),
|
||||
'gasprice': gasPrice.toWei(),
|
||||
'value': 0,
|
||||
'nonce': nonce,
|
||||
'data': bytes.fromhex(data) }
|
||||
def make_tx_in(
|
||||
self,
|
||||
from_addr,
|
||||
to_addr,
|
||||
amt,
|
||||
start_gas,
|
||||
gasPrice,
|
||||
nonce,
|
||||
method_sig = 'transfer(address,uint256)',
|
||||
from_addr2 = None):
|
||||
data = self.create_data(
|
||||
to_addr,
|
||||
amt,
|
||||
method_sig = method_sig,
|
||||
from_addr = from_addr2)
|
||||
return {
|
||||
'to': bytes.fromhex(self.addr),
|
||||
'startgas': start_gas.toWei(),
|
||||
'gasprice': gasPrice.toWei(),
|
||||
'value': 0,
|
||||
'nonce': nonce,
|
||||
'data': bytes.fromhex(data)}
|
||||
|
||||
async def txsign(self,tx_in,key,from_addr,chain_id=None):
|
||||
|
||||
|
|
@ -136,17 +154,27 @@ class TokenCommon(MMGenObject):
|
|||
async def txsend(self,txhex):
|
||||
return (await self.rpc.call('eth_sendRawTransaction','0x'+txhex)).replace('0x','',1)
|
||||
|
||||
async def transfer( self,from_addr,to_addr,amt,key,start_gas,gasPrice,
|
||||
method_sig='transfer(address,uint256)',
|
||||
from_addr2=None,
|
||||
return_data=False):
|
||||
async def transfer(
|
||||
self,
|
||||
from_addr,
|
||||
to_addr,
|
||||
amt,
|
||||
key,
|
||||
start_gas,
|
||||
gasPrice,
|
||||
method_sig = 'transfer(address,uint256)',
|
||||
from_addr2=None,
|
||||
return_data=False):
|
||||
tx_in = self.make_tx_in(
|
||||
from_addr,to_addr,amt,
|
||||
start_gas,gasPrice,
|
||||
nonce = int(await self.rpc.call('eth_getTransactionCount','0x'+from_addr,'pending'),16),
|
||||
method_sig = method_sig,
|
||||
from_addr2 = from_addr2 )
|
||||
(txhex,coin_txid) = await self.txsign(tx_in,key,from_addr)
|
||||
from_addr,
|
||||
to_addr,
|
||||
amt,
|
||||
start_gas,
|
||||
gasPrice,
|
||||
nonce = int(await self.rpc.call('eth_getTransactionCount','0x'+from_addr,'pending'),16),
|
||||
method_sig = method_sig,
|
||||
from_addr2 = from_addr2 )
|
||||
txhex,_ = await self.txsign(tx_in,key,from_addr)
|
||||
return await self.txsend(txhex)
|
||||
|
||||
class Token(TokenCommon):
|
||||
|
|
|
|||
|
|
@ -36,4 +36,5 @@ class coin_msg(coin_msg):
|
|||
proto = self.proto).pubhex2addr(
|
||||
ec_recover_pubkey( self.cfg, message, sig, msghash_type )) == addr
|
||||
|
||||
class exported_sigs(coin_msg.exported_sigs,signed_online): pass
|
||||
class exported_sigs(coin_msg.exported_sigs,signed_online):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class EthereumRPCClient(RPCClient,metaclass=AsyncInit):
|
|||
proto,
|
||||
daemon,
|
||||
backend,
|
||||
ignore_wallet ):
|
||||
ignore_wallet):
|
||||
|
||||
self.proto = proto
|
||||
self.daemon = daemon
|
||||
|
|
|
|||
|
|
@ -97,7 +97,8 @@ Actions: [q]uit menu, [D]elete addr, add [l]abel, [R]efresh balance:
|
|||
)
|
||||
|
||||
def do_sort(self,key=None,reverse=False):
|
||||
if key == 'txid': return
|
||||
if key == 'txid':
|
||||
return
|
||||
super().do_sort(key=key,reverse=reverse)
|
||||
|
||||
async def get_rpc_data(self):
|
||||
|
|
|
|||
|
|
@ -41,10 +41,10 @@ class OnlineSigned(Signed,TxBase.OnlineSigned):
|
|||
try:
|
||||
ret = await self.rpc.call('eth_sendRawTransaction','0x'+self.serialized)
|
||||
except:
|
||||
raise
|
||||
ret = False
|
||||
raise # TODO: raises immediately
|
||||
ret = False # TODO: unreachable code
|
||||
|
||||
if ret == False:
|
||||
if ret is False: # TODO: unreachable code
|
||||
rmsg(f'Send of MMGen transaction {self.txid} failed')
|
||||
if exit_on_fail:
|
||||
sys.exit(1)
|
||||
|
|
|
|||
|
|
@ -85,4 +85,5 @@ class mainnet(CoinProtocol.DummyWIF,CoinProtocol.Base):
|
|||
return MoneroViewKey.__new__(MoneroViewKey,viewkey_str)
|
||||
|
||||
class testnet(mainnet): # use stagenet for testnet
|
||||
addr_ver_info = { '18': 'monero', '24': 'monero_sub', '19': 'monero_integrated' } # testnet is {'35','3f','36'}
|
||||
# testnet is {'35','3f','36'}
|
||||
addr_ver_info = { '18': 'monero', '24': 'monero_sub', '19': 'monero_integrated' }
|
||||
|
|
|
|||
20
mmgen/rpc.py
20
mmgen/rpc.py
|
|
@ -219,10 +219,8 @@ class RPCBackends:
|
|||
for s in ('--header',f'{k}: {v}'):
|
||||
yield s
|
||||
if caller.auth_type:
|
||||
"""
|
||||
Authentication with curl is insecure, as it exposes the user's credentials
|
||||
via the command line. Use for testing only.
|
||||
"""
|
||||
# Authentication with curl is insecure, as it exposes the user's credentials
|
||||
# via the command line. Use for testing only.
|
||||
for s in ('--user',f'{caller.auth.user}:{caller.auth.passwd}'):
|
||||
yield s
|
||||
if caller.auth_type == 'digest':
|
||||
|
|
@ -237,7 +235,7 @@ class RPCBackends:
|
|||
async def run(self,payload,timeout,host_path):
|
||||
data = json.dumps(payload,cls=json_encoder)
|
||||
if len(data) > self.arg_max:
|
||||
return self.httplib(payload,timeout=timeout)
|
||||
return self.httplib(payload,timeout=timeout) # TODO: check
|
||||
dmsg_rpc_backend(self.host_url,host_path,payload)
|
||||
exec_cmd = [
|
||||
'curl',
|
||||
|
|
@ -397,8 +395,10 @@ class RPCClient(MMGenObject):
|
|||
try:
|
||||
m = t['error']['message']
|
||||
except:
|
||||
try: m = t['error']
|
||||
except: m = t
|
||||
try:
|
||||
m = t['error']
|
||||
except:
|
||||
m = t
|
||||
die( 'RPCFailure', m )
|
||||
else:
|
||||
import http
|
||||
|
|
@ -407,8 +407,10 @@ class RPCClient(MMGenObject):
|
|||
try:
|
||||
m = json.loads(text)['error']['message']
|
||||
except:
|
||||
try: m = text.decode()
|
||||
except: m = text
|
||||
try:
|
||||
m = text.decode()
|
||||
except:
|
||||
m = text
|
||||
die( 'RPCFailure', f'{s.value} {s.name}: {m}' )
|
||||
|
||||
async def stop_daemon(self,quiet=False,silent=False):
|
||||
|
|
|
|||
|
|
@ -96,7 +96,8 @@ class Sha2(object):
|
|||
"""
|
||||
mlpack = self.pack_msglen()
|
||||
padlen = self.blkSize - (len(self.M) % self.blkSize) - len(mlpack) - 1
|
||||
if padlen < 0: padlen += self.blkSize
|
||||
if padlen < 0:
|
||||
padlen += self.blkSize
|
||||
self.M = self.M + bytes([0x80] + [0] * padlen) + mlpack
|
||||
|
||||
def bytesToWords(self):
|
||||
|
|
@ -117,8 +118,11 @@ class Sha2(object):
|
|||
def processBlock(self,offset):
|
||||
'Process a blkSize-byte chunk of the message'
|
||||
|
||||
def rrotate(a,b): return ((a << self.wordBits-b) & self.wordMask) | (a >> b)
|
||||
def addm(a,b): return (a + b) & self.wordMask
|
||||
def rrotate(a,b):
|
||||
return ((a << self.wordBits-b) & self.wordMask) | (a >> b)
|
||||
|
||||
def addm(a,b):
|
||||
return (a + b) & self.wordMask
|
||||
|
||||
# Copy chunk into first 16 words of message schedule array
|
||||
for i in range(16):
|
||||
|
|
|
|||
|
|
@ -77,7 +77,8 @@ class SubSeed(SeedBase):
|
|||
# field maximums: idx: 4294967295 (1000000), nonce: 65535 (1000), short: 255 (1)
|
||||
scramble_key = idx.to_bytes(4,'big') + nonce.to_bytes(2,'big') + short.to_bytes(1,'big')
|
||||
from .crypto import Crypto
|
||||
return Crypto(parent_list.parent_seed.cfg).scramble_seed(seed.data,scramble_key)[:16 if short else seed.byte_len]
|
||||
return Crypto(parent_list.parent_seed.cfg).scramble_seed(
|
||||
seed.data,scramble_key)[:16 if short else seed.byte_len]
|
||||
|
||||
class SubSeedList(MMGenObject):
|
||||
have_short = True
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class tool_cmd(tool_cmd_base):
|
|||
|
||||
async def txview(
|
||||
self,
|
||||
varargs_call_sig = { # hack to allow for multiple filenames
|
||||
varargs_call_sig = { # hack to allow for multiple filenames - must be second argument!
|
||||
'args': (
|
||||
'mmgen_tx_file(s)',
|
||||
'pager',
|
||||
|
|
|
|||
|
|
@ -55,7 +55,13 @@ class TwCtl(MMGenObject,metaclass=AsyncInit):
|
|||
def __new__(cls,cfg,proto,*args,**kwargs):
|
||||
return MMGenObject.__new__(proto.base_proto_subclass(cls,'tw.ctl'))
|
||||
|
||||
async def __init__(self,cfg,proto,mode='r',token_addr=None,rpc_ignore_wallet=False):
|
||||
async def __init__(
|
||||
self,
|
||||
cfg,
|
||||
proto,
|
||||
mode = 'r',
|
||||
token_addr = None,
|
||||
rpc_ignore_wallet = False):
|
||||
|
||||
assert mode in ('r','w','i'), f"{mode!r}: wallet mode must be 'r','w' or 'i'"
|
||||
if mode == 'i':
|
||||
|
|
@ -102,7 +108,8 @@ class TwCtl(MMGenObject,metaclass=AsyncInit):
|
|||
self.orig_data = get_data_from_file( self.cfg, self.tw_fn, quiet=True )
|
||||
self.data = json.loads(self.orig_data)
|
||||
except:
|
||||
try: os.stat(self.tw_fn)
|
||||
try:
|
||||
os.stat(self.tw_fn)
|
||||
except:
|
||||
self.orig_data = ''
|
||||
self.init_empty()
|
||||
|
|
|
|||
|
|
@ -375,7 +375,13 @@ class TwView(MMGenObject,metaclass=AsyncInit):
|
|||
min(7,max(len(str(getattr(d,k).to_integral_value())) for d in data)) + 1 + self.disp_prec
|
||||
for k in self.amt_keys}
|
||||
|
||||
async def format(self,display_type,color=True,interactive=False,line_processing=None,scroll=False):
|
||||
async def format(
|
||||
self,
|
||||
display_type,
|
||||
color = True,
|
||||
interactive = False,
|
||||
line_processing = None,
|
||||
scroll = False):
|
||||
|
||||
def make_display():
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ def get_seed_for_seed_id(sid,infiles,saved_seeds):
|
|||
elif subseeds_checked == False:
|
||||
seed = saved_seeds[list(saved_seeds)[0]].subseed_by_seed_id(sid,print_msg=True)
|
||||
subseeds_checked = True
|
||||
if not seed: continue
|
||||
if not seed:
|
||||
continue
|
||||
elif cfg.in_fmt:
|
||||
cfg._util.qmsg(f'Need seed data for Seed ID {sid}')
|
||||
seed = Wallet(cfg).seed
|
||||
|
|
|
|||
|
|
@ -62,7 +62,15 @@ class Util:
|
|||
else:
|
||||
self.stdout_or_pager = Msg_r
|
||||
|
||||
def compare_chksums(self,chk1,desc1,chk2,desc2,hdr='',die_on_fail=False,verbose=False):
|
||||
def compare_chksums(
|
||||
self,
|
||||
chk1,
|
||||
desc1,
|
||||
chk2,
|
||||
desc2,
|
||||
hdr = '',
|
||||
die_on_fail = False,
|
||||
verbose = False):
|
||||
|
||||
if not chk1 == chk2:
|
||||
fs = "{} ERROR: {} checksum ({}) doesn't match {} checksum ({})"
|
||||
|
|
@ -356,9 +364,12 @@ def is_hex_str_lc(s):
|
|||
return set(s) <= set(hexdigits_lc)
|
||||
|
||||
def is_utf8(s):
|
||||
try: s.decode('utf8')
|
||||
except: return False
|
||||
else: return True
|
||||
try:
|
||||
s.decode('utf8')
|
||||
except:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def remove_whitespace(s,ws='\t\r\n '):
|
||||
return s.translate(dict((ord(e),None) for e in ws))
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ class wallet(wallet):
|
|||
else: # Prompt, using old value as default
|
||||
hp = self._get_hash_preset_from_user( old_preset=old_hp, add_desc=add_desc )
|
||||
if (not self.cfg.keep_hash_preset) and self.op == 'pwchg_new':
|
||||
self.cfg._util.qmsg('Hash preset {}'.format( 'unchanged' if hp == old_hp else f'changed to {hp!r}' ))
|
||||
self.cfg._util.qmsg('Hash preset {}'.format(
|
||||
'unchanged' if hp == old_hp else f'changed to {hp!r}'))
|
||||
elif self.cfg.hash_preset:
|
||||
hp = self.cfg.hash_preset
|
||||
self.cfg._util.qmsg(f'Using hash preset {hp!r} requested on command line')
|
||||
|
|
|
|||
|
|
@ -66,11 +66,11 @@ xmrwallet_uargs = namedtuple('xmrwallet_uargs',[
|
|||
xmrwallet_uarg_info = (
|
||||
lambda e,hp: {
|
||||
'daemon': e('HOST:PORT', hp),
|
||||
'tx_relay_daemon': e('HOST:PORT[:PROXY_HOST:PROXY_PORT]', rf'({hp})(?::({hp}))?'),
|
||||
'newaddr_spec': e('WALLET_NUM[:ACCOUNT][,"label text"]', rf'(\d+)(?::(\d+))?(?:,(.*))?'),
|
||||
'transfer_spec': e('SOURCE_WALLET_NUM:ACCOUNT:ADDRESS,AMOUNT', rf'(\d+):(\d+):([{b58a}]+),([0-9.]+)'),
|
||||
'tx_relay_daemon': e('HOST:PORT[:PROXY_HOST:PROXY_PORT]', rf'({hp})(?::({hp}))?'),
|
||||
'newaddr_spec': e('WALLET_NUM[:ACCOUNT][,"label text"]', r'(\d+)(?::(\d+))?(?:,(.*))?'),
|
||||
'transfer_spec': e('SOURCE_WALLET_NUM:ACCOUNT:ADDRESS,AMOUNT', rf'(\d+):(\d+):([{b58a}]+),([0-9.]+)'),
|
||||
'sweep_spec': e('SOURCE_WALLET_NUM:ACCOUNT[,DEST_WALLET_NUM]', r'(\d+):(\d+)(?:,(\d+))?'),
|
||||
'label_spec': e('WALLET_NUM:ACCOUNT:ADDRESS,"label text"', rf'(\d+):(\d+):(\d+),(.*)'),
|
||||
'label_spec': e('WALLET_NUM:ACCOUNT:ADDRESS,"label text"', r'(\d+):(\d+):(\d+),(.*)'),
|
||||
})(
|
||||
namedtuple('uarg_info_entry',['annot','pat']),
|
||||
r'(?:[^:]+):(?:\d+)'
|
||||
|
|
@ -744,9 +744,12 @@ class MoneroWalletOps:
|
|||
def __init__(self,cfg,uarg_tuple):
|
||||
|
||||
def wallet_exists(fn):
|
||||
try: fn.stat()
|
||||
except: return False
|
||||
else: return True
|
||||
try:
|
||||
fn.stat()
|
||||
except:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def check_wallets():
|
||||
for d in self.addr_data:
|
||||
|
|
@ -907,7 +910,7 @@ class MoneroWalletOps:
|
|||
processed += await self.process_wallet(
|
||||
d,
|
||||
fn,
|
||||
last = n == len(self.addr_data)-1 )
|
||||
last = n==len(self.addr_data)-1 )
|
||||
gmsg(f'\n{processed} wallet{suf(processed)} {self.stem}ed')
|
||||
return processed
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,11 @@
|
|||
# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
|
||||
# Copyright (C)2013-2023 The MMGen Project <mmgen@tuta.io>
|
||||
# Licensed under the GNU General Public License, Version 3:
|
||||
# https://www.gnu.org/licenses
|
||||
# Public project repositories:
|
||||
# https://github.com/mmgen/mmgen
|
||||
# https://gitlab.com/mmgen/mmgen
|
||||
|
||||
[metadata]
|
||||
name = MMGen
|
||||
version = file: mmgen/data/version
|
||||
|
|
|
|||
8
setup.py
8
setup.py
|
|
@ -1,4 +1,12 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
|
||||
# Copyright (C)2013-2023 The MMGen Project <mmgen@tuta.io>
|
||||
# Licensed under the GNU General Public License, Version 3:
|
||||
# https://www.gnu.org/licenses
|
||||
# Public project repositories:
|
||||
# https://github.com/mmgen/mmgen
|
||||
# https://gitlab.com/mmgen/mmgen
|
||||
|
||||
import sys,os
|
||||
from setuptools import setup,Extension
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue