Browse Source

proto.eth.tx: minor cleanups, fixes

The MMGen Project 2 weeks ago
parent
commit
ef640d10a9

+ 13 - 11
mmgen/proto/eth/contract.py

@@ -21,6 +21,8 @@ proto.eth.contract: Ethereum ERC20 token classes
 """
 
 from decimal import Decimal
+from collections import namedtuple
+
 from . import rlp
 
 from . import erigon_sleep
@@ -135,21 +137,21 @@ class TokenCommon(MMGenObject):
 			res = await self.rpc.call('eth_chainId')
 			chain_id = None if res is None else int(res, 16)
 
-		tx = Transaction(**tx_in).sign(key, chain_id)
+		etx = Transaction(**tx_in).sign(key, chain_id)
 
-		if tx.sender.hex() != from_addr:
-			die(3, f'Sender address {from_addr!r} does not match address of key {tx.sender.hex()!r}!')
+		if etx.sender.hex() != from_addr:
+			die(3, f'Sender address {from_addr!r} does not match address of key {etx.sender.hex()!r}!')
 
 		if self.cfg.debug:
 			msg('TOKEN DATA:')
-			pp_msg(tx.to_dict())
+			pp_msg(etx.to_dict())
 			msg('PARSED ABI DATA:\n  {}'.format(
-				'\n  '.join(parse_abi(tx.data.hex()))))
+				'\n  '.join(parse_abi(etx.data.hex()))))
 
-		return (
-			rlp.encode(tx).hex(),
-			CoinTxID(tx.hash.hex())
-		)
+		return namedtuple('signed_contract_transaction', ['etx', 'txhex', 'txid'])(
+			etx,
+			rlp.encode(etx).hex(),
+			CoinTxID(etx.hash.hex()))
 
 # The following are used for token deployment only:
 
@@ -173,8 +175,8 @@ class TokenCommon(MMGenObject):
 				gasPrice,
 				nonce = int(await self.rpc.call('eth_getTransactionCount', '0x'+from_addr, 'pending'), 16),
 				method_sig = method_sig)
-		txhex, _ = await self.txsign(tx_in, key, from_addr)
-		return await self.txsend(txhex)
+		res = await self.txsign(tx_in, key, from_addr)
+		return await self.txsend(res.txhex)
 
 class Token(TokenCommon):
 

+ 4 - 7
mmgen/proto/eth/tx/info.py

@@ -30,11 +30,8 @@ class TxInfo(TxInfo):
 
 	def format_body(self, blockcount, nonmm_str, max_mmwid, enl, *, terse, sort):
 		tx = self.tx
-		m = {}
-		for k in ('inputs', 'outputs'):
-			if len(getattr(tx, k)):
-				m[k] = getattr(tx, k)[0].mmid if len(getattr(tx, k)) else ''
-				m[k] = ' ' + m[k].hl() if m[k] else ' ' + MMGenID.hlc(nonmm_str)
+		def mmid_disp(io):
+			return ' ' + (io.mmid.hl() if io.mmid else MMGenID.hlc(nonmm_str))
 		fs = """
 			From:      {f}{f_mmid}
 			To:        {t}{t_mmid}
@@ -56,8 +53,8 @@ class TxInfo(TxInfo):
 			c      = tx.proto.dcoin if len(tx.outputs) else '',
 			g      = yellow(tx.pretty_fmt_fee(t['gasPrice'].to_unit('Gwei'))),
 			G      = yellow(tx.pretty_fmt_fee(t['startGas'].to_unit('Kwei'))),
-			t_mmid = m['outputs'] if len(tx.outputs) else '',
-			f_mmid = m['inputs']) + '\n\n'
+			f_mmid = mmid_disp(tx.inputs[0]),
+			t_mmid = mmid_disp(tx.outputs[0]) if tx.outputs else '') + '\n\n'
 
 	def format_abs_fee(self, iwidth, /, *, color=None):
 		return self.tx.fee.fmt(iwidth, color=color) + (' (max)' if self.tx.txobj['data'] else '')

+ 11 - 9
mmgen/proto/eth/tx/unsigned.py

@@ -40,8 +40,7 @@ class Unsigned(Completed, TxBase.Unsigned):
 		self.txobj = o
 		return d # 'token_addr', 'decimals' required by Token subclass
 
-	async def do_sign(self, wif):
-		o = self.txobj
+	async def do_sign(self, o, wif):
 		o_conv = {
 			'to':       bytes.fromhex(o['to'] or ''),
 			'startgas': o['startGas'].toWei(),
@@ -59,10 +58,10 @@ class Unsigned(Completed, TxBase.Unsigned):
 		self.serialized = rlp.encode(etx).hex()
 		self.coin_txid = CoinTxID(etx.hash.hex())
 
-		if o['data']:
+		if o['data']: # contract-creating transaction
 			if o['to']:
-				assert self.txobj['token_addr'] == TokenAddr(self.proto, etx.creates.hex()), 'Token address mismatch'
-			else: # token- or contract-creating transaction
+				raise ValueError('contract-creating transaction cannot have to-address')
+			else:
 				self.txobj['token_addr'] = TokenAddr(self.proto, etx.creates.hex())
 
 	async def sign(self, tx_num_str, keys): # return TX object or False; don't exit or raise exception
@@ -73,10 +72,12 @@ class Unsigned(Completed, TxBase.Unsigned):
 		except TransactionChainMismatch:
 			return False
 
+		o = self.txobj
+
 		msg_r(f'Signing transaction{tx_num_str}...')
 
 		try:
-			await self.do_sign(keys[0].sec.wif)
+			await self.do_sign(o, keys[0].sec.wif)
 			msg('OK')
 			from ....tx import SignedTX
 			return await SignedTX(cfg=self.cfg, data=self.__dict__, automount=self.automount)
@@ -96,8 +97,7 @@ class TokenUnsigned(TokenCompleted, Unsigned):
 		o['data'] = t.create_data(o['to'], o['amt'])
 		o['token_to'] = t.transferdata2sendaddr(o['data'])
 
-	async def do_sign(self, wif):
-		o = self.txobj
+	async def do_sign(self, o, wif):
 		t = Token(self.cfg, self.proto, o['token_addr'], o['decimals'])
 		tx_in = t.make_tx_in(
 				to_addr   = o['to'],
@@ -105,7 +105,9 @@ class TokenUnsigned(TokenCompleted, Unsigned):
 				start_gas = self.start_gas,
 				gasPrice  = o['gasPrice'],
 				nonce     = o['nonce'])
-		(self.serialized, self.coin_txid) = await t.txsign(tx_in, wif, o['from'], chain_id=o['chainId'])
+		res = await t.txsign(tx_in, wif, o['from'], chain_id=o['chainId'])
+		self.serialized = res.txhex
+		self.coin_txid = res.txid
 
 class AutomountUnsigned(TxBase.AutomountUnsigned, Unsigned):
 	pass

+ 9 - 5
test/cmdtest_d/ct_ethdev.py

@@ -721,9 +721,9 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
 			self.eth_args
 			+ [f'--coin={self.proto.coin}']
 			+ ['--rpc-host=bad_host'] # ETH signing must work without RPC
-			+ add_args
 			+ ([], ['--yes'])[ni]
 			+ ([f'--keys-from-file={keyfile}'] if dev_send else [])
+			+ add_args
 			+ [txfile, dfl_words_file])
 		return self.txsign_ui_common(t, ni=ni, has_label=True)
 
@@ -924,7 +924,7 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
 		return t
 
 	def txsign4(self):
-		return self.txsign(ni=True, ext='.45495,50000]{}.regtest.rawtx', dev_send=True)
+		return self.txsign(ext='.45495,50000]{}.regtest.rawtx', add_args=['--no-quiet', '--no-yes'])
 	def txsend4(self):
 		return self.txsend(ext='.45495,50000]{}.regtest.sigtx')
 	def bal4(self):
@@ -1222,8 +1222,8 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
 			input_sels_prompt = 'to spend from',
 			add_comment       = tx_comment_lat_cyr_gr,
 			file_desc         = file_desc)
-	def token_txsign(self, ext='', token=''):
-		return self.txsign(ni=True, ext=ext, add_args=['--token='+token])
+	def token_txsign(self, ext='', token='', add_args=[], ni=True):
+		return self.txsign(ni=ni, ext=ext, add_args=[f'--token={token}'] + add_args)
 	def token_txsend(self, ext='', token=''):
 		return self.txsend(ext=ext, add_args=['--token='+token])
 
@@ -1232,7 +1232,11 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
 	def token_txview1_raw(self):
 		return self.txview(ext_fs='1.23456,50000]{}.regtest.rawtx')
 	def token_txsign1(self):
-		return self.token_txsign(ext='1.23456,50000]{}.regtest.rawtx', token='mm1')
+		return self.token_txsign(
+			ext = '1.23456,50000]{}.regtest.rawtx',
+			token = 'mm1',
+			ni = False,
+			add_args = ['--no-quiet', '--no-yes'])
 	def token_txsend1(self):
 		return self.token_txsend(ext='1.23456,50000]{}.regtest.sigtx', token='mm1')
 	def token_txview1_sig(self):