Browse Source

mmgen-txsend: new `process_tx()` function: tx.online: cleanups

The MMGen Project 1 month ago
parent
commit
392b3700af

+ 4 - 3
mmgen/main_txbump.py

@@ -17,10 +17,11 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 """
 """
-mmgen-txbump: Create, and optionally send and sign, a replacement transaction
-              on supporting networks
+mmgen-txbump: Create, and optionally send and sign, a replacement transaction on supported networks
 """
 """
 
 
+import sys
+
 from .cfg import gc, Config
 from .cfg import gc, Config
 from .util import msg, msg_r, die, async_run
 from .util import msg, msg_r, die, async_run
 from .color import green
 from .color import green
@@ -207,7 +208,7 @@ async def main():
 				TxKeys(cfg, tx2, seedfiles=seedfiles, keylist=kl, keyaddrlist=kal).keys):
 				TxKeys(cfg, tx2, seedfiles=seedfiles, keylist=kl, keyaddrlist=kal).keys):
 			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(cfg, asi if cfg.autosign else None)
+			sys.exit(await tx4.send(cfg, asi if cfg.autosign else None))
 		else:
 		else:
 			die(2, 'Transaction could not be signed')
 			die(2, 'Transaction could not be signed')
 	else:
 	else:

+ 4 - 2
mmgen/main_txdo.py

@@ -20,6 +20,8 @@
 mmgen-txdo: Create, sign and send an online MMGen transaction
 mmgen-txdo: Create, sign and send an online MMGen transaction
 """
 """
 
 
+import sys
+
 from .cfg import gc, Config
 from .cfg import gc, Config
 from .util import die, fmt_list, async_run
 from .util import die, fmt_list, async_run
 from .subseed import SubSeedIdxRange
 from .subseed import SubSeedIdxRange
@@ -192,8 +194,8 @@ async def main():
 	if tx3:
 	if tx3:
 		tx3.file.write(ask_write=False)
 		tx3.file.write(ask_write=False)
 		tx4 = await SentTX(cfg=cfg, data=tx3.__dict__)
 		tx4 = await SentTX(cfg=cfg, data=tx3.__dict__)
-		await tx4.send(cfg, asi=None)
+		return await tx4.send(cfg, asi=None)
 	else:
 	else:
 		die(2, 'Transaction could not be signed')
 		die(2, 'Transaction could not be signed')
 
 
-async_run(cfg, main)
+sys.exit(async_run(cfg, main))

+ 26 - 28
mmgen/main_txsend.py

@@ -110,11 +110,9 @@ def init_autosign(arg):
 	si = Signable.automount_transaction(asi)
 	si = Signable.automount_transaction(asi)
 	if cfg.abort:
 	if cfg.abort:
 		si.shred_abortable() # prompts user, then raises exception or exits
 		si.shred_abortable() # prompts user, then raises exception or exits
+	elif post_send_op and (si.unsent or si.unsigned):
+		die(1, 'Transaction is {}'.format('unsent' if si.unsent else 'unsigned'))
 	elif post_send_op:
 	elif post_send_op:
-		if si.unsent:
-			die(1, 'Transaction is unsent')
-		if si.unsigned:
-			die(1, 'Transaction is unsigned')
 		if not is_int(arg):
 		if not is_int(arg):
 			die(2, f'{arg}: invalid transaction index (must be a non-negative integer)')
 			die(2, f'{arg}: invalid transaction index (must be a non-negative integer)')
 		tx_idx = int(arg)
 		tx_idx = int(arg)
@@ -139,38 +137,28 @@ if not cfg.status:
 
 
 from .tx import OnlineSignedTX
 from .tx import OnlineSignedTX
 
 
-async def main():
-
-	global cfg
+async def process_tx(tx):
 
 
-	if cfg.autosign and post_send_op:
-		tx = await si.get_last_sent(idx=tx_idx)
-	else:
-		tx = await OnlineSignedTX(
-			cfg        = cfg,
-			filename   = infile,
-			automount  = cfg.autosign,
-			quiet_open = True)
+	cfg._util.vmsg(f'Getting {tx.desc} ‘{tx.infile}’')
 
 
 	if tx.is_compat:
 	if tx.is_compat:
 		return await tx.compat_send()
 		return await tx.compat_send()
 
 
-	cfg = Config({'_clone': cfg, 'proto': tx.proto, 'coin': tx.proto.coin})
+	txcfg = Config({'_clone': cfg, 'proto': tx.proto, 'coin': tx.proto.coin})
 
 
-	if cfg.tx_proxy:
-		from .tx.tx_proxy import check_client
-		check_client(cfg)
+	if not post_send_op:
+		if cfg.tx_proxy:
+			from .tx.tx_proxy import check_client
+			check_client(txcfg)
 
 
 	from .rpc import rpc_init
 	from .rpc import rpc_init
-	tx.rpc = await rpc_init(cfg)
-
-	cfg._util.vmsg(f'Getting {tx.desc} ‘{tx.infile}’')
-
-	if cfg.mark_sent:
-		await tx.post_send(asi)
-		sys.exit(0)
+	tx.rpc = await rpc_init(txcfg)
 
 
 	if not post_send_op:
 	if not post_send_op:
+		if cfg.mark_sent:
+			await tx.post_send(asi)
+			return 0
+
 		if tx.is_swap and not tx.check_swap_expiry():
 		if tx.is_swap and not tx.check_swap_expiry():
 			die(1, 'Swap quote has expired. Please re-create the transaction')
 			die(1, 'Swap quote has expired. Please re-create the transaction')
 
 
@@ -180,6 +168,16 @@ async def main():
 				if not cfg.autosign:
 				if not cfg.autosign:
 					tx.file.write(ask_write_default_yes=True)
 					tx.file.write(ask_write_default_yes=True)
 
 
-	await tx.send(cfg, asi)
+	return await tx.send(txcfg, asi)
+
+async def main():
+	if cfg.autosign and post_send_op:
+		return await process_tx(await si.get_last_sent(idx=tx_idx))
+	else:
+		return await process_tx(await OnlineSignedTX(
+			cfg        = cfg,
+			filename   = infile,
+			automount  = cfg.autosign,
+			quiet_open = True))
 
 
-async_run(cfg, main)
+sys.exit(async_run(cfg, main))

+ 1 - 0
mmgen/proto/xmr/tx/completed.py

@@ -26,6 +26,7 @@ class Completed(Base):
 			'network': proto.network})
 			'network': proto.network})
 		self.proto = proto
 		self.proto = proto
 		self.filename = filename
 		self.filename = filename
+		self.infile = filename
 
 
 	@cached_property
 	@cached_property
 	def compat_tx(self):
 	def compat_tx(self):

+ 15 - 9
mmgen/proto/xmr/tx/online.py

@@ -15,17 +15,20 @@ proto.xmr.tx.online: Monero online signed transaction class
 from .completed import Completed
 from .completed import Completed
 
 
 class OnlineSigned(Completed):
 class OnlineSigned(Completed):
+	desc = 'signed transaction'
 
 
 	async def compat_send(self):
 	async def compat_send(self):
+		"""
+		returns integer exit val to system
+		"""
 		from ....xmrwallet import op as xmrwallet_op
 		from ....xmrwallet import op as xmrwallet_op
 		op_name = 'daemon' if self.cfg.status else 'submit'
 		op_name = 'daemon' if self.cfg.status else 'submit'
 		op = xmrwallet_op(op_name, self.cfg, self.filename, None, compat_call=True)
 		op = xmrwallet_op(op_name, self.cfg, self.filename, None, compat_call=True)
 		if self.cfg.status:
 		if self.cfg.status:
-			from ....util import msg, ymsg, suf
+			from ....util import msg, msg_r, ymsg, suf
+			ret = 0
 			txid = self.compat_tx.data.txid
 			txid = self.compat_tx.data.txid
-			if self.cfg.verbose:
-				msg(self.compat_tx.get_info())
-			elif not self.cfg.quiet:
+			if not (self.cfg.verbose or self.cfg.quiet):
 				from ....obj import CoinTxID
 				from ....obj import CoinTxID
 				msg('{} TxID: {}'.format(self.cfg.coin, CoinTxID(txid).hl()))
 				msg('{} TxID: {}'.format(self.cfg.coin, CoinTxID(txid).hl()))
 			res = op.dc.call_raw('get_transactions', txs_hashes=[txid])
 			res = op.dc.call_raw('get_transactions', txs_hashes=[txid])
@@ -38,16 +41,19 @@ class OnlineSigned(Completed):
 					msg('Transaction has {} confirmation{}'.format(confs, suf(confs)))
 					msg('Transaction has {} confirmation{}'.format(confs, suf(confs)))
 			else:
 			else:
 				ymsg('An RPC error occurred while fetching transaction data')
 				ymsg('An RPC error occurred while fetching transaction data')
-				return False
+				ret = 1
+			if self.cfg.verbose:
+				msg_r('\n' + self.compat_tx.get_info())
+			return ret
 		else:
 		else:
 			await op.restart_wallet_daemon()
 			await op.restart_wallet_daemon()
-			return await op.main()
+			return int(not await op.main())
 
 
 class Sent(OnlineSigned):
 class Sent(OnlineSigned):
-	pass
+	desc = 'sent transaction'
 
 
 class AutomountOnlineSigned(OnlineSigned):
 class AutomountOnlineSigned(OnlineSigned):
-	pass
+	desc = 'signed automount transaction'
 
 
 class AutomountSent(AutomountOnlineSigned):
 class AutomountSent(AutomountOnlineSigned):
-	pass
+	desc = 'sent automount transaction'

+ 8 - 4
mmgen/tx/online.py

@@ -12,7 +12,7 @@
 tx.online: online signed transaction class
 tx.online: online signed transaction class
 """
 """
 
 
-import sys, time, asyncio
+import time, asyncio
 
 
 from ..util import msg, Msg, gmsg, ymsg, make_timestr, die
 from ..util import msg, Msg, gmsg, ymsg, make_timestr, die
 from ..color import pink, yellow
 from ..color import pink, yellow
@@ -63,7 +63,9 @@ class OnlineSigned(Signed):
 			ask_write     = False)
 			ask_write     = False)
 
 
 	async def send(self, cfg, asi):
 	async def send(self, cfg, asi):
-
+		"""
+		returns integer exit val to system
+		"""
 		status_exitval = None
 		status_exitval = None
 		sent_status = None
 		sent_status = None
 		all_ok = True
 		all_ok = True
@@ -85,9 +87,10 @@ class OnlineSigned(Signed):
 			if coin_txid := getattr(self, f'coin_txid{idx}', None):
 			if coin_txid := getattr(self, f'coin_txid{idx}', None):
 				txhex = getattr(self, f'serialized{idx}')
 				txhex = getattr(self, f'serialized{idx}')
 				if cfg.status:
 				if cfg.status:
-					cfg._util.qmsg(f'{self.proto.coin} TxID: {coin_txid.hl()}')
 					if cfg.verbose:
 					if cfg.verbose:
 						await self.post_network_send(coin_txid)
 						await self.post_network_send(coin_txid)
+					else:
+						cfg._util.qmsg(f'{self.proto.coin} TxID: {coin_txid.hl()}')
 					status_exitval = await self.status.display(idx=idx)
 					status_exitval = await self.status.display(idx=idx)
 				elif cfg.receipt:
 				elif cfg.receipt:
 					if res := await self.get_receipt(coin_txid, receipt_only=True):
 					if res := await self.get_receipt(coin_txid, receipt_only=True):
@@ -147,7 +150,8 @@ class OnlineSigned(Signed):
 		if status_exitval is not None:
 		if status_exitval is not None:
 			if cfg.verbose:
 			if cfg.verbose:
 				self.info.view_with_prompt('View transaction details?', pause=False)
 				self.info.view_with_prompt('View transaction details?', pause=False)
-			sys.exit(status_exitval)
+			return status_exitval
+		return 0
 
 
 class AutomountOnlineSigned(AutomountSigned, OnlineSigned):
 class AutomountOnlineSigned(AutomountSigned, OnlineSigned):
 	pass
 	pass

+ 10 - 3
test/cmdtest_d/automount.py

@@ -224,7 +224,13 @@ class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtest):
 	def alice_txsend5(self):
 	def alice_txsend5(self):
 		return self._user_txsend('alice', need_rbf=True)
 		return self._user_txsend('alice', need_rbf=True)
 
 
-	def _alice_txstatus(self, expect, exit_val=None, need_rbf=False, idx=None):
+	def _alice_txstatus(
+			self,
+			expect,
+			exit_val = None,
+			need_rbf = False,
+			idx      = None,
+			verbose  = True):
 
 
 		if need_rbf and not self.proto.cap('rbf'):
 		if need_rbf and not self.proto.cap('rbf'):
 			return 'skip'
 			return 'skip'
@@ -232,11 +238,12 @@ class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtest):
 		self.insert_device_online()
 		self.insert_device_online()
 		t = self.spawn(
 		t = self.spawn(
 				'mmgen-txsend',
 				'mmgen-txsend',
-				['--alice', '--autosign', '--status', '--verbose']
+				['--alice', '--autosign', '--status']
+				+ (['--verbose'] if verbose else [])
 				+ ([] if idx is None else [str(idx)]),
 				+ ([] if idx is None else [str(idx)]),
 				no_passthru_opts = ['coin'],
 				no_passthru_opts = ['coin'],
 				exit_val = exit_val)
 				exit_val = exit_val)
-		t.expect(expect)
+		t.expect(expect, regex=True)
 		if not exit_val:
 		if not exit_val:
 			t.expect('view: ', 'n')
 			t.expect('view: ', 'n')
 		t.read()
 		t.read()

+ 1 - 1
test/cmdtest_d/xmr_autosign.py

@@ -816,7 +816,7 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
 		return self._alice_txstatus(['--quiet'], expect_str='confirmations')
 		return self._alice_txstatus(['--quiet'], expect_str='confirmations')
 
 
 	def alice_txstatus3(self):
 	def alice_txstatus3(self):
-		return self._alice_txstatus(['--verbose'], expect_str='Info for transaction .* confirmations')
+		return self._alice_txstatus(['--verbose'], expect_str='confirmations.*Info for transaction')
 
 
 	def _alice_txstatus(self, add_opts=[], expect_str=None):
 	def _alice_txstatus(self, add_opts=[], expect_str=None):
 		return self._alice_txops(
 		return self._alice_txops(