Browse Source

tx: new `Sent` class; tx.send() clean up error handling

The MMGen Project 8 months ago
parent
commit
8d6f9f598b

+ 2 - 2
mmgen/main_txbump.py

@@ -175,8 +175,8 @@ async def main():
 		if tx3:
 		if tx3:
 			tx4 = await OnlineSignedTX(cfg=cfg,data=tx3.__dict__)
 			tx4 = await OnlineSignedTX(cfg=cfg,data=tx3.__dict__)
 			tx4.file.write(ask_write=False)
 			tx4.file.write(ask_write=False)
-			await tx4.send(exit_on_fail=True)
-			tx4.file.write(ask_write=False)
+			if await tx4.send():
+				tx4.file.write(ask_write=False)
 		else:
 		else:
 			die(2,'Transaction could not be signed')
 			die(2,'Transaction could not be signed')
 	else:
 	else:

+ 6 - 6
mmgen/main_txdo.py

@@ -124,7 +124,7 @@ FMT CODES:
 
 
 cfg = Config(opts_data=opts_data)
 cfg = Config(opts_data=opts_data)
 
 
-from .tx import NewTX,OnlineSignedTX
+from .tx import NewTX, SentTX
 from .tx.sign import txsign,get_seed_files,get_keyaddrlist,get_keylist
 from .tx.sign import txsign,get_seed_files,get_keyaddrlist,get_keylist
 
 
 seed_files = get_seed_files(cfg,cfg._args)
 seed_files = get_seed_files(cfg,cfg._args)
@@ -147,11 +147,11 @@ async def main():
 	tx3 = await txsign(cfg,tx2,seed_files,kl,kal)
 	tx3 = await txsign(cfg,tx2,seed_files,kl,kal)
 
 
 	if tx3:
 	if tx3:
-		tx4 = await OnlineSignedTX(cfg=cfg,data=tx3.__dict__)
-		tx4.file.write(ask_write=False)
-		await tx4.send(exit_on_fail=True)
-		tx4.file.write(ask_overwrite=False,ask_write=False)
-		tx4.print_contract_addr()
+		tx3.file.write(ask_write=False)
+		tx4 = await SentTX(cfg=cfg, data=tx3.__dict__)
+		if await tx4.send():
+			tx4.file.write(ask_overwrite=False,ask_write=False)
+			tx4.print_contract_addr()
 	else:
 	else:
 		die(2,'Transaction could not be signed')
 		die(2,'Transaction could not be signed')
 
 

+ 7 - 6
mmgen/main_txsend.py

@@ -56,7 +56,7 @@ if not cfg.status:
 
 
 async def main():
 async def main():
 
 
-	from .tx import OnlineSignedTX
+	from .tx import OnlineSignedTX, SentTX
 
 
 	tx = await OnlineSignedTX(
 	tx = await OnlineSignedTX(
 		cfg        = cfg,
 		cfg        = cfg,
@@ -79,10 +79,11 @@ async def main():
 		if tx.add_comment(): # edits an existing comment, returns true if changed
 		if tx.add_comment(): # edits an existing comment, returns true if changed
 			tx.file.write(ask_write_default_yes=True)
 			tx.file.write(ask_write_default_yes=True)
 
 
-	await tx.send(exit_on_fail=True)
-	tx.file.write(
-		ask_overwrite = False,
-		ask_write     = False)
-	tx.print_contract_addr()
+	if await tx.send():
+		tx2 = await SentTX(cfg=cfg, data=tx.__dict__)
+		tx2.file.write(
+			ask_overwrite = False,
+			ask_write     = False)
+		tx2.print_contract_addr()
 
 
 async_run(main())
 async_run(main())

+ 11 - 12
mmgen/proto/btc/tx/online.py

@@ -12,15 +12,14 @@
 proto.btc.tx.online: Bitcoin online signed transaction class
 proto.btc.tx.online: Bitcoin online signed transaction class
 """
 """
 
 
-import sys
-
 from ....tx import online as TxBase
 from ....tx import online as TxBase
-from ....util import msg,ymsg,rmsg,die
+from ....util import msg,die
+from ....color import orange
 from .signed import Signed
 from .signed import Signed
 
 
 class OnlineSigned(Signed,TxBase.OnlineSigned):
 class OnlineSigned(Signed,TxBase.OnlineSigned):
 
 
-	async def send(self,prompt_user=True,exit_on_fail=False):
+	async def send(self,prompt_user=True):
 
 
 		self.check_correct_chain()
 		self.check_correct_chain()
 
 
@@ -49,6 +48,7 @@ class OnlineSigned(Signed,TxBase.OnlineSigned):
 				ret = await self.rpc.call('sendrawtransaction',self.serialized)
 				ret = await self.rpc.call('sendrawtransaction',self.serialized)
 			except Exception as e:
 			except Exception as e:
 				errmsg = str(e)
 				errmsg = str(e)
+				nl = '\n'
 				if errmsg.count('Signature must use SIGHASH_FORKID'):
 				if errmsg.count('Signature must use SIGHASH_FORKID'):
 					m = (
 					m = (
 						'The Aug. 1 2017 UAHF has activated on this chain.\n'
 						'The Aug. 1 2017 UAHF has activated on this chain.\n'
@@ -61,20 +61,19 @@ class OnlineSigned(Signed,TxBase.OnlineSigned):
 					m = "Transaction with nLockTime {!r} can't be included in this block!".format(
 					m = "Transaction with nLockTime {!r} can't be included in this block!".format(
 						self.strfmt_locktime(self.get_serialized_locktime()))
 						self.strfmt_locktime(self.get_serialized_locktime()))
 				else:
 				else:
-					m = errmsg
-				ymsg(m)
-				rmsg(f'Send of MMGen transaction {self.txid} failed')
-				if exit_on_fail:
-					sys.exit(1)
-				return False
+					m,nl = ('','')
+				msg(orange('\n'+errmsg))
+				die(2, f'{m}{nl}Send of MMGen transaction {self.txid} failed')
 			else:
 			else:
 				assert ret == self.coin_txid, 'txid mismatch (after sending)'
 				assert ret == self.coin_txid, 'txid mismatch (after sending)'
 
 
 		msg(m.format(self.coin_txid.hl()))
 		msg(m.format(self.coin_txid.hl()))
-		self.add_timestamp()
+		self.add_sent_timestamp()
 		self.add_blockcount()
 		self.add_blockcount()
-		self.desc = 'sent transaction'
 		return True
 		return True
 
 
 	def print_contract_addr(self):
 	def print_contract_addr(self):
 		pass
 		pass
+
+class Sent(TxBase.Sent, OnlineSigned):
+	pass

+ 22 - 25
mmgen/proto/eth/tx/online.py

@@ -12,14 +12,15 @@
 proto.eth.tx.online: Ethereum online signed transaction class
 proto.eth.tx.online: Ethereum online signed transaction class
 """
 """
 
 
-from ....util import msg,rmsg,die
+from ....util import msg,die
+from ....color import orange
 from ....tx import online as TxBase
 from ....tx import online as TxBase
 from .. import erigon_sleep
 from .. import erigon_sleep
 from .signed import Signed,TokenSigned
 from .signed import Signed,TokenSigned
 
 
 class OnlineSigned(Signed,TxBase.OnlineSigned):
 class OnlineSigned(Signed,TxBase.OnlineSigned):
 
 
-	async def send(self,prompt_user=True,exit_on_fail=False):
+	async def send(self,prompt_user=True):
 
 
 		self.check_correct_chain()
 		self.check_correct_chain()
 
 
@@ -36,32 +37,22 @@ class OnlineSigned(Signed,TxBase.OnlineSigned):
 			self.confirm_send()
 			self.confirm_send()
 
 
 		if self.cfg.bogus_send:
 		if self.cfg.bogus_send:
-			ret = None
+			m = 'BOGUS transaction NOT sent: {}'
 		else:
 		else:
 			try:
 			try:
 				ret = await self.rpc.call('eth_sendRawTransaction','0x'+self.serialized)
 				ret = await self.rpc.call('eth_sendRawTransaction','0x'+self.serialized)
-			except:
-				raise # TODO: raises immediately
-				ret = False # TODO: unreachable code
-
-		if ret is False: # TODO: unreachable code
-			rmsg(f'Send of MMGen transaction {self.txid} failed')
-			if exit_on_fail:
-				import sys
-				sys.exit(1)
-			return False
-		else:
-			if self.cfg.bogus_send:
-				m = 'BOGUS transaction NOT sent: {}'
-			else:
-				m = 'Transaction sent: {}'
-				assert ret == '0x'+self.coin_txid,'txid mismatch (after sending)'
-				await erigon_sleep(self)
-			self.desc = 'sent transaction'
-			msg(m.format(self.coin_txid.hl()))
-			self.add_timestamp()
-			self.add_blockcount()
-			return True
+			except Exception as e:
+				msg(orange('\n'+str(e)))
+				die(2, f'Send of MMGen transaction {self.txid} failed')
+			m = 'Transaction sent: {}'
+			assert ret == '0x'+self.coin_txid,'txid mismatch (after sending)'
+			await erigon_sleep(self)
+
+		msg(m.format(self.coin_txid.hl()))
+		self.add_sent_timestamp()
+		self.add_blockcount()
+
+		return True
 
 
 	def print_contract_addr(self):
 	def print_contract_addr(self):
 		if 'token_addr' in self.txobj:
 		if 'token_addr' in self.txobj:
@@ -80,3 +71,9 @@ class TokenOnlineSigned(TokenSigned,OnlineSigned):
 		t = Token(self.cfg,self.proto,o['token_addr'],o['decimals'])
 		t = Token(self.cfg,self.proto,o['token_addr'],o['decimals'])
 		o['amt'] = t.transferdata2amt(o['data'])
 		o['amt'] = t.transferdata2amt(o['data'])
 		o['token_to'] = t.transferdata2sendaddr(o['data'])
 		o['token_to'] = t.transferdata2sendaddr(o['data'])
+
+class Sent(TxBase.Sent, OnlineSigned):
+	pass
+
+class TokenSent(TxBase.Sent, TokenOnlineSigned):
+	pass

+ 3 - 1
mmgen/tx/__init__.py

@@ -73,7 +73,8 @@ async def _get_obj_async( _clsname, _modname, *args, **kwargs ):
 	# signing.
 	# signing.
 	if proto and proto.tokensym and clsname in (
 	if proto and proto.tokensym and clsname in (
 			'New',
 			'New',
-			'OnlineSigned'):
+			'OnlineSigned',
+			'Sent'):
 		from ..tw.ctl import TwCtl
 		from ..tw.ctl import TwCtl
 		kwargs['twctl'] = await TwCtl(cfg,proto)
 		kwargs['twctl'] = await TwCtl(cfg,proto)
 
 
@@ -92,4 +93,5 @@ NewTX          = _get_async('New',          'new')
 CompletedTX    = _get_async('Completed',    'completed')
 CompletedTX    = _get_async('Completed',    'completed')
 SignedTX       = _get_async('Signed',       'signed')
 SignedTX       = _get_async('Signed',       'signed')
 OnlineSignedTX = _get_async('OnlineSigned', 'online')
 OnlineSignedTX = _get_async('OnlineSigned', 'online')
+SentTX         = _get_async('Sent',         'online')
 BumpTX         = _get_async('Bump',         'bump')
 BumpTX         = _get_async('Bump',         'bump')

+ 4 - 0
mmgen/tx/base.py

@@ -77,6 +77,7 @@ class Base(MMGenObject):
 	txid         = None
 	txid         = None
 	coin_txid    = None
 	coin_txid    = None
 	timestamp    = None
 	timestamp    = None
+	sent_timestamp = None
 	blockcount   = None
 	blockcount   = None
 	locktime     = None
 	locktime     = None
 	chain        = None
 	chain        = None
@@ -162,6 +163,9 @@ class Base(MMGenObject):
 	def add_timestamp(self):
 	def add_timestamp(self):
 		self.timestamp = make_timestamp()
 		self.timestamp = make_timestamp()
 
 
+	def add_sent_timestamp(self):
+		self.sent_timestamp = make_timestamp()
+
 	def add_blockcount(self):
 	def add_blockcount(self):
 		self.blockcount = self.rpc.blockcount
 		self.blockcount = self.rpc.blockcount
 
 

+ 4 - 2
mmgen/tx/completed.py

@@ -58,8 +58,10 @@ class Completed(Base):
 		see twctl:import_token()
 		see twctl:import_token()
 		"""
 		"""
 		from .unsigned import Unsigned
 		from .unsigned import Unsigned
-		if ext == Unsigned.ext:
-			return Unsigned
+		from .online import Sent
+		for cls in (Unsigned, Sent):
+			if ext == getattr(cls, 'ext'):
+				return cls
 
 
 		if proto.tokensym:
 		if proto.tokensym:
 			from .online import OnlineSigned as Signed
 			from .online import OnlineSigned as Signed

+ 8 - 0
mmgen/tx/file.py

@@ -72,6 +72,11 @@ class MMGenTxFile(MMGenObject):
 			self.chksum = HexStr(tx_data.pop(0))
 			self.chksum = HexStr(tx_data.pop(0))
 			assert self.chksum == make_chksum_6(' '.join(tx_data)),'file data does not match checksum'
 			assert self.chksum == make_chksum_6(' '.join(tx_data)),'file data does not match checksum'
 
 
+			if len(tx_data) == 7:
+				desc = 'sent timestamp'
+				(_, tx.sent_timestamp) = tx_data.pop(-1).split()
+				assert _ == 'Sent', 'invalid sent timestamp line'
+
 			if len(tx_data) == 6:
 			if len(tx_data) == 6:
 				assert len(tx_data[-1]) == 64,'invalid coin TxID length'
 				assert len(tx_data[-1]) == 64,'invalid coin TxID length'
 				desc = 'coin TxID'
 				desc = 'coin TxID'
@@ -186,6 +191,9 @@ class MMGenTxFile(MMGenObject):
 				lines.append('-') # keep old tx files backwards compatible
 				lines.append('-') # keep old tx files backwards compatible
 			lines.append(tx.coin_txid)
 			lines.append(tx.coin_txid)
 
 
+		if tx.sent_timestamp:
+			lines.append(f'Sent {tx.sent_timestamp}')
+
 		self.chksum = make_chksum_6(' '.join(lines))
 		self.chksum = make_chksum_6(' '.join(lines))
 		fmt_data = '\n'.join([self.chksum] + lines) + '\n'
 		fmt_data = '\n'.join([self.chksum] + lines) + '\n'
 		if len(fmt_data) > tx.cfg.max_tx_file_size:
 		if len(fmt_data) > tx.cfg.max_tx_file_size:

+ 1 - 1
mmgen/tx/info.py

@@ -56,7 +56,7 @@ class TxInfo:
 					orange(self.strfmt_locktime(terse=True)) if tx.locktime else
 					orange(self.strfmt_locktime(terse=True)) if tx.locktime else
 					green('None') ))
 					green('None') ))
 
 
-			for attr,label in [('timestamp','Created:')]:
+			for attr,label in [('timestamp','Created:'),('sent_timestamp','Sent:')]:
 				if (val := getattr(tx,attr)) is not None:
 				if (val := getattr(tx,attr)) is not None:
 					_ = decode_timestamp(val)
 					_ = decode_timestamp(val)
 					yield f'{label:8} {make_timestr(_)} ({format_elapsed_hr(_)})\n'
 					yield f'{label:8} {make_timestr(_)} ({format_elapsed_hr(_)})\n'

+ 4 - 0
mmgen/tx/online.py

@@ -30,3 +30,7 @@ class OnlineSigned(Signed):
 			action  = f'broadcast this transaction to the {self.proto.coin} {self.proto.network.upper()} network',
 			action  = f'broadcast this transaction to the {self.proto.coin} {self.proto.network.upper()} network',
 			expect  = 'YES' if self.cfg.quiet or self.cfg.yes else 'YES, I REALLY WANT TO DO THIS' )
 			expect  = 'YES' if self.cfg.quiet or self.cfg.yes else 'YES, I REALLY WANT TO DO THIS' )
 		msg('Sending transaction')
 		msg('Sending transaction')
+
+class Sent(OnlineSigned):
+	desc = 'sent transaction'
+	ext = 'subtx'