Monero: new automated wallet syncing utility
- mmgen-tool: `syncmonerowallets`: batch-sync Monero wallets non-interactively - mmgen-tool: `keyaddrlist2monerowallet` -> `keyaddrlist2monerowallets`
This commit is contained in:
parent
83e9899b38
commit
258651a531
4 changed files with 107 additions and 65 deletions
|
|
@ -53,6 +53,9 @@ Wallet/TX operations (coin daemon must be running):
|
|||
txview - show raw/signed {pnm} transaction in human-readable form
|
||||
twview - view tracking wallet
|
||||
|
||||
keyaddrlist2monerowallets - create Monero wallets from key-address list
|
||||
syncmonerowallets - sync Monero wallets from key-address list
|
||||
|
||||
General utilities:
|
||||
hexdump - encode data into formatted hexadecimal form (file or stdin)
|
||||
unhexdump - decode formatted hexadecimal data (file or stdin)
|
||||
|
|
|
|||
148
mmgen/tool.py
148
mmgen/tool.py
|
|
@ -94,7 +94,8 @@ cmd_data = OrderedDict([
|
|||
('Decrypt', ['<infile> [str]',"outfile [str='']","hash_preset [str='']"]),
|
||||
('Bytespec', ['<bytespec> [str]']),
|
||||
|
||||
('Keyaddrlist2monerowallet',['<{} XMR key-address file> [str]'.format(pnm),'blockheight [int=(current height)]']),
|
||||
('Keyaddrlist2monerowallets',['<{} XMR key-address file> [str]'.format(pnm),'blockheight [int=(current height)]']),
|
||||
('Syncmonerowallets', ['<{} XMR key-address file> [str]'.format(pnm)]),
|
||||
])
|
||||
|
||||
def usage(command):
|
||||
|
|
@ -475,10 +476,12 @@ def Rand2file(outfile,nbytes,threads=4,silent=False):
|
|||
|
||||
def Bytespec(s): Msg(str(parse_nbytes(s)))
|
||||
|
||||
def Keyaddrlist2monerowallet(infile,blockheight=None):
|
||||
import pexpect
|
||||
def Syncmonerowallets(infile): monero_wallet_ops(infile=infile,op='sync')
|
||||
|
||||
if blockheight != None and int(blockheight) < 0: blockheight = 0
|
||||
def Keyaddrlist2monerowallets(infile,blockheight=None):
|
||||
monero_wallet_ops(infile=infile,op='create',blockheight=blockheight)
|
||||
|
||||
def monero_wallet_ops(infile,op,blockheight=None):
|
||||
|
||||
def run_cmd(cmd):
|
||||
import subprocess as sp
|
||||
|
|
@ -495,15 +498,6 @@ def Keyaddrlist2monerowallet(infile,blockheight=None):
|
|||
die(1,'Unable to connect to monerod!')
|
||||
return int(ret[8:].split('/')[0])
|
||||
|
||||
cur_height = test_rpc()
|
||||
|
||||
from mmgen.protocol import init_coin
|
||||
init_coin('xmr')
|
||||
from mmgen.addr import AddrList
|
||||
al = KeyAddrList(infile)
|
||||
sid = al.al_id.sid
|
||||
os.environ['LANG'] = 'C'
|
||||
|
||||
def my_expect(p,m,s,regex=False):
|
||||
if m: msg_r(' {}...'.format(m))
|
||||
ret = (p.expect_exact,p.expect)[regex](s)
|
||||
|
|
@ -520,53 +514,95 @@ def Keyaddrlist2monerowallet(infile,blockheight=None):
|
|||
if m: msg('OK')
|
||||
vmsg("sendline: '{}' => {}".format(s,ret))
|
||||
|
||||
def create():
|
||||
gmsg('\nCreating {} wallet{}'.format(dl,suf(dl)))
|
||||
for n,d in enumerate(al.data):
|
||||
def create(n,d,fn):
|
||||
try: os.stat(fn)
|
||||
except: pass
|
||||
else: die(1,"Wallet '{}' already exists!".format(fn))
|
||||
p = pexpect.spawn('monero-wallet-cli --generate-from-spend-key {}'.format(fn))
|
||||
my_expect(p,'Awaiting initial prompt','Secret spend key: ')
|
||||
my_sendline(p,'',d.sec,65)
|
||||
my_expect(p,'','Enter new wallet password: ')
|
||||
my_sendline(p,'Sending password',d.wallet_passwd,33)
|
||||
my_expect(p,'','Confirm password: ')
|
||||
my_sendline(p,'Sending password again',d.wallet_passwd,33)
|
||||
my_expect(p,'','of your choice: ')
|
||||
my_sendline(p,'','1',2)
|
||||
my_expect(p,'monerod generating wallet','Generated new wallet: ')
|
||||
my_expect(p,'','\n')
|
||||
if d.addr not in p.before:
|
||||
die(3,'Addresses do not match!\n MMGen: {}\n Monero: {}'.format(d.addr,p.before))
|
||||
my_expect(p,'','View key: ')
|
||||
my_expect(p,'','\n')
|
||||
if d.viewkey not in p.before:
|
||||
die(3,'View keys do not match!\n MMGen: {}\n Monero: {}'.format(d.viewkey,p.before))
|
||||
my_expect(p,'','(YYYY-MM-DD): ')
|
||||
h = str(blockheight or cur_height-1)
|
||||
my_sendline(p,'',h,len(h)+1)
|
||||
ret = my_expect(p,'',['Starting refresh','Still apply restore height? (Y/Yes/N/No): '])
|
||||
if ret == 1:
|
||||
my_sendline(p,'','Y',2)
|
||||
m = ' Warning: {}: blockheight argument is higher than current blockheight'
|
||||
ymsg(m.format(blockheight))
|
||||
elif blockheight != None:
|
||||
p.logfile = sys.stderr
|
||||
my_expect(p,'Syncing wallet','\[wallet.*$',regex=True)
|
||||
p.logfile = None
|
||||
my_sendline(p,'Exiting','exit',5)
|
||||
p.read()
|
||||
|
||||
def sync(n,d,fn):
|
||||
try: os.stat(fn)
|
||||
except: die(1,"Wallet '{}' does not exist!".format(fn))
|
||||
p = pexpect.spawn('monero-wallet-cli --wallet-file={}'.format(fn))
|
||||
my_expect(p,'Awaiting password prompt','Wallet password: ')
|
||||
my_sendline(p,'Sending password',d.wallet_passwd,33)
|
||||
|
||||
msg(' Starting refresh...')
|
||||
height = None
|
||||
while True:
|
||||
ret = p.expect([r' / .*',r'\[wallet.*:.*'])
|
||||
if ret == 0: # TODO: coverage
|
||||
height = p.after
|
||||
msg_r('\r Block {}{}'.format(p.before.split()[-1],height))
|
||||
elif ret == 1:
|
||||
if height:
|
||||
height = height.split()[-1]
|
||||
msg('\r Block {h} / {h}'.format(h=height))
|
||||
else:
|
||||
msg(' Wallet in sync')
|
||||
msg(' '+[l for l in p.before.splitlines() if l[:8] == 'Balance:'][0])
|
||||
my_sendline(p,'Exiting','exit',5)
|
||||
p.read()
|
||||
break
|
||||
else:
|
||||
die(2,"\nExpect failed: (return value: {})".format(ret))
|
||||
|
||||
def process_wallets():
|
||||
m = { 'create': ('Creat','Generat',create,False),
|
||||
'sync': ('Sync', 'Sync', sync, True) }
|
||||
opt.accept_defaults = opt.accept_defaults or m[op][3]
|
||||
from mmgen.protocol import init_coin
|
||||
init_coin('xmr')
|
||||
from mmgen.addr import AddrList
|
||||
al = KeyAddrList(infile)
|
||||
dl = len(al.data)
|
||||
gmsg('\n{}ing {} wallet{}'.format(m[op][0],dl,suf(dl)))
|
||||
for n,d in enumerate(al.data): # [d.sec,d.wallet_passwd,d.viewkey,d.addr]
|
||||
fn = '{}{}-{}-MoneroWallet'.format(
|
||||
(opt.outdir+'/' if opt.outdir else ''),
|
||||
sid,d.idx)
|
||||
gmsg("\nGenerating wallet {}/{} ({})".format(n+1,dl,fn))
|
||||
try: os.stat(fn)
|
||||
except: pass
|
||||
else: die(1,"Wallet '{}' already exists!".format(fn))
|
||||
# pmsg([d.sec,d.wallet_passwd,d.viewkey,d.addr,fn])
|
||||
p = pexpect.spawn('monero-wallet-cli --generate-from-spend-key {}'.format(fn))
|
||||
my_expect(p,'Awaiting initial prompt','Secret spend key: ')
|
||||
my_sendline(p,'',d.sec,65)
|
||||
my_expect(p,'','Enter new wallet password: ')
|
||||
my_sendline(p,'Sending password',d.wallet_passwd,33)
|
||||
my_expect(p,'','Confirm password: ')
|
||||
my_sendline(p,'Sending password again',d.wallet_passwd,33)
|
||||
my_expect(p,'','of your choice: ')
|
||||
my_sendline(p,'','1',2)
|
||||
my_expect(p,'monerod generating wallet','Generated new wallet: ')
|
||||
my_expect(p,'','\n')
|
||||
if d.addr not in p.before:
|
||||
die(3,'Addresses do not match!\n MMGen: {}\n Monero: {}'.format(d.addr,p.before))
|
||||
my_expect(p,'','View key: ')
|
||||
my_expect(p,'','\n')
|
||||
if d.viewkey not in p.before:
|
||||
die(3,'View keys do not match!\n MMGen: {}\n Monero: {}'.format(d.viewkey,p.before))
|
||||
my_expect(p,'','(YYYY-MM-DD): ')
|
||||
h = str(blockheight or cur_height-1)
|
||||
my_sendline(p,'',h,len(h)+1)
|
||||
ret = my_expect(p,'',['Starting refresh','Still apply restore height? (Y/Yes/N/No): '])
|
||||
if ret == 1:
|
||||
my_sendline(p,'','Y',2)
|
||||
m = ' Warning: {}: blockheight argument is higher than current blockheight'
|
||||
ymsg(m.format(blockheight))
|
||||
elif blockheight != None:
|
||||
p.logfile = sys.stderr
|
||||
my_expect(p,'Syncing wallet','\[wallet.*$',regex=True)
|
||||
p.logfile = None
|
||||
my_sendline(p,'Exiting','exit',5)
|
||||
p.read()
|
||||
al.al_id.sid,
|
||||
d.idx)
|
||||
gmsg('\n{}ing wallet {}/{} ({})'.format(m[op][1],n+1,dl,fn))
|
||||
m[op][2](n,d,fn)
|
||||
gmsg('\n{} wallet{} {}ed'.format(dl,suf(dl),m[op][0].lower()))
|
||||
|
||||
os.environ['LANG'] = 'C'
|
||||
import pexpect
|
||||
if blockheight != None and int(blockheight) < 0: blockheight = 0 # TODO: non-zero coverage
|
||||
cur_height = test_rpc()
|
||||
|
||||
dl = len(al.data)
|
||||
try:
|
||||
create()
|
||||
gmsg('\n{} wallet{} created'.format(dl,suf(dl)))
|
||||
process_wallets()
|
||||
except KeyboardInterrupt:
|
||||
rdie(1,'\nUser interrupt\n')
|
||||
except EOFError:
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ while getopts hinPt OPT
|
|||
do
|
||||
case "$OPT" in
|
||||
h) printf " %-16s Test MMGen release\n" "${PROGNAME}:"
|
||||
echo " USAGE: $PROGNAME [options] branch [tests]"
|
||||
echo " USAGE: $PROGNAME [options] [branch] [tests]"
|
||||
echo " OPTIONS: '-h' Print this help message"
|
||||
echo " '-i' Install only; don't run tests"
|
||||
echo " '-n' Don't install; test in place"
|
||||
|
|
@ -50,10 +50,12 @@ shift $((OPTIND-1))
|
|||
|
||||
RED="\e[31;1m" GREEN="\e[32;1m" YELLOW="\e[33;1m" RESET="\e[0m"
|
||||
|
||||
BRANCH=$1; shift
|
||||
BRANCHES=$(git branch)
|
||||
FOUND_BRANCH=$(for b in ${BRANCHES/\*}; do [ "$b" == "$BRANCH" ] && echo ok; done)
|
||||
[ "$FOUND_BRANCH" ] || { echo "Branch '$BRANCH' not found!"; exit; }
|
||||
[ "$NO_INSTALL" ] || {
|
||||
BRANCH=$1; shift
|
||||
BRANCHES=$(git branch)
|
||||
FOUND_BRANCH=$(for b in ${BRANCHES/\*}; do [ "$b" == "$BRANCH" ] && echo ok; done)
|
||||
[ "$FOUND_BRANCH" ] || { echo "Branch '$BRANCH' not found!"; exit; }
|
||||
}
|
||||
|
||||
set -e
|
||||
|
||||
|
|
@ -158,8 +160,10 @@ s_monero='Testing generation and wallet creation operations for Monero'
|
|||
s_monero='The monerod (mainnet) daemon must be running for the following tests'
|
||||
ROUNDS=1000
|
||||
t_monero=(
|
||||
'python cmds/mmgen-keygen --accept-defaults --outdir $TMPDIR --coin=xmr test/ref/98831F3A.mmwords 3,99,2,22-29,101-109'
|
||||
'python cmds/mmgen-tool -q --accept-defaults --outdir $TMPDIR keyaddrlist2monerowallet $TMPDIR/988*XMR*akeys')
|
||||
'python cmds/mmgen-keygen --accept-defaults --outdir $TMPDIR --coin=xmr test/ref/98831F3A.mmwords 3,99,2,22-24,101-104'
|
||||
'python cmds/mmgen-tool -q --accept-defaults --outdir $TMPDIR keyaddrlist2monerowallets $TMPDIR/988*XMR*akeys'
|
||||
'python cmds/mmgen-tool -q --outdir $TMPDIR syncmonerowallets $TMPDIR/988*XMR*akeys'
|
||||
)
|
||||
[ "$MINGW" ] && t_monero=("$t_monero")
|
||||
f_monero='Monero tests completed'
|
||||
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -145,7 +145,6 @@ setup(
|
|||
'mmgen.main_txsign',
|
||||
'mmgen.main_txsend',
|
||||
'mmgen.main_txdo',
|
||||
'mmgen.txcreate',
|
||||
'mmgen.txsign',
|
||||
'mmgen.main_tool',
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue