MMGenTxInput, MMGenTxOutput: make 'amt' attribute a property

- type checking 'amt' at runtime eliminates the need to reload tx module
  when g.proto changes
This commit is contained in:
The MMGen Project 2019-03-19 15:04:18 +00:00
commit 785582e30d
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
7 changed files with 27 additions and 18 deletions

View file

@ -162,7 +162,6 @@ def do_umount():
subprocess.call(['umount',mountpoint])
def sign_tx_file(txfile):
from importlib import reload
try:
g.testnet = False
g.coin = 'BTC'
@ -183,10 +182,6 @@ def sign_tx_file(txfile):
g.token = tmp_tx.dcoin
g.dcoin = tmp_tx.dcoin or g.coin
reload(sys.modules['mmgen.tx'])
if g.proto.base_coin == 'ETH':
reload(sys.modules['mmgen.altcoins.eth.tx'])
tx = mmgen.tx.MMGenTX(txfile)
if g.proto.sign_mode == 'daemon':

View file

@ -119,7 +119,6 @@ tx1.create_fn()
gmsg("\nCreating transaction for short chain ({})".format(opt.other_coin))
init_coin(opt.other_coin)
reload(sys.modules['mmgen.tx'])
tx2 = MMGenSplitTX()
tx2.inputs = tx1.inputs

View file

@ -192,9 +192,10 @@ class Hilite(object):
# Reassignment and deletion forbidden
class MMGenImmutableAttr(object): # Descriptor
def __init__(self,name,dtype,typeconv=True):
def __init__(self,name,dtype,typeconv=True,no_type_check=False):
self.typeconv = typeconv
assert type(dtype) in (str,type)
self.no_type_check = no_type_check
assert type(dtype) in (str,type) or dtype is None
self.name = name
self.dtype = dtype
@ -214,10 +215,11 @@ class MMGenImmutableAttr(object): # Descriptor
instance.__dict__[self.name] = \
globals()[self.dtype](value,on_fail='raise') if type(self.dtype) == str else self.dtype(value)
else: # check type
if type(value) != self.dtype:
if type(value) == self.dtype or self.no_type_check:
instance.__dict__[self.name] = value
else:
m = "Attribute '{}' of {} instance must of type {}"
raise TypeError(m.format(self.name,type(instance),self.dtype))
instance.__dict__[self.name] = value
def __delete__(self,instance):
m = "Atribute '{}' of {} instance cannot be deleted"
@ -250,11 +252,13 @@ class MMGenListItemAttr(MMGenImmutableAttr): # Descriptor
class MMGenListItem(MMGenObject):
valid_attrs = None
valid_attrs_extra = set()
def __init__(self,*args,**kwargs):
if self.valid_attrs == None:
type(self).valid_attrs = (
{e for e in dir(self) if e[:2] != '__'} - {'pformat','pmsg','pdie','valid_attrs'} )
( {e for e in dir(self) if e[:2] != '__'} | self.valid_attrs_extra ) -
{'pformat','pmsg','pdie','valid_attrs','valid_attrs_extra'} )
if args:
raise ValueError('Non-keyword args not allowed')
for k in kwargs:

View file

@ -209,7 +209,7 @@ class DeserializedTX(dict,MMGenObject):
class MMGenTxIO(MMGenListItem):
vout = MMGenListItemAttr('vout',int,typeconv=False)
amt = MMGenImmutableAttr('amt',g.proto.coin_amt,typeconv=False) # require amt to be of proper type
_amt = MMGenImmutableAttr('amt',None,no_type_check=True,typeconv=False)
label = MMGenListItemAttr('label','TwComment',reassign_ok=True)
mmid = MMGenListItemAttr('mmid','MMGenID')
addr = MMGenImmutableAttr('addr','CoinAddr')
@ -217,6 +217,22 @@ class MMGenTxIO(MMGenListItem):
txid = MMGenListItemAttr('txid','CoinTxID')
have_wif = MMGenListItemAttr('have_wif',bool,typeconv=False,delete_ok=True)
valid_attrs_extra = {'amt'}
# Setting self.amt is runtime-dependent, so make it a property
# Make underlying self._amt an MMGenImmutableAttr so that reassignment is prevented
@property
def amt(self):
if type(self._amt) != g.proto.coin_amt:
raise ValueError('{}: invalid coin_amt type (must be {})'.format(type(self._amt),g.proto.coin_amt))
return self._amt
@amt.setter
def amt(self,val):
if type(val) != g.proto.coin_amt:
raise ValueError('{}: invalid coin_amt type (must be {})'.format(type(val),g.proto.coin_amt))
self._amt = val
class MMGenTxInput(MMGenTxIO):
scriptPubKey = MMGenListItemAttr('scriptPubKey','HexStr')
sequence = MMGenListItemAttr('sequence',int,typeconv=False)

View file

@ -164,7 +164,7 @@ t_obj=(
"$objtest_py --coin=ltc --testnet=1")
f_obj='Data object test complete'
i_unit='Unit tests'
i_unit='Unit'
s_unit='Running unit'
t_unit=("$unit_tests_py")
f_unit='Unit tests run complete'

View file

@ -48,8 +48,6 @@ if opt.verbose:
from mmgen.protocol import init_coin
init_coin('BCH')
reload(sys.modules['mmgen.tx'])
if opt.verbose:
gmsg('Converting transaction to {} format'.format(g.coin))

View file

@ -137,16 +137,13 @@ class UnitTests(object):
('bch',False,'test/ref/460D4D-BCH[10.19764,tl=1320969600].rawtx') )
from mmgen.protocol import init_coin
from mmgen.tx import MMGenTX
from importlib import reload
print_info('test/ref/*rawtx','MMGen reference transactions')
for n,(coin,tn,fn) in enumerate(fns):
init_coin(coin,tn)
rpc_init(reinit=True)
reload(sys.modules['mmgen.tx'])
test_tx(MMGenTX(fn).hex,fn,n+1)
init_coin('btc',False)
rpc_init(reinit=True)
reload(sys.modules['mmgen.tx'])
Msg('OK')
from mmgen.tx import DeserializedTX