tool: new fstr class
This commit is contained in:
parent
c66da635a2
commit
3c0c961385
7 changed files with 47 additions and 44 deletions
|
|
@ -24,6 +24,7 @@ mmgen-tool: Perform various MMGen- and cryptocoin-related operations.
|
|||
import sys, os, importlib
|
||||
from .cfg import gc, Config
|
||||
from .util import msg, Msg, die, capfirst, suf, async_run, isAsync
|
||||
from .tool.common import fstr
|
||||
|
||||
opts_data = {
|
||||
'filter_codes': ['-'],
|
||||
|
|
@ -211,17 +212,17 @@ def create_call_sig(cmd, cls, *, as_string=False):
|
|||
for i, a in enumerate(args[nargs:]))
|
||||
|
||||
if as_string:
|
||||
get_type_from_ann = lambda x: 'str or STDIN' if ann[x] == 'sstr' else ann[x].__name__
|
||||
get_type_from_ann = lambda x: 'str or STDIN' if ann[x] == fstr else ann[x].__name__
|
||||
return ' '.join(
|
||||
[f'{a} [{get_type_from_ann(a)}]' for a in args[:nargs]] +
|
||||
[f'{a} [{dfl_types[n].__name__}={dfls[n]!r}]' for n, a in enumerate(args[nargs:])])
|
||||
else:
|
||||
get_type_from_ann = lambda x: 'str' if ann[x] == 'sstr' else ann[x].__name__
|
||||
get_type_from_ann = lambda x: 'str' if ann[x] == fstr else ann[x].__name__
|
||||
return (
|
||||
[(a, get_type_from_ann(a)) for a in args[:nargs]], # c_args
|
||||
{a: dfls[n] for n, a in enumerate(args[nargs:])}, # c_kwargs
|
||||
{a: dfl_types[n] for n, a in enumerate(args[nargs:])}, # c_kwargs_types
|
||||
('STDIN_OK' if nargs and ann[args[0]] == 'sstr' else flag), # flag
|
||||
('STDIN_OK' if nargs and ann[args[0]] == fstr else flag), # flag
|
||||
ann) # ann
|
||||
|
||||
def process_args(cmd, cmd_args, cls):
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ tool.coin: Cryptocoin routines for the 'mmgen-tool' utility
|
|||
from collections import namedtuple
|
||||
generator_data = namedtuple('generator_data', ['kg', 'ag'])
|
||||
|
||||
from .common import tool_cmd_base
|
||||
from .common import tool_cmd_base, fstr
|
||||
|
||||
from ..key import PrivKey
|
||||
from ..addr import CoinAddr, MMGenAddrType
|
||||
|
|
@ -57,7 +57,7 @@ class tool_cmd(tool_cmd_base):
|
|||
pubkey_type = self.mmtype.pubkey_type,
|
||||
compressed = self.mmtype.compressed).wif
|
||||
|
||||
def privhex2pair(self, privhex: 'sstr'):
|
||||
def privhex2pair(self, privhex: fstr):
|
||||
"generate a wifkey/address pair from the provided hexadecimal key"
|
||||
gd = self._init_generators()
|
||||
privkey = PrivKey(
|
||||
|
|
@ -74,13 +74,13 @@ class tool_cmd(tool_cmd_base):
|
|||
from ..crypto import Crypto
|
||||
return self.privhex2pair(Crypto(self.cfg).get_random(32).hex())
|
||||
|
||||
def wif2hex(self, wifkey: 'sstr'):
|
||||
def wif2hex(self, wifkey: fstr):
|
||||
"convert a private key from WIF to hexadecimal format"
|
||||
return PrivKey(
|
||||
self.proto,
|
||||
wif = wifkey).hex()
|
||||
|
||||
def hex2wif(self, privhex: 'sstr'):
|
||||
def hex2wif(self, privhex: fstr):
|
||||
"convert a private key from hexadecimal to WIF format"
|
||||
return PrivKey(
|
||||
self.proto,
|
||||
|
|
@ -88,7 +88,7 @@ class tool_cmd(tool_cmd_base):
|
|||
pubkey_type = self.mmtype.pubkey_type,
|
||||
compressed = self.mmtype.compressed).wif
|
||||
|
||||
def wif2addr(self, wifkey: 'sstr'):
|
||||
def wif2addr(self, wifkey: fstr):
|
||||
"generate a coin address from a key in WIF format"
|
||||
gd = self._init_generators()
|
||||
privkey = PrivKey(
|
||||
|
|
@ -96,7 +96,7 @@ class tool_cmd(tool_cmd_base):
|
|||
wif = wifkey)
|
||||
return gd.ag.to_addr(gd.kg.gen_data(privkey))
|
||||
|
||||
def wif2redeem_script(self, wifkey: 'sstr'): # new
|
||||
def wif2redeem_script(self, wifkey: fstr): # new
|
||||
"convert a WIF private key to a Segwit P2SH-P2WPKH redeem script"
|
||||
assert self.mmtype.name == 'segwit', 'This command is meaningful only for --type=segwit'
|
||||
gd = self._init_generators()
|
||||
|
|
@ -105,7 +105,7 @@ class tool_cmd(tool_cmd_base):
|
|||
wif = wifkey)
|
||||
return gd.ag.to_segwit_redeem_script(gd.kg.gen_data(privkey))
|
||||
|
||||
def wif2segwit_pair(self, wifkey: 'sstr'):
|
||||
def wif2segwit_pair(self, wifkey: fstr):
|
||||
"generate a Segwit P2SH-P2WPKH redeem script and address from a WIF private key"
|
||||
assert self.mmtype.name == 'segwit', 'This command is meaningful only for --type=segwit'
|
||||
gd = self._init_generators()
|
||||
|
|
@ -116,7 +116,7 @@ class tool_cmd(tool_cmd_base):
|
|||
gd.ag.to_segwit_redeem_script(data),
|
||||
gd.ag.to_addr(data))
|
||||
|
||||
def _privhex2out(self, privhex: 'sstr', *, output_pubhex=False):
|
||||
def _privhex2out(self, privhex: fstr, *, output_pubhex=False):
|
||||
gd = self._init_generators()
|
||||
pk = PrivKey(
|
||||
self.proto,
|
||||
|
|
@ -126,15 +126,15 @@ class tool_cmd(tool_cmd_base):
|
|||
data = gd.kg.gen_data(pk)
|
||||
return data.pubkey.hex() if output_pubhex else gd.ag.to_addr(data)
|
||||
|
||||
def privhex2addr(self, privhex: 'sstr'):
|
||||
def privhex2addr(self, privhex: fstr):
|
||||
"generate a coin address from raw hexadecimal private key data"
|
||||
return self._privhex2out(privhex)
|
||||
|
||||
def privhex2pubhex(self, privhex: 'sstr'): # new
|
||||
def privhex2pubhex(self, privhex: fstr): # new
|
||||
"generate a hexadecimal public key from raw hexadecimal private key data"
|
||||
return self._privhex2out(privhex, output_pubhex=True)
|
||||
|
||||
def pubhex2addr(self, pubkeyhex: 'sstr'):
|
||||
def pubhex2addr(self, pubkeyhex: fstr):
|
||||
"convert a hexadecimal pubkey to an address"
|
||||
if self.proto.base_proto == 'Ethereum' and len(pubkeyhex) == 128: # support raw ETH pubkeys
|
||||
pubkeyhex = '04' + pubkeyhex
|
||||
|
|
@ -147,13 +147,13 @@ class tool_cmd(tool_cmd_base):
|
|||
compressed = self.mmtype.compressed,
|
||||
))
|
||||
|
||||
def pubhex2redeem_script(self, pubkeyhex: 'sstr'): # new
|
||||
def pubhex2redeem_script(self, pubkeyhex: fstr): # new
|
||||
"convert a hexadecimal pubkey to a Segwit P2SH-P2WPKH redeem script"
|
||||
assert self.mmtype.name == 'segwit', 'This command is meaningful only for --type=segwit'
|
||||
from ..proto.btc.common import hash160
|
||||
return self.proto.pubhash2redeem_script(hash160(bytes.fromhex(pubkeyhex))).hex()
|
||||
|
||||
def redeem_script2addr(self, redeem_script_hex: 'sstr'): # new
|
||||
def redeem_script2addr(self, redeem_script_hex: fstr): # new
|
||||
"convert a Segwit P2SH-P2WPKH redeem script to an address"
|
||||
assert self.mmtype.name == 'segwit', 'This command is meaningful only for --type=segwit'
|
||||
assert redeem_script_hex.startswith('0014'), f'{redeem_script_hex!r}: invalid redeem script'
|
||||
|
|
@ -161,7 +161,7 @@ class tool_cmd(tool_cmd_base):
|
|||
from ..proto.btc.common import hash160
|
||||
return self.proto.pubhash2addr(hash160(bytes.fromhex(redeem_script_hex)), 'p2sh')
|
||||
|
||||
def pubhash2addr(self, pubhashhex: 'sstr'):
|
||||
def pubhash2addr(self, pubhashhex: fstr):
|
||||
"convert public key hash to address"
|
||||
pubhash = bytes.fromhex(pubhashhex)
|
||||
match self.mmtype.name:
|
||||
|
|
@ -182,25 +182,25 @@ class tool_cmd(tool_cmd_base):
|
|||
die(2, f'{ap.fmt} addresses cannot be converted to {ptype}')
|
||||
return ap.bytes.hex()
|
||||
|
||||
def addr2pubhex(self, addr: 'sstr'):
|
||||
def addr2pubhex(self, addr: fstr):
|
||||
"convert coin address to public key"
|
||||
return self._addr2pub(addr, ptype='pubkey')
|
||||
|
||||
def addr2pubhash(self, addr: 'sstr'):
|
||||
def addr2pubhash(self, addr: fstr):
|
||||
"convert coin address to public key hash"
|
||||
return self._addr2pub(addr, ptype='pubhash')
|
||||
|
||||
def addr2scriptpubkey(self, addr: 'sstr'):
|
||||
def addr2scriptpubkey(self, addr: fstr):
|
||||
"convert coin address to scriptPubKey"
|
||||
from ..proto.btc.tx.base import addr2scriptPubKey
|
||||
return addr2scriptPubKey(self.proto, CoinAddr(self.proto, addr))
|
||||
|
||||
def scriptpubkey2addr(self, hexstr: 'sstr'):
|
||||
def scriptpubkey2addr(self, hexstr: fstr):
|
||||
"convert scriptPubKey to coin address"
|
||||
from ..proto.btc.tx.base import decodeScriptPubKey
|
||||
return decodeScriptPubKey(self.proto, hexstr).addr
|
||||
|
||||
def eth_checksummed_addr(self, addr: 'sstr'):
|
||||
def eth_checksummed_addr(self, addr: fstr):
|
||||
"create a checksummed Ethereum address"
|
||||
from ..protocol import init_proto
|
||||
return init_proto(self.cfg, 'eth').checksummed_addr(addr)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ tool.common: Base class and shared routines for the 'mmgen-tool' utility
|
|||
|
||||
from ..objmethods import MMGenObject
|
||||
|
||||
class fstr(str):
|
||||
pass
|
||||
|
||||
def options_annot_str(l):
|
||||
return "(valid choices: '{}')".format("','".join(l))
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ tool.help: Help screen routines for the 'mmgen-tool' utility
|
|||
|
||||
from .. import main_tool
|
||||
|
||||
from .common import tool_cmd_base
|
||||
from .common import tool_cmd_base, fstr
|
||||
|
||||
def main_help():
|
||||
|
||||
|
|
@ -156,12 +156,12 @@ def gen_tool_cmd_usage(mod, cmdname):
|
|||
yield f'Required {ARGS} (type shown in square brackets):'
|
||||
yield ''
|
||||
for argname, argtype in args:
|
||||
have_sstr = ann.get(argname) == 'sstr'
|
||||
have_fstr = ann.get(argname) == fstr
|
||||
yield ' {a:{w}} [{b}]{c}{d}'.format(
|
||||
a = argname,
|
||||
b = argtype,
|
||||
c = " (use '-' to read from STDIN)" if have_sstr else '',
|
||||
d = ' ' + ann[argname] if isinstance(ann.get(argname), str) and not have_sstr else '',
|
||||
c = " (use '-' to read from STDIN)" if have_fstr else '',
|
||||
d = ' ' + ann[argname] if isinstance(ann.get(argname), str) and not have_fstr else '',
|
||||
w = max_w)
|
||||
|
||||
if kwargs:
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ tool.mnemonic: Mnemonic routines for the 'mmgen-tool' utility
|
|||
|
||||
from collections import namedtuple
|
||||
|
||||
from .common import tool_cmd_base, options_annot_str
|
||||
from .common import tool_cmd_base, options_annot_str, fstr
|
||||
|
||||
from ..baseconv import baseconv
|
||||
from ..xmrseed import xmrseed
|
||||
|
|
@ -93,14 +93,14 @@ class tool_cmd(tool_cmd_base):
|
|||
"generate a random 256-bit mnemonic seed phrase"
|
||||
return self._do_random_mn(32, fmt)
|
||||
|
||||
def hex2mn(self, hexstr: 'sstr', fmt: mn_opts_disp = dfl_mnemonic_fmt):
|
||||
def hex2mn(self, hexstr: fstr, fmt: mn_opts_disp = dfl_mnemonic_fmt):
|
||||
"convert a 16, 24 or 32-byte hexadecimal string to a mnemonic seed phrase"
|
||||
if fmt == 'xmrseed':
|
||||
hexstr = self._xmr_reduce(bytes.fromhex(hexstr)).hex()
|
||||
f = mnemonic_fmts[fmt]
|
||||
return ' '.join(f.conv_cls(fmt).fromhex(hexstr, pad=f.pad))
|
||||
|
||||
def mn2hex(self, seed_mnemonic: 'sstr', fmt: mn_opts_disp = dfl_mnemonic_fmt):
|
||||
def mn2hex(self, seed_mnemonic: fstr, fmt: mn_opts_disp = dfl_mnemonic_fmt):
|
||||
"convert a mnemonic seed phrase to a hexadecimal string"
|
||||
f = mnemonic_fmts[fmt]
|
||||
return f.conv_cls(fmt).tohex(seed_mnemonic.split(), pad=f.pad)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import os
|
|||
|
||||
from ..cfg import gc
|
||||
|
||||
from .common import tool_cmd_base
|
||||
from .common import tool_cmd_base, fstr
|
||||
|
||||
class tool_cmd(tool_cmd_base):
|
||||
"general string conversion and hashing utilities"
|
||||
|
|
@ -100,7 +100,7 @@ class tool_cmd(tool_cmd_base):
|
|||
from ..crypto import Crypto
|
||||
return Crypto(self.cfg).get_random(nbytes).hex()
|
||||
|
||||
def hexreverse(self, hexstr: 'sstr'):
|
||||
def hexreverse(self, hexstr: fstr):
|
||||
"reverse bytes of a hexadecimal string"
|
||||
return bytes.fromhex(hexstr.strip())[::-1].hex()
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ class tool_cmd(tool_cmd_base):
|
|||
data = get_data_from_file(self.cfg, infile, dash=True, quiet=True, binary=True)
|
||||
return data.hex()
|
||||
|
||||
def unhexlify(self, hexstr: 'sstr'):
|
||||
def unhexlify(self, hexstr: fstr):
|
||||
"convert a hexadecimal string to bytes (warning: outputs binary data)"
|
||||
return bytes.fromhex(hexstr)
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ class tool_cmd(tool_cmd_base):
|
|||
hexdata = get_data_from_file(self.cfg, infile, dash=True, quiet=True)
|
||||
return decode_pretty_hexdump(hexdata)
|
||||
|
||||
def hash160(self, hexstr: 'sstr'):
|
||||
def hash160(self, hexstr: fstr):
|
||||
"compute ripemd160(sha256(data)) (convert hex pubkey to hex addr)"
|
||||
from ..proto.btc.common import hash160
|
||||
return hash160(bytes.fromhex(hexstr)).hex()
|
||||
|
|
@ -165,7 +165,7 @@ class tool_cmd(tool_cmd_base):
|
|||
return make_chksum_6(
|
||||
get_data_from_file(self.cfg, infile, dash=True, quiet=True, binary=True))
|
||||
|
||||
def str2id6(self, string: 'sstr'): # retain ignoring of space for backwards compat
|
||||
def str2id6(self, string: fstr): # retain ignoring of space for backwards compat
|
||||
"generate 6-character MMGen ID for a string, ignoring spaces in string"
|
||||
from ..util import make_chksum_6
|
||||
return make_chksum_6(''.join(string.split()))
|
||||
|
|
@ -192,43 +192,43 @@ class tool_cmd(tool_cmd_base):
|
|||
data = get_data_from_file(self.cfg, infile, dash=True, quiet=True, binary=True)
|
||||
return baseconv('b58').frombytes(data, pad=pad, tostr=True)
|
||||
|
||||
def b58tobytes(self, b58_str: 'sstr', *, pad: 'pad output to this width' = 0):
|
||||
def b58tobytes(self, b58_str: fstr, *, pad: 'pad output to this width' = 0):
|
||||
"convert a base 58 string to bytes (warning: outputs binary data)"
|
||||
from ..baseconv import baseconv
|
||||
return baseconv('b58').tobytes(b58_str, pad=pad)
|
||||
|
||||
def hextob58(self, hexstr: 'sstr', *, pad: 'pad output to this width' = 0):
|
||||
def hextob58(self, hexstr: fstr, *, pad: 'pad output to this width' = 0):
|
||||
"convert a hexadecimal string to base 58"
|
||||
from ..baseconv import baseconv
|
||||
return baseconv('b58').fromhex(hexstr, pad=pad, tostr=True)
|
||||
|
||||
def b58tohex(self, b58_str: 'sstr', *, pad: 'pad output to this width' = 0):
|
||||
def b58tohex(self, b58_str: fstr, *, pad: 'pad output to this width' = 0):
|
||||
"convert a base 58 string to hexadecimal"
|
||||
from ..baseconv import baseconv
|
||||
return baseconv('b58').tohex(b58_str, pad=pad)
|
||||
|
||||
def hextob58chk(self, hexstr: 'sstr'):
|
||||
def hextob58chk(self, hexstr: fstr):
|
||||
"convert a hexadecimal string to base58-check encoding"
|
||||
from ..proto.btc.common import b58chk_encode
|
||||
return b58chk_encode(bytes.fromhex(hexstr))
|
||||
|
||||
def b58chktohex(self, b58chk_str: 'sstr'):
|
||||
def b58chktohex(self, b58chk_str: fstr):
|
||||
"convert a base58-check encoded string to hexadecimal"
|
||||
from ..proto.btc.common import b58chk_decode
|
||||
return b58chk_decode(b58chk_str).hex()
|
||||
|
||||
def hextob32(self, hexstr: 'sstr', *, pad: 'pad output to this width' = 0):
|
||||
def hextob32(self, hexstr: fstr, *, pad: 'pad output to this width' = 0):
|
||||
"convert a hexadecimal string to an MMGen-flavor base 32 string"
|
||||
from ..baseconv import baseconv
|
||||
return baseconv('b32').fromhex(hexstr, pad=pad, tostr=True)
|
||||
|
||||
def b32tohex(self, b32_str: 'sstr', *, pad: 'pad output to this width' = 0):
|
||||
def b32tohex(self, b32_str: fstr, *, pad: 'pad output to this width' = 0):
|
||||
"convert an MMGen-flavor base 32 string to hexadecimal"
|
||||
from ..baseconv import baseconv
|
||||
return baseconv('b32').tohex(b32_str.upper(), pad=pad)
|
||||
|
||||
def hextob6d(self,
|
||||
hexstr: 'sstr',
|
||||
hexstr: fstr,
|
||||
*,
|
||||
pad: 'pad output to this width' = 0,
|
||||
add_spaces: 'add a space after every 5th character' = True):
|
||||
|
|
@ -238,7 +238,7 @@ class tool_cmd(tool_cmd_base):
|
|||
ret = baseconv('b6d').fromhex(hexstr, pad=pad, tostr=True)
|
||||
return block_format(ret, gw=5, cols=None).strip() if add_spaces else ret
|
||||
|
||||
def b6dtohex(self, b6d_str: 'sstr', *, pad: 'pad output to this width' = 0):
|
||||
def b6dtohex(self, b6d_str: fstr, *, pad: 'pad output to this width' = 0):
|
||||
"convert a die roll base6 (base6d) string to hexadecimal"
|
||||
from ..baseconv import baseconv
|
||||
from ..util import remove_whitespace
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ ignore = [
|
|||
[tool.ruff.lint.per-file-ignores]
|
||||
"protobuf.py" = [ "UP045" ] # Use `X | None` for type annotations
|
||||
"mmgen/rpc/backends/curl.py" = [ "ASYNC221" ] # blocking method in async function
|
||||
"mmgen/tool/*" = [ "F821" ] # Undefined name `sstr`
|
||||
"create-bip-hd-chain-params.py" = [ "F401" ]
|
||||
|
||||
"examples/*" = [ "ASYNC230" ] # open() in async function
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue