altcoin.py -> altcoin/params.py, test/altcointest.py
This commit is contained in:
parent
a8a849f143
commit
525b54af8e
8 changed files with 509 additions and 496 deletions
0
mmgen/altcoin/__init__.py
Executable file
0
mmgen/altcoin/__init__.py
Executable file
|
|
@ -1,23 +1,15 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
|
||||
# Copyright (C)2013-2023 The MMGen Project <mmgen@tuta.io>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# Licensed under the GNU General Public License, Version 3:
|
||||
# https://www.gnu.org/licenses
|
||||
# Public project repositories:
|
||||
# https://github.com/mmgen/mmgen-wallet
|
||||
# https://gitlab.com/mmgen/mmgen-wallet
|
||||
|
||||
"""
|
||||
altcoin.py - Coin constants for Bitcoin-derived altcoins
|
||||
altcoin.py - Constants for Bitcoin-derived altcoins
|
||||
"""
|
||||
|
||||
# Sources:
|
||||
|
|
@ -38,19 +30,9 @@ altcoin.py - Coin constants for Bitcoin-derived altcoins
|
|||
import sys
|
||||
from collections import namedtuple
|
||||
|
||||
from .cfg import gc,Config
|
||||
from .util import msg
|
||||
|
||||
def test_equal(desc,a,b,*cdata):
|
||||
if type(a) is int:
|
||||
a = hex(a)
|
||||
b = hex(b)
|
||||
(network,coin,_,b_desc,verbose) = cdata
|
||||
if verbose:
|
||||
msg(f' {desc:20}: {a!r}')
|
||||
if a != b:
|
||||
raise ValueError(
|
||||
f'{desc.capitalize()}s for {coin.upper()} {network} do not match:\n CoinInfo: {a}\n {b_desc}: {b}' )
|
||||
from ..cfg import gc
|
||||
from ..protocol import CoinProtocol
|
||||
from ..proto.btc.params import mainnet
|
||||
|
||||
ce = namedtuple('CoinInfoEntry',
|
||||
['name','symbol','wif_ver_num','p2pkh_info','p2sh_info','has_segwit','trust_level'])
|
||||
|
|
@ -274,196 +256,6 @@ class CoinInfo:
|
|||
('POT', 'https://github.com/potcoin/Potcoin/blob/master/src/base58.h'),
|
||||
)
|
||||
|
||||
# Sources (see above) that are in agreement for these coins
|
||||
# No check for segwit, p2sh check skipped if source doesn't support it
|
||||
cross_checks = {
|
||||
'2GIVE': ['wn'],
|
||||
'42': ['vg','wn'],
|
||||
'611': ['wn'],
|
||||
'AC': ['lb','vg'],
|
||||
'ACOIN': ['wn'],
|
||||
'ALF': ['wn'],
|
||||
'ANC': ['vg','wn'],
|
||||
'APEX': ['wn'],
|
||||
'ARCO': ['wn'],
|
||||
'ARG': ['pc'],
|
||||
'AUR': ['vg','wn'],
|
||||
'BCH': ['wn'],
|
||||
'BLK': ['lb','vg','wn'],
|
||||
'BQC': ['vg','wn'],
|
||||
'BSTY': ['wn'],
|
||||
'BTC': ['lb','vg','wn'],
|
||||
'BTCD': ['lb','vg','wn'],
|
||||
'BUCKS': ['wn'],
|
||||
'CASH': ['wn'],
|
||||
'CBX': ['wn'],
|
||||
'CCN': ['lb','vg','wn'],
|
||||
'CDN': ['lb','vg','wn'],
|
||||
'CHC': ['wn'],
|
||||
'CLAM': ['lb','vg'],
|
||||
'CON': ['vg','wn'],
|
||||
'CPC': ['wn'],
|
||||
'DASH': ['lb','pc','vg','wn'],
|
||||
'DCR': ['pc'],
|
||||
'DFC': ['pc'],
|
||||
'DGB': ['lb','vg'],
|
||||
'DGC': ['lb','vg','wn'],
|
||||
'DOGE': ['lb','pc','vg','wn'],
|
||||
'DOGED': ['lb','vg','wn'],
|
||||
'DOPE': ['lb','vg'],
|
||||
'DVC': ['vg','wn'],
|
||||
'EFL': ['lb','vg','wn'],
|
||||
'EMC': ['vg'],
|
||||
'EMD': ['wn'],
|
||||
'ESP': ['wn'],
|
||||
'FAI': ['pc'],
|
||||
'FC2': ['wn'],
|
||||
'FIBRE': ['wn'],
|
||||
'FJC': ['wn'],
|
||||
'FLO': ['wn'],
|
||||
'FLT': ['wn'],
|
||||
'FST': ['wn'],
|
||||
'FTC': ['lb','pc','vg','wn'],
|
||||
'GCR': ['lb','vg'],
|
||||
'GOOD': ['wn'],
|
||||
'GRC': ['vg','wn'],
|
||||
'GUN': ['vg','wn'],
|
||||
'HAM': ['vg','wn'],
|
||||
'HTML5': ['wn'],
|
||||
'HYP': ['wn'],
|
||||
'ICASH': ['wn'],
|
||||
'INFX': ['wn'],
|
||||
'IPC': ['wn'],
|
||||
'JBS': ['lb','pc','vg','wn'],
|
||||
'JUDGE': ['wn'],
|
||||
'LANA': ['wn'],
|
||||
'LAT': ['wn'],
|
||||
'LDOGE': ['wn'],
|
||||
'LMC': ['wn'],
|
||||
'LTC': ['lb','vg','wn'],
|
||||
'MARS': ['wn'],
|
||||
'MEC': ['pc','wn'],
|
||||
'MINT': ['wn'],
|
||||
'MOBI': ['wn'],
|
||||
'MONA': ['lb','vg'],
|
||||
'MOON': ['wn'],
|
||||
'MUE': ['lb','vg'],
|
||||
'MXT': ['wn'],
|
||||
'MYR': ['pc'],
|
||||
'MYRIAD': ['vg','wn'],
|
||||
'MZC': ['lb','pc','vg','wn'],
|
||||
'NEOS': ['lb','vg'],
|
||||
'NEVA': ['wn'],
|
||||
'NKA': ['wn'],
|
||||
'NLG': ['vg','wn'],
|
||||
'NMC': ['lb','vg'],
|
||||
'NVC': ['lb','vg','wn'],
|
||||
'OK': ['lb','vg'],
|
||||
'OMC': ['vg','wn'],
|
||||
'ONION': ['vg','wn'],
|
||||
'PART': ['wn'],
|
||||
'PINK': ['vg','wn'],
|
||||
'PIVX': ['wn'],
|
||||
'PKB': ['lb','vg','wn'],
|
||||
'PND': ['lb','vg','wn'],
|
||||
'POT': ['lb','vg','wn'],
|
||||
'PPC': ['lb','vg','wn'],
|
||||
'PTC': ['vg','wn'],
|
||||
'PXC': ['wn'],
|
||||
'QRK': ['wn'],
|
||||
'RAIN': ['wn'],
|
||||
'RBT': ['wn'],
|
||||
'RBY': ['lb','vg'],
|
||||
'RDD': ['vg','wn'],
|
||||
'RIC': ['pc','vg','wn'],
|
||||
'SDC': ['lb','vg'],
|
||||
'SIB': ['wn'],
|
||||
'SMLY': ['wn'],
|
||||
'SONG': ['wn'],
|
||||
'SPR': ['vg','wn'],
|
||||
'START': ['lb','vg'],
|
||||
'SYS': ['wn'],
|
||||
'TAJ': ['wn'],
|
||||
'TIT': ['wn'],
|
||||
'TPC': ['lb','vg'],
|
||||
'TRC': ['wn'],
|
||||
'TTC': ['wn'],
|
||||
'TX': ['wn'],
|
||||
'UNO': ['pc','vg','wn'],
|
||||
'VIA': ['lb','pc','vg','wn'],
|
||||
'VPN': ['lb','vg'],
|
||||
'VTC': ['lb','vg','wn'],
|
||||
'WDC': ['vg','wn'],
|
||||
'WISC': ['wn'],
|
||||
'WKC': ['vg','wn'],
|
||||
'WSX': ['wn'],
|
||||
'XCN': ['wn'],
|
||||
'XGB': ['wn'],
|
||||
'XPM': ['lb','vg','wn'],
|
||||
'XST': ['wn'],
|
||||
'XVC': ['wn'],
|
||||
'ZET': ['wn'],
|
||||
'ZOOM': ['lb','vg'],
|
||||
'ZRC': ['lb','vg']
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def verify_leading_symbols(cls,quiet=False,verbose=False):
|
||||
|
||||
for network in ('mainnet','testnet'):
|
||||
for coin in [e.symbol for e in cls.coin_constants[network]]:
|
||||
e = cls.get_entry(coin,network)
|
||||
cdata = (network,coin,e,'Computed value',verbose)
|
||||
|
||||
if not quiet:
|
||||
msg(f'{coin} {network}')
|
||||
|
||||
vn_info = e.p2pkh_info
|
||||
ret = cls.find_addr_leading_symbol(vn_info[0])
|
||||
test_equal('P2PKH leading symbol',vn_info[1],ret,*cdata)
|
||||
|
||||
vn_info = e.p2sh_info
|
||||
if vn_info:
|
||||
ret = cls.find_addr_leading_symbol(vn_info[0])
|
||||
test_equal('P2SH leading symbol',vn_info[1],ret,*cdata)
|
||||
|
||||
@classmethod
|
||||
def verify_core_coin_data(cls,cfg,quiet=False,verbose=False):
|
||||
from .protocol import CoinProtocol,init_proto
|
||||
|
||||
for network in ('mainnet','testnet'):
|
||||
for coin in gc.core_coins:
|
||||
e = cls.get_entry(coin,network)
|
||||
if e:
|
||||
proto = init_proto( cfg, coin, network=network )
|
||||
cdata = (network,coin,e,type(proto).__name__,verbose)
|
||||
if not quiet:
|
||||
msg(f'Verifying {coin.upper()} {network}')
|
||||
|
||||
if coin != 'bch': # TODO
|
||||
test_equal('coin name',e.name,proto.name,*cdata)
|
||||
|
||||
if e.trust_level != -1:
|
||||
test_equal('Trust level',e.trust_level,CoinProtocol.coins[coin].trust_level,*cdata)
|
||||
|
||||
test_equal(
|
||||
'WIF version number',
|
||||
e.wif_ver_num,
|
||||
int.from_bytes(proto.wif_ver_bytes['std'],'big'),
|
||||
*cdata )
|
||||
|
||||
test_equal(
|
||||
'P2PKH version number',
|
||||
e.p2pkh_info[0],
|
||||
int.from_bytes(proto.addr_fmt_to_ver_bytes['p2pkh'],'big'),
|
||||
*cdata )
|
||||
|
||||
test_equal(
|
||||
'P2SH version number',
|
||||
e.p2sh_info[0],
|
||||
int.from_bytes(proto.addr_fmt_to_ver_bytes['p2sh'],'big'),
|
||||
*cdata )
|
||||
|
||||
@classmethod
|
||||
def get_supported_coins(cls,network):
|
||||
return [e for e in cls.coin_constants[network] if e.trust_level != -1]
|
||||
|
|
@ -476,225 +268,35 @@ class CoinInfo:
|
|||
return None
|
||||
return cls.coin_constants[network][idx]
|
||||
|
||||
# Data is one of the coin_constants lists above. Normalize ints to hex of correct width, add
|
||||
# missing leading letters, set trust level from external_tests.
|
||||
# Insert a coin entry from outside source, set version info leading letters to '?' and trust level
|
||||
# to 0, then run CoinInfo.fix_table(data). 'has_segwit' field is updated manually for now.
|
||||
@classmethod
|
||||
def fix_table(cls,data):
|
||||
import re
|
||||
def make_proto(e,testnet=False):
|
||||
|
||||
def myhex(n):
|
||||
return '0x{:0{}x}'.format(n,2 if n < 256 else 4)
|
||||
proto = ('X_' if e.name[0] in '0123456789' else '') + e.name + ('Testnet' if testnet else '')
|
||||
|
||||
def fix_ver_info(e,k):
|
||||
e[k] = list(e[k])
|
||||
e[k][0] = myhex(e[k][0])
|
||||
s1 = cls.find_addr_leading_symbol(int(e[k][0][2:],16))
|
||||
m = f'Fixing leading address letter for coin {e["symbol"]} ({e[k][1]!r} --> {s1})'
|
||||
if e[k][1] != '?':
|
||||
assert s1 == e[k][1], f'First letters do not match! {m}'
|
||||
else:
|
||||
msg(m)
|
||||
e[k][1] = s1
|
||||
e[k] = tuple(e[k])
|
||||
if hasattr(CoinProtocol,proto):
|
||||
return
|
||||
|
||||
old_sym = None
|
||||
for sym in sorted([e.symbol for e in data]):
|
||||
if sym == old_sym:
|
||||
msg(f'{sym!r}: duplicate coin symbol in data!')
|
||||
sys.exit(2)
|
||||
old_sym = sym
|
||||
def num2hexstr(n):
|
||||
return '{:0{}x}'.format(n,(4,2)[n < 256])
|
||||
|
||||
tt = cls.create_trust_table()
|
||||
|
||||
name_w = max(len(e.name) for e in data)
|
||||
fs = '\t({:%s} {:10} {:7} {:17} {:17} {:6} {}),' % (name_w+3)
|
||||
for e in data:
|
||||
e = e._asdict()
|
||||
e['wif_ver_num'] = myhex(e['wif_ver_num'])
|
||||
sym,trust = e['symbol'],e['trust_level']
|
||||
|
||||
fix_ver_info(e,'p2pkh_info')
|
||||
if isinstance(e['p2sh_info'],tuple):
|
||||
fix_ver_info(e,'p2sh_info')
|
||||
|
||||
for k in e.keys():
|
||||
e[k] = repr(e[k])
|
||||
e[k] = re.sub(r"'0x(..)'",r'0x\1',e[k])
|
||||
e[k] = re.sub(r"'0x(....)'",r'0x\1',e[k])
|
||||
e[k] = re.sub(r' ',r'',e[k]) + ('',',')[k != 'trust_level']
|
||||
|
||||
if trust != -1:
|
||||
if sym in tt:
|
||||
src = tt[sym]
|
||||
if src != trust:
|
||||
msg(f'Updating trust for coin {sym!r}: {trust} -> {src}')
|
||||
e['trust_level'] = src
|
||||
else:
|
||||
if trust != 0:
|
||||
msg(f'Downgrading trust for coin {sym!r}: {trust} -> 0')
|
||||
e['trust_level'] = 0
|
||||
|
||||
if sym in cls.cross_checks:
|
||||
if int(e['trust_level']) == 0 and len(cls.cross_checks[sym]) > 1:
|
||||
msg(f'Upgrading trust for coin {sym!r}: {e["trust_level"]} -> 1')
|
||||
e['trust_level'] = 1
|
||||
|
||||
print(fs.format(*e.values()))
|
||||
msg(f'Processed {len(data)} entries')
|
||||
|
||||
@classmethod
|
||||
def find_addr_leading_symbol(cls,ver_num,verbose=False):
|
||||
|
||||
if ver_num == 0:
|
||||
return '1'
|
||||
|
||||
def phash2addr(ver_num,pk_hash):
|
||||
from .proto.btc.common import b58chk_encode
|
||||
bl = ver_num.bit_length()
|
||||
ver_bytes = int.to_bytes(ver_num,bl//8 + bool(bl%8),'big')
|
||||
return b58chk_encode(ver_bytes + pk_hash)
|
||||
|
||||
low = phash2addr(ver_num,b'\x00'*20)
|
||||
high = phash2addr(ver_num,b'\xff'*20)
|
||||
|
||||
if verbose:
|
||||
print('low address: ' + low)
|
||||
print('high address: ' + high)
|
||||
|
||||
l1,h1 = low[0],high[0]
|
||||
return (l1,h1) if l1 != h1 else l1
|
||||
|
||||
@classmethod
|
||||
def print_symbols(cls,include_names=False,reverse=False):
|
||||
for e in cls.coin_constants['mainnet']:
|
||||
if reverse:
|
||||
print(f'{e.symbol:6} {e.name}')
|
||||
else:
|
||||
name_w = max(len(e.name) for e in cls.coin_constants['mainnet'])
|
||||
print((f'{e.name:{name_w}} ' if include_names else '') + e.symbol)
|
||||
|
||||
@classmethod
|
||||
def create_trust_table(cls):
|
||||
tt = {}
|
||||
mn = cls.external_tests['mainnet']
|
||||
for ext_prog in mn:
|
||||
assert len(set(mn[ext_prog])) == len(mn[ext_prog]), f'Duplicate entry in {ext_prog!r}!'
|
||||
for coin in mn[ext_prog]:
|
||||
if coin in tt:
|
||||
tt[coin] += 1
|
||||
else:
|
||||
tt[coin] = 1
|
||||
for k in cls.trust_override:
|
||||
tt[k] = cls.trust_override[k]
|
||||
return tt
|
||||
|
||||
trust_override = {'BTC':3,'BCH':3,'LTC':3,'DASH':1,'EMC':2}
|
||||
|
||||
@classmethod
|
||||
def get_test_support(cls,coin,addr_type,network,toolname=None,verbose=False):
|
||||
"""
|
||||
If requested tool supports coin/addr_type/network triplet, return tool name.
|
||||
If 'tool' is None, return tool that supports coin/addr_type/network triplet.
|
||||
Return None on failure.
|
||||
"""
|
||||
all_tools = [toolname] if toolname else list(cls.external_tests[network].keys())
|
||||
coin = coin.upper()
|
||||
|
||||
for tool in all_tools:
|
||||
if coin in cls.external_tests[network][tool]:
|
||||
break
|
||||
else:
|
||||
if verbose:
|
||||
m1 = 'Requested tool {t!r} does not support coin {c} on network {n}'
|
||||
m2 = 'No test tool found for coin {c} on network {n}'
|
||||
msg((m1 if toolname else m2).format(t=tool,c=coin,n=network))
|
||||
return None
|
||||
|
||||
if addr_type == 'zcash_z':
|
||||
if toolname in (None,'zcash-mini'):
|
||||
return 'zcash-mini'
|
||||
else:
|
||||
if verbose:
|
||||
msg(f"Address type {addr_type!r} supported only by tool 'zcash-mini'")
|
||||
return None
|
||||
|
||||
try:
|
||||
bl = cls.external_tests_blacklist[addr_type][tool]
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
if bl is True or coin in bl:
|
||||
if verbose:
|
||||
msg(f'Tool {tool!r} blacklisted for coin {coin}, addr_type {addr_type!r}')
|
||||
return None
|
||||
|
||||
if toolname: # skip whitelists
|
||||
return tool
|
||||
|
||||
if addr_type in ('segwit','bech32'):
|
||||
st = cls.external_tests_segwit_whitelist
|
||||
if addr_type in st and coin in st[addr_type]:
|
||||
return tool
|
||||
else:
|
||||
if verbose:
|
||||
m1 = 'Requested tool {t!r} does not support coin {c}, addr_type {a!r}, on network {n}'
|
||||
m2 = 'No test tool found supporting coin {c}, addr_type {a!r}, on network {n}'
|
||||
msg((m1 if toolname else m2).format(t=tool,c=coin,n=network,a=addr_type))
|
||||
return None
|
||||
|
||||
return tool
|
||||
|
||||
external_tests = {
|
||||
'mainnet': {
|
||||
# List in order of preference.
|
||||
# If 'tool' is not specified, the first tool supporting the coin will be selected.
|
||||
'pycoin': (
|
||||
'DASH', # only compressed
|
||||
'BCH',
|
||||
'BTC','LTC','VIA','FTC','DOGE','MEC',
|
||||
'JBS','MZC','RIC','DFC','FAI','ARG','ZEC','DCR'),
|
||||
'keyconv': (
|
||||
'BCH',
|
||||
# broken: PIVX
|
||||
'42','AC','AIB','ANC','ARS','ATMOS','AUR','BLK','BQC','BTC','TEST','BTCD','CCC','CCN','CDN',
|
||||
'CLAM','CNC','CNOTE','CON','CRW','DEEPONION','DGB','DGC','DMD','DOGED','DOGE','DOPE',
|
||||
'DVC','EFL','EMC','EXCL','FAIR','FLOZ','FTC','GAME','GAP','GCR','GRC','GRS','GUN','HAM','HODL',
|
||||
'IXC','JBS','LBRY','LEAF','LTC','MMC','MONA','MUE','MYRIAD','MZC','NEOS','NLG','NMC','NVC',
|
||||
'NYAN','OK','OMC','PIGGY','PINK','PKB','PND','POT','PPC','PTC','PTS','QTUM','RBY','RDD',
|
||||
'RIC','SCA','SDC','SKC','SPR','START','SXC','TPC','UIS','UNO','VIA','VPN','VTC','WDC','WKC',
|
||||
'WUBS', 'XC', 'XPM', 'YAC', 'ZOOM', 'ZRC'),
|
||||
'ethkey': ('ETH','ETC'),
|
||||
'zcash-mini': ('ZEC',),
|
||||
'monero-python': ('XMR',),
|
||||
},
|
||||
'testnet': {
|
||||
'pycoin': {
|
||||
'DASH':'tDASH', # only compressed
|
||||
'BCH':'XTN',
|
||||
'BTC':'XTN','LTC':'XLT','VIA':'TVI','FTC':'FTX','DOGE':'XDT','DCR':'DCRT'
|
||||
},
|
||||
'ethkey': {},
|
||||
'keyconv': {}
|
||||
}
|
||||
}
|
||||
external_tests_segwit_whitelist = {
|
||||
# Whitelists apply to the *first* tool in cls.external_tests supporting the given coin/addr_type.
|
||||
# They're ignored if specific tool is requested.
|
||||
'segwit': ('BTC',), # LTC Segwit broken on pycoin: uses old fmt
|
||||
'bech32': ('BTC','LTC'),
|
||||
'compressed': (
|
||||
'BTC','LTC','VIA','FTC','DOGE','DASH','MEC','MYR','UNO',
|
||||
'JBS','MZC','RIC','DFC','FAI','ARG','ZEC','DCR','ZEC'
|
||||
),
|
||||
}
|
||||
external_tests_blacklist = {
|
||||
# Unconditionally block testing of the given coin/addr_type with given tool, or all coins if True
|
||||
'legacy': {},
|
||||
'segwit': { 'keyconv': True },
|
||||
'bech32': { 'keyconv': True },
|
||||
}
|
||||
setattr(
|
||||
CoinProtocol,
|
||||
proto,
|
||||
type(
|
||||
proto,
|
||||
(mainnet,),
|
||||
{
|
||||
'base_coin': e.symbol,
|
||||
'addr_ver_info': dict(
|
||||
[( num2hexstr(e.p2pkh_info[0]), 'p2pkh' )] +
|
||||
([( num2hexstr(e.p2sh_info[0]), 'p2sh' )] if e.p2sh_info else [])
|
||||
),
|
||||
'wif_ver_num': { 'std': num2hexstr(e.wif_ver_num) },
|
||||
'mmtypes': ('L','C','S') if e.has_segwit else ('L','C'),
|
||||
'dfl_mmtype': 'L',
|
||||
'mmcaps': ('key','addr'),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
def init_genonly_altcoins(usr_coin=None,testnet=False):
|
||||
"""
|
||||
|
|
@ -704,6 +306,7 @@ def init_genonly_altcoins(usr_coin=None,testnet=False):
|
|||
If usr_coin is None, initializes all coins for current network with trust level >-1.
|
||||
Returns trust_level of usr_coin, or 0 (untrusted) if usr_coin is None.
|
||||
"""
|
||||
|
||||
data = { 'mainnet': (), 'testnet': () }
|
||||
networks = ['mainnet'] + (['testnet'] if testnet else [])
|
||||
network = 'testnet' if testnet else 'mainnet'
|
||||
|
|
@ -713,7 +316,6 @@ def init_genonly_altcoins(usr_coin=None,testnet=False):
|
|||
data[network] = CoinInfo.get_supported_coins(network)
|
||||
else:
|
||||
if usr_coin.lower() in gc.core_coins: # core coin, so return immediately
|
||||
from .protocol import CoinProtocol
|
||||
return CoinProtocol.coins[usr_coin.lower()].trust_level
|
||||
for network in networks:
|
||||
data[network] = (CoinInfo.get_entry(usr_coin,network),)
|
||||
|
|
@ -724,43 +326,6 @@ def init_genonly_altcoins(usr_coin=None,testnet=False):
|
|||
if cinfo.trust_level == -1:
|
||||
raise ValueError(f'{usr_coin.upper()!r}: unsupported (disabled) coin for network {network.upper()}')
|
||||
|
||||
create_altcoin_protos(data)
|
||||
|
||||
def create_altcoin_protos(data):
|
||||
|
||||
from .protocol import CoinProtocol
|
||||
from .proto.btc.params import mainnet
|
||||
|
||||
def make_proto(e,testnet=False):
|
||||
|
||||
proto = ('X_' if e.name[0] in '0123456789' else '') + e.name + ('Testnet' if testnet else '')
|
||||
|
||||
if hasattr(CoinProtocol,proto):
|
||||
return
|
||||
|
||||
def num2hexstr(n):
|
||||
return '{:0{}x}'.format(n,(4,2)[n < 256])
|
||||
|
||||
setattr(
|
||||
CoinProtocol,
|
||||
proto,
|
||||
type(
|
||||
proto,
|
||||
(mainnet,),
|
||||
{
|
||||
'base_coin': e.symbol,
|
||||
'addr_ver_info': dict(
|
||||
[( num2hexstr(e.p2pkh_info[0]), 'p2pkh' )] +
|
||||
([( num2hexstr(e.p2sh_info[0]), 'p2sh' )] if e.p2sh_info else [])
|
||||
),
|
||||
'wif_ver_num': { 'std': num2hexstr(e.wif_ver_num) },
|
||||
'mmtypes': ('L','C','S') if e.has_segwit else ('L','C'),
|
||||
'dfl_mmtype': 'L',
|
||||
'mmcaps': ('key','addr'),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
for e in data['mainnet']:
|
||||
make_proto(e)
|
||||
|
||||
|
|
@ -773,21 +338,3 @@ def create_altcoin_protos(data):
|
|||
CoinProtocol.coins[e.symbol.lower()] = CoinProtocol.proto_info(
|
||||
name = 'X_'+e.name if e.name[0] in '0123456789' else e.name,
|
||||
trust_level = e.trust_level )
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
opts_data = {
|
||||
'text': {
|
||||
'desc': 'Check altcoin data',
|
||||
'usage':'[opts]',
|
||||
'options': '-q, --quiet Be quieter\n-v, --verbose Be more verbose'
|
||||
}
|
||||
}
|
||||
|
||||
cfg = Config( opts_data=opts_data, need_amt=False )
|
||||
|
||||
msg('Checking CoinInfo WIF/P2PKH/P2SH version numbers and trust levels against protocol.py')
|
||||
CoinInfo.verify_core_coin_data( cfg, cfg.quiet, cfg.verbose )
|
||||
|
||||
msg('Checking CoinInfo address leading symbols')
|
||||
CoinInfo.verify_leading_symbols( cfg.quiet, cfg.verbose )
|
||||
|
|
@ -34,7 +34,7 @@ _nw = namedtuple('coin_networks',['mainnet','testnet','regtest'])
|
|||
|
||||
class CoinProtocol(MMGenObject):
|
||||
|
||||
proto_info = namedtuple('proto_info',['name','trust_level']) # trust levels: see altcoin.py
|
||||
proto_info = namedtuple('proto_info',['name','trust_level']) # trust levels: see altcoin/params.py
|
||||
|
||||
# keys are mirrored in gc.core_coins:
|
||||
coins = {
|
||||
|
|
@ -258,7 +258,7 @@ def init_proto(
|
|||
coin = coin.lower()
|
||||
|
||||
if coin not in CoinProtocol.coins:
|
||||
from .altcoin import init_genonly_altcoins
|
||||
from .altcoin.params import init_genonly_altcoins
|
||||
init_genonly_altcoins( coin, testnet=testnet ) # raises exception on failure
|
||||
|
||||
name = CoinProtocol.coins[coin].name
|
||||
|
|
@ -298,7 +298,7 @@ def warn_trustlevel(cfg):
|
|||
if coinsym.lower() in CoinProtocol.coins:
|
||||
trust_level = CoinProtocol.coins[coinsym.lower()].trust_level
|
||||
else:
|
||||
from .altcoin import CoinInfo
|
||||
from .altcoin.params import CoinInfo
|
||||
e = CoinInfo.get_entry(coinsym,'mainnet')
|
||||
trust_level = e.trust_level if e else None
|
||||
if trust_level in (None,-1):
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class tool_api(
|
|||
def coins(self):
|
||||
"""The available coins"""
|
||||
from ..protocol import CoinProtocol
|
||||
from ..altcoin import CoinInfo
|
||||
from ..altcoin.params import CoinInfo
|
||||
return sorted(set(
|
||||
[c.upper() for c in CoinProtocol.coins]
|
||||
+ [c.symbol for c in CoinInfo.get_supported_coins(self.proto.network)]
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ install_requires =
|
|||
|
||||
packages =
|
||||
mmgen
|
||||
mmgen.altcoin
|
||||
mmgen.contrib
|
||||
mmgen.data
|
||||
mmgen.help
|
||||
|
|
|
|||
465
test/altcointest.py
Executable file
465
test/altcointest.py
Executable file
|
|
@ -0,0 +1,465 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
|
||||
# Copyright (C)2013-2023 The MMGen Project <mmgen@tuta.io>
|
||||
# Licensed under the GNU General Public License, Version 3:
|
||||
# https://www.gnu.org/licenses
|
||||
# Public project repositories:
|
||||
# https://github.com/mmgen/mmgen-wallet
|
||||
# https://gitlab.com/mmgen/mmgen-wallet
|
||||
|
||||
"""
|
||||
altcointest.py - Test constants for Bitcoin-derived altcoins
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
try:
|
||||
from include import test_init
|
||||
except ImportError:
|
||||
from test.include import test_init
|
||||
|
||||
from mmgen.cfg import gc,Config
|
||||
from mmgen.util import msg
|
||||
from mmgen.altcoin.params import CoinInfo
|
||||
|
||||
def test_equal(desc,a,b,*cdata):
|
||||
if type(a) is int:
|
||||
a = hex(a)
|
||||
b = hex(b)
|
||||
(network,coin,_,b_desc,verbose) = cdata
|
||||
if verbose:
|
||||
msg(f' {desc:20}: {a!r}')
|
||||
if a != b:
|
||||
raise ValueError(
|
||||
f'{desc.capitalize()}s for {coin.upper()} {network} do not match:\n CoinInfo: {a}\n {b_desc}: {b}' )
|
||||
|
||||
class TestCoinInfo(CoinInfo):
|
||||
|
||||
# Sources (see CoinInfo) that are in agreement for these coins
|
||||
# No check for segwit, p2sh check skipped if source doesn't support it
|
||||
cross_checks = {
|
||||
'2GIVE': ['wn'],
|
||||
'42': ['vg','wn'],
|
||||
'611': ['wn'],
|
||||
'AC': ['lb','vg'],
|
||||
'ACOIN': ['wn'],
|
||||
'ALF': ['wn'],
|
||||
'ANC': ['vg','wn'],
|
||||
'APEX': ['wn'],
|
||||
'ARCO': ['wn'],
|
||||
'ARG': ['pc'],
|
||||
'AUR': ['vg','wn'],
|
||||
'BCH': ['wn'],
|
||||
'BLK': ['lb','vg','wn'],
|
||||
'BQC': ['vg','wn'],
|
||||
'BSTY': ['wn'],
|
||||
'BTC': ['lb','vg','wn'],
|
||||
'BTCD': ['lb','vg','wn'],
|
||||
'BUCKS': ['wn'],
|
||||
'CASH': ['wn'],
|
||||
'CBX': ['wn'],
|
||||
'CCN': ['lb','vg','wn'],
|
||||
'CDN': ['lb','vg','wn'],
|
||||
'CHC': ['wn'],
|
||||
'CLAM': ['lb','vg'],
|
||||
'CON': ['vg','wn'],
|
||||
'CPC': ['wn'],
|
||||
'DASH': ['lb','pc','vg','wn'],
|
||||
'DCR': ['pc'],
|
||||
'DFC': ['pc'],
|
||||
'DGB': ['lb','vg'],
|
||||
'DGC': ['lb','vg','wn'],
|
||||
'DOGE': ['lb','pc','vg','wn'],
|
||||
'DOGED': ['lb','vg','wn'],
|
||||
'DOPE': ['lb','vg'],
|
||||
'DVC': ['vg','wn'],
|
||||
'EFL': ['lb','vg','wn'],
|
||||
'EMC': ['vg'],
|
||||
'EMD': ['wn'],
|
||||
'ESP': ['wn'],
|
||||
'FAI': ['pc'],
|
||||
'FC2': ['wn'],
|
||||
'FIBRE': ['wn'],
|
||||
'FJC': ['wn'],
|
||||
'FLO': ['wn'],
|
||||
'FLT': ['wn'],
|
||||
'FST': ['wn'],
|
||||
'FTC': ['lb','pc','vg','wn'],
|
||||
'GCR': ['lb','vg'],
|
||||
'GOOD': ['wn'],
|
||||
'GRC': ['vg','wn'],
|
||||
'GUN': ['vg','wn'],
|
||||
'HAM': ['vg','wn'],
|
||||
'HTML5': ['wn'],
|
||||
'HYP': ['wn'],
|
||||
'ICASH': ['wn'],
|
||||
'INFX': ['wn'],
|
||||
'IPC': ['wn'],
|
||||
'JBS': ['lb','pc','vg','wn'],
|
||||
'JUDGE': ['wn'],
|
||||
'LANA': ['wn'],
|
||||
'LAT': ['wn'],
|
||||
'LDOGE': ['wn'],
|
||||
'LMC': ['wn'],
|
||||
'LTC': ['lb','vg','wn'],
|
||||
'MARS': ['wn'],
|
||||
'MEC': ['pc','wn'],
|
||||
'MINT': ['wn'],
|
||||
'MOBI': ['wn'],
|
||||
'MONA': ['lb','vg'],
|
||||
'MOON': ['wn'],
|
||||
'MUE': ['lb','vg'],
|
||||
'MXT': ['wn'],
|
||||
'MYR': ['pc'],
|
||||
'MYRIAD': ['vg','wn'],
|
||||
'MZC': ['lb','pc','vg','wn'],
|
||||
'NEOS': ['lb','vg'],
|
||||
'NEVA': ['wn'],
|
||||
'NKA': ['wn'],
|
||||
'NLG': ['vg','wn'],
|
||||
'NMC': ['lb','vg'],
|
||||
'NVC': ['lb','vg','wn'],
|
||||
'OK': ['lb','vg'],
|
||||
'OMC': ['vg','wn'],
|
||||
'ONION': ['vg','wn'],
|
||||
'PART': ['wn'],
|
||||
'PINK': ['vg','wn'],
|
||||
'PIVX': ['wn'],
|
||||
'PKB': ['lb','vg','wn'],
|
||||
'PND': ['lb','vg','wn'],
|
||||
'POT': ['lb','vg','wn'],
|
||||
'PPC': ['lb','vg','wn'],
|
||||
'PTC': ['vg','wn'],
|
||||
'PXC': ['wn'],
|
||||
'QRK': ['wn'],
|
||||
'RAIN': ['wn'],
|
||||
'RBT': ['wn'],
|
||||
'RBY': ['lb','vg'],
|
||||
'RDD': ['vg','wn'],
|
||||
'RIC': ['pc','vg','wn'],
|
||||
'SDC': ['lb','vg'],
|
||||
'SIB': ['wn'],
|
||||
'SMLY': ['wn'],
|
||||
'SONG': ['wn'],
|
||||
'SPR': ['vg','wn'],
|
||||
'START': ['lb','vg'],
|
||||
'SYS': ['wn'],
|
||||
'TAJ': ['wn'],
|
||||
'TIT': ['wn'],
|
||||
'TPC': ['lb','vg'],
|
||||
'TRC': ['wn'],
|
||||
'TTC': ['wn'],
|
||||
'TX': ['wn'],
|
||||
'UNO': ['pc','vg','wn'],
|
||||
'VIA': ['lb','pc','vg','wn'],
|
||||
'VPN': ['lb','vg'],
|
||||
'VTC': ['lb','vg','wn'],
|
||||
'WDC': ['vg','wn'],
|
||||
'WISC': ['wn'],
|
||||
'WKC': ['vg','wn'],
|
||||
'WSX': ['wn'],
|
||||
'XCN': ['wn'],
|
||||
'XGB': ['wn'],
|
||||
'XPM': ['lb','vg','wn'],
|
||||
'XST': ['wn'],
|
||||
'XVC': ['wn'],
|
||||
'ZET': ['wn'],
|
||||
'ZOOM': ['lb','vg'],
|
||||
'ZRC': ['lb','vg']
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def verify_leading_symbols(cls,quiet=False,verbose=False):
|
||||
|
||||
for network in ('mainnet','testnet'):
|
||||
for coin in [e.symbol for e in cls.coin_constants[network]]:
|
||||
e = cls.get_entry(coin,network)
|
||||
cdata = (network,coin,e,'Computed value',verbose)
|
||||
|
||||
if not quiet:
|
||||
msg(f'{coin} {network}')
|
||||
|
||||
vn_info = e.p2pkh_info
|
||||
ret = cls.find_addr_leading_symbol(vn_info[0])
|
||||
test_equal('P2PKH leading symbol',vn_info[1],ret,*cdata)
|
||||
|
||||
vn_info = e.p2sh_info
|
||||
if vn_info:
|
||||
ret = cls.find_addr_leading_symbol(vn_info[0])
|
||||
test_equal('P2SH leading symbol',vn_info[1],ret,*cdata)
|
||||
|
||||
@classmethod
|
||||
def verify_core_coin_data(cls,cfg,quiet=False,verbose=False):
|
||||
from mmgen.protocol import CoinProtocol,init_proto
|
||||
|
||||
for network in ('mainnet','testnet'):
|
||||
for coin in gc.core_coins:
|
||||
e = cls.get_entry(coin,network)
|
||||
if e:
|
||||
proto = init_proto( cfg, coin, network=network )
|
||||
cdata = (network,coin,e,type(proto).__name__,verbose)
|
||||
if not quiet:
|
||||
msg(f'Verifying {coin.upper()} {network}')
|
||||
|
||||
if coin != 'bch': # TODO
|
||||
test_equal('coin name',e.name,proto.name,*cdata)
|
||||
|
||||
if e.trust_level != -1:
|
||||
test_equal('Trust level',e.trust_level,CoinProtocol.coins[coin].trust_level,*cdata)
|
||||
|
||||
test_equal(
|
||||
'WIF version number',
|
||||
e.wif_ver_num,
|
||||
int.from_bytes(proto.wif_ver_bytes['std'],'big'),
|
||||
*cdata )
|
||||
|
||||
test_equal(
|
||||
'P2PKH version number',
|
||||
e.p2pkh_info[0],
|
||||
int.from_bytes(proto.addr_fmt_to_ver_bytes['p2pkh'],'big'),
|
||||
*cdata )
|
||||
|
||||
test_equal(
|
||||
'P2SH version number',
|
||||
e.p2sh_info[0],
|
||||
int.from_bytes(proto.addr_fmt_to_ver_bytes['p2sh'],'big'),
|
||||
*cdata )
|
||||
|
||||
# Data is one of the coin_constants lists above. Normalize ints to hex of correct width, add
|
||||
# missing leading letters, set trust level from external_tests.
|
||||
# Insert a coin entry from outside source, set version info leading letters to '?' and trust level
|
||||
# to 0, then run TestCoinInfo.fix_table(data). 'has_segwit' field is updated manually for now.
|
||||
@classmethod
|
||||
def fix_table(cls,data):
|
||||
import re
|
||||
|
||||
def myhex(n):
|
||||
return '0x{:0{}x}'.format(n,2 if n < 256 else 4)
|
||||
|
||||
def fix_ver_info(e,k):
|
||||
e[k] = list(e[k])
|
||||
e[k][0] = myhex(e[k][0])
|
||||
s1 = cls.find_addr_leading_symbol(int(e[k][0][2:],16))
|
||||
m = f'Fixing leading address letter for coin {e["symbol"]} ({e[k][1]!r} --> {s1})'
|
||||
if e[k][1] != '?':
|
||||
assert s1 == e[k][1], f'First letters do not match! {m}'
|
||||
else:
|
||||
msg(m)
|
||||
e[k][1] = s1
|
||||
e[k] = tuple(e[k])
|
||||
|
||||
old_sym = None
|
||||
for sym in sorted([e.symbol for e in data]):
|
||||
if sym == old_sym:
|
||||
msg(f'{sym!r}: duplicate coin symbol in data!')
|
||||
sys.exit(2)
|
||||
old_sym = sym
|
||||
|
||||
tt = cls.create_trust_table()
|
||||
|
||||
name_w = max(len(e.name) for e in data)
|
||||
fs = '\t({:%s} {:10} {:7} {:17} {:17} {:6} {}),' % (name_w+3)
|
||||
for e in data:
|
||||
e = e._asdict()
|
||||
e['wif_ver_num'] = myhex(e['wif_ver_num'])
|
||||
sym,trust = e['symbol'],e['trust_level']
|
||||
|
||||
fix_ver_info(e,'p2pkh_info')
|
||||
if isinstance(e['p2sh_info'],tuple):
|
||||
fix_ver_info(e,'p2sh_info')
|
||||
|
||||
for k in e.keys():
|
||||
e[k] = repr(e[k])
|
||||
e[k] = re.sub(r"'0x(..)'",r'0x\1',e[k])
|
||||
e[k] = re.sub(r"'0x(....)'",r'0x\1',e[k])
|
||||
e[k] = re.sub(r' ',r'',e[k]) + ('',',')[k != 'trust_level']
|
||||
|
||||
if trust != -1:
|
||||
if sym in tt:
|
||||
src = tt[sym]
|
||||
if src != trust:
|
||||
msg(f'Updating trust for coin {sym!r}: {trust} -> {src}')
|
||||
e['trust_level'] = src
|
||||
else:
|
||||
if trust != 0:
|
||||
msg(f'Downgrading trust for coin {sym!r}: {trust} -> 0')
|
||||
e['trust_level'] = 0
|
||||
|
||||
if sym in cls.cross_checks:
|
||||
if int(e['trust_level']) == 0 and len(cls.cross_checks[sym]) > 1:
|
||||
msg(f'Upgrading trust for coin {sym!r}: {e["trust_level"]} -> 1')
|
||||
e['trust_level'] = 1
|
||||
|
||||
print(fs.format(*e.values()))
|
||||
msg(f'Processed {len(data)} entries')
|
||||
|
||||
@classmethod
|
||||
def find_addr_leading_symbol(cls,ver_num,verbose=False):
|
||||
|
||||
if ver_num == 0:
|
||||
return '1'
|
||||
|
||||
def phash2addr(ver_num,pk_hash):
|
||||
from mmgen.proto.btc.common import b58chk_encode
|
||||
bl = ver_num.bit_length()
|
||||
ver_bytes = int.to_bytes(ver_num,bl//8 + bool(bl%8),'big')
|
||||
return b58chk_encode(ver_bytes + pk_hash)
|
||||
|
||||
low = phash2addr(ver_num,b'\x00'*20)
|
||||
high = phash2addr(ver_num,b'\xff'*20)
|
||||
|
||||
if verbose:
|
||||
print('low address: ' + low)
|
||||
print('high address: ' + high)
|
||||
|
||||
l1,h1 = low[0],high[0]
|
||||
return (l1,h1) if l1 != h1 else l1
|
||||
|
||||
@classmethod
|
||||
def print_symbols(cls,include_names=False,reverse=False):
|
||||
for e in cls.coin_constants['mainnet']:
|
||||
if reverse:
|
||||
print(f'{e.symbol:6} {e.name}')
|
||||
else:
|
||||
name_w = max(len(e.name) for e in cls.coin_constants['mainnet'])
|
||||
print((f'{e.name:{name_w}} ' if include_names else '') + e.symbol)
|
||||
|
||||
@classmethod
|
||||
def create_trust_table(cls):
|
||||
tt = {}
|
||||
mn = cls.external_tests['mainnet']
|
||||
for ext_prog in mn:
|
||||
assert len(set(mn[ext_prog])) == len(mn[ext_prog]), f'Duplicate entry in {ext_prog!r}!'
|
||||
for coin in mn[ext_prog]:
|
||||
if coin in tt:
|
||||
tt[coin] += 1
|
||||
else:
|
||||
tt[coin] = 1
|
||||
for k in cls.trust_override:
|
||||
tt[k] = cls.trust_override[k]
|
||||
return tt
|
||||
|
||||
trust_override = {'BTC':3,'BCH':3,'LTC':3,'DASH':1,'EMC':2}
|
||||
|
||||
@classmethod
|
||||
def get_test_support(cls,coin,addr_type,network,toolname=None,verbose=False):
|
||||
"""
|
||||
If requested tool supports coin/addr_type/network triplet, return tool name.
|
||||
If 'tool' is None, return tool that supports coin/addr_type/network triplet.
|
||||
Return None on failure.
|
||||
"""
|
||||
all_tools = [toolname] if toolname else list(cls.external_tests[network].keys())
|
||||
coin = coin.upper()
|
||||
|
||||
for tool in all_tools:
|
||||
if coin in cls.external_tests[network][tool]:
|
||||
break
|
||||
else:
|
||||
if verbose:
|
||||
m1 = 'Requested tool {t!r} does not support coin {c} on network {n}'
|
||||
m2 = 'No test tool found for coin {c} on network {n}'
|
||||
msg((m1 if toolname else m2).format(t=tool,c=coin,n=network))
|
||||
return None
|
||||
|
||||
if addr_type == 'zcash_z':
|
||||
if toolname in (None,'zcash-mini'):
|
||||
return 'zcash-mini'
|
||||
else:
|
||||
if verbose:
|
||||
msg(f"Address type {addr_type!r} supported only by tool 'zcash-mini'")
|
||||
return None
|
||||
|
||||
try:
|
||||
bl = cls.external_tests_blacklist[addr_type][tool]
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
if bl is True or coin in bl:
|
||||
if verbose:
|
||||
msg(f'Tool {tool!r} blacklisted for coin {coin}, addr_type {addr_type!r}')
|
||||
return None
|
||||
|
||||
if toolname: # skip whitelists
|
||||
return tool
|
||||
|
||||
if addr_type in ('segwit','bech32'):
|
||||
st = cls.external_tests_segwit_whitelist
|
||||
if addr_type in st and coin in st[addr_type]:
|
||||
return tool
|
||||
else:
|
||||
if verbose:
|
||||
m1 = 'Requested tool {t!r} does not support coin {c}, addr_type {a!r}, on network {n}'
|
||||
m2 = 'No test tool found supporting coin {c}, addr_type {a!r}, on network {n}'
|
||||
msg((m1 if toolname else m2).format(t=tool,c=coin,n=network,a=addr_type))
|
||||
return None
|
||||
|
||||
return tool
|
||||
|
||||
external_tests = {
|
||||
'mainnet': {
|
||||
# List in order of preference.
|
||||
# If 'tool' is not specified, the first tool supporting the coin will be selected.
|
||||
'pycoin': (
|
||||
'DASH', # only compressed
|
||||
'BCH',
|
||||
'BTC','LTC','VIA','FTC','DOGE','MEC',
|
||||
'JBS','MZC','RIC','DFC','FAI','ARG','ZEC','DCR'),
|
||||
'keyconv': (
|
||||
'BCH',
|
||||
# broken: PIVX
|
||||
'42','AC','AIB','ANC','ARS','ATMOS','AUR','BLK','BQC','BTC','TEST','BTCD','CCC','CCN','CDN',
|
||||
'CLAM','CNC','CNOTE','CON','CRW','DEEPONION','DGB','DGC','DMD','DOGED','DOGE','DOPE',
|
||||
'DVC','EFL','EMC','EXCL','FAIR','FLOZ','FTC','GAME','GAP','GCR','GRC','GRS','GUN','HAM','HODL',
|
||||
'IXC','JBS','LBRY','LEAF','LTC','MMC','MONA','MUE','MYRIAD','MZC','NEOS','NLG','NMC','NVC',
|
||||
'NYAN','OK','OMC','PIGGY','PINK','PKB','PND','POT','PPC','PTC','PTS','QTUM','RBY','RDD',
|
||||
'RIC','SCA','SDC','SKC','SPR','START','SXC','TPC','UIS','UNO','VIA','VPN','VTC','WDC','WKC',
|
||||
'WUBS', 'XC', 'XPM', 'YAC', 'ZOOM', 'ZRC'),
|
||||
'ethkey': ('ETH','ETC'),
|
||||
'zcash-mini': ('ZEC',),
|
||||
'monero-python': ('XMR',),
|
||||
},
|
||||
'testnet': {
|
||||
'pycoin': {
|
||||
'DASH':'tDASH', # only compressed
|
||||
'BCH':'XTN',
|
||||
'BTC':'XTN','LTC':'XLT','VIA':'TVI','FTC':'FTX','DOGE':'XDT','DCR':'DCRT'
|
||||
},
|
||||
'ethkey': {},
|
||||
'keyconv': {}
|
||||
}
|
||||
}
|
||||
external_tests_segwit_whitelist = {
|
||||
# Whitelists apply to the *first* tool in cls.external_tests supporting the given coin/addr_type.
|
||||
# They're ignored if specific tool is requested.
|
||||
'segwit': ('BTC',), # LTC Segwit broken on pycoin: uses old fmt
|
||||
'bech32': ('BTC','LTC'),
|
||||
'compressed': (
|
||||
'BTC','LTC','VIA','FTC','DOGE','DASH','MEC','MYR','UNO',
|
||||
'JBS','MZC','RIC','DFC','FAI','ARG','ZEC','DCR','ZEC'
|
||||
),
|
||||
}
|
||||
external_tests_blacklist = {
|
||||
# Unconditionally block testing of the given coin/addr_type with given tool, or all coins if True
|
||||
'legacy': {},
|
||||
'segwit': { 'keyconv': True },
|
||||
'bech32': { 'keyconv': True },
|
||||
}
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
opts_data = {
|
||||
'text': {
|
||||
'desc': 'Check altcoin data',
|
||||
'usage':'[opts]',
|
||||
'options': '-q, --quiet Be quieter\n-v, --verbose Be more verbose'
|
||||
}
|
||||
}
|
||||
|
||||
cfg = Config( opts_data=opts_data, need_amt=False )
|
||||
|
||||
msg('Checking CoinInfo WIF/P2PKH/P2SH version numbers and trust levels against protocol.py')
|
||||
TestCoinInfo.verify_core_coin_data( cfg, cfg.quiet, cfg.verbose )
|
||||
|
||||
msg('Checking CoinInfo address leading symbols')
|
||||
TestCoinInfo.verify_leading_symbols( cfg.quiet, cfg.verbose )
|
||||
|
|
@ -558,8 +558,8 @@ def main():
|
|||
from subprocess import run,PIPE,DEVNULL
|
||||
from collections import namedtuple
|
||||
from mmgen.protocol import init_proto,CoinProtocol
|
||||
from mmgen.altcoin import init_genonly_altcoins
|
||||
from mmgen.altcoin import CoinInfo as cinfo
|
||||
from mmgen.altcoin.params import init_genonly_altcoins
|
||||
from test.altcointest import TestCoinInfo as cinfo
|
||||
from mmgen.key import PrivKey
|
||||
from mmgen.addr import MMGenAddrType
|
||||
from mmgen.addrgen import KeyGenerator,AddrGenerator
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ init_tests() {
|
|||
|
||||
d_alt="altcoin module"
|
||||
t_alt="
|
||||
- python3 -m mmgen.altcoin $altcoin_mod_opts
|
||||
- python3 -m test.altcointest $altcoin_mod_opts
|
||||
"
|
||||
|
||||
d_obj="data objects"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue