Browse Source

mmgen-swaptx{create,do}: add `--stream-interval` option

The MMGen Project 6 months ago
parent
commit
4cad3c3bd5

+ 1 - 1
mmgen/data/version

@@ -1 +1 @@
-15.1.dev36
+15.1.dev37

+ 4 - 0
mmgen/help/help_notes.py

@@ -35,6 +35,10 @@ class help_notes:
 		pfx, sfx, sep, conj = (('', '', ',', ' or '), ("‘", "’", "’,‘", "’ or ‘"))[use_quotes]
 		return pfx + sep.join(u[0] for u in cu[:-1]) + ('', conj)[len(cu)>1] + cu[-1][0] + sfx
 
+	def stream_interval(self):
+		from ..tx.new_swap import get_swap_proto_mod
+		return get_swap_proto_mod(self.cfg.swap_proto).SwapCfg(self.cfg).si.dfl
+
 	def fee_spec_names(self, *, proto=None, linebreak=' '):
 		cu = (proto or self.proto).coin_amt.units
 		return (

+ 2 - 0
mmgen/main_txcreate.py

@@ -73,6 +73,7 @@ opts_data = {
 			-- -m, --minconf=     n  Minimum number of confirmations required to spend
 			+                        outputs (default: 1)
 			-- -q, --quiet           Suppress warnings; overwrite files without prompting
+			-s -r, --stream-interval=N Set block interval for streaming swap (default: {si})
 			bt -R, --no-rbf          Make transaction non-replaceable (non-replace-by-fee
 			+                        according to BIP 125)
 			-s -s, --swap-proto      Swap protocol to use (Default: {x_dfl},
@@ -97,6 +98,7 @@ opts_data = {
 			a_info = help_notes('account_info_desc'),
 			fu     = help_notes('rel_fee_desc'),
 			fl     = help_notes('fee_spec_letters'),
+			si     = help_notes('stream_interval'),
 			fe_all = fmt_list(cfg._autoset_opts['fee_estimate_mode'].choices, fmt='no_spc'),
 			fe_dfl = cfg._autoset_opts['fee_estimate_mode'].choices[0],
 			x_all = fmt_list(cfg._autoset_opts['swap_proto'].choices, fmt='no_spc'),

+ 2 - 0
mmgen/main_txdo.py

@@ -94,6 +94,7 @@ opts_data = {
 			+                         for password hashing (default: '{gc.dfl_hash_preset}')
 			-- -P, --passwd-file=   f Get {pnm} wallet passphrase from file 'f'
 			-- -q, --quiet            Suppress warnings; overwrite files without prompting
+			-s -r, --stream-interval=N Set block interval for streaming swap (default: {si})
 			bt -R, --no-rbf           Make transaction non-replaceable (non-replace-by-fee
 			+                         according to BIP 125)
 			-s -s, --swap-proto       Swap protocol to use (Default: {x_dfl},
@@ -145,6 +146,7 @@ column below:
 			fl      = help_notes('fee_spec_letters'),
 			dsl     = help_notes('dfl_seed_len'),
 			ss      = help_notes('dfl_subseeds'),
+			si      = help_notes('stream_interval'),
 			tx_proxies = help_notes('tx_proxies'),
 			ss_max  = SubSeedIdxRange.max_idx,
 			fe_all  = fmt_list(cfg._autoset_opts['fee_estimate_mode'].choices, fmt='no_spc'),

+ 20 - 1
mmgen/swap/cfg.py

@@ -13,10 +13,13 @@ swap.cfg: swap configuration class the MMGen Wallet suite
 """
 
 import re
+from collections import namedtuple
 
 from ..amt import UniAmt
 from ..util import die
 
+_mmd = namedtuple('swap_config_option', ['min', 'max', 'dfl'])
+
 class SwapCfg:
 
 	# The trade limit, i.e., set 100000000 to get a minimum of 1 full asset, else a refund
@@ -24,7 +27,7 @@ class SwapCfg:
 	trade_limit = None
 
 	# Swap interval for streaming swap in blocks. Optional. If 0, do not stream
-	stream_interval = 3
+	si = _mmd(1, 20, 3) # stream_interval
 
 	# Swap quantity for streaming swap.
 	# The interval value determines the frequency of swaps in blocks
@@ -38,9 +41,25 @@ class SwapCfg:
 		if cfg.trade_limit is not None:
 			self.set_trade_limit(desc='parameter for --trade-limit')
 
+		if cfg.stream_interval is None:
+			self.stream_interval = self.si.dfl
+		else:
+			self.set_stream_interval(desc='parameter for --stream-interval')
+
 	def set_trade_limit(self, *, desc):
 		s = self.cfg.trade_limit
 		if re.match(r'-*[0-9]+(\.[0-9]+)*%*$', s):
 			self.trade_limit = 1 - float(s[:-1]) / 100 if s.endswith('%') else UniAmt(s)
 		else:
 			die('SwapCfgValueError', f'{s}: invalid {desc}')
+
+	def set_stream_interval(self, *, desc):
+		s = self.cfg.stream_interval
+		from ..util import is_int
+		if not is_int(s):
+			die('SwapCfgValueError', f'{s}: invalid {desc} (not an integer)')
+		self.stream_interval = si = int(s)
+		if si < self.si.min:
+			die('SwapCfgValueError', f'{si}: invalid {desc} (< {self.si.min})')
+		if si > self.si.max:
+			die('SwapCfgValueError', f'{si}: invalid {desc} (> {self.si.max})')

+ 2 - 2
test/cmdtest_d/ethswap.py

@@ -415,8 +415,8 @@ class CmdTestEthSwapEth(CmdTestEthSwapMethods, CmdTestSwapMethods, CmdTestEthdev
 		return self._swaptxcreate_ui_common(
 			self._swaptxcreate(
 				['ETH', '8.765', 'BTC', f'{dfl_sid}:B:4'],
-				add_opts = ['--trade-limit=3%']),
-			expect = ':2019e4/3/0')
+				add_opts = ['--trade-limit=3%' ,'--stream-interval=7']),
+			expect = ':2019e4/7/0')
 
 	def swaptxcreate3a(self):
 		t = self._swaptxcreate(['ETH', '0.7654321', 'ETH.MM1'], add_opts=['--gas=fallback'])

+ 4 - 4
test/cmdtest_d/swap.py

@@ -534,16 +534,16 @@ class CmdTestSwap(CmdTestSwapMethods, CmdTestRegtest, CmdTestAutosignThreaded):
 		return self._swaptxcreate_ui_common(
 			self._swaptxcreate(
 				['BCH', '1.234', f'{self.sid}:C:{idx}', 'LTC', f'{self.sid}:B:3'],
-				add_opts = ['--trade-limit=0%']),
-			expect = ':3541e5/3/0')
+				add_opts = ['--trade-limit=0%', '--stream-interval=1']),
+			expect = ':3541e5/1/0')
 
 	def swaptxcreate2(self):
 		t = self._swaptxcreate(
 			['BCH', 'LTC'],
-			add_opts = ['--no-quiet', '--trade-limit=3.337%'])
+			add_opts = ['--no-quiet', '--stream-interval=10', '--trade-limit=3.337%'])
 		t.expect('Enter a number> ', '1')
 		t.expect('OK? (Y/n): ', 'y')
-		return self._swaptxcreate_ui_common(t, reload_quote=True, expect=':1386e6/3/0')
+		return self._swaptxcreate_ui_common(t, reload_quote=True, expect=':1386e6/10/0')
 
 	def swaptxcreate3(self):
 		return self._swaptxcreate_ui_common(

+ 34 - 19
test/modtest_d/swap.py

@@ -16,20 +16,23 @@ class unit_tests:
 
 	def cfg(self, name, ut, desc='Swap configuration'):
 
-		for tl_arg, tl_chk in (
-				(None,      None),
-				('1',       UniAmt('1')),
-				('33',      UniAmt('33')),
-				('2%',      0.98),
-				('-2%',     1.02),
-				('3.333%',  0.96667),
-				('-3.333%', 1.03333),
-				('1.2345',  UniAmt('1.2345'))):
-			cfg_data = {'trade_limit': tl_arg}
+		for tl_arg, tl_chk, si_arg in (
+				(None,      None,             None),
+				('1',       UniAmt('1'),      None),
+				('33',      UniAmt('33'),     7),
+				('2%',      0.98,             14),
+				('-2%',     1.02,             1),
+				('3.333%',  0.96667,          1),
+				('-3.333%', 1.03333,          3),
+				('1.2345',  UniAmt('1.2345'), 10)):
+			cfg_data = {
+				'trade_limit': tl_arg,
+				'stream_interval': None if si_arg is None else str(si_arg)}
 			sc = SwapCfg(Config(cfg_data))
 			vmsg(f'  trade_limit:     {tl_arg} => {sc.trade_limit}')
+			vmsg(f'  stream_interval: {si_arg} => {sc.stream_interval}')
 			assert sc.trade_limit == tl_chk
-			assert sc.stream_interval == 3
+			assert sc.stream_interval == sc.si.dfl if si_arg is None else si_arg
 			assert sc.stream_quantity == 0
 
 		vmsg('\n  Testing error handling')
@@ -40,9 +43,21 @@ class unit_tests:
 		def bad2():
 			SwapCfg(Config({'trade_limit': '1.23x'}))
 
+		def bad3():
+			SwapCfg(Config({'stream_interval': 30}))
+
+		def bad4():
+			SwapCfg(Config({'stream_interval': 0}))
+
+		def bad5():
+			SwapCfg(Config({'stream_interval': 'x'}))
+
 		ut.process_bad_data((
 			('bad1', 'SwapCfgValueError', 'invalid parameter', bad1),
 			('bad2', 'SwapCfgValueError', 'invalid parameter', bad2),
+			('bad3', 'SwapCfgValueError', 'invalid parameter', bad3),
+			('bad4', 'SwapCfgValueError', 'invalid parameter', bad4),
+			('bad5', 'SwapCfgValueError', 'invalid parameter', bad5),
 		), pfx='')
 
 		return True
@@ -78,15 +93,15 @@ class unit_tests:
 
 			vmsg(f'\nTesting asset {cyan(asset_name)}:')
 
-			for limit, limit_chk, suf in (
-				('123.4567',   12340000000, '1234e7/3/0'),
-				('1.234567',   123400000,   '1234e5/3/0'),
-				('0.01234567', 1234000,     '1234e3/3/0'),
-				('0.00012345', 12345,       '12345/3/0'),
-				(None,         0,           '0/3/0'),
+			for limit, limit_chk, si, suf in (
+				('123.4567',   12340000000, None, '1234e7/3/0'),
+				('1.234567',   123400000,   1,    '1234e5/1/0'),
+				('0.01234567', 1234000,     10,   '1234e3/10/0'),
+				('0.00012345', 12345,       20,   '12345/20/0'),
+				(None,         0,           3,    '0/3/0'),
 			):
 				vmsg('\nTesting memo initialization:')
-				swap_cfg = SwapCfg(Config({'trade_limit': limit}))
+				swap_cfg = SwapCfg(Config({'trade_limit': limit, 'stream_interval': si}))
 				m = Memo(
 					swap_cfg,
 					proto,
@@ -112,7 +127,7 @@ class unit_tests:
 				assert p.asset == token or coin.upper()
 				assert p.address == addr.views[addr.view_pref]
 				assert p.trade_limit == limit_chk
-				assert p.stream_interval == 3
+				assert p.stream_interval == si or swap_cfg.si.dfl, f'{p.stream_interval} != {swap_cfg.si.dfl}'
 				assert p.stream_quantity == 0 # auto
 
 			vmsg('\nTesting is_partial_memo():')