py3port: new HexBytes class
This commit is contained in:
parent
793c808797
commit
af2bec1220
8 changed files with 49 additions and 25 deletions
|
|
@ -68,7 +68,7 @@ class AddrGeneratorSegwit(AddrGenerator):
|
|||
|
||||
def to_segwit_redeem_script(self,pubhex):
|
||||
assert pubhex.compressed,'Uncompressed public keys incompatible with Segwit'
|
||||
return HexStr(g.proto.pubhex2redeem_script(pubhex))
|
||||
return HexBytes(g.proto.pubhex2redeem_script(pubhex))
|
||||
|
||||
class AddrGeneratorBech32(AddrGenerator):
|
||||
def to_addr(self,pubhex):
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class EthereumMMGenTX(MMGenTX):
|
|||
usr_rel_fee = None # not in MMGenTX
|
||||
disable_fee_check = False
|
||||
txobj = None # ""
|
||||
data = HexStr('')
|
||||
data = HexBytes('')
|
||||
|
||||
def __init__(self,*args,**kwargs):
|
||||
super(EthereumMMGenTX,self).__init__(*args,**kwargs)
|
||||
|
|
@ -55,7 +55,7 @@ class EthereumMMGenTX(MMGenTX):
|
|||
if hasattr(opt,'contract_data') and opt.contract_data:
|
||||
m = "'--contract-data' option may not be used with token transaction"
|
||||
assert not 'Token' in type(self).__name__, m
|
||||
self.data = HexStr(open(opt.contract_data).read().strip())
|
||||
self.data = HexBytes(open(opt.contract_data).read().strip())
|
||||
self.disable_fee_check = True
|
||||
|
||||
@classmethod
|
||||
|
|
@ -84,7 +84,7 @@ class EthereumMMGenTX(MMGenTX):
|
|||
def check_pubkey_scripts(self): pass
|
||||
|
||||
def check_sigs(self,deserial_tx=None):
|
||||
if is_hex_str(self.hex):
|
||||
if is_hex_bytes(self.hex):
|
||||
self.mark_signed()
|
||||
return True
|
||||
return False
|
||||
|
|
@ -105,7 +105,7 @@ class EthereumMMGenTX(MMGenTX):
|
|||
'gasPrice': ETHAmt(d['gasprice'],'wei'),
|
||||
'startGas': ETHAmt(d['startgas'],'wei'),
|
||||
'nonce': ETHNonce(d['nonce']),
|
||||
'data': HexStr(d['data']) }
|
||||
'data': HexBytes(d['data']) }
|
||||
if o['data'] and not o['to']:
|
||||
self.token_addr = TokenAddr(hexlify(etx.creates).decode())
|
||||
txid = CoinTxID(hexlify(etx.hash))
|
||||
|
|
@ -119,7 +119,7 @@ class EthereumMMGenTX(MMGenTX):
|
|||
'startGas': ETHAmt(d['startGas']),
|
||||
'nonce': ETHNonce(d['nonce']),
|
||||
'chainId': Int(d['chainId']),
|
||||
'data': HexStr(d['data']) }
|
||||
'data': HexBytes(d['data']) }
|
||||
self.tx_gas = o['startGas'] # approximate, but better than nothing
|
||||
self.data = o['data']
|
||||
if o['data'] and not o['to']: self.disable_fee_check = True
|
||||
|
|
@ -413,7 +413,7 @@ class EthereumTokenMMGenTX(EthereumMMGenTX):
|
|||
|
||||
def set_g_token(self):
|
||||
g.dcoin = self.dcoin
|
||||
if is_hex_str(self.hex): return # for txsend we can leave g.token uninitialized
|
||||
if is_hex_bytes(self.hex): return # for txsend we can leave g.token uninitialized
|
||||
d = json.loads(self.hex)
|
||||
if g.token.upper() == self.dcoin:
|
||||
g.token = d['token_addr']
|
||||
|
|
|
|||
40
mmgen/obj.py
40
mmgen/obj.py
|
|
@ -559,18 +559,20 @@ class TwLabel(str,InitErrors,MMGenObject):
|
|||
m = "{}\n{!r}: value cannot be converted to TwLabel"
|
||||
return cls.init_fail(m.format(e.args[0],s),on_fail)
|
||||
|
||||
class HexStr(str,Hilite,InitErrors):
|
||||
class HexBytes(bytes,Hilite,InitErrors):
|
||||
color = 'red'
|
||||
trunc_ok = False
|
||||
dtype = bytes
|
||||
def __new__(cls,s,on_fail='die',case='lower'):
|
||||
if type(s) == cls: return s
|
||||
assert case in ('upper','lower')
|
||||
cls.arg_chk(cls,on_fail)
|
||||
if issubclass(type(s),bytes): s = s.decode()
|
||||
try:
|
||||
assert type(s) in (str,str,bytes),'not a string'
|
||||
assert type(s) == str,'not a string'
|
||||
assert set(s) <= set(getattr(hexdigits,case)()),'not {}case hexadecimal symbols'.format(case)
|
||||
assert not len(s) % 2,'odd-length string'
|
||||
return str.__new__(cls,s)
|
||||
return cls.dtype.__new__(cls,s.encode() if cls.dtype == bytes else s)
|
||||
except Exception as e:
|
||||
m = "{!r}: value cannot be converted to {} (value is {})"
|
||||
return cls.init_fail(m.format(s,cls.__name__,e.args[0]),on_fail)
|
||||
|
|
@ -578,25 +580,41 @@ class HexStr(str,Hilite,InitErrors):
|
|||
class Str(str,Hilite): pass
|
||||
class Int(int,Hilite): pass
|
||||
|
||||
class HexStrWithWidth(HexStr):
|
||||
class HexBytesWithWidth(HexBytes):
|
||||
color = 'nocolor'
|
||||
trunc_ok = False
|
||||
hexcase = 'lower'
|
||||
width = None
|
||||
parent_cls = HexBytes
|
||||
def __new__(cls,s,on_fail='die'):
|
||||
cls.arg_chk(cls,on_fail)
|
||||
try:
|
||||
ret = HexStr.__new__(cls,s,case=cls.hexcase,on_fail='raise')
|
||||
ret = cls.parent_cls.__new__(cls,s,case=cls.hexcase,on_fail='raise')
|
||||
assert len(s) == cls.width,'Value is not {} characters wide'.format(cls.width)
|
||||
return ret
|
||||
except Exception as e:
|
||||
m = "{}\n{!r}: value cannot be converted to {}"
|
||||
return cls.init_fail(m.format(e.args[0],s,cls.__name__),on_fail)
|
||||
|
||||
class MMGenTxID(HexStrWithWidth): color,width,hexcase = 'red',6,'upper'
|
||||
class MoneroViewKey(HexStrWithWidth): color,width,hexcase = 'cyan',64,'lower'
|
||||
class CoinTxID(HexBytesWithWidth): color,width,hexcase = 'purple',64,'lower'
|
||||
|
||||
class HexStr(str,Hilite,InitErrors):
|
||||
color = 'red'
|
||||
trunc_ok = False
|
||||
dtype = str
|
||||
def __new__(cls,s,on_fail='die',case='lower'):
|
||||
return HexBytes.__new__(cls,s,on_fail=on_fail,case=case)
|
||||
|
||||
class HexStrWithWidth(HexStr):
|
||||
color = 'nocolor'
|
||||
hexcase = 'lower'
|
||||
width = None
|
||||
parent_cls = HexStr
|
||||
def __new__(cls,s,on_fail='die'):
|
||||
return HexBytesWithWidth.__new__(cls,s,on_fail=on_fail)
|
||||
|
||||
class WalletPassword(HexStrWithWidth): color,width,hexcase = 'blue',32,'lower'
|
||||
class CoinTxID(HexStrWithWidth): color,width,hexcase = 'purple',64,'lower'
|
||||
class MoneroViewKey(HexStrWithWidth): color,width,hexcase = 'cyan',64,'lower'
|
||||
class MMGenTxID(HexStrWithWidth): color,width,hexcase = 'red',6,'upper'
|
||||
|
||||
class WifKey(str,Hilite,InitErrors):
|
||||
width = 53
|
||||
|
|
@ -613,11 +631,11 @@ class WifKey(str,Hilite,InitErrors):
|
|||
m = '{!r}: invalid value for WIF key ({})'.format(s,e.args[0])
|
||||
return cls.init_fail(m,on_fail)
|
||||
|
||||
class PubKey(HexStr,MMGenObject): # TODO: add some real checks
|
||||
class PubKey(HexBytes,MMGenObject): # TODO: add some real checks
|
||||
def __new__(cls,s,compressed,on_fail='die'):
|
||||
try:
|
||||
assert type(compressed) == bool,"'compressed' must be of type bool"
|
||||
me = HexStr.__new__(cls,s,case='lower',on_fail='raise')
|
||||
me = HexBytes.__new__(cls,s,case='lower',on_fail='raise')
|
||||
me.compressed = compressed
|
||||
return me
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -110,11 +110,15 @@ class CoinDaemonRPCConnection(object):
|
|||
dmsg_rpc(' RPC POST data ==> {}\n'.format(p))
|
||||
|
||||
ca_type = self.coin_amt_type if hasattr(self,'coin_amt_type') else str
|
||||
from mmgen.obj import CoinTxID,HexBytes
|
||||
class MyJSONEncoder(json.JSONEncoder):
|
||||
def default(self,obj):
|
||||
if isinstance(obj,g.proto.coin_amt):
|
||||
return ca_type(obj)
|
||||
return json.JSONEncoder.default(self,obj)
|
||||
elif isinstance(obj,CoinTxID) or isinstance(obj,HexBytes):
|
||||
return obj.decode()
|
||||
else:
|
||||
return json.JSONEncoder.default(self,obj)
|
||||
|
||||
http_hdr = { 'Content-Type': 'application/json' }
|
||||
if self.auth:
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view, add [l]abel:
|
|||
twmmid = MMGenImmutableAttr('twmmid','TwMMGenID')
|
||||
addr = MMGenImmutableAttr('addr','CoinAddr')
|
||||
confs = MMGenImmutableAttr('confs',int,typeconv=False)
|
||||
scriptPubKey = MMGenImmutableAttr('scriptPubKey','HexStr')
|
||||
scriptPubKey = MMGenImmutableAttr('scriptPubKey','HexBytes')
|
||||
days = MMGenListItemAttr('days',int,typeconv=False)
|
||||
skip = MMGenListItemAttr('skip',str,typeconv=False,reassign_ok=True)
|
||||
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
|
|||
|
||||
class MMGenTxInput(MMGenListItem):
|
||||
for k in txio_attrs: locals()[k] = txio_attrs[k] # in lieu of inheritance
|
||||
scriptPubKey = MMGenListItemAttr('scriptPubKey','HexStr')
|
||||
scriptPubKey = MMGenListItemAttr('scriptPubKey','HexBytes')
|
||||
sequence = MMGenListItemAttr('sequence',(int,int)[g.platform=='win'],typeconv=False)
|
||||
|
||||
class MMGenTxOutput(MMGenListItem):
|
||||
|
|
@ -368,7 +368,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
|
|||
if self.inputs[0].sequence:
|
||||
i[0]['sequence'] = self.inputs[0].sequence
|
||||
o = dict([(e.addr,e.amt) for e in self.outputs])
|
||||
self.hex = g.rpch.createrawtransaction(i,o)
|
||||
self.hex = HexBytes(g.rpch.createrawtransaction(i,o))
|
||||
self.update_txid()
|
||||
|
||||
# returns true if comment added or changed
|
||||
|
|
@ -729,7 +729,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
|
|||
return False
|
||||
|
||||
try:
|
||||
self.hex = ret['hex']
|
||||
self.hex = HexBytes(ret['hex'])
|
||||
self.compare_size_and_estimated_size()
|
||||
dt = DeserializedTX(self.hex)
|
||||
self.check_hex_tx_matches_mmgen_tx(dt)
|
||||
|
|
@ -1113,7 +1113,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
|
|||
return out # TX label might contain non-ascii chars
|
||||
|
||||
def check_txfile_hex_data(self):
|
||||
self.hex = HexStr(self.hex,on_fail='raise')
|
||||
self.hex = HexBytes(self.hex,on_fail='raise')
|
||||
|
||||
def parse_tx_file(self,infile,metadata_only=False,silent_open=False):
|
||||
|
||||
|
|
|
|||
|
|
@ -241,6 +241,8 @@ def is_int(s):
|
|||
|
||||
# https://en.wikipedia.org/wiki/Base32#RFC_4648_Base32_alphabet
|
||||
# https://tools.ietf.org/html/rfc4648
|
||||
def is_hex_bytes(s): return set(list(s.lower())) <= set(list(hexdigits.lower().encode()))
|
||||
|
||||
def is_hex_str(s): return set(list(s.lower())) <= set(list(hexdigits.lower()))
|
||||
def is_hex_str_lc(s): return set(list(s)) <= set(list(hexdigits.lower()))
|
||||
def is_hex_str_uc(s): return set(list(s)) <= set(list(hexdigits.upper()))
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ tests = OrderedDict([
|
|||
'F00BAA12:S:9999999 comment',
|
||||
tw_pfx+'x comment')
|
||||
}),
|
||||
('HexStr', {
|
||||
('HexBytes', {
|
||||
'bad': (1,[],'\0','\1','я','g','gg','FF','f00'),
|
||||
'good': ('deadbeef','f00baa12')
|
||||
}),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue