From 785582e30de653371a5704aa395b753a6ca13d24 Mon Sep 17 00:00:00 2001 From: MMGen Date: Tue, 19 Mar 2019 15:04:18 +0000 Subject: [PATCH] MMGenTxInput, MMGenTxOutput: make 'amt' attribute a property - type checking 'amt' at runtime eliminates the need to reload tx module when g.proto changes --- mmgen/main_autosign.py | 5 ----- mmgen/main_split.py | 1 - mmgen/obj.py | 14 +++++++++----- mmgen/tx.py | 18 +++++++++++++++++- scripts/test-release.sh | 2 +- scripts/tx-btc2bch.py | 2 -- test/unit_tests.py | 3 --- 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/mmgen/main_autosign.py b/mmgen/main_autosign.py index f91554f0..73d6d0e2 100755 --- a/mmgen/main_autosign.py +++ b/mmgen/main_autosign.py @@ -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': diff --git a/mmgen/main_split.py b/mmgen/main_split.py index 3aaedaaa..9e4045f1 100755 --- a/mmgen/main_split.py +++ b/mmgen/main_split.py @@ -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 diff --git a/mmgen/obj.py b/mmgen/obj.py index 6fed1360..7947f050 100755 --- a/mmgen/obj.py +++ b/mmgen/obj.py @@ -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: diff --git a/mmgen/tx.py b/mmgen/tx.py index 1498c40a..e4bb0301 100755 --- a/mmgen/tx.py +++ b/mmgen/tx.py @@ -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) diff --git a/scripts/test-release.sh b/scripts/test-release.sh index 7a0e5c7f..6dd4d1bc 100755 --- a/scripts/test-release.sh +++ b/scripts/test-release.sh @@ -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' diff --git a/scripts/tx-btc2bch.py b/scripts/tx-btc2bch.py index d32f4522..60cfc98c 100755 --- a/scripts/tx-btc2bch.py +++ b/scripts/tx-btc2bch.py @@ -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)) diff --git a/test/unit_tests.py b/test/unit_tests.py index f588f060..5a44043f 100755 --- a/test/unit_tests.py +++ b/test/unit_tests.py @@ -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