tool.py: fix tool API; test.py: add tool_api test, minor fixes
This commit is contained in:
parent
777f4201a5
commit
7412bf56ef
5 changed files with 118 additions and 24 deletions
|
|
@ -273,7 +273,7 @@ class MMGenToolCmds(metaclass=MMGenToolCmdMeta):
|
|||
def __init__(self,proto=None,mmtype=None):
|
||||
from .protocol import init_proto_from_opts
|
||||
self.proto = proto or init_proto_from_opts()
|
||||
self.mmtype = mmtype or getattr(opt,'type',None) or self.proto.dfl_mmtype
|
||||
self.mmtype = MMGenAddrType(self.proto,(mmtype or getattr(opt,'type',None) or self.proto.dfl_mmtype))
|
||||
if g.token:
|
||||
self.proto.tokensym = g.token.upper()
|
||||
|
||||
|
|
@ -470,7 +470,7 @@ class MMGenToolCmdCoin(MMGenToolCmds):
|
|||
|
||||
def wif2redeem_script(self,wifkey:'sstr'): # new
|
||||
"convert a WIF private key to a Segwit P2SH-P2WPKH redeem script"
|
||||
assert self.mmtype == 'segwit','This command is meaningful only for --type=segwit'
|
||||
assert self.mmtype.name == 'segwit','This command is meaningful only for --type=segwit'
|
||||
gd = self.init_generators()
|
||||
privhex = PrivKey(
|
||||
self.proto,
|
||||
|
|
@ -479,7 +479,7 @@ class MMGenToolCmdCoin(MMGenToolCmds):
|
|||
|
||||
def wif2segwit_pair(self,wifkey:'sstr'):
|
||||
"generate both a Segwit P2SH-P2WPKH redeem script and address from WIF"
|
||||
assert self.mmtype == 'segwit','This command is meaningful only for --type=segwit'
|
||||
assert self.mmtype.name == 'segwit','This command is meaningful only for --type=segwit'
|
||||
gd = self.init_generators()
|
||||
pubhex = gd.kg.to_pubhex(PrivKey(
|
||||
self.proto,
|
||||
|
|
@ -505,26 +505,26 @@ class MMGenToolCmdCoin(MMGenToolCmds):
|
|||
|
||||
def pubhex2addr(self,pubkeyhex:'sstr'):
|
||||
"convert a hex pubkey to an address"
|
||||
if self.mmtype == 'segwit':
|
||||
if self.mmtype.name == 'segwit':
|
||||
return self.proto.pubhex2segwitaddr(pubkeyhex)
|
||||
else:
|
||||
return self.pubhash2addr(hash160(pubkeyhex))
|
||||
|
||||
def pubhex2redeem_script(self,pubkeyhex:'sstr'): # new
|
||||
"convert a hex pubkey to a Segwit P2SH-P2WPKH redeem script"
|
||||
assert self.mmtype == 'segwit','This command is meaningful only for --type=segwit'
|
||||
assert self.mmtype.name == 'segwit','This command is meaningful only for --type=segwit'
|
||||
return self.proto.pubhex2redeem_script(pubkeyhex)
|
||||
|
||||
def redeem_script2addr(self,redeem_scripthex:'sstr'): # new
|
||||
"convert a Segwit P2SH-P2WPKH redeem script to an address"
|
||||
assert self.mmtype == 'segwit','This command is meaningful only for --type=segwit'
|
||||
assert self.mmtype.name == 'segwit','This command is meaningful only for --type=segwit'
|
||||
assert redeem_scripthex[:4] == '0014','{!r}: invalid redeem script'.format(redeem_scripthex)
|
||||
assert len(redeem_scripthex) == 44,'{} bytes: invalid redeem script length'.format(len(redeem_scripthex)//2)
|
||||
return self.pubhash2addr(hash160(redeem_scripthex))
|
||||
|
||||
def pubhash2addr(self,pubhashhex:'sstr'):
|
||||
"convert public key hash to address"
|
||||
if self.mmtype == 'bech32':
|
||||
if self.mmtype.name == 'bech32':
|
||||
return self.proto.pubhash2bech32addr(pubhashhex)
|
||||
else:
|
||||
gd = self.init_generators('addrtype_only')
|
||||
|
|
@ -1222,10 +1222,11 @@ class tool_api(
|
|||
"""
|
||||
Initializer - takes no arguments
|
||||
"""
|
||||
super().__init__()
|
||||
import mmgen.opts
|
||||
opts.UserOpts._reset_ok += ('usr_randchars',)
|
||||
if not hasattr(opt,'version'):
|
||||
opts.init()
|
||||
self.mmtype = self.proto.dfl_mmtype
|
||||
opts.init(add_opts=['use_old_ed25519'])
|
||||
super().__init__()
|
||||
|
||||
def init_coin(self,coinsym,network):
|
||||
"""
|
||||
|
|
@ -1236,7 +1237,7 @@ class tool_api(
|
|||
from .protocol import init_proto,init_genonly_altcoins
|
||||
altcoin_trust_level = init_genonly_altcoins(coinsym,testnet=network in ('testnet','regtest'))
|
||||
warn_altcoins(coinsym,altcoin_trust_level)
|
||||
self.proto = init_proto(coinsym,network=network) # FIXME
|
||||
self.proto = init_proto(coinsym,network=network)
|
||||
return self.proto
|
||||
|
||||
@property
|
||||
|
|
@ -1265,14 +1266,14 @@ class tool_api(
|
|||
The available address types for current coin/network pair. The
|
||||
first-listed is the default
|
||||
"""
|
||||
return [MMGenAddrType(proto=proto,id_str=id_str).name for id_str in self.proto.mmtypes]
|
||||
return [MMGenAddrType(proto=self.proto,id_str=id_str).name for id_str in self.proto.mmtypes]
|
||||
|
||||
def print_addrtypes(self):
|
||||
"""
|
||||
Print the available address types for current coin/network pair along with
|
||||
a description. The first-listed is the default
|
||||
"""
|
||||
for t in [MMGenAddrType(proto=proto,id_str=id_str).name for id_str in self.proto.mmtypes]:
|
||||
for t in [MMGenAddrType(proto=self.proto,id_str=id_str) for id_str in self.proto.mmtypes]:
|
||||
print('{:<12} - {}'.format(t.name,t.desc))
|
||||
|
||||
@property
|
||||
|
|
@ -1282,7 +1283,7 @@ class tool_api(
|
|||
|
||||
@addrtype.setter
|
||||
def addrtype(self,val):
|
||||
self.mmtype = val
|
||||
self.mmtype = MMGenAddrType(self.proto,val)
|
||||
|
||||
@property
|
||||
def usr_randchars(self):
|
||||
|
|
|
|||
82
test/misc/tool_api_test.py
Executable file
82
test/misc/tool_api_test.py
Executable file
|
|
@ -0,0 +1,82 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# Copyright (C)2013-2020 The MMGen Project <mmgen@tuta.io>
|
||||
|
||||
"""
|
||||
tool_api_test.py: test the MMGen suite tool API
|
||||
"""
|
||||
|
||||
import sys,os
|
||||
os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(os.path.dirname(sys.argv[0])))))
|
||||
sys.path[0] = os.curdir
|
||||
|
||||
def check_equal(a,b):
|
||||
assert a == b, f'{a} != {b}'
|
||||
|
||||
def msg(*args,**kwargs):
|
||||
print(*args,**kwargs,file=sys.stdout)
|
||||
|
||||
def init_coin(t,coinsym,network,addrtype,triplet):
|
||||
t.init_coin(coinsym,network)
|
||||
t.addrtype = addrtype
|
||||
check_equal(type(t.addrtype).__name__,'MMGenAddrType')
|
||||
check_equal(f'{t.coin} {t.proto.cls_name} {t.addrtype}', triplet)
|
||||
msg('\ncoin/proto/type:',triplet)
|
||||
|
||||
def run_test():
|
||||
key_bytes = bytes.fromhex('deadbeef' * 8)
|
||||
|
||||
from mmgen.tool import tool_api
|
||||
tool = tool_api()
|
||||
|
||||
tool.coins
|
||||
tool.print_addrtypes()
|
||||
|
||||
check_equal(f'{tool.coin} {tool.proto.cls_name} {tool.addrtype}', 'BTC Bitcoin L' )
|
||||
|
||||
tool.usr_randchars # getter
|
||||
tool.usr_randchars = 0 # setter
|
||||
check_equal(tool.usr_randchars,0)
|
||||
|
||||
init_coin(tool,'xmr','mainnet','M','XMR Monero M')
|
||||
msg('\n'.join(tool.randpair()))
|
||||
|
||||
init_coin(tool,'etc','mainnet','E','ETC EthereumClassic E')
|
||||
msg('\n'.join(tool.randpair()))
|
||||
|
||||
init_coin(tool,'ltc','regtest','bech32','LTC LitecoinRegtest B')
|
||||
|
||||
wif,addr = tool.randpair()
|
||||
from mmgen.obj import PrivKey,CoinAddr
|
||||
msg('wif:',PrivKey(proto=tool.proto,wif=wif).wif)
|
||||
msg('addr:',CoinAddr(proto=tool.proto,addr=addr))
|
||||
|
||||
wif = PrivKey(proto=tool.proto,s=key_bytes,compressed=True,pubkey_type='std').wif
|
||||
addr = tool.wif2addr(wif)
|
||||
msg('wif:',PrivKey(proto=tool.proto,wif=wif).wif)
|
||||
msg('addr:',CoinAddr(proto=tool.proto,addr=addr))
|
||||
|
||||
addr_chk = tool.privhex2addr(key_bytes.hex())
|
||||
|
||||
check_equal(addr,addr_chk)
|
||||
check_equal(wif,'cV3ZRqf8PhyfiFwtJfkvGu2qmBsazE1wXoA2A16S3nixb3BTvvVx')
|
||||
check_equal(addr,'rltc1qvmqas4maw7lg9clqu6kqu9zq9cluvllnz4kj9y')
|
||||
|
||||
init_coin(tool,'zec','mainnet','Z','ZEC Zcash Z')
|
||||
|
||||
wif = PrivKey(proto=tool.proto,s=key_bytes,compressed=True,pubkey_type='zcash_z').wif
|
||||
addr = tool.wif2addr(wif)
|
||||
msg('wif:',wif)
|
||||
msg('addr:',CoinAddr(proto=tool.proto,addr=addr))
|
||||
|
||||
addr_chk = tool.privhex2addr(key_bytes.hex())
|
||||
wif_chk = PrivKey(proto=tool.proto,wif=wif).wif
|
||||
|
||||
check_equal(addr,addr_chk)
|
||||
check_equal(wif,wif_chk)
|
||||
check_equal(
|
||||
addr,
|
||||
'zchFELwBxqsAubsLQ8yZgPCDDGukjXJssgCbiTPwFNmFwn9haLnDatzfhLdZzJT4PcU4o2yr92B52UFirUzEdF6ZYM2gBkM' )
|
||||
|
||||
run_test()
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
[{'address': '153AwzcymCgiy7dBxHkpeSn8yzbfnRvVPx',
|
||||
'amount': BTCAmt('34.21677044'),
|
||||
'confirmations': 7528082,
|
||||
'label': '96325D83:L:99 This label has a control character (tab) here: [ ]',
|
||||
'scriptPubKey': '76a9142c49a3ad8d89af713197e55190a7c3bc47e0208e88ac',
|
||||
'spendable': False,
|
||||
'txid': '2588cbbea1f3413ee4556c0f12f825f8670771862864a44f5ad39a71e1afdb13',
|
||||
'vout': 3}]
|
||||
[
|
||||
{
|
||||
"address": "153AwzcymCgiy7dBxHkpeSn8yzbfnRvVPx",
|
||||
"amount": "34.21677044",
|
||||
"confirmations": 7528082,
|
||||
"label": "96325D83:L:99 This label has a control character (tab) here: [\t]",
|
||||
"scriptPubKey": "76a9142c49a3ad8d89af713197e55190a7c3bc47e0208e88ac",
|
||||
"spendable": false,
|
||||
"txid": "2588cbbea1f3413ee4556c0f12f825f8670771862864a44f5ad39a71e1afdb13",
|
||||
"vout": 3
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
|
|||
t.license()
|
||||
wcls = MMGenWallet
|
||||
t.passphrase(wcls.desc,self.cfgs['1']['wpasswd'])
|
||||
t.expect('Generating subseed.*10S',regex=True)
|
||||
t.expect(r'Generating subseed.*\D10S',regex=True)
|
||||
t.passphrase_new('new '+wcls.desc,'foo')
|
||||
t.usr_rand(self.usr_rand_chars)
|
||||
fn = t.written_to_file(capfirst(wcls.desc))
|
||||
|
|
@ -238,7 +238,7 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
|
|||
t = self.spawn('mmgen-subwalletgen', args)
|
||||
t.license()
|
||||
t.passphrase(icls.desc,self.cfgs['1']['wpasswd'])
|
||||
t.expect('Generating subseed.*3L',regex=True)
|
||||
t.expect(r'Generating subseed.*\D3L',regex=True)
|
||||
fn = t.written_to_file(capfirst(ocls.desc))
|
||||
ext = get_extension(fn)
|
||||
assert ext == ocls.ext,'incorrect file extension: {}'.format(ext)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ class TestSuiteTool(TestSuiteMain,TestSuiteBase):
|
|||
('tool_encrypt', (9,"'mmgen-tool encrypt' (random data)", [])),
|
||||
('tool_decrypt', (9,"'mmgen-tool decrypt' (random data)", [[[enc_infn+'.mmenc'],9]])),
|
||||
('tool_twview_bad_comment',(9,"'mmgen-tool twview' (with bad comment)", [])),
|
||||
('tool_api', (9,'tool API (initialization, config methods)',[])),
|
||||
# ('tool_encrypt_ref', (9,"'mmgen-tool encrypt' (reference text)", [])),
|
||||
)
|
||||
|
||||
|
|
@ -80,3 +81,9 @@ class TestSuiteTool(TestSuiteMain,TestSuiteBase):
|
|||
t.read()
|
||||
t.req_exit_val = 2
|
||||
return t
|
||||
|
||||
def tool_api(self):
|
||||
t = self.spawn('tool_api_test.py',cmd_dir='test/misc')
|
||||
t.expect('legacy.*compressed.*segwit.*bech32',regex=True)
|
||||
t.read()
|
||||
return t
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue