Browse Source

autosign: support testnet, ERC20 tokens

MMGen 6 years ago
parent
commit
4df12def5f

+ 28 - 1
mmgen/main_autosign.py

@@ -101,6 +101,7 @@ This command is currently available only on Linux-based platforms.
 cmd_args = opts.init(opts_data,add_opts=['mmgen_keys_from_file','in_fmt'])
 cmd_args = opts.init(opts_data,add_opts=['mmgen_keys_from_file','in_fmt'])
 
 
 import mmgen.tx
 import mmgen.tx
+import mmgen.altcoins.eth.tx
 from mmgen.txsign import txsign
 from mmgen.txsign import txsign
 from mmgen.protocol import CoinProtocol,init_coin
 from mmgen.protocol import CoinProtocol,init_coin
 
 
@@ -155,14 +156,40 @@ def do_umount():
 
 
 def sign_tx_file(txfile):
 def sign_tx_file(txfile):
 	try:
 	try:
-		init_coin(mmgen.tx.MMGenTX(txfile,coin_sym_only=True).coin)
+		g.testnet = False
+		g.coin = 'BTC'
+		tmp_tx = mmgen.tx.MMGenTX(txfile,metadata_only=True)
+		init_coin(tmp_tx.coin)
+
+		if tmp_tx.chain != 'mainnet':
+			if tmp_tx.chain == 'testnet' or (
+				hasattr(g.proto,'chain_name') and tmp_tx.chain != g.proto.chain_name):
+				g.testnet = True
+				init_coin(tmp_tx.coin)
+
+		if hasattr(g.proto,'chain_name'):
+			m = 'Protocol chain name ({}) does not match chain name from TX file ({})'
+			assert tmp_tx.chain == g.proto.chain_name, m.format(tmp_tx.chain,g.proto.chain_name)
+
+		g.chain = tmp_tx.chain
+		g.token = tmp_tx.dcoin
+		g.dcoin = tmp_tx.dcoin or g.coin
+
 		reload(sys.modules['mmgen.tx'])
 		reload(sys.modules['mmgen.tx'])
+		if g.coin == 'ETH':
+			reload(sys.modules['mmgen.altcoins.eth.tx'])
+
 		tx = mmgen.tx.MMGenTX(txfile)
 		tx = mmgen.tx.MMGenTX(txfile)
+
 		if g.proto.sign_mode == 'daemon':
 		if g.proto.sign_mode == 'daemon':
 			rpc_init(reinit=True)
 			rpc_init(reinit=True)
+
 		txsign(tx,wfs,None,None)
 		txsign(tx,wfs,None,None)
 		tx.write_to_file(ask_write=False)
 		tx.write_to_file(ask_write=False)
 		return True
 		return True
+	except Exception as e:
+		msg('An error occurred: {}'.format(e))
+		return False
 	except:
 	except:
 		return False
 		return False
 
 

+ 2 - 0
mmgen/obj.py

@@ -304,6 +304,8 @@ class AddrIdxList(list,InitErrors,MMGenObject):
 			m = "{!r}: value cannot be converted to AddrIdxList ({})"
 			m = "{!r}: value cannot be converted to AddrIdxList ({})"
 			return type(self).init_fail(m.format(idx_list or fmt_str,e[0]),on_fail)
 			return type(self).init_fail(m.format(idx_list or fmt_str,e[0]),on_fail)
 
 
+class UnknownCoinAmt(Decimal): pass
+
 class BTCAmt(Decimal,Hilite,InitErrors):
 class BTCAmt(Decimal,Hilite,InitErrors):
 	color = 'yellow'
 	color = 'yellow'
 	max_prec = 8
 	max_prec = 8

+ 16 - 10
mmgen/tx.py

@@ -272,7 +272,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 		desc = 'transaction outputs'
 		desc = 'transaction outputs'
 		member_type = 'MMGenTxOutput'
 		member_type = 'MMGenTxOutput'
 
 
-	def __init__(self,filename=None,coin_sym_only=False,caller=None,silent_open=False):
+	def __init__(self,filename=None,metadata_only=False,caller=None,silent_open=False):
 		self.inputs      = self.MMGenTxInputList()
 		self.inputs      = self.MMGenTxInputList()
 		self.outputs     = self.MMGenTxOutputList()
 		self.outputs     = self.MMGenTxOutputList()
 		self.send_amt    = g.proto.coin_amt('0')  # total amt minus change
 		self.send_amt    = g.proto.coin_amt('0')  # total amt minus change
@@ -293,8 +293,8 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 		self.locktime    = None
 		self.locktime    = None
 
 
 		if filename:
 		if filename:
-			self.parse_tx_file(filename,coin_sym_only=coin_sym_only,silent_open=silent_open)
-			if coin_sym_only: return
+			self.parse_tx_file(filename,metadata_only=metadata_only,silent_open=silent_open)
+			if metadata_only: return
 			self.check_pubkey_scripts()
 			self.check_pubkey_scripts()
 			self.check_sigs() # marks the tx as signed
 			self.check_sigs() # marks the tx as signed
 
 
@@ -1114,7 +1114,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 	def check_txfile_hex_data(self):
 	def check_txfile_hex_data(self):
 		self.hex = HexStr(self.hex,on_fail='raise')
 		self.hex = HexStr(self.hex,on_fail='raise')
 
 
-	def parse_tx_file(self,infile,coin_sym_only=False,silent_open=False):
+	def parse_tx_file(self,infile,metadata_only=False,silent_open=False):
 
 
 		def eval_io_data(raw_data,desc):
 		def eval_io_data(raw_data,desc):
 			from ast import literal_eval
 			from ast import literal_eval
@@ -1176,19 +1176,25 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 			if ':' in self.coin:
 			if ':' in self.coin:
 				self.coin,self.dcoin = self.coin.split(':')
 				self.coin,self.dcoin = self.coin.split(':')
 
 
-			if coin_sym_only: return
-
 			if len(metadata) == 5:
 			if len(metadata) == 5:
 				t = metadata.pop(0)
 				t = metadata.pop(0)
 				self.chain = (t.lower(),None)[t=='Unknown']
 				self.chain = (t.lower(),None)[t=='Unknown']
 
 
 			desc = 'metadata (4 items minimum required)'
 			desc = 'metadata (4 items minimum required)'
-			self.txid,send_amt,self.timestamp,blockcount = metadata
-			desc = 'metadata'
-			self.txid = MMGenTxID(self.txid,on_fail='raise')
-			self.send_amt = g.proto.coin_amt(send_amt,on_fail='raise')
+			txid,send_amt,self.timestamp,blockcount = metadata
+
+			desc = 'txid in metadata'
+			self.txid = MMGenTxID(txid,on_fail='raise')
+			desc = 'send amount in metadata'
+			self.send_amt = UnknownCoinAmt(send_amt) # temporary, for 'metadata_only'
 			desc = 'block count in metadata'
 			desc = 'block count in metadata'
 			self.blockcount = int(blockcount)
 			self.blockcount = int(blockcount)
+
+			if metadata_only: return
+
+			desc = 'send amount in metadata'
+			self.send_amt = g.proto.coin_amt(send_amt,on_fail='raise')
+
 			desc = 'transaction hex data'
 			desc = 'transaction hex data'
 			self.check_txfile_hex_data()
 			self.check_txfile_hex_data()
 			# the following ops will all fail if g.coin doesn't match self.coin
 			# the following ops will all fail if g.coin doesn't match self.coin

+ 1 - 1
scripts/test-release.sh

@@ -217,7 +217,7 @@ t_eth=(
 f_eth='Ethereum tests completed'
 f_eth='Ethereum tests completed'
 
 
 i_autosign='Autosign'
 i_autosign='Autosign'
-s_autosign='The bitcoin, bitcoin-abc and litecoin (mainnet) daemons must be running for the following test'
+s_autosign='The bitcoin, bitcoin-abc and litecoin mainnet and testnet daemons must be running for the following test'
 t_autosign=("$test_py -On autosign")
 t_autosign=("$test_py -On autosign")
 f_autosign='Autosign test complete'
 f_autosign='Autosign test complete'
 
 

+ 6 - 0
test/ref/ethereum/5881D2-MM1[1.23456,50000].rawtx

@@ -0,0 +1,6 @@
+1a6cfb
+ETH:MM1 FOUNDATION 5881D2 1.23456 20180729_000000 1234567
+{"nonce": "0", "chainId": "1", "from": "0d25b006dfa012b17da252e852b6e2b5ebf5ddc8", "token_addr": "d5f051401ca478b34c80d0b5a119e437dc6d9df5", "data": "", "startGas": "0.00000000000006", "to": "6e0fbe42e1343309b3ccb9068dbad6132f86c96f", "decimals": "18", "amt": "1.23456", "gasPrice": "0.00000005"}
+[{'confs': 0, 'label': u'', 'mmid': '98831F3A:E:11', 'amt': '1000', 'addr': '0d25b006dfa012b17da252e852b6e2b5ebf5ddc8'}]
+[{'is_chg': False, 'mmid': '98831F3A:E:12', 'amt': '1.23456', 'addr': '6e0fbe42e1343309b3ccb9068dbad6132f86c96f'}]
+TvwWgaAnrkQFpAxxjBa4PHvJ8NsJDsurtiv2HuzdnXWjQmY7LHyt6PZn5J7BNtB5VzHtBG7bUosCAMFon8yxUe2mYTZoH9e6dpoAz9E6JDZtUNYz9YnF1Z3jFND1X89RuKAk6YVBrfWseeyHR8vZDdaFzBPK5SPos

+ 6 - 0
test/ref/ethereum/6BDB25-MM1[1.23456,50000].testnet.rawtx

@@ -0,0 +1,6 @@
+334f63
+ETH:MM1 KOVAN 6BDB25 1.23456 20180729_111111 7654321
+{"nonce": "0", "chainId": "42", "from": "69b2da9c0646d79ef461c79eba14943352590e4b", "token_addr": "d5f051401ca478b34c80d0b5a119e437dc6d9df5", "data": "", "startGas": "0.00000000000006", "to": "1e94936c64ef12fd4991537b714d4946839699a4", "decimals": "18", "amt": "1.23456", "gasPrice": "0.00000005"}
+[{'confs': 0, 'label': u'', 'mmid': '98831F3A:E:11', 'amt': '1000', 'addr': '69b2da9c0646d79ef461c79eba14943352590e4b'}]
+[{'is_chg': False, 'mmid': '98831F3A:E:12', 'amt': '1.23456', 'addr': '1e94936c64ef12fd4991537b714d4946839699a4'}]
+TvwWgaAnrkQFpAxxjBa4PHvJ8NsJDsurtiv2HuzdnXWjQmY7LHyt6PZn5J7BNtB5VzHtBG7bUosCAMFon8yxUe2mYTZoH9e6dpoAz9E6JDZtUNYz9YnF1Z3jFND1X89RuKAk6YVBrfWseeyHR8vZDdaFzBPK5SPos

+ 8 - 5
test/test.py

@@ -583,7 +583,9 @@ cfgs = {
 			'ltc': ('AF3CDF-LTC[620.76194,1453,tl=1320969600].rawtx',
 			'ltc': ('AF3CDF-LTC[620.76194,1453,tl=1320969600].rawtx',
 					'A5A1E0-LTC[1454.64322,1453,tl=1320969600].testnet.rawtx'),
 					'A5A1E0-LTC[1454.64322,1453,tl=1320969600].testnet.rawtx'),
 			'eth': ('88FEFD-ETH[23.45495,40000].rawtx',
 			'eth': ('88FEFD-ETH[23.45495,40000].rawtx',
-					'B472BD-ETH[23.45495,40000].testnet.rawtx')
+					'B472BD-ETH[23.45495,40000].testnet.rawtx'),
+			'erc20': ('5881D2-MM1[1.23456,50000].rawtx',
+					'6BDB25-MM1[1.23456,50000].testnet.rawtx')
 		},
 		},
 		'ic_wallet':       u'98831F3A-5482381C-18460FB1[256,1].mmincog',
 		'ic_wallet':       u'98831F3A-5482381C-18460FB1[256,1].mmincog',
 		'ic_wallet_hex':   u'98831F3A-1630A9F2-870376A9[256,1].mmincox',
 		'ic_wallet_hex':   u'98831F3A-1630A9F2-870376A9[256,1].mmincox',
@@ -2314,9 +2316,10 @@ class MMGenTestSuite(object):
 
 
 	def autosign(self,name): # tests everything except device detection, mount/unmount
 	def autosign(self,name): # tests everything except device detection, mount/unmount
 		if skip_for_win(): return
 		if skip_for_win(): return
-		fdata = (('btc',''),('bch',''),('ltc','litecoin'),('eth','ethereum'))
-		tfns = [cfgs['8']['ref_tx_file'][c][0] for c,d in fdata]
-		tfs = [os.path.join(ref_dir,d[1],fn) for d,fn in zip(fdata,tfns)]
+		fdata = (('btc',''),('bch',''),('ltc','litecoin'),('eth','ethereum'),('erc20','ethereum'))
+		tfns  = [cfgs['8']['ref_tx_file'][c][1] for c,d in fdata] + \
+				[cfgs['8']['ref_tx_file'][c][0] for c,d in fdata]
+		tfs = [os.path.join(ref_dir,d[1],fn) for d,fn in zip(fdata+fdata,tfns)]
 		try: os.mkdir(os.path.join(cfg['tmpdir'],'tx'))
 		try: os.mkdir(os.path.join(cfg['tmpdir'],'tx'))
 		except: pass
 		except: pass
 		for f,fn in zip(tfs,tfns):
 		for f,fn in zip(tfs,tfns):
@@ -2341,7 +2344,7 @@ class MMGenTestSuite(object):
 		t.ok()
 		t.ok()
 
 
 		t = MMGenExpect(name,'mmgen-autosign',opts+['wait'],extra_desc='(sign)')
 		t = MMGenExpect(name,'mmgen-autosign',opts+['wait'],extra_desc='(sign)')
-		t.expect('4 transactions signed')
+		t.expect('10 transactions signed')
 		t.expect('1 transaction failed to sign')
 		t.expect('1 transaction failed to sign')
 		t.expect('Waiting.')
 		t.expect('Waiting.')
 		t.kill(2)
 		t.kill(2)