Browse Source

protocol.py: add Regtest coin protocols, related changes

The MMGen Project 4 years ago
parent
commit
534f58994b
6 changed files with 65 additions and 53 deletions
  1. 3 4
      mmgen/addr.py
  2. 2 2
      mmgen/obj.py
  3. 2 2
      mmgen/opts.py
  4. 49 33
      mmgen/protocol.py
  5. 6 9
      mmgen/tool.py
  6. 3 3
      test/test_py_d/ts_regtest.py

+ 3 - 4
mmgen/addr.py

@@ -698,8 +698,7 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
 				mmtype = MMGenAddrType(al_mmtype,on_fail='raise')
 				mmtype = MMGenAddrType(al_mmtype,on_fail='raise')
 
 
 			from .protocol import init_proto
 			from .protocol import init_proto
-			base_coin = init_proto(al_coin or 'BTC',testnet=False).base_coin
-			return base_coin,mmtype,tn
+			return (init_proto(al_coin or 'BTC').base_coin, mmtype, tn)
 
 
 		def check_coin_mismatch(base_coin): # die if addrfile coin doesn't match g.coin
 		def check_coin_mismatch(base_coin): # die if addrfile coin doesn't match g.coin
 			m = '{} address file format, but base coin is {}!'
 			m = '{} address file format, but base coin is {}!'
@@ -960,8 +959,8 @@ Record this checksum: it will be used to verify the password file in the future
 			pw_len_hex = baseconv.seedlen_map_rev['xmrseed'][self.pw_len] * 2
 			pw_len_hex = baseconv.seedlen_map_rev['xmrseed'][self.pw_len] * 2
 			# take most significant part
 			# take most significant part
 			bytes_trunc = bytes.fromhex(hex_sec[:pw_len_hex])
 			bytes_trunc = bytes.fromhex(hex_sec[:pw_len_hex])
-			from .protocol import CoinProtocol
-			bytes_preproc = CoinProtocol.Monero().preprocess_key(bytes_trunc,None)
+			from .protocol import init_proto
+			bytes_preproc = init_proto('xmr').preprocess_key(bytes_trunc,None)
 			return ' '.join(baseconv.frombytes(bytes_preproc,wl_id='xmrseed'))
 			return ' '.join(baseconv.frombytes(bytes_preproc,wl_id='xmrseed'))
 		else:
 		else:
 			# take least significant part
 			# take least significant part

+ 2 - 2
mmgen/obj.py

@@ -541,8 +541,8 @@ class CoinAddr(str,Hilite,InitErrors,MMGenObject):
 		if type(g.proto).__name__.startswith('Ethereum'):
 		if type(g.proto).__name__.startswith('Ethereum'):
 			return True
 			return True
 
 
-		from mmgen.protocol import CoinProtocol
-		proto = CoinProtocol.get_protocol_by_chain(chain)
+		from mmgen.protocol import init_proto
+		proto = init_proto(g.coin,network=chain)
 
 
 		if self.addr_fmt == 'bech32':
 		if self.addr_fmt == 'bech32':
 			return self[:len(proto.bech32_hrp)] == proto.bech32_hrp
 			return self[:len(proto.bech32_hrp)] == proto.bech32_hrp

+ 2 - 2
mmgen/opts.py

@@ -273,7 +273,7 @@ def init(opts_data=None,add_opts=[],opt_filter=None,parse_only=False):
 	if g.regtest: # These are equivalent for now
 	if g.regtest: # These are equivalent for now
 		g.testnet = True
 		g.testnet = True
 
 
-	g.network = 'testnet' if g.testnet else 'mainnet'
+	g.network = 'regtest' if g.regtest else 'testnet' if g.testnet else 'mainnet'
 
 
 	from .protocol import init_genonly_altcoins,init_proto
 	from .protocol import init_genonly_altcoins,init_proto
 	altcoin_trust_level = init_genonly_altcoins(g.coin)
 	altcoin_trust_level = init_genonly_altcoins(g.coin)
@@ -309,7 +309,7 @@ def init(opts_data=None,add_opts=[],opt_filter=None,parse_only=False):
 	if g.bob or g.alice:
 	if g.bob or g.alice:
 		g.testnet = True
 		g.testnet = True
 		g.regtest = True
 		g.regtest = True
-		g.proto = init_proto(g.coin,g.testnet)
+		g.proto = init_proto(g.coin,regtest=True)
 		g.rpc_host = 'localhost'
 		g.rpc_host = 'localhost'
 		g.data_dir = os.path.join(g.data_dir_root,'regtest',g.coin.lower(),('alice','bob')[g.bob])
 		g.data_dir = os.path.join(g.data_dir_root,'regtest',g.coin.lower(),('alice','bob')[g.bob])
 		from .regtest import MMGenRegtest
 		from .regtest import MMGenRegtest

+ 49 - 33
mmgen/protocol.py

@@ -71,32 +71,33 @@ finfo = namedtuple('fork_info',['height','hash','name','replayable'])
 
 
 class CoinProtocol(MMGenObject):
 class CoinProtocol(MMGenObject):
 
 
-	proto_info = namedtuple('proto_info',['mainnet','testnet','trust_level']) # trust levels: see altcoin.py
+	proto_info = namedtuple('proto_info',['base_name','trust_level']) # trust levels: see altcoin.py
 	coins = {
 	coins = {
-		'btc': proto_info('Bitcoin',         'BitcoinTestnet',         5),
-		'bch': proto_info('BitcoinCash',     'BitcoinCashTestnet',     5),
-		'ltc': proto_info('Litecoin',        'LitecoinTestnet',        5),
-		'eth': proto_info('Ethereum',        'EthereumTestnet',        4),
-		'etc': proto_info('EthereumClassic', 'EthereumClassicTestnet', 4),
-		'zec': proto_info('Zcash',           'ZcashTestnet',           2),
-		'xmr': proto_info('Monero',          'MoneroTestnet',          4)
+		'btc': proto_info('Bitcoin',         5),
+		'bch': proto_info('BitcoinCash',     5),
+		'ltc': proto_info('Litecoin',        5),
+		'eth': proto_info('Ethereum',        4),
+		'etc': proto_info('EthereumClassic', 4),
+		'zec': proto_info('Zcash',           2),
+		'xmr': proto_info('Monero',          4)
 	}
 	}
 	core_coins = tuple(coins.keys()) # coins may be added by init_genonly_altcoins(), so save
 	core_coins = tuple(coins.keys()) # coins may be added by init_genonly_altcoins(), so save
 
 
-	@staticmethod
-	def get_protocol_by_chain(chain):
-		return init_proto(g.coin,{'mainnet':False,'testnet':True,'regtest':True}[chain])
-
 	class Common(MMGenObject):
 	class Common(MMGenObject):
+		networks = ('mainnet','testnet','regtest')
+
+		def __init__(self,coin,base_name,network):
+			self.coin    = coin.upper()
+			self.name    = base_name[0].lower() + base_name[1:]
+			self.network = network
 
 
 		def is_testnet(self):
 		def is_testnet(self):
-			return type(self).__name__.endswith('Testnet')
+			return self.network in ('testnet','regtest')
 
 
 		def cap(self,s):
 		def cap(self,s):
 			return s in self.caps
 			return s in self.caps
 
 
 	class Bitcoin(Common): # chainparams.cpp
 	class Bitcoin(Common): # chainparams.cpp
-		name            = 'bitcoin'
 		mod_clsname     = 'bitcoin'
 		mod_clsname     = 'bitcoin'
 		daemon_name     = 'bitcoind'
 		daemon_name     = 'bitcoind'
 		daemon_family   = 'bitcoind'
 		daemon_family   = 'bitcoind'
@@ -236,7 +237,10 @@ class CoinProtocol(MMGenObject):
 		data_subdir         = 'testnet'
 		data_subdir         = 'testnet'
 		daemon_data_subdir  = 'testnet3'
 		daemon_data_subdir  = 'testnet3'
 		rpc_port            = 18332
 		rpc_port            = 18332
-		bech32_hrps         = {'testnet':'tb','regtest':'bcrt'}
+		bech32_hrp          = 'tb'
+
+	class BitcoinRegtest(BitcoinTestnet):
+		bech32_hrp          = 'bcrt'
 
 
 	class BitcoinCash(Bitcoin):
 	class BitcoinCash(Bitcoin):
 		# TODO: assumes MSWin user installs in custom dir 'Bitcoin_ABC'
 		# TODO: assumes MSWin user installs in custom dir 'Bitcoin_ABC'
@@ -263,6 +267,9 @@ class CoinProtocol(MMGenObject):
 		data_subdir    = 'testnet'
 		data_subdir    = 'testnet'
 		daemon_data_subdir = 'testnet3'
 		daemon_data_subdir = 'testnet3'
 
 
+	class BitcoinCashRegtest(BitcoinCashTestnet):
+		pass
+
 	class B2X(Bitcoin):
 	class B2X(Bitcoin):
 		daemon_name     = 'bitcoind-2x'
 		daemon_name     = 'bitcoind-2x'
 		daemon_data_dir = os.path.join(os.getenv('APPDATA'),'Bitcoin_2X') if g.platform == 'win' \
 		daemon_data_dir = os.path.join(os.getenv('APPDATA'),'Bitcoin_2X') if g.platform == 'win' \
@@ -283,7 +290,6 @@ class CoinProtocol(MMGenObject):
 
 
 	class Litecoin(Bitcoin):
 	class Litecoin(Bitcoin):
 		block0          = '12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2'
 		block0          = '12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2'
-		name            = 'litecoin'
 		daemon_name     = 'litecoind'
 		daemon_name     = 'litecoind'
 		daemon_data_dir = os.path.join(os.getenv('APPDATA'),'Litecoin') if g.platform == 'win' \
 		daemon_data_dir = os.path.join(os.getenv('APPDATA'),'Litecoin') if g.platform == 'win' \
 							else os.path.join(g.home_dir,'.litecoin')
 							else os.path.join(g.home_dir,'.litecoin')
@@ -306,7 +312,10 @@ class CoinProtocol(MMGenObject):
 		data_subdir        = 'testnet'
 		data_subdir        = 'testnet'
 		daemon_data_subdir = 'testnet4'
 		daemon_data_subdir = 'testnet4'
 		rpc_port           = 19332
 		rpc_port           = 19332
-		bech32_hrps        = {'testnet':'tltc','regtest':'rltc'}
+		bech32_hrp         = 'tltc'
+
+	class LitecoinRegtest(LitecoinTestnet):
+		bech32_hrp        = 'rltc'
 
 
 	class BitcoinAddrgen(Bitcoin):
 	class BitcoinAddrgen(Bitcoin):
 		mmcaps = ('key','addr')
 		mmcaps = ('key','addr')
@@ -330,7 +339,6 @@ class CoinProtocol(MMGenObject):
 		addr_len      = 20
 		addr_len      = 20
 		mmtypes       = ('E',)
 		mmtypes       = ('E',)
 		dfl_mmtype    = 'E'
 		dfl_mmtype    = 'E'
-		name          = 'ethereum'
 		mod_clsname   = 'ethereum'
 		mod_clsname   = 'ethereum'
 		base_coin     = 'ETH'
 		base_coin     = 'ETH'
 		pubkey_type   = 'std' # required by DummyWIF
 		pubkey_type   = 'std' # required by DummyWIF
@@ -365,7 +373,6 @@ class CoinProtocol(MMGenObject):
 		chain_name  = 'kovan'
 		chain_name  = 'kovan'
 
 
 	class EthereumClassic(Ethereum):
 	class EthereumClassic(Ethereum):
-		name       = 'ethereumClassic' # TODO
 		rpc_port   = 8555 # start Parity with --jsonrpc-port=8555 or --ports-shift=10
 		rpc_port   = 8555 # start Parity with --jsonrpc-port=8555 or --ports-shift=10
 		chain_name = 'ethereum_classic' # chain_id 0x3d (61)
 		chain_name = 'ethereum_classic' # chain_id 0x3d (61)
 
 
@@ -374,7 +381,6 @@ class CoinProtocol(MMGenObject):
 		chain_name = 'classic-testnet' # aka Morden, chain_id 0x3e (62) (UNTESTED)
 		chain_name = 'classic-testnet' # aka Morden, chain_id 0x3e (62) (UNTESTED)
 
 
 	class Zcash(BitcoinAddrgen):
 	class Zcash(BitcoinAddrgen):
-		name           = 'zcash'
 		base_coin      = 'ZEC'
 		base_coin      = 'ZEC'
 		addr_ver_bytes = { '1cb8': 'p2pkh', '1cbd': 'p2sh', '169a': 'zcash_z', 'a8abd3': 'viewkey' }
 		addr_ver_bytes = { '1cb8': 'p2pkh', '1cbd': 'p2sh', '169a': 'zcash_z', 'a8abd3': 'viewkey' }
 		wif_ver_num    = { 'std': '80', 'zcash_z': 'ab36' }
 		wif_ver_num    = { 'std': '80', 'zcash_z': 'ab36' }
@@ -405,7 +411,6 @@ class CoinProtocol(MMGenObject):
 
 
 # https://github.com/monero-project/monero/blob/master/src/cryptonote_config.h
 # https://github.com/monero-project/monero/blob/master/src/cryptonote_config.h
 	class Monero(DummyWIF,BitcoinAddrgen):
 	class Monero(DummyWIF,BitcoinAddrgen):
-		name           = 'monero'
 		base_coin      = 'XMR'
 		base_coin      = 'XMR'
 		addr_ver_bytes = { '12': 'monero', '2a': 'monero_sub' }
 		addr_ver_bytes = { '12': 'monero', '2a': 'monero_sub' }
 		addr_len       = 68
 		addr_len       = 68
@@ -445,18 +450,32 @@ class CoinProtocol(MMGenObject):
 	class MoneroTestnet(Monero):
 	class MoneroTestnet(Monero):
 		addr_ver_bytes = { '35': 'monero', '3f': 'monero_sub' }
 		addr_ver_bytes = { '35': 'monero', '3f': 'monero_sub' }
 
 
-def init_proto(coin,testnet):
+def init_proto(coin,testnet=False,regtest=False,network=None):
+
+	assert type(testnet) == bool
+	assert type(regtest) == bool
+
+	if network is None:
+		network = 'regtest' if regtest else 'testnet' if testnet else 'mainnet'
+	else:
+		assert network in CoinProtocol.Common.networks
+		assert testnet == False
+		assert regtest == False
+
 	coin = coin.lower()
 	coin = coin.lower()
-	assert type(testnet) == bool, type(testnet)
 	if coin not in CoinProtocol.coins:
 	if coin not in CoinProtocol.coins:
 		raise ValueError(
 		raise ValueError(
 			'{}: not a valid coin for network {}\nSupported coins: {}'.format(
 			'{}: not a valid coin for network {}\nSupported coins: {}'.format(
 				coin.upper(),g.network.upper(),
 				coin.upper(),g.network.upper(),
 				' '.join(c.upper() for c in CoinProtocol.coins) ))
 				' '.join(c.upper() for c in CoinProtocol.coins) ))
-	proto = getattr(CoinProtocol,CoinProtocol.coins[coin][testnet])
-	if hasattr(proto,'bech32_hrps'):
-		proto.bech32_hrp = proto.bech32_hrps[('testnet','regtest')[g.regtest]]
-	return proto()
+
+	base_name = CoinProtocol.coins[coin].base_name
+	proto_name = base_name + ('' if network == 'mainnet' else network.capitalize())
+
+	return getattr(CoinProtocol,proto_name)(
+		coin      = coin,
+		base_name = base_name,
+		network   = network )
 
 
 def init_genonly_altcoins(usr_coin=None):
 def init_genonly_altcoins(usr_coin=None):
 	"""
 	"""
@@ -513,8 +532,6 @@ def make_init_genonly_altcoins_str(data):
 		return f"""
 		return f"""
 	class {proto}(CoinProtocol.BitcoinAddrgen{tn_str}):
 	class {proto}(CoinProtocol.BitcoinAddrgen{tn_str}):
 		base_coin      = {coin!r}
 		base_coin      = {coin!r}
-		name           = {e.name.lower()!r}
-		nameCaps       = {e.name!r}
 		addr_ver_bytes = {{ {num2hexstr(e.p2pkh_info[0])}: 'p2pkh'{p2sh_info} }}
 		addr_ver_bytes = {{ {num2hexstr(e.p2pkh_info[0])}: 'p2pkh'{p2sh_info} }}
 		wif_ver_num    = {{ 'std': {num2hexstr(e.wif_ver_num)} }}
 		wif_ver_num    = {{ 'std': {num2hexstr(e.wif_ver_num)} }}
 		mmtypes        = ('L','C'{sw_mmtype})
 		mmtypes        = ('L','C'{sw_mmtype})
@@ -535,10 +552,9 @@ def make_init_genonly_altcoins_str(data):
 				proto = 'X_'+proto
 				proto = 'X_'+proto
 			if hasattr(CoinProtocol,proto) or coin.lower() in CoinProtocol.coins:
 			if hasattr(CoinProtocol,proto) or coin.lower() in CoinProtocol.coins:
 				continue
 				continue
-			yield 'CoinProtocol.coins[{!r}] = CoinProtocol.proto_info({!r},{},{})'.format(
+			yield 'CoinProtocol.coins[{!r}] = CoinProtocol.proto_info({!r},{})'.format(
 				coin.lower(),
 				coin.lower(),
 				proto,
 				proto,
-				('None',f"'{proto}Testnet'")[coin in [e.symbol for e in data['testnet']]],
 				e.trust_level )
 				e.trust_level )
 
 
 	return '\n'.join(gen_text()) + '\n'
 	return '\n'.join(gen_text()) + '\n'
@@ -546,7 +562,7 @@ def make_init_genonly_altcoins_str(data):
 def init_coin(coin,testnet=None):
 def init_coin(coin,testnet=None):
 	if testnet is not None:
 	if testnet is not None:
 		g.testnet = testnet
 		g.testnet = testnet
-	g.network = ('mainnet','testnet')[g.testnet]
+	g.network = 'regtest' if g.regtest else 'testnet' if g.testnet else 'mainnet'
 	g.coin = coin.upper()
 	g.coin = coin.upper()
-	g.proto = init_proto(g.coin,g.testnet)
+	g.proto = init_proto(g.coin,testnet=g.testnet,regtest=g.regtest)
 	return g.proto
 	return g.proto

+ 6 - 9
mmgen/tool.py

@@ -526,12 +526,12 @@ class MMGenToolCmdMnemonic(MMGenToolCmds):
 
 
 	@staticmethod
 	@staticmethod
 	def _xmr_reduce(bytestr):
 	def _xmr_reduce(bytestr):
-		from .protocol import CoinProtocol
-		p = CoinProtocol.Monero()
-		if len(bytestr) != p.privkey_len:
+		from .protocol import init_proto
+		proto = init_proto('xmr')
+		if len(bytestr) != proto.privkey_len:
 			m = '{!r}: invalid bit length for Monero private key (must be {})'
 			m = '{!r}: invalid bit length for Monero private key (must be {})'
-			die(1,m.format(len(bytestr*8),p.privkey_len*8))
-		return p.preprocess_key(bytestr,None)
+			die(1,m.format(len(bytestr*8),proto.privkey_len*8))
+		return proto.preprocess_key(bytestr,None)
 
 
 	def _do_random_mn(self,nbytes:int,fmt:str):
 	def _do_random_mn(self,nbytes:int,fmt:str):
 		assert nbytes in (16,24,32), 'nbytes must be 16, 24 or 32'
 		assert nbytes in (16,24,32), 'nbytes must be 16, 24 or 32'
@@ -1208,10 +1208,7 @@ class tool_api(
 	@property
 	@property
 	def network(self):
 	def network(self):
 		"""The currently configured network"""
 		"""The currently configured network"""
-		if g.network == 'testnet':
-			return ('testnet','regtest')[g.regtest]
-		else:
-			return g.network
+		return g.network
 
 
 	@property
 	@property
 	def addrtypes(self):
 	def addrtypes(self):

+ 3 - 3
test/test_py_d/ts_regtest.py

@@ -344,7 +344,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 					x='-α' if g.debug_utf8 else ''))
 					x='-α' if g.debug_utf8 else ''))
 			if mmtype == g.proto.mmtypes[0] and user == 'bob':
 			if mmtype == g.proto.mmtypes[0] and user == 'bob':
 				psave = g.proto
 				psave = g.proto
-				g.proto = init_proto(g.coin,True)
+				g.proto = init_proto(g.coin,regtest=True)
 				self._add_comments_to_addr_file(addrfile,addrfile,use_labels=True)
 				self._add_comments_to_addr_file(addrfile,addrfile,use_labels=True)
 				g.proto = psave
 				g.proto = psave
 			t = self.spawn( 'mmgen-addrimport',
 			t = self.spawn( 'mmgen-addrimport',
@@ -568,7 +568,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 			sid,self.altcoin_pfx,id_str,addr_range,x='-α' if g.debug_utf8 else '')
 			sid,self.altcoin_pfx,id_str,addr_range,x='-α' if g.debug_utf8 else '')
 		addrfile = get_file_with_ext(self._user_dir(user),ext,no_dot=True)
 		addrfile = get_file_with_ext(self._user_dir(user),ext,no_dot=True)
 		psave = g.proto
 		psave = g.proto
-		g.proto = init_proto(g.coin,True)
+		g.proto = init_proto(g.coin,regtest=True)
 		silence()
 		silence()
 		addr = AddrList(addrfile).data[idx].addr
 		addr = AddrList(addrfile).data[idx].addr
 		end_silence()
 		end_silence()
@@ -810,7 +810,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 			"MMGen address '{}' not found in tracking wallet".format(addr))
 			"MMGen address '{}' not found in tracking wallet".format(addr))
 
 
 	def alice_add_label_badaddr4(self):
 	def alice_add_label_badaddr4(self):
-		addr = init_proto(g.coin,True).pubhash2addr('00'*20,False) # testnet zero address
+		addr = init_proto(g.coin,regtest=True).pubhash2addr('00'*20,False) # testnet zero address
 		return self.alice_add_label_badaddr(addr,
 		return self.alice_add_label_badaddr(addr,
 			"Address '{}' not found in tracking wallet".format(addr))
 			"Address '{}' not found in tracking wallet".format(addr))