Browse Source

LTC support/testing fixes

- examples/halving-calculator.py: support LTC and BCH
- test/test.py regtest: support Litecoin Core v0.18.1
- test/unit_tests.py: add LTC test
The MMGen Project 4 years ago
parent
commit
cfa8d19cd0
6 changed files with 31 additions and 24 deletions
  1. 10 9
      examples/halving-calculator.py
  2. 1 1
      mmgen/daemon.py
  3. 2 0
      mmgen/protocol.py
  4. 5 6
      mmgen/rpc.py
  5. 1 1
      test/test_py_d/ts_regtest.py
  6. 12 7
      test/unit_tests_d/ut_rpc.py

+ 10 - 9
examples/halving-calculator.py

@@ -9,7 +9,7 @@ from mmgen.common import *
 
 opts.init({
 	'text': {
-		'desc': 'Estimate date of next Bitcoin halving',
+		'desc': 'Estimate date of next block subsidy halving',
 		'usage':'[opts]',
 		'options': """
 -h, --help          Print this help message
@@ -18,20 +18,20 @@ opts.init({
                     estimate
 """,
 	'notes': """
-Requires a running Bitcoin Core node
+Requires a running coin daemon
+Specify coin with --coin=btc (default)/--coin=bch/--coin=ltc
 If necessary, invoke with --rpc-host/--rpc-port/--rpc-user/--rpc-password
 Specify aiohttp backend with --rpc-backend=aiohttp (Linux only)
 """
 	}
 })
 
-HalvingInterval = 210000 # src/chainparams.cpp
-
 def date(t):
 	return '{}-{:02}-{:02} {:02}:{:02}:{:02}'.format(*time.gmtime(t)[:6])
 
 def dhms(t):
-	return f'{t//60//60//24} days, {t//60//60%24:02}:{t//60%60:02}:{t%60:02} h/m/s'
+	t,neg = (-t,'-') if t < 0 else (t,' ')
+	return f'{neg}{t//60//60//24} days, {t//60//60%24:02}:{t//60%60:02}:{t%60:02} h/m/s'
 
 def time_diff_warning(t_diff):
 	if abs(t_diff) > 60*60:
@@ -48,8 +48,9 @@ async def main():
 	c = await rpc_init(proto)
 
 	tip = await c.call('getblockcount')
-	remaining = HalvingInterval - tip % HalvingInterval
-	sample_size = int(opt.sample_size) if opt.sample_size else max(remaining,144)
+	assert tip > 1, 'block tip must be > 1'
+	remaining = proto.halving_interval - tip % proto.halving_interval
+	sample_size = int(opt.sample_size) if opt.sample_size else min(tip-1,max(remaining,144))
 
 	# aiohttp backend will perform these two calls concurrently:
 	cur,old = await c.gathered_call('getblockstats',((tip,),(tip - sample_size,)))
@@ -64,10 +65,10 @@ async def main():
 	print(f'Current block:      {tip}')
 	print(f'Next halving block: {tip + remaining}')
 	print(f'Blocks until halving: {remaining}')
-	print('Current block subsidy: {} BTC'.format(str(sub).rstrip('0')))
+	print('Current block subsidy: {} {}'.format(str(sub).rstrip('0'),proto.coin))
 	print(f'Current block discovery rate (over last {sample_size} blocks): {bdr/60:0.1f} minutes')
 	print(f'Current clock time (UTC): {date(clock_time)}')
 	print(f'Est. halving date (UTC):  {date(cur["time"] + t_rem)}')
-	print(f'Est. time until halving:  {dhms(cur["time"] + t_rem - clock_time)}')
+	print(f'Est. time until halving: {dhms(cur["time"] + t_rem - clock_time)}')
 
 run_session(main())

+ 1 - 1
mmgen/daemon.py

@@ -457,7 +457,7 @@ class BitcoinDaemon(CoinDaemon):
 		elif self.daemon_id == 'bch':
 			self.coin_specific_coind_args = ['--usecashaddr=0']
 		elif self.daemon_id == 'ltc':
-			self.coin_specific_coind_args = ['--mempoolreplacement=1']
+			self.coin_specific_coind_args = ['--mempoolreplacement=1','--txindex=1']
 
 		if self.network == 'testnet':
 			self.lockfile = os.path.join(self.datadir,self.testnet_dir,'.cookie')

+ 2 - 0
mmgen/protocol.py

@@ -231,6 +231,7 @@ class CoinProtocol(MMGenObject):
 		bech32_hrp      = 'bc'
 		sign_mode       = 'daemon'
 		avg_bdi         = int(9.7 * 60) # average block discovery interval (historical)
+		halving_interval = 210000
 
 		def hex2wif(self,hexpriv,pubkey_type,compressed): # input is preprocessed hex
 			sec = bytes.fromhex(hexpriv)
@@ -366,6 +367,7 @@ class CoinProtocol(MMGenObject):
 		forks           = []
 		bech32_hrp      = 'ltc'
 		avg_bdi         = 150
+		halving_interval = 840000
 
 	class LitecoinTestnet(Litecoin):
 		# addr ver nums same as Bitcoin testnet, except for 'p2sh'

+ 5 - 6
mmgen/rpc.py

@@ -329,7 +329,7 @@ class BitcoinRPCClient(RPCClient,metaclass=aInitMeta):
 	async def __ainit__(self,proto,daemon,backend):
 
 		self.proto = proto
-		self.daemon_data_dir = daemon.datadir
+		self.daemon = daemon
 
 		super().__init__(
 			host = 'localhost' if g.test_suite else (g.rpc_host or 'localhost'),
@@ -387,14 +387,13 @@ class BitcoinRPCClient(RPCClient,metaclass=aInitMeta):
 
 	def get_daemon_cfg_fn(self):
 		# Use dirname() to remove 'bob' or 'alice' component
-		cfg_dir = os.path.dirname(g.data_dir) if self.proto.regtest else self.daemon_data_dir
 		return os.path.join(
-			cfg_dir,
-			(self.proto.is_fork_of or self.proto.name).lower() + '.conf' )
+			(os.path.dirname(g.data_dir) if self.proto.regtest else self.daemon.datadir),
+			self.daemon.cfg_file )
 
 	def get_daemon_auth_cookie_fn(self):
 		return os.path.join(
-			self.daemon_data_dir,
+			self.daemon.datadir,
 			self.proto.daemon_data_subdir,
 			'.cookie' )
 
@@ -482,7 +481,7 @@ class EthereumRPCClient(RPCClient,metaclass=aInitMeta):
 
 	async def __ainit__(self,proto,daemon,backend):
 		self.proto = proto
-		self.daemon_data_dir = daemon.datadir
+		self.daemon = daemon
 
 		super().__init__(
 			host = 'localhost' if g.test_suite else (g.rpc_host or 'localhost'),

+ 1 - 1
test/test_py_d/ts_regtest.py

@@ -285,7 +285,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 		return t
 
 	def halving_calculator_bob(self):
-		t = self.spawn('halving-calculator.py',['--bob','--sample-size=144'],cmd_dir='examples')
+		t = self.spawn('halving-calculator.py',['--bob'],cmd_dir='examples')
 		t.expect('time until halving')
 		t.read()
 		return t

+ 12 - 7
test/unit_tests_d/ut_rpc.py

@@ -13,11 +13,11 @@ from mmgen.daemon import CoinDaemon,MoneroWalletDaemon
 def auth_test(proto,d):
 	d.stop()
 	if g.platform != 'win':
-		qmsg(f'\n  Testing authentication with credentials from bitcoin.conf:')
+		qmsg(f'\n  Testing authentication with credentials from {d.cfg_file}:')
 		d.remove_datadir()
 		os.makedirs(d.datadir)
 
-		cf = os.path.join(d.datadir,'bitcoin.conf')
+		cf = os.path.join(d.datadir,d.cfg_file)
 		open(cf,'a').write('\nrpcuser = ut_rpc\nrpcpassword = ut_rpc_passw0rd\n')
 
 		d.add_flag('keep_cfg_file')
@@ -25,7 +25,7 @@ def auth_test(proto,d):
 
 		async def do():
 			rpc = await rpc_init(proto)
-			assert rpc.auth.user == 'ut_rpc', 'user is not ut_rpc!'
+			assert rpc.auth.user == 'ut_rpc', f'{rpc.auth.user}: user is not ut_rpc!'
 
 		run_session(do())
 		d.stop()
@@ -54,6 +54,8 @@ class init_test:
 		rpc = await rpc_init(proto,backend)
 		do_msg(rpc)
 
+	ltc = bch
+
 	async def eth(proto,backend):
 		rpc = await rpc_init(proto,backend)
 		do_msg(rpc)
@@ -76,14 +78,17 @@ def run_test(coin,auth):
 
 class unit_tests:
 
-	altcoin_deps = ('bch','eth','xmr_wallet')
-
-	def bch(self,name,ut):
-		return run_test('bch',auth=True)
+	altcoin_deps = ('ltc','bch','eth','xmr_wallet')
 
 	def btc(self,name,ut):
 		return run_test('btc',auth=True)
 
+	def ltc(self,name,ut):
+		return run_test('ltc',auth=True)
+
+	def bch(self,name,ut):
+		return run_test('bch',auth=True)
+
 	def eth(self,name,ut):
 		return run_test('eth',auth=False)