Key/address generation support for 144 altcoins
Support for these coins is EXPERIMENTAL, use at your own risk
EXAMPLE: generate 10 Dogecoin key/address pairs with your default wallet:
`mmgen-keygen --coin=doge 1-10`
Keys for different coins are distinct, so users needn't worry about key reuse.
Supported alts: 2give,42,611,ac,acoin,alf,anc,apex,arco,arg,aur,b2x,bcf,bch,blk,bmc,bqc,bsty,btcd,btq,bucks,cann,cash,cat,cbx,ccn,cdn,chc,clam,con,cpc,crps,csh,dash,dcr,dfc,dgb,dgc,doge,doged,dope,dvc,efl,emc,emd,enrg,esp,etc,eth,fai,fc2,fibre,fjc,flo,flt,fst,ftc,gcr,good,grc,gun,ham,html5,hyp,icash,infx,inpay,ipc,jbs,judge,lana,lat,ldoge,lmc,ltc,mars,mcar,mec,mint,mobi,mona,moon,mrs,mue,mxt,myr,myriad,mzc,neos,neva,nka,nlg,nmc,nto,nvc,ok,omc,omni,onion,onx,part,pink,pivx,pkb,pnd,pot,ppc,ptc,pxc,qrk,rain,rbt,rby,rdd,ric,sdc,sib,smly,song,spr,start,sys,taj,tit,tpc,trc,ttc,tx,uno,via,vpn,vtc,wash,wdc,wisc,wkc,wsx,xcn,xgb,xmg,xpm,xpoke,xred,xst,xvc,zec,zet,zlq,zoom,zrc
Test the new functionality with `scripts/test-release.sh -Pn master alts`
B2X support disabled pending further testing
This commit is contained in:
parent
4876ee47ed
commit
91ac2effb3
21 changed files with 794 additions and 112 deletions
|
|
@ -15,7 +15,7 @@ an online and offline computer to provide a robust solution for securely
|
|||
storing, tracking, sending and receiving Bitcoins.
|
||||
|
||||
The online computer is used only for tracking balances and creating and sending
|
||||
transactions. **Thus it holds no private keys that can be hacked or stolen.**
|
||||
transactions. Thus it holds no private keys that can be hacked or stolen.
|
||||
All transactions are signed offline: **your seed and private keys never touch a
|
||||
network-connected device.** The offline computer used for wallet creation,
|
||||
address generation and transaction signing is typically a low-powered device
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ cmd_args = opts.init(opts_data,add_opts=['mmgen_keys_from_file','in_fmt'])
|
|||
|
||||
import mmgen.tx
|
||||
from mmgen.txsign import txsign
|
||||
from mmgen.protocol import CoinProtocol
|
||||
from mmgen.protocol import CoinProtocol,init_coin
|
||||
|
||||
if opt.stealth_led: opt.led = True
|
||||
|
||||
|
|
@ -154,8 +154,7 @@ def do_umount():
|
|||
|
||||
def sign_tx_file(txfile):
|
||||
try:
|
||||
g.coin = mmgen.tx.MMGenTX(txfile,md_only=True).coin
|
||||
g.proto = CoinProtocol(g.coin,g.testnet)
|
||||
init_coin(mmgen.tx.MMGenTX(txfile,md_only=True).coin)
|
||||
reload(sys.modules['mmgen.tx'])
|
||||
tx = mmgen.tx.MMGenTX(txfile)
|
||||
rpc_init(reinit=True)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,14 @@ def sc_dmsg(desc,data):
|
|||
Msg('sc_debug_{}: {}'.format(desc,data))
|
||||
|
||||
class AddrGenerator(MMGenObject):
|
||||
def __new__(cls,gen_method):
|
||||
def __new__(cls,addr_type):
|
||||
if type(addr_type) == str: # allow override w/o check
|
||||
gen_method = addr_type
|
||||
elif type(addr_type) == MMGenAddrType:
|
||||
assert addr_type in g.proto.mmtypes,'{}: invalid address type for coin {}'.format(addr_type,g.coin)
|
||||
gen_method = addr_type.gen_method
|
||||
else:
|
||||
raise TypeError,'{}: incorrect argument type for {}()'.format(type(addr_type),cls.__name__)
|
||||
d = {
|
||||
'p2pkh': AddrGeneratorP2PKH,
|
||||
'segwit': AddrGeneratorSegwit,
|
||||
|
|
@ -108,7 +115,14 @@ class AddrGeneratorZcashZ(AddrGenerator):
|
|||
|
||||
class KeyGenerator(MMGenObject):
|
||||
|
||||
def __new__(cls,pubkey_type,generator=None,silent=False):
|
||||
def __new__(cls,addr_type,generator=None,silent=False):
|
||||
if type(addr_type) == str: # allow override w/o check
|
||||
pubkey_type = addr_type
|
||||
elif type(addr_type) == MMGenAddrType:
|
||||
assert addr_type in g.proto.mmtypes,'{}: invalid address type for coin {}'.format(addr_type,g.coin)
|
||||
pubkey_type = addr_type.pubkey_type
|
||||
else:
|
||||
raise TypeError,'{}: incorrect argument type for {}()'.format(type(addr_type),cls.__name__)
|
||||
if pubkey_type == 'std':
|
||||
if cls.test_for_secp256k1(silent=silent) and generator != 1:
|
||||
if not opt.key_generator or opt.key_generator == 2 or generator == 2:
|
||||
|
|
@ -330,8 +344,8 @@ Removed %s duplicate WIF key%s from keylist (also in {pnm} key-address file
|
|||
has_viewkey = self.al_id.mmtype.has_viewkey
|
||||
|
||||
if self.gen_addrs:
|
||||
kg = KeyGenerator(pubkey_type)
|
||||
ag = AddrGenerator(self.al_id.mmtype.gen_method)
|
||||
kg = KeyGenerator(self.al_id.mmtype)
|
||||
ag = AddrGenerator(self.al_id.mmtype)
|
||||
|
||||
t_addrs,num,pos,out = len(addrnums),0,0,AddrListList()
|
||||
le = self.entry_type
|
||||
|
|
@ -529,8 +543,8 @@ Removed %s duplicate WIF key%s from keylist (also in {pnm} key-address file
|
|||
ret.append(a)
|
||||
|
||||
if self.has_keys and keypress_confirm('Check key-to-address validity?'):
|
||||
kg = KeyGenerator(self.al_id.mmtype.pubkey_type)
|
||||
ag = AddrGenerator(self.al_id.mmtype.gen_method)
|
||||
kg = KeyGenerator(self.al_id.mmtype)
|
||||
ag = AddrGenerator(self.al_id.mmtype)
|
||||
llen = len(ret)
|
||||
for n,e in enumerate(ret):
|
||||
msg_r('\rVerifying keys %s/%s' % (n+1,llen))
|
||||
|
|
|
|||
529
mmgen/altcoin.py
Executable file
529
mmgen/altcoin.py
Executable file
|
|
@ -0,0 +1,529 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# Copyright (C)2013-2017 Philemon <mmgen-py@yandex.com>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
"""
|
||||
altcoin.py - Coin constants for Bitcoin-derived altcoins
|
||||
"""
|
||||
|
||||
# Sources:
|
||||
# lb: https://github.com/libbitcoin/libbitcoin/wiki/Altcoin-Version-Mappings
|
||||
# pc: https://github.com/richardkiss/pycoin/blob/master/pycoin/networks/legacy_networks.py
|
||||
# vg: https://github.com/exploitagency/vanitygen-plus/blob/master/keyconv.c
|
||||
# wn: https://walletgenerator.net
|
||||
# cc: https://www.cryptocompare.com/api/data/coinlist/ (names,symbols only)
|
||||
|
||||
# WIP:
|
||||
# NSR: 149/191 c/u, 63/('S'), 64/('S'|'T')
|
||||
# NBT: 150/191 c/u, 25/('B'), 26/('B')
|
||||
|
||||
import sys
|
||||
def msg(s): sys.stderr.write(s+'\n')
|
||||
|
||||
class CoinInfo(object):
|
||||
coin_constants = {}
|
||||
coin_constants['mainnet'] = (
|
||||
# NAME SYM WIF P2PKH P2SH SEGWIT TRUST
|
||||
# trust levels: 0=untested 1=low 2=med 3=high
|
||||
('Bitcoin', 'BTC', 0x80, (0x00,'1'), (0x05,'3'), True, 3),
|
||||
('BitcoinSegwit2X', 'B2X', 0x80, (0x00,'1'), (0x05,'3'), True, 2),
|
||||
('Bcash', 'BCH', 0x80, (0x00,'1'), (0x05,'3'), False, 3),
|
||||
('2GiveCoin', '2GIVE', 0xa7, (0x27,('G','H')), None, False, 0),
|
||||
('42Coin', '42', 0x88, (0x08,'4'), None, False, 1),
|
||||
('ACoin', 'ACOIN', 0xe6, (0x17,'A'), None, False, 0),
|
||||
('Alphacoin', 'ALF', 0xd2, (0x52,('Z','a')), None, False, 0),
|
||||
('Anoncoin', 'ANC', 0x97, (0x17,'A'), None, False, 1),
|
||||
('Apexcoin', 'APEX', 0x97, (0x17,'A'), None, False, 0),
|
||||
('Aquariuscoin', 'ARCO', 0x97, (0x17,'A'), None, False, 0),
|
||||
('Argentum', 'ARG', 0x97, (0x17,'A'), (0x05,'3'), False, 1),
|
||||
('AsiaCoin', 'AC', 0x97, (0x17,'A'), (0x08,'4'), False, 1),
|
||||
('Auroracoin', 'AUR', 0x97, (0x17,'A'), None, False, 1),
|
||||
('BBQcoin', 'BQC', 0xd5, (0x55,'b'), None, False, 1),
|
||||
('BitcoinDark', 'BTCD', 0xbc, (0x3c,'R'), (0x55,'b'), False, 1),
|
||||
('BitcoinFast', 'BCF', 0xe0, (0x60,('f','g')), None, False, 0),
|
||||
('BitQuark', 'BTQ', 0xba, (0x3a,'Q'), None, False, 0),
|
||||
('Blackcoin', 'BLK', 0x99, (0x19,'B'), (0x55,'b'), False, 1),
|
||||
('BlackmoonCrypto', 'BMC', 0x83, (0x03,'2'), None, False, 0),
|
||||
('BlockCat', 'CAT', 0x95, (0x15,'9'), None, False, 0),
|
||||
('CanadaECoin', 'CDN', 0x9c, (0x1c,'C'), (0x05,'3'), False, 1),
|
||||
('CannabisCoin', 'CANN', 0x9c, (0x1c,'C'), None, False, 0),
|
||||
('CannaCoin', 'CCN', 0x9c, (0x1c,'C'), (0x05,'3'), False, 1),
|
||||
('Capricoin', 'CPC', 0x9c, (0x1c,'C'), None, False, 0),
|
||||
('CashCoin', 'CASH', 0xa2, (0x22,('E','F')), None, False, 0),
|
||||
('CashOut', 'CSH', 0xa2, (0x22,('E','F')), None, False, 0),
|
||||
('ChainCoin', 'CHC', 0x9c, (0x1c,'C'), None, False, 0),
|
||||
('Clams', 'CLAM', 0x85, (0x89,'x'), (0x0d,'6'), False, 1),
|
||||
('CoinMagi', 'XMG', 0x94, (0x14,'9'), None, False, 0),
|
||||
('Condensate', 'RAIN', 0xbc, (0x3c,'R'), None, False, 0),
|
||||
('CryptoBullion', 'CBX', 0x8b, (0x0b,'5'), None, False, 0),
|
||||
('Cryptonite', 'XCN', 0x80, (0x1c,'C'), None, False, 0),
|
||||
('CryptoPennies', 'CRPS', 0xc2, (0x42,'T'), None, False, 0),
|
||||
('Dash', 'DASH', 0xcc, (0x4c,'X'), (0x10,'7'), False, 1),
|
||||
('Decred', 'DCR', 0x22de, (0x073f,'D'), (0x071a,'D'), False, 1),
|
||||
('DeepOnion', 'ONION', 0x9f, (0x1f,'D'), None, False, 1),
|
||||
('Defcoin', 'DFC', 0x9e, (0x1e,'D'), (0x05,'3'), False, 1),
|
||||
('Devcoin', 'DVC', 0x80, (0x00,'1'), None, False, 1),
|
||||
('DigiByte', 'DGB', 0x80, (0x1e,'D'), (0x05,'3'), False, 1),
|
||||
('DigiCoin', 'DGC', 0x9e, (0x1e,'D'), (0x05,'3'), False, 1),
|
||||
('DogecoinDark', 'DOGED', 0x9e, (0x1e,'D'), (0x21,'E'), False, 1),
|
||||
('Dogecoin', 'DOGE', 0x9e, (0x1e,'D'), (0x16,('9','A')), False, 2),
|
||||
('DopeCoin', 'DOPE', 0x88, (0x08,'4'), (0x05,'3'), False, 1),
|
||||
('EGulden', 'EFL', 0xb0, (0x30,'L'), (0x05,'3'), False, 1),
|
||||
('Emerald', 'EMD', 0xa2, (0x22,('E','F')), None, False, 0),
|
||||
('Emercoin', 'EMC', 0x80, (0x21,'E'), (0x5c,'e'), False, 2),
|
||||
('EnergyCoin', 'ENRG', 0xdc, (0x5c,'e'), None, False, 0),
|
||||
('Espers', 'ESP', 0xa1, (0x21,'E'), None, False, 0),
|
||||
('Faircoin', 'FAI', 0xdf, (0x5f,'f'), (0x24,'F'), False, 1),
|
||||
('Fastcoin', 'FST', 0xe0, (0x60,('f','g')), None, False, 0),
|
||||
('Feathercoin', 'FTC', 0x8e, (0x0e,('6','7')), (0x05,'3'), False, 2),
|
||||
('Fibre', 'FIBRE', 0xa3, (0x23,'F'), None, False, 0),
|
||||
('FlorinCoin', 'FLO', 0xb0, (0x23,'F'), None, False, 0),
|
||||
('Fluttercoin', 'FLT', 0xa3, (0x23,'F'), None, False, 0),
|
||||
('Fuel2Coin', 'FC2', 0x80, (0x24,'F'), None, False, 0),
|
||||
('Fujicoin', 'FJC', 0xa4, (0x24,'F'), None, False, 0),
|
||||
('Fujinto', 'NTO', 0xa4, (0x24,'F'), None, False, 0),
|
||||
('GlobalBoost', 'BSTY', 0xa6, (0x26,'G'), None, False, 0),
|
||||
('GlobalCurrencyReserve', 'GCR', 0x9a, (0x26,'G'), (0x61,'g'), False, 1),
|
||||
('GoldenBird', 'XGB', 0xaf, (0x2f,('K','L')), None, False, 0),
|
||||
('Goodcoin', 'GOOD', 0xa6, (0x26,'G'), None, False, 0),
|
||||
('GridcoinResearch', 'GRC', 0xbe, (0x3e,('R','S')), None, False, 1),
|
||||
('Gulden', 'NLG', 0xa6, (0x26,'G'), None, False, 1),
|
||||
('Guncoin', 'GUN', 0xa7, (0x27,('G','H')), None, False, 1),
|
||||
('HamRadioCoin', 'HAM', 0x80, (0x00,'1'), None, False, 1),
|
||||
('HTML5Coin', 'HTML5', 0xa8, (0x28,'H'), None, False, 0),
|
||||
('HyperStake', 'HYP', 0xf5, (0x75,'p'), None, False, 0),
|
||||
('iCash', 'ICASH', 0xcc, (0x66,'i'), None, False, 0),
|
||||
('ImperiumCoin', 'IPC', 0xb0, (0x30,'L'), None, False, 0),
|
||||
('IncaKoin', 'NKA', 0xb5, (0x35,'N'), None, False, 0),
|
||||
('Influxcoin', 'INFX', 0xe6, (0x66,'i'), None, False, 0),
|
||||
('InPay', 'INPAY', 0xb7, (0x37,'P'), None, False, 0),
|
||||
# ('iXcoin', 'IXC', 0x80, (0x8a,'x'), None, False, 1),
|
||||
('Judgecoin', 'JUDGE', 0xab, (0x2b,'J'), None, False, 0),
|
||||
('Jumbucks', 'JBS', 0xab, (0x2b,'J'), (0x69,'j'), False, 2),
|
||||
('Lanacoin', 'LANA', 0xb0, (0x30,'L'), None, False, 0),
|
||||
('Latium', 'LAT', 0x80, (0x17,'A'), None, False, 0),
|
||||
('Litecoin', 'LTC', 0xb0, (0x30,'L'), (0x05,'3'), True, 3),
|
||||
('LiteDoge', 'LDOGE', 0xab, (0x5a,'d'), None, False, 0),
|
||||
('LomoCoin', 'LMC', 0xb0, (0x30,'L'), None, False, 0),
|
||||
('Marscoin', 'MARS', 0xb2, (0x32,'M'), None, False, 0),
|
||||
('MarsCoin', 'MRS', 0xb2, (0x32,'M'), None, False, 0),
|
||||
('MartexCoin', 'MXT', 0xb2, (0x32,'M'), None, False, 0),
|
||||
('MasterCar', 'MCAR', 0xe6, (0x17,'A'), None, False, 0),
|
||||
('MazaCoin', 'MZC', 0xe0, (0x32,'M'), (0x09,('4','5')), False, 2),
|
||||
('MegaCoin', 'MEC', 0xb2, (0x32,'M'), None, False, 1),
|
||||
('MintCoin', 'MINT', 0xb3, (0x33,'M'), None, False, 0),
|
||||
('Mobius', 'MOBI', 0x80, (0x00,'1'), None, False, 0),
|
||||
('MonaCoin', 'MONA', 0xb0, (0x32,'M'), (0x05,'3'), False, 1),
|
||||
('MonetaryUnit', 'MUE', 0x8f, (0x0f,'7'), (0x09,('4','5')), False, 1),
|
||||
('MoonCoin', 'MOON', 0x83, (0x03,'2'), None, False, 0),
|
||||
('MyriadCoin', 'MYR', 0xb2, (0x32,'M'), (0x09,('4','5')), False, 1),
|
||||
('Myriadcoin', 'MYRIAD', 0xb2, (0x32,'M'), None, False, 1),
|
||||
('Namecoin', 'NMC', 0xb4, (0x34,('M','N')), (0x0d,'6'), False, 1),
|
||||
('Neoscoin', 'NEOS', 0xef, (0x3f,'S'), (0xbc,'2'), False, 1),
|
||||
('NevaCoin', 'NEVA', 0xb1, (0x35,'N'), None, False, 0),
|
||||
('Novacoin', 'NVC', 0x88, (0x08,'4'), (0x14,'9'), False, 1),
|
||||
('OKCash', 'OK', 0xb7, (0x37,'P'), (0x1c,'C'), False, 1),
|
||||
('Omnicoin', 'OMC', 0xf3, (0x73,'o'), None, False, 1),
|
||||
('Omni', 'OMNI', 0xf3, (0x73,'o'), None, False, 0),
|
||||
('Onix', 'ONX', 0x80, (0x8a,'x'), None, False, 0),
|
||||
('PandaCoin', 'PND', 0xb7, (0x37,'P'), (0x16,('9','A')), False, 1),
|
||||
('ParkByte', 'PKB', 0xb7, (0x37,'P'), (0x1c,'C'), False, 1),
|
||||
('Particl', 'PART', 0x6c, (0x38,'P'), None, False, 0),
|
||||
('Paycoin', 'CON', 0xb7, (0x37,'P'), None, False, 1),
|
||||
('Peercoin', 'PPC', 0xb7, (0x37,'P'), (0x75,'p'), False, 1),
|
||||
('PesetaCoin', 'PTC', 0xaf, (0x2f,('K','L')), None, False, 1),
|
||||
('PhoenixCoin', 'PXC', 0xb8, (0x38,'P'), None, False, 0),
|
||||
('PinkCoin', 'PINK', 0x83, (0x03,'2'), None, False, 1),
|
||||
('PIVX', 'PIVX', 0xd4, (0x1e,'D'), None, False, 0),
|
||||
('PokeChain', 'XPOKE', 0x9c, (0x1c,'C'), None, False, 0),
|
||||
('Potcoin', 'POT', 0xb7, (0x37,'P'), (0x05,'3'), False, 1),
|
||||
('Primecoin', 'XPM', 0x97, (0x17,'A'), (0x53,'a'), False, 1),
|
||||
('Quark', 'QRK', 0xba, (0x3a,'Q'), None, False, 0),
|
||||
('ReddCoin', 'RDD', 0xbd, (0x3d,'R'), None, False, 1),
|
||||
('Riecoin', 'RIC', 0x80, (0x3c,'R'), (0x05,'3'), False, 2),
|
||||
('Rimbit', 'RBT', 0xbc, (0x3c,'R'), None, False, 0),
|
||||
('Rubycoin', 'RBY', 0xbd, (0x3d,'R'), (0x55,'b'), False, 1),
|
||||
('ShadowCash', 'SDC', 0xbf, (0x3f,'S'), (0x7d,'s'), False, 1),
|
||||
('Sibcoin', 'SIB', 0x80, (0x3f,'S'), None, False, 0),
|
||||
('SixEleven', '611', 0x80, (0x34,('M','N')), None, False, 0),
|
||||
('SmileyCoin', 'SMLY', 0x99, (0x19,'B'), None, False, 0),
|
||||
('Songcoin', 'SONG', 0xbf, (0x3f,'S'), None, False, 0),
|
||||
('Spreadcoin', 'SPR', 0xbf, (0x3f,'S'), None, False, 1),
|
||||
('Startcoin', 'START', 0xfd, (0x7d,'s'), (0x05,'3'), False, 1),
|
||||
('StealthCoin', 'XST', 0xbe, (0x3e,('R','S')), None, False, 0),
|
||||
('SwagBucks', 'BUCKS', 0x99, (0x3f,'S'), None, False, 0),
|
||||
('SysCoin', 'SYS', 0x80, (0x00,'1'), None, False, 0),
|
||||
('TajCoin', 'TAJ', 0x6f, (0x41,'T'), None, False, 0),
|
||||
('Templecoin', 'TPC', 0xc1, (0x41,'T'), (0x05,'3'), False, 1),
|
||||
('Terracoin', 'TRC', 0x80, (0x00,'1'), None, False, 0),
|
||||
('Titcoin', 'TIT', 0x80, (0x00,'1'), None, False, 0),
|
||||
('TittieCoin', 'TTC', 0xc1, (0x41,'T'), None, False, 0),
|
||||
('Transfer', 'TX', 0x99, (0x42,'T'), None, False, 0),
|
||||
('Unobtanium', 'UNO', 0xe0, (0x82,'u'), (0x1e,'D'), False, 2),
|
||||
('Vcash', 'XVC', 0xc7, (0x47,'V'), None, False, 0),
|
||||
('Vertcoin', 'VTC', 0xc7, (0x47,'V'), (0x05,'3'), False, 1),
|
||||
('Viacoin', 'VIA', 0xc7, (0x47,'V'), (0x21,'E'), False, 2),
|
||||
('VpnCoin', 'VPN', 0xc7, (0x47,'V'), (0x05,'3'), False, 1),
|
||||
('WankCoin', 'WKC', 0x80, (0x00,'1'), None, False, 1),
|
||||
('WashingtonCoin', 'WASH', 0xc9, (0x49,'W'), None, False, 0),
|
||||
('WeAreSatoshi', 'WSX', 0x97, (0x87,'w'), None, False, 0),
|
||||
('WisdomCoin', 'WISC', 0x87, (0x49,'W'), None, False, 0),
|
||||
('WorldCoin', 'WDC', 0xc9, (0x49,'W'), None, False, 1),
|
||||
('XRealEstateDevcoin', 'XRED', 0x80, (0x00,'1'), None, False, 0),
|
||||
('ZetaCoin', 'ZET', 0xe0, (0x50,'Z'), None, False, 0),
|
||||
('ZiftrCoin', 'ZRC', 0xd0, (0x50,'Z'), (0x05,'3'), False, 1),
|
||||
('ZLiteQubit', 'ZLQ', 0xe0, (0x26,'G'), None, False, 0),
|
||||
('Zoomcoin', 'ZOOM', 0xe7, (0x67,'i'), (0x5c,'e'), False, 1),
|
||||
)
|
||||
|
||||
coin_constants['testnet'] = (
|
||||
('Dash', 'DASH', 0xef, (0x8c,'y'), (0x13,('8','9')), False, 1),
|
||||
('Decred', 'DCR', 0x230e, (0x0f21,'T'), (0x0e6c,'S'), False, 1),
|
||||
('Dogecoin', 'DOGE', 0xf1, (0x71,'n'), (0xc4,'2'), False, 2),
|
||||
('Feathercoin', 'FTC', 0xc1, (0x41,'T'), (0xc4,'2'), False, 2),
|
||||
('Viacoin', 'VIA', 0xff, (0x7f,'t'), (0xc4,'2'), False, 2),
|
||||
('Emercoin', 'EMC', 0xef, (0x6f,('m','n')), (0xc4,'2'), False, 2),
|
||||
)
|
||||
|
||||
coin_sources = (
|
||||
('BTC', 'https://github.com/bitcoin/bitcoin/blob/master/src/chainparams.cpp'),
|
||||
('EMC', 'https://github.com/emercoin/emercoin/blob/master/src/chainparams.cpp'), # checked mn,tn
|
||||
('LTC', 'https://github.com/litecoin-project/litecoin/blob/master-0.10/src/chainparams.cpp'),
|
||||
('DOGE', 'https://github.com/dogecoin/dogecoin/blob/master/src/chainparams.cpp'),
|
||||
('RDD', 'https://github.com/reddcoin-project/reddcoin/blob/master/src/base58.h'),
|
||||
('DASH', 'https://github.com/dashpay/dash/blob/master/src/chainparams.cpp'),
|
||||
('PPC', 'https://github.com/belovachap/peercoin/blob/master/src/base58.h'),
|
||||
('NMC', 'https://github.com/domob1812/namecore/blob/master/src/chainparams.cpp'),
|
||||
('FTC', 'https://github.com/FeatherCoin/Feathercoin/blob/master-0.8/src/base58.h'),
|
||||
('BLK', 'https://github.com/rat4/blackcoin/blob/master/src/chainparams.cpp'),
|
||||
('NSR', 'https://nubits.com/nushares/introduction'),
|
||||
('NBT', 'https://bitbucket.org/JordanLeePeershares/nubit/NuBit / src /base58.h'),
|
||||
('MZC', 'https://github.com/MazaCoin/MazaCoin/blob/master/src/chainparams.cpp'),
|
||||
('VIA', 'https://github.com/viacoin/viacoin/blob/master/src/chainparams.cpp'),
|
||||
('RBY', 'https://github.com/rubycoinorg/rubycoin/blob/master/src/base58.h'),
|
||||
('GRS', 'https://github.com/GroestlCoin/groestlcoin/blob/master/src/groestlcoin.cpp'),
|
||||
('DGC', 'https://github.com/DGCDev/digitalcoin/blob/master/src/chainparams.cpp'),
|
||||
('CCN', 'https://github.com/Cannacoin-Project/Cannacoin/blob/Proof-of-Stake/src/base58.h'),
|
||||
('DGB', 'https://github.com/digibyte/digibyte/blob/master/src/chainparams.cpp'),
|
||||
('MONA', 'https://github.com/monacoinproject/monacoin/blob/master-0.10/src/chainparams.cpp'),
|
||||
('CLAM', 'https://github.com/nochowderforyou/clams/blob/master/src/chainparams.cpp'),
|
||||
('XPM', 'https://github.com/primecoin/primecoin/blob/master/src/base58.h'),
|
||||
('NEOS', 'https://github.com/bellacoin/neoscoin/blob/master/src/chainparams.cpp'),
|
||||
('JBS', 'https://github.com/jyap808/jumbucks/blob/master/src/base58.h'),
|
||||
('ZRC', 'https://github.com/ZiftrCOIN/ziftrcoin/blob/master/src/chainparams.cpp'),
|
||||
('VTC', 'https://github.com/vertcoin/vertcoin/blob/master/src/base58.h'),
|
||||
('NXT', 'https://bitbucket.org/JeanLucPicard/nxt/src and unofficial at https://github.com/Blackcomb/nxt'),
|
||||
('MUE', 'https://github.com/MonetaryUnit/MUE-Src/blob/master/src/chainparams.cpp'),
|
||||
('ZOOM', 'https://github.com/zoom-c/zoom/blob/master/src/base58.h'),
|
||||
('VPN', 'https://github.com/Bit-Net/VpnCoin/blob/master/src/base58.h'),
|
||||
('CDN', 'https://github.com/ThisIsOurCoin/canadaecoin/blob/master/src/base58.h'),
|
||||
('SDC', 'https://github.com/ShadowProject/shadow/blob/master/src/chainparams.cpp'),
|
||||
('PKB', 'https://github.com/parkbyte/ParkByte/blob/master/src/base58.h'),
|
||||
('PND', 'https://github.com/coinkeeper/2015-04-19_21-22_pandacoin/blob/master/src/base58.h'),
|
||||
('START', 'https://github.com/startcoin-project/startcoin/blob/master/src/base58.h'),
|
||||
('GCR', 'https://github.com/globalcurrencyreserve/gcr/blob/master/src/chainparams.cpp'),
|
||||
('NVC', 'https://github.com/novacoin-project/novacoin/blob/master/src/base58.h'),
|
||||
('AC', 'https://github.com/AsiaCoin/AsiaCoinFix/blob/master/src/base58.h'),
|
||||
('BTCD', 'https://github.com/jl777/btcd/blob/master/src/base58.h'),
|
||||
('DOPE', 'https://github.com/dopecoin-dev/DopeCoinV3/blob/master/src/base58.h'),
|
||||
('TPC', 'https://github.com/9cat/templecoin/blob/templecoin/src/base58.h'),
|
||||
('OK', 'https://github.com/okcashpro/okcash/blob/master/src/chainparams.cpp'),
|
||||
('DOGED', 'https://github.com/doged/dogedsource/blob/master/src/base58.h'),
|
||||
('EFL', 'https://github.com/Electronic-Gulden-Foundation/egulden/blob/master/src/base58.h'),
|
||||
('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']
|
||||
}
|
||||
|
||||
# data is one of the coin_constants lists above
|
||||
# normalize ints to hex, format width, add missing leading letters, set trust level from external_tests
|
||||
# Insert a coin entry from outside source, set leading letters to '?' and trust to 0, then run fix_table()
|
||||
# segwit column 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_col(line,n):
|
||||
line[n] = list(line[n])
|
||||
line[n][0] = myhex(line[n][0])
|
||||
s1 = cls.find_addr_leading_symbol(int(line[n][0][2:],16))
|
||||
m = 'Fixing coin {} [in data: {!r}] [computed: {}]'.format(line[0],line[n][1],s1)
|
||||
if line[n][1] != '?':
|
||||
assert s1 == line[n][1],'First letters do not match! {}'.format(m)
|
||||
else:
|
||||
msg(m)
|
||||
line[n][1] = s1
|
||||
line[n] = tuple(line[n])
|
||||
|
||||
old_sym = None
|
||||
for sym in sorted([e[1] for e in data]):
|
||||
if sym == old_sym:
|
||||
msg("'{}': duplicate coin symbol in data!".format(sym))
|
||||
sys.exit(2)
|
||||
old_sym = sym
|
||||
|
||||
tt = cls.create_trust_table()
|
||||
|
||||
w = max(len(e[0]) for e in data)
|
||||
fs = '\t({{:{}}} {{:10}} {{:7}} {{:17}} {{:17}} {{:6}} {{}}),'.format(w+3)
|
||||
for line in data:
|
||||
line = list(line)
|
||||
line[2] = myhex(line[2])
|
||||
|
||||
fix_col(line,3)
|
||||
if type(line[4]) == tuple: fix_col(line,4)
|
||||
|
||||
sym,trust = line[1],line[6]
|
||||
|
||||
for n in range(len(line)):
|
||||
line[n] = repr(line[n])
|
||||
line[n] = re.sub(r"'0x(..)'",r'0x\1',line[n])
|
||||
line[n] = re.sub(r"'0x(....)'",r'0x\1',line[n])
|
||||
line[n] = re.sub(r' ',r'',line[n]) + ('',',')[n != len(line)-1]
|
||||
|
||||
from mmgen.util import pmsg,pdie
|
||||
# pmsg(sym)
|
||||
# pdie(tt)
|
||||
if sym in tt:
|
||||
src = tt[sym]
|
||||
if src != trust:
|
||||
msg("Updating trust for coin '{}': {} -> {}".format(sym,trust,src))
|
||||
line[6] = src
|
||||
else:
|
||||
if trust != 0:
|
||||
msg("Downgrading trust for coin '{}': {} -> {}".format(sym,trust,0))
|
||||
line[6] = 0
|
||||
|
||||
if sym in cls.cross_checks:
|
||||
if int(line[6]) == 0 and len(cls.cross_checks[sym]) > 1:
|
||||
msg("Upgrading trust for coin '{}': {} -> {}".format(sym,line[6],1))
|
||||
line[6] = 1
|
||||
|
||||
print(fs.format(*line))
|
||||
msg('Processed {} entries'.format(len(data)))
|
||||
|
||||
@classmethod
|
||||
def find_addr_leading_symbol(cls,ver_num,verbose=False):
|
||||
|
||||
def phash2addr(ver_num,pk_hash):
|
||||
from mmgen.protocol import _b58chk_encode
|
||||
s = '{:0{}x}'.format(ver_num,2 if ver_num < 256 else 4) + pk_hash
|
||||
lzeroes = (len(s) - len(s.lstrip('0'))) / 2 # non-zero only for ver num '00' (BTC p2pkh)
|
||||
return ('1' * lzeroes) + _b58chk_encode(s)
|
||||
|
||||
low = phash2addr(ver_num,'00'*20)
|
||||
high = phash2addr(ver_num,'ff'*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):
|
||||
w = max(len(e[0]) for e in cls.coin_constants['mainnet'])
|
||||
for line in cls.coin_constants['mainnet']:
|
||||
if reverse:
|
||||
print('{:6} {}'.format(line[1],line[0]))
|
||||
else:
|
||||
print(('','{:{}} '.format(line[0],w))[include_names] + line[1])
|
||||
|
||||
@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]),"Duplicate entry in '{}'!".format(ext_prog)
|
||||
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}
|
||||
external_tests = {
|
||||
'mainnet': {
|
||||
'pycoin': (
|
||||
# broken: DASH - only compressed, LTC segwit old fmt
|
||||
'BTC','LTC','VIA','FTC','DOGE','MEC','MYR','UNO',
|
||||
'JBS','MZC','RIC','DFC','FAI','ARG','ZEC','DCR'),
|
||||
'pyethereum': ('ETH','ETC'),
|
||||
'zcash_mini': ('ZEC',),
|
||||
'keyconv': ( # all supported by vanitygen-plus 'keyconv' util
|
||||
# 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')
|
||||
},
|
||||
'testnet': {
|
||||
'pycoin': {
|
||||
# broken: DASH - only compressed { 'DASH':'tDASH' }
|
||||
'BTC':'XTN','LTC':'XLT','VIA':'TVI','FTC':'FTX','DOGE':'XDT','DCR':'DCRT'
|
||||
},
|
||||
'pyethereum': {},
|
||||
'keyconv': {}
|
||||
}
|
||||
}
|
||||
external_tests_segwit_compressed = {
|
||||
'segwit': ('BTC'),
|
||||
'compressed': (
|
||||
'BTC','LTC','VIA','FTC','DOGE','DASH','MEC','MYR','UNO',
|
||||
'JBS','MZC','RIC','DFC','FAI','ARG','ZEC','DCR','ZEC'),
|
||||
}
|
||||
|
|
@ -51,3 +51,9 @@ def launch(what):
|
|||
sys.stderr.write('\nUser interrupt\n')
|
||||
except EOFError:
|
||||
sys.stderr.write('\nEnd of file\n')
|
||||
except Exception as e:
|
||||
if os.getenv('MMGEN_TRACEBACK'):
|
||||
raise
|
||||
else:
|
||||
sys.stderr.write('{!r}\n'.format(e[0]))
|
||||
sys.exit(2)
|
||||
|
|
|
|||
|
|
@ -96,12 +96,11 @@ if mmids[0] == mmids[1]:
|
|||
die(2,'Both transactions have the same output! ({})'.format(mmids[0]))
|
||||
|
||||
from mmgen.tx import MMGenSplitTX
|
||||
from mmgen.protocol import CoinProtocol
|
||||
from mmgen.protocol import init_coin
|
||||
|
||||
if opt.tx_fees:
|
||||
for idx,g_coin in ((1,opt.other_coin),(0,g.coin)):
|
||||
g.coin = g_coin
|
||||
g.proto = CoinProtocol(g.coin,g.testnet)
|
||||
init_coin(g_coin)
|
||||
opt.tx_fee = opt.tx_fees.split(',')[idx]
|
||||
opts.opt_is_tx_fee(opt.tx_fee,'transaction fee') or sys.exit(1)
|
||||
|
||||
|
|
@ -119,9 +118,7 @@ tx1.create_fn()
|
|||
|
||||
gmsg("\nCreating transaction for short chain ({})".format(opt.other_coin))
|
||||
|
||||
from mmgen.protocol import CoinProtocol
|
||||
g.coin = opt.other_coin
|
||||
g.proto = CoinProtocol(g.coin,g.testnet)
|
||||
init_coin(opt.other_coin)
|
||||
reload(sys.modules['mmgen.tx'])
|
||||
|
||||
tx2 = MMGenSplitTX()
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ supported commands), use '-' as the first argument.
|
|||
cmd_help = """
|
||||
Cryptocoin address/key operations (compressed public keys supported):
|
||||
addr2hexaddr - convert coin address from base58 to hex format
|
||||
hex2wif - convert a private key from hex to WIF format (use 'pubkey_type=zcash_z' for zcash-z key)
|
||||
hex2wif - convert a private key from hex to WIF format (use '--type=zcash_z' for zcash-z key)
|
||||
pubhash2addr - convert public key hash to address
|
||||
privhex2addr - generate coin address from private key in hex format
|
||||
privhex2pubhex - generate a hex public key from a hex private key
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ if not opt.status: do_license_msg()
|
|||
|
||||
from mmgen.tx import *
|
||||
|
||||
tx = MMGenTX(infile) # sig check performed here
|
||||
tx = MMGenTX(infile,silent_open=True) # sig check performed here
|
||||
vmsg("Signed transaction file '%s' is valid" % infile)
|
||||
|
||||
if not tx.marked_signed():
|
||||
|
|
|
|||
|
|
@ -170,9 +170,23 @@ def override_from_env():
|
|||
gname = name[idx:].lower()
|
||||
setattr(g,gname,set_for_type(val,getattr(g,gname),name,invert_bool))
|
||||
|
||||
def warn_altcoins(trust_level):
|
||||
if trust_level == None: return
|
||||
tl = (red('COMPLETELY UNTESTED'),red('LOW'),yellow('MEDIUM'),green('HIGH'))
|
||||
m = """
|
||||
Support for coin '{}' is EXPERIMENTAL. The {pn} project assumes no
|
||||
responsibility for any loss of funds you may incur.
|
||||
This coin's {pn} testing status: {}
|
||||
Are you sure you want to continue?
|
||||
""".strip().format(g.coin,tl[trust_level],pn=g.proj_name)
|
||||
if os.getenv('MMGEN_TEST_SUITE'):
|
||||
msg(m); return
|
||||
if not keypress_confirm(m):
|
||||
sys.exit(0)
|
||||
|
||||
def init(opts_f,add_opts=[],opt_filter=None):
|
||||
|
||||
from mmgen.protocol import CoinProtocol,BitcoinProtocol
|
||||
from mmgen.protocol import CoinProtocol,BitcoinProtocol,init_genonly_altcoins
|
||||
g.proto = BitcoinProtocol # this must be initialized to something before opts_f is called
|
||||
|
||||
# most, but not all, of these set the corresponding global var
|
||||
|
|
@ -239,6 +253,8 @@ def init(opts_f,add_opts=[],opt_filter=None):
|
|||
|
||||
if g.regtest: g.testnet = True # These are equivalent for now
|
||||
|
||||
altcoin_trust_level = init_genonly_altcoins(opt.coin)
|
||||
|
||||
# g.testnet is set, so we can set g.proto
|
||||
g.proto = CoinProtocol(g.coin,g.testnet)
|
||||
|
||||
|
|
@ -300,6 +316,8 @@ def init(opts_f,add_opts=[],opt_filter=None):
|
|||
for k in ('prog_name','desc','usage','options','notes'):
|
||||
if k in opts_data: del opts_data[k]
|
||||
|
||||
warn_altcoins(altcoin_trust_level)
|
||||
|
||||
return args
|
||||
|
||||
def opt_is_tx_fee(val,desc):
|
||||
|
|
|
|||
|
|
@ -84,10 +84,9 @@ class BitcoinProtocol(MMGenObject):
|
|||
(None,'','b2x',True)
|
||||
]
|
||||
caps = ('rbf','segwit')
|
||||
mmcaps = ('key','addr','rpc')
|
||||
mmcaps = ('key','addr','rpc','tx')
|
||||
base_coin = 'BTC'
|
||||
addr_width = 34
|
||||
addr_hex_width = 40
|
||||
|
||||
@staticmethod
|
||||
def get_protocol_by_chain(chain):
|
||||
|
|
@ -207,7 +206,7 @@ class BitcoinCashTestnetProtocol(BitcoinCashProtocol):
|
|||
addr_width = 35
|
||||
|
||||
class B2XProtocol(BitcoinProtocol):
|
||||
daemon_name = 'bitcoind-2x'
|
||||
daemon_name = 'bitcoind-2x'
|
||||
daemon_data_dir = os.path.join(os.getenv('APPDATA'),'Bitcoin_2X') if g.platform == 'win' \
|
||||
else os.path.join(g.home_dir,'.bitcoin-2x')
|
||||
rpc_port = 8338
|
||||
|
|
@ -218,12 +217,12 @@ class B2XProtocol(BitcoinProtocol):
|
|||
]
|
||||
|
||||
class B2XTestnetProtocol(B2XProtocol):
|
||||
addr_ver_num = { 'p2pkh': ('6f',('m','n')), 'p2sh': ('c4','2') }
|
||||
wif_ver_num = { 'std': 'ef' }
|
||||
data_subdir = 'testnet'
|
||||
daemon_data_subdir = 'testnet5'
|
||||
rpc_port = 18338
|
||||
addr_width = 35
|
||||
addr_ver_num = { 'p2pkh': ('6f',('m','n')), 'p2sh': ('c4','2') }
|
||||
wif_ver_num = { 'std': 'ef' }
|
||||
data_subdir = 'testnet'
|
||||
daemon_data_subdir = 'testnet5'
|
||||
rpc_port = 18338
|
||||
addr_width = 35
|
||||
|
||||
class LitecoinProtocol(BitcoinProtocol):
|
||||
block0 = '12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2'
|
||||
|
|
@ -250,9 +249,7 @@ class LitecoinTestnetProtocol(LitecoinProtocol):
|
|||
addr_width = 35
|
||||
|
||||
class BitcoinProtocolAddrgen(BitcoinProtocol): mmcaps = ('key','addr')
|
||||
class BitcoinProtocolKeygen(BitcoinProtocol): mmcaps = ('key',)
|
||||
class BitcoinTestnetProtocolAddrgen(BitcoinTestnetProtocol): mmcaps = ('key','addr')
|
||||
class BitcoinTestnetProtocolKeygen(BitcoinTestnetProtocol): mmcaps = ('key',)
|
||||
|
||||
class EthereumProtocol(BitcoinProtocolAddrgen):
|
||||
|
||||
|
|
@ -299,9 +296,8 @@ class ZcashProtocol(BitcoinProtocolAddrgen):
|
|||
'zcash_z': ('169a','zc'),
|
||||
'viewkey': ('0b1c','V') }
|
||||
wif_ver_num = { 'std': '80', 'zcash_z': 'ab36' }
|
||||
mmtypes = ('C','Z')
|
||||
dfl_mmtype = 'C'
|
||||
addr_hex_width = 40
|
||||
mmtypes = ('L','C','Z')
|
||||
dfl_mmtype = 'L'
|
||||
|
||||
@classmethod
|
||||
def preprocess_key(cls,hexpriv,pubkey_type): # zero the first four bits
|
||||
|
|
@ -328,35 +324,22 @@ class ZcashTestnetProtocol(ZcashProtocol):
|
|||
'zcash_z': ('16b6','??'),
|
||||
'viewkey': ('0b2a','??') }
|
||||
|
||||
class DashProtocol(BitcoinProtocolAddrgen):
|
||||
name = 'dash'
|
||||
base_coin = 'DASH'
|
||||
addr_ver_num = { 'p2pkh': ('4c','X'), 'p2sh': ('10','7') }
|
||||
wif_ver_num = { 'std': 'cc' }
|
||||
mmtypes = ('C',)
|
||||
dfl_mmtype = 'C'
|
||||
|
||||
class DashTestnetProtocol(DashProtocol):
|
||||
# "Dash", "testnet", "tDASH", b'\xef', b'\x8c', b'\x13'
|
||||
addr_ver_num = { 'p2pkh': ('8c','y'), 'p2sh': ('13','?') }
|
||||
wif_ver_num = { 'std': 'ef' }
|
||||
|
||||
class CoinProtocol(MMGenObject):
|
||||
coins = {
|
||||
'btc': (BitcoinProtocol,BitcoinTestnetProtocol),
|
||||
'bch': (BitcoinCashProtocol,BitcoinCashTestnetProtocol),
|
||||
'b2x': (B2XProtocol,B2XTestnetProtocol),
|
||||
'ltc': (LitecoinProtocol,LitecoinTestnetProtocol),
|
||||
'dash': (DashProtocol,DashTestnetProtocol),
|
||||
'zec': (ZcashProtocol,ZcashTestnetProtocol),
|
||||
'eth': (EthereumProtocol,EthereumTestnetProtocol),
|
||||
'etc': (EthereumClassicProtocol,EthereumClassicTestnetProtocol),
|
||||
'zec': (ZcashProtocol,ZcashTestnetProtocol),
|
||||
}
|
||||
def __new__(cls,coin,testnet):
|
||||
coin = coin.lower()
|
||||
assert type(testnet) == bool
|
||||
m = "'{}': not a valid coin. Valid choices are '{}'"
|
||||
assert coin in cls.coins,m.format(coin,"','".join(cls.coins))
|
||||
from mmgen.altcoin import CoinInfo as ci
|
||||
all_coins = sorted(set([e[1].lower() for e in ci.coin_constants['mainnet']] + cls.coins.keys()))
|
||||
m = "'{}': not a valid coin. Valid choices are {}"
|
||||
assert coin in cls.coins,m.format(coin,','.join(all_coins))
|
||||
return cls.coins[coin][testnet]
|
||||
|
||||
@classmethod
|
||||
|
|
@ -365,3 +348,60 @@ class CoinProtocol(MMGenObject):
|
|||
if name == proto.__name__[:-8].lower():
|
||||
return proto.base_coin
|
||||
return False
|
||||
|
||||
def init_genonly_altcoins(usr_coin,trust_level=None):
|
||||
from mmgen.altcoin import CoinInfo as ci
|
||||
if trust_level is None:
|
||||
if not usr_coin or usr_coin.lower() in CoinProtocol.coins: return None
|
||||
usr_coin = usr_coin.upper()
|
||||
mn_coins = [e[1] for e in ci.coin_constants['mainnet']]
|
||||
if usr_coin not in mn_coins: return None
|
||||
trust_level = ci.coin_constants['mainnet'][mn_coins.index(usr_coin)][6]
|
||||
data = {}
|
||||
for k in ('mainnet','testnet'):
|
||||
data[k] = [e for e in ci.coin_constants[k] if e[6] >= trust_level]
|
||||
exec(make_init_genonly_altcoins_str(data))
|
||||
return trust_level
|
||||
|
||||
def make_init_genonly_altcoins_str(data):
|
||||
|
||||
def make_proto(e,testnet=False):
|
||||
tn_str = 'Testnet' if testnet else ''
|
||||
proto,coin = '{}{}Protocol'.format(e[0],tn_str),e[1]
|
||||
if proto[0] in '0123456789': proto = 'X_'+proto
|
||||
if proto in globals(): return ''
|
||||
if coin.lower() in CoinProtocol.coins: return ''
|
||||
def num2hexstr(n):
|
||||
return '{:0{}x}'.format(n,2 if n < 256 else 4)
|
||||
o = ['class {}(Bitcoin{}ProtocolAddrgen):'.format(proto,tn_str)]
|
||||
o += ["base_coin = '{}'".format(coin)]
|
||||
o += ["name = '{}'".format(e[0].lower())]
|
||||
o += ["nameCaps = '{}'".format(e[0])]
|
||||
a = "addr_ver_num = {{ 'p2pkh': ({!r},{!r})".format(num2hexstr(e[3][0]),e[3][1])
|
||||
b = ", 'p2sh': ({!r},{!r})".format(num2hexstr(e[4][0]),e[4][1]) if e[4] else ''
|
||||
o += [a+b+' }']
|
||||
o += ["wif_ver_num = {{ 'std': {!r} }}".format(num2hexstr(e[2]))]
|
||||
o += ["mmtypes = ('L','C'{})".format(",'S'" if e[5] else '')]
|
||||
o += ["dfl_mmtype = '{}'".format('L')]
|
||||
return '\n\t'.join(o) + '\n'
|
||||
|
||||
out = ''
|
||||
for e in data['mainnet']:
|
||||
out += make_proto(e)
|
||||
for e in data['testnet']:
|
||||
out += make_proto(e,testnet=True)
|
||||
|
||||
tn_coins = [e[1] for e in data['testnet']]
|
||||
fs = "CoinProtocol.coins['{}'] = ({}Protocol,{})\n"
|
||||
for e in data['mainnet']:
|
||||
proto,coin = e[0],e[1]
|
||||
if proto[0] in '0123456789': proto = 'X_'+proto
|
||||
if proto+'Protocol' in globals(): continue
|
||||
if coin.lower() in CoinProtocol.coins: continue
|
||||
out += fs.format(coin.lower(),proto,('None',proto+'TestnetProtocol')[coin in tn_coins])
|
||||
# print out
|
||||
return out
|
||||
|
||||
def init_coin(coin):
|
||||
g.coin = coin
|
||||
g.proto = CoinProtocol(coin,g.testnet)
|
||||
|
|
|
|||
|
|
@ -225,8 +225,8 @@ def print_convert_results(indata,enc,dec,dtype):
|
|||
|
||||
from mmgen.obj import MMGenAddrType
|
||||
at = MMGenAddrType((hasattr(opt,'type') and opt.type) or g.proto.dfl_mmtype)
|
||||
kg = KeyGenerator(at.pubkey_type)
|
||||
ag = AddrGenerator(at.gen_method)
|
||||
kg = KeyGenerator(at)
|
||||
ag = AddrGenerator(at)
|
||||
|
||||
def Hexdump(infile,cols=8,line_nums=True):
|
||||
Msg(pretty_hexdump(
|
||||
|
|
|
|||
38
mmgen/tx.py
38
mmgen/tx.py
|
|
@ -266,7 +266,7 @@ class MMGenTX(MMGenObject):
|
|||
desc = 'transaction outputs'
|
||||
member_type = 'MMGenTxOutput'
|
||||
|
||||
def __init__(self,filename=None,md_only=False,caller=None):
|
||||
def __init__(self,filename=None,md_only=False,caller=None,silent_open=False):
|
||||
self.inputs = self.MMGenTxInputList()
|
||||
self.outputs = self.MMGenTxOutputList()
|
||||
self.send_amt = g.proto.coin_amt('0') # total amt minus change
|
||||
|
|
@ -285,7 +285,7 @@ class MMGenTX(MMGenObject):
|
|||
self.locktime = None
|
||||
|
||||
if filename:
|
||||
self.parse_tx_file(filename,md_only=md_only)
|
||||
self.parse_tx_file(filename,md_only=md_only,silent_open=silent_open)
|
||||
if md_only: return
|
||||
self.check_sigs() # marks the tx as signed
|
||||
|
||||
|
|
@ -727,22 +727,42 @@ class MMGenTX(MMGenObject):
|
|||
ret = g.rpch.gettransaction(self.coin_txid,on_fail='silent')
|
||||
if not 'bip125-replaceable' in ret or not 'confirmations' in ret or ret['confirmations'] > 0:
|
||||
return False
|
||||
return -ret['confirmations'] + 1 # 1: replacement in mempool, 2: replacement confirmed
|
||||
return -ret['confirmations'] + 1,ret # 1: replacement in mempool, 2: replacement confirmed
|
||||
|
||||
def is_in_utxos(self):
|
||||
return 'txid' in g.rpch.getrawtransaction(self.coin_txid,True,on_fail='silent')
|
||||
|
||||
def get_status(self,status=False):
|
||||
if self.is_in_mempool():
|
||||
msg(('Warning: transaction is in mempool!','Transaction is in mempool')[status])
|
||||
if status:
|
||||
d = g.rpch.gettransaction(self.coin_txid,on_fail='silent')
|
||||
r = '{}replaceable'.format(('NOT ','')[d['bip125-replaceable']=='yes'])
|
||||
t = d['timereceived']
|
||||
m = 'Sent {} ({} h/m/s ago)'
|
||||
b = m.format(time.strftime('%c',time.gmtime(t)),secs_to_dhms(int(time.time()-t)))
|
||||
if opt.quiet:
|
||||
msg('Transaction is in mempool')
|
||||
else:
|
||||
msg('TX status: in mempool, {}\n{}'.format(r,b))
|
||||
else:
|
||||
msg('Warning: transaction is in mempool!')
|
||||
elif self.is_in_wallet():
|
||||
confs = self.is_in_wallet()
|
||||
die(0,'Transaction has {} confirmation{}'.format(confs,suf(confs,'s')))
|
||||
elif self.is_in_utxos():
|
||||
die(2,red('ERROR: transaction is in the blockchain (but not in the tracking wallet)!'))
|
||||
ret = self.is_replaced() # 1: replacement in mempool, 2: replacement confirmed
|
||||
if ret:
|
||||
die(1,'Transaction has been replaced'+('',', and the replacement TX is confirmed')[ret==2]+'!')
|
||||
else:
|
||||
ret = self.is_replaced() # ret[0]==1: replacement in mempool, ret[0]==2: replacement confirmed
|
||||
if ret and ret[0]:
|
||||
m1 = 'Transaction has been replaced'
|
||||
m2 = ('',', and the replacement TX is confirmed')[ret[0]==2]
|
||||
msg('{}{}!'.format(m1,m2))
|
||||
if not opt.quiet:
|
||||
msg('Replacing transactions:')
|
||||
rt = ret[1]['walletconflicts']
|
||||
for t,s in [(tx,'size' in g.rpch.getmempoolentry(tx,on_fail='silent')) for tx in rt]:
|
||||
msg(' {}{}'.format(t,('',' in mempool')[s]))
|
||||
die(0,'')
|
||||
|
||||
def send(self,prompt_user=True,exit_on_fail=False):
|
||||
|
||||
|
|
@ -946,9 +966,9 @@ class MMGenTX(MMGenObject):
|
|||
|
||||
return out # TX label might contain non-ascii chars
|
||||
|
||||
def parse_tx_file(self,infile,md_only=False):
|
||||
def parse_tx_file(self,infile,md_only=False,silent_open=False):
|
||||
|
||||
tx_data = get_lines_from_file(infile,self.desc+' data')
|
||||
tx_data = get_lines_from_file(infile,self.desc+' data',silent=silent_open)
|
||||
|
||||
try:
|
||||
desc = 'data'
|
||||
|
|
|
|||
|
|
@ -212,6 +212,12 @@ def make_timestr(secs=None):
|
|||
tv = time.gmtime(t)[:6]
|
||||
return '{:04d}/{:02d}/{:02d} {:02d}:{:02d}:{:02d}'.format(*tv)
|
||||
|
||||
def secs_to_dhms(secs):
|
||||
dsecs = secs/3600
|
||||
return '{}{:02d}:{:02d}:{:02d}'.format(
|
||||
('','{} day{}, '.format(dsecs/24,suf(dsecs/24)))[dsecs > 24],
|
||||
dsecs % 24, (secs/60) % 60, secs % 60)
|
||||
|
||||
def secs_to_hms(secs):
|
||||
return '{:02d}:{:02d}:{:02d}'.format(secs/3600, (secs/60) % 60, secs % 60)
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ f_obj='Data object test complete'
|
|||
i_alts='Gen-only altcoin'
|
||||
s_alts='The following tests will test generation operations for all supported altcoins'
|
||||
ROUNDS=100
|
||||
ROUNDS_LOW=20
|
||||
ROUNDS_SPEC=500
|
||||
t_alts=(
|
||||
'test/scrambletest.py'
|
||||
|
|
@ -110,7 +111,6 @@ t_alts=(
|
|||
"test/gentest.py --coin=ltc 2 $ROUNDS"
|
||||
"test/gentest.py --coin=ltc --type=compressed 2 $ROUNDS"
|
||||
"test/gentest.py --coin=ltc --type=segwit 2 $ROUNDS"
|
||||
"test/gentest.py --coin=dash 2 $ROUNDS"
|
||||
"test/gentest.py --coin=zec 2 $ROUNDS"
|
||||
"test/gentest.py --coin=etc 2 $ROUNDS"
|
||||
"test/gentest.py --coin=eth 2 $ROUNDS"
|
||||
|
|
@ -122,11 +122,15 @@ t_alts=(
|
|||
"test/gentest.py --coin=ltc 2:ext $ROUNDS"
|
||||
"test/gentest.py --coin=ltc --type=compressed 2:ext $ROUNDS"
|
||||
# "test/gentest.py --coin=ltc --type=segwit 2:ext $ROUNDS" # pycoin generates old-style LTC Segwit addrs
|
||||
"test/gentest.py --coin=dash 2:ext $ROUNDS"
|
||||
"test/gentest.py --coin=zec 2:ext $ROUNDS"
|
||||
"test/gentest.py --coin=etc 2:ext $ROUNDS"
|
||||
"test/gentest.py --coin=eth 2:ext $ROUNDS"
|
||||
"test/gentest.py --coin=zec --type=zcash_z 2:ext $ROUNDS_SPEC")
|
||||
"test/gentest.py --coin=zec 2:ext $ROUNDS"
|
||||
"test/gentest.py --coin=zec --type=zcash_z 2:ext $ROUNDS_SPEC"
|
||||
|
||||
"test/gentest.py --all 2:pycoin $ROUNDS_LOW"
|
||||
"test/gentest.py --all 2:pyethereum $ROUNDS_LOW"
|
||||
"test/gentest.py --all 2:keyconv $ROUNDS_LOW")
|
||||
|
||||
f_alts='Gen-only altcoin tests completed'
|
||||
|
||||
i_misc_ni='Miscellaneous operations (non-interactive)'
|
||||
|
|
@ -164,7 +168,8 @@ i_btc_rt='Bitcoin regtest'
|
|||
s_btc_rt="The following tests will test MMGen's regtest (Bob and Alice) mode"
|
||||
t_btc_rt=(
|
||||
'test/test.py -On regtest'
|
||||
'test/test.py -On regtest_split')
|
||||
# 'test/test.py -On regtest_split' # no official B2X support, so skip
|
||||
)
|
||||
f_btc_rt='Regtest (Bob and Alice) mode tests for BTC completed'
|
||||
|
||||
i_bch='Bitcoin cash (BCH)'
|
||||
|
|
@ -211,7 +216,6 @@ s_ltc_rt="The following tests will test MMGen's regtest (Bob and Alice) mode"
|
|||
t_ltc_rt=('test/test.py --coin=ltc -On regtest')
|
||||
f_ltc_rt='Regtest (Bob and Alice) mode tests for LTC completed'
|
||||
|
||||
# TODO: ethereum support for tooltest
|
||||
i_tool='Tooltest'
|
||||
s_tool='The following tests will run test/tooltest.py for all supported coins'
|
||||
t_tool=(
|
||||
|
|
@ -222,6 +226,8 @@ t_tool=(
|
|||
'test/tooltest.py --coin=eth cryptocoin'
|
||||
'test/tooltest.py --coin=etc cryptocoin'
|
||||
'test/tooltest.py --coin=dash cryptocoin'
|
||||
'test/tooltest.py --coin=doge cryptocoin'
|
||||
'test/tooltest.py --coin=emc cryptocoin'
|
||||
'test/tooltest.py --coin=zec cryptocoin'
|
||||
'test/tooltest.py --coin=zec --type=zcash_z cryptocoin')
|
||||
f_tool='tooltest tests completed'
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import sys,traceback,os
|
|||
sys.path.insert(0,'.')
|
||||
|
||||
if 'TMUX' in os.environ: del os.environ['TMUX']
|
||||
os.environ['MMGEN_TRACEBACK'] = '1'
|
||||
|
||||
f = open('my.err','w')
|
||||
|
||||
|
|
|
|||
|
|
@ -39,16 +39,14 @@ if g.coin != 'BTC':
|
|||
|
||||
if len(cmd_args) != 1: opts.usage()
|
||||
|
||||
from mmgen.protocol import CoinProtocol
|
||||
|
||||
import mmgen.tx
|
||||
tx = mmgen.tx.MMGenTX(cmd_args[0])
|
||||
|
||||
if opt.verbose:
|
||||
gmsg('Original transaction is in {} format'.format(g.coin))
|
||||
|
||||
g.coin = 'BCH'
|
||||
g.proto = CoinProtocol(g.coin,g.testnet)
|
||||
from mmgen.protocol import init_coin
|
||||
init_coin('BCH')
|
||||
|
||||
reload(sys.modules['mmgen.tx'])
|
||||
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -109,6 +109,7 @@ setup(
|
|||
py_modules = [
|
||||
'mmgen.__init__',
|
||||
'mmgen.addr',
|
||||
'mmgen.altcoin',
|
||||
'mmgen.protocol',
|
||||
'mmgen.color',
|
||||
'mmgen.common',
|
||||
|
|
|
|||
103
test/gentest.py
103
test/gentest.py
|
|
@ -24,6 +24,7 @@ import sys,os
|
|||
pn = os.path.dirname(sys.argv[0])
|
||||
os.chdir(os.path.join(pn,os.pardir))
|
||||
sys.path.__setitem__(0,os.path.abspath(os.curdir))
|
||||
os.environ['MMGEN_TEST_SUITE'] = '1'
|
||||
|
||||
from binascii import hexlify
|
||||
|
||||
|
|
@ -33,10 +34,11 @@ from mmgen.obj import MMGenAddrType
|
|||
|
||||
rounds = 100
|
||||
opts_data = lambda: {
|
||||
'desc': "Test address generation in various ways",
|
||||
'desc': 'Test address generation in various ways',
|
||||
'usage':'[options] [spec] [rounds | dump file]',
|
||||
'options': """
|
||||
-h, --help Print this help message
|
||||
-a, --all Test all supported coins for external generator 'ext'
|
||||
--, --longhelp Print help message for long options (common options)
|
||||
-q, --quiet Produce quieter output
|
||||
-t, --type=t Specify address type (valid options: 'compressed','segwit','zcash_z')
|
||||
|
|
@ -62,8 +64,11 @@ EXAMPLES:
|
|||
(compare addrs generated with secp256k1 library to {dn} wallet dump)
|
||||
|
||||
External libraries required for the 'ext' generator:
|
||||
+ pyethereum (for ETH,ETC) https://github.com/ethereum/pyethereum
|
||||
+ pycoin (for all other coins) https://github.com/richardkiss/pycoin
|
||||
+ pyethereum (for ETH,ETC) https://github.com/ethereum/pyethereum
|
||||
+ zcash-mini (for zcash_z addresses) https://github.com/FiloSottile/zcash-mini
|
||||
+ pycoin (for supported coins) https://github.com/richardkiss/pycoin
|
||||
+ keyconv (for all other coins) https://github.com/exploitagency/vanitygen-plus
|
||||
('keyconv' generates uncompressed addresses only)
|
||||
""".format(prog='gentest.py',pnm=g.proj_name,snum=rounds,dn=g.proto.daemon_name)
|
||||
}
|
||||
|
||||
|
|
@ -78,6 +83,12 @@ addr_type = MMGenAddrType(opt.type or g.proto.dfl_mmtype)
|
|||
def pyethereum_sec2addr(sec):
|
||||
return sec,eth.privtoaddr(sec).encode('hex')
|
||||
|
||||
def keyconv_sec2addr(sec):
|
||||
p = sp.Popen(['keyconv','-C',g.coin,sec.wif],stderr=sp.PIPE,stdout=sp.PIPE)
|
||||
o = p.stdout.read().splitlines()
|
||||
# print p.stderr.read()
|
||||
return o[1].split()[1],o[0].split()[1]
|
||||
|
||||
def zcash_mini_sec2addr(sec):
|
||||
p = sp.Popen(['zcash-mini','-key','-simple'],stderr=sp.PIPE,stdin=sp.PIPE,stdout=sp.PIPE)
|
||||
p.stdin.write(sec.wif+'\n')
|
||||
|
|
@ -85,41 +96,52 @@ def zcash_mini_sec2addr(sec):
|
|||
return sec.wif,o[0],o[-1]
|
||||
|
||||
def pycoin_sec2addr(sec):
|
||||
if g.testnet: # pycoin/networks/all.py pycoin/networks/legacy_networks.py
|
||||
coin = { 'BTC':'XTN', 'LTC':'XLT', 'DASH':'tDASH' }[g.coin]
|
||||
else:
|
||||
coin = g.coin
|
||||
coin = ci.external_tests['testnet']['pycoin'][g.coin] if g.testnet else g.coin
|
||||
key = pcku.parse_key(sec,PREFIX_TRANSFORMS,coin)
|
||||
if key is None: die(1,"can't parse {}".format(sec))
|
||||
o = pcku.create_output(sec,key)[0]
|
||||
# pmsg(o)
|
||||
suf = ('_uncompressed','')[addr_type.compressed]
|
||||
wif = o['wif{}'.format(suf)]
|
||||
addr = o['p2sh_segwit' if addr_type.name == 'segwit' else '{}_address{}'.format(coin,suf)]
|
||||
return wif,addr
|
||||
|
||||
# pycoin/networks/all.py pycoin/networks/legacy_networks.py
|
||||
def init_external_prog():
|
||||
global b_desc,ext_lib,ext_sec2addr,sp,eth,pcku,PREFIX_TRANSFORMS
|
||||
if addr_type.name == 'zcash_z':
|
||||
global b,b_desc,ext_lib,ext_sec2addr,sp,eth,pcku,PREFIX_TRANSFORMS
|
||||
def test_support(k):
|
||||
if b == k: return True
|
||||
if b != 'ext' and b != k: return False
|
||||
if g.coin in ci.external_tests['mainnet'][k] and not g.testnet: return True
|
||||
if g.coin in ci.external_tests['testnet'][k]: return True
|
||||
return False
|
||||
if b == 'zcash_mini' or addr_type.name == 'zcash_z':
|
||||
import subprocess as sp
|
||||
ext_sec2addr = zcash_mini_sec2addr
|
||||
ext_lib = 'zcash_mini'
|
||||
elif addr_type.name == 'ethereum':
|
||||
elif test_support('pyethereum'):
|
||||
try:
|
||||
import ethereum.utils as eth
|
||||
except:
|
||||
die(1,"Unable to import 'pyethereum' module. Is pyethereum installed?")
|
||||
raise ImportError,"Unable to import 'pyethereum' module. Is pyethereum installed?"
|
||||
ext_sec2addr = pyethereum_sec2addr
|
||||
ext_lib = 'pyethereum'
|
||||
else:
|
||||
elif test_support('pycoin'):
|
||||
try:
|
||||
import pycoin.cmds.ku as pcku
|
||||
except:
|
||||
die(1,"Unable to import module 'ku'. Is pycoin installed?")
|
||||
raise ImportError,"Unable to import module 'ku'. Is pycoin installed?"
|
||||
PREFIX_TRANSFORMS = pcku.prefix_transforms_for_network(g.coin)
|
||||
ext_sec2addr = pycoin_sec2addr
|
||||
ext_lib = 'pycoin'
|
||||
elif test_support('keyconv'):
|
||||
import subprocess as sp
|
||||
ext_sec2addr = keyconv_sec2addr
|
||||
ext_lib = 'keyconv'
|
||||
else:
|
||||
m = '{}: coin supported by MMGen but unsupported by gentest.py for {}'
|
||||
raise ValueError,m.format(g.coin,('mainnet','testnet')[g.testnet])
|
||||
b_desc = ext_lib
|
||||
b = 'ext'
|
||||
|
||||
def match_error(sec,wif,a_addr,b_addr,a,b):
|
||||
qmsg_r(red('\nERROR: Values do not match!'))
|
||||
|
|
@ -131,6 +153,14 @@ def match_error(sec,wif,a_addr,b_addr,a,b):
|
|||
""".format(sec,wif,a_addr,b_addr,pnm=g.proj_name,a=kg_a.desc,b=b_desc).rstrip())
|
||||
|
||||
def compare_test():
|
||||
for k in ('segwit','compressed'):
|
||||
if addr_type.name == k and g.coin not in ci.external_tests_segwit_compressed[k]:
|
||||
msg('{} testing not supported for coin {}'.format(addr_type.name.capitalize(),g.coin))
|
||||
return
|
||||
if 'ext_lib' in globals():
|
||||
if g.coin not in ci.external_tests[('mainnet','testnet')[g.testnet]][ext_lib]:
|
||||
msg("Coin '{}' incompatible with external generator '{}'".format(g.coin,ext_lib))
|
||||
return
|
||||
m = "Comparing address generators '{}' and '{}' for coin {}"
|
||||
last_t = time.time()
|
||||
qmsg(green(m.format(kg_a.desc,(ext_lib if b == 'ext' else kg_b.desc),g.coin)))
|
||||
|
|
@ -142,10 +172,10 @@ def compare_test():
|
|||
sec = PrivKey(os.urandom(32),compressed=addr_type.compressed,pubkey_type=addr_type.pubkey_type)
|
||||
ph = kg_a.to_pubhex(sec)
|
||||
a_addr = ag.to_addr(ph)
|
||||
if opt.type == 'zcash_z':
|
||||
if addr_type.name == 'zcash_z':
|
||||
a_vk = ag.to_viewkey(ph)
|
||||
if b == 'ext':
|
||||
if opt.type == 'zcash_z':
|
||||
if addr_type.name == 'zcash_z':
|
||||
b_wif,b_addr,b_vk = ext_sec2addr(sec)
|
||||
if b_vk != a_vk:
|
||||
match_error(sec,sec.wif,a_vk,b_vk,a,b)
|
||||
|
|
@ -195,6 +225,7 @@ def dump_test():
|
|||
match_error(sec,wif,a_addr,b_addr,3,a)
|
||||
qmsg(green(('\n','')[bool(opt.verbose)] + 'OK'))
|
||||
|
||||
from mmgen.altcoin import CoinInfo as ci
|
||||
urounds,fh = None,None
|
||||
dump = []
|
||||
if len(cmd_args) == 2:
|
||||
|
|
@ -205,7 +236,7 @@ if len(cmd_args) == 2:
|
|||
try:
|
||||
fh = open(cmd_args[1])
|
||||
except:
|
||||
die(1,"Second argument must be filename or positive integer")
|
||||
die(1,'Second argument must be filename or positive integer')
|
||||
else:
|
||||
for line in fh.readlines():
|
||||
if 'addr=' in line:
|
||||
|
|
@ -224,31 +255,43 @@ except:
|
|||
a = int(a)
|
||||
assert 1 <= a <= len(g.key_generators)
|
||||
except:
|
||||
die(1,"First argument must be one or two generator IDs, colon separated")
|
||||
die(1,'First argument must be one or two generator IDs, colon separated')
|
||||
else:
|
||||
try:
|
||||
a = int(a)
|
||||
assert 1 <= a <= len(g.key_generators)
|
||||
if b == 'ext':
|
||||
assert 1 <= a <= len(g.key_generators),'{}: invalid key generator'.format(a)
|
||||
if b in ('ext','pyethereum','pycoin','keyconv','zcash_mini'):
|
||||
init_external_prog()
|
||||
else:
|
||||
b = int(b)
|
||||
assert 1 <= b <= len(g.key_generators)
|
||||
assert a != b
|
||||
except:
|
||||
die(1,"%s: invalid generator IDs" % cmd_args[0])
|
||||
assert 1 <= b <= len(g.key_generators),'{}: invalid key generator'.format(b)
|
||||
assert a != b,'Key generators are the same!'
|
||||
except Exception as e:
|
||||
die(1,'{}\n{}: invalid generator argument'.format(e[0],cmd_args[0]))
|
||||
|
||||
from mmgen.addr import KeyGenerator,AddrGenerator
|
||||
from mmgen.obj import PrivKey
|
||||
|
||||
kg_a = KeyGenerator(addr_type.pubkey_type,a)
|
||||
ag = AddrGenerator(addr_type.gen_method)
|
||||
kg_a = KeyGenerator(addr_type,a)
|
||||
ag = AddrGenerator(addr_type)
|
||||
|
||||
if a and b:
|
||||
if b != 'ext':
|
||||
kg_b = KeyGenerator(addr_type.pubkey_type,b)
|
||||
b_desc = kg_b.desc
|
||||
compare_test()
|
||||
if opt.all:
|
||||
from mmgen.protocol import init_coin,init_genonly_altcoins
|
||||
init_genonly_altcoins('btc',trust_level=0)
|
||||
mmgen_supported = [e[1] for e in ci.coin_constants['mainnet']]
|
||||
for coin in ci.external_tests[('mainnet','testnet')[g.testnet]][ext_lib]:
|
||||
if coin not in mmgen_supported and ext_lib != 'pyethereum': continue
|
||||
init_coin(coin)
|
||||
tmp_addr_type = addr_type if addr_type in g.proto.mmtypes else MMGenAddrType(g.proto.dfl_mmtype)
|
||||
kg_a = KeyGenerator(tmp_addr_type,a)
|
||||
ag = AddrGenerator(tmp_addr_type)
|
||||
compare_test()
|
||||
else:
|
||||
if b != 'ext':
|
||||
kg_b = KeyGenerator(addr_type,b)
|
||||
b_desc = kg_b.desc
|
||||
compare_test()
|
||||
elif a and not fh:
|
||||
speed_test()
|
||||
elif a and dump:
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import sys,os,subprocess
|
|||
repo_root = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]),os.pardir)))
|
||||
os.chdir(repo_root)
|
||||
sys.path.__setitem__(0,repo_root)
|
||||
os.environ['MMGEN_TEST_SUITE'] = '1'
|
||||
|
||||
# Import this _after_ local path's been added to sys.path
|
||||
from mmgen.common import *
|
||||
|
|
@ -60,13 +61,14 @@ test_data = OrderedDict([
|
|||
('bch', ('456d7f5f1c4bfe3b','(none)', '', '', '1MU7EdgqYy9JX35L25hR6CmXXcSEBDAwyv')),
|
||||
('bch_compressed',('bf98a4af5464a4ef','compressed', '-C', 'COMPRESSED','1F97Jd89wwmu4ELadesAdGDzg3d8Y6j5iP')),
|
||||
('ltc', ('b11f16632e63ba92','ltc:legacy', '-LTC','LTC', 'LMxB474SVfxeYdqxNrM1WZDZMnifteSMv1')),
|
||||
('ltc_compressed',('7ccf465d466ee7d3','ltc:compressed', '-LTC-C', 'LTC:COMPRESSED', 'LdkebBKVXSs6NNoPJWGM8KciDnL8LhXXjb')),
|
||||
('ltc_segwit', ('9460f5ba15e82768','ltc:segwit', '-LTC-S', 'LTC:SEGWIT', 'MQrY3vEbqKMBgegXrSaR93R2HoTDE5bKrY')),
|
||||
('ltc_compressed',('7ccf465d466ee7d3','ltc:compressed', '-LTC-C','LTC:COMPRESSED', 'LdkebBKVXSs6NNoPJWGM8KciDnL8LhXXjb')),
|
||||
('ltc_segwit', ('9460f5ba15e82768','ltc:segwit', '-LTC-S','LTC:SEGWIT', 'MQrY3vEbqKMBgegXrSaR93R2HoTDE5bKrY')),
|
||||
('eth', ('213ed116869b19f2','eth', '-ETH', 'ETH','e704b6cfd9f0edb2e6cfbd0c913438d37ede7b35')),
|
||||
('etc', ('909def37096f5ab8','etc', '-ETC', 'ETC','1a6acbef8c38f52f20d04ecded2992b04d8608d7')),
|
||||
('dash', ('bb21cf88c198ab8c','dash:compressed','-DASH-C','DASH:COMPRESSED','XsjAJvCxkxYh55ZvCZMFEv2eJUVo5xxbwi')),
|
||||
('zec', ('637f7b8117b524ed','zec:compressed', '-ZEC-C', 'ZEC:COMPRESSED', 't1d47QeTehQye4Mms1Lmx7dPjKVoTtHXKmu')),
|
||||
('zec_zcash_z', ('b15570d033df9b1a','zec:zcash_z', '-ZEC-Z', 'ZEC:ZCASH_Z', 'zcLMMsnzfFYZWU4avRBnuc83yh4jTtJXbtP32uWrs3ickzu1krMU4ppZCQPTwwfE9hLnRuFDSYF8VFW13aT9eeQK8aov3Ge')),
|
||||
('dash', ('1319d347b021f952','dash:legacy', '-DASH','DASH','XoK491fppGNZQUUS9uEFkT6L9u8xxVFJNJ')),
|
||||
('zec', ('0bf9b5b20af7b5a0','zec:legacy', '-ZEC', 'ZEC', 't1URz8BHxV38v3gsaN6oHQNKC16s35R9WkY')),
|
||||
('zec_zcash_z', ('b15570d033df9b1a','zec:zcash_z', '-ZEC-Z','ZEC:ZCASH_Z','zcLMMsnzfFYZWU4avRBnuc83yh4jTtJXbtP32uWrs3ickzu1krMU4ppZCQPTwwfE9hLnRuFDSYF8VFW13aT9eeQK8aov3Ge')),
|
||||
('emc', ('7e1a29853d2db875','emc:legacy', '-EMC', 'EMC','EU4L6x2b5QUb2gRQsBAAuB8TuPEwUxCNZU')),
|
||||
])
|
||||
|
||||
def run_tests():
|
||||
|
|
|
|||
11
test/test.py
11
test/test.py
|
|
@ -791,11 +791,12 @@ for a,b in cmd_group['regtest']:
|
|||
cmd_list['regtest'].append(a)
|
||||
cmd_data[a] = (17,b,[[[],17]])
|
||||
|
||||
cmd_data['info_regtest_split'] = 'regtest mode with fork and coin split',[17]
|
||||
for a,b in cmd_group['regtest_split']:
|
||||
cmd_list['regtest_split'].append(a)
|
||||
cmd_data[a] = (19,b,[[[],19]])
|
||||
|
||||
# disable until B2X officially supported
|
||||
# cmd_data['info_regtest_split'] = 'regtest mode with fork and coin split',[17]
|
||||
# for a,b in cmd_group['regtest_split']:
|
||||
# cmd_list['regtest_split'].append(a)
|
||||
# cmd_data[a] = (19,b,[[[],19]])
|
||||
#
|
||||
cmd_data['info_misc'] = 'miscellaneous operations',[18]
|
||||
for a,b in cmd_group['misc']:
|
||||
cmd_list['misc'].append(a)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import sys,os,subprocess
|
|||
repo_root = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]),os.pardir)))
|
||||
os.chdir(repo_root)
|
||||
sys.path.__setitem__(0,repo_root)
|
||||
os.environ['MMGEN_TEST_SUITE'] = '1'
|
||||
|
||||
# Import this _after_ local path's been added to sys.path
|
||||
from mmgen.common import *
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue