# Copyright (c) 2016-2017, Neil Booth # Copyright (c) 2017, the ElectrumX authors # # All rights reserved. # # The MIT License (MIT) # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. '''Module providing coin abstraction. Anything coin-specific should go in this file and be subclassed where necessary for appropriate handling. ''' from collections import namedtuple import re import struct from decimal import Decimal from hashlib import sha256 from functools import partial import base64 from typing import Type, List import torba.server.util as util from torba.server.hash import Base58, hash160, double_sha256, hash_to_hex_str from torba.server.hash import HASHX_LEN, hex_str_to_hash from torba.server.script import ScriptPubKey, OpCodes import torba.server.tx as lib_tx import torba.server.block_processor as block_proc import torba.server.daemon as daemon from torba.server.session import ElectrumX, DashElectrumX Block = namedtuple("Block", "raw header transactions") OP_RETURN = OpCodes.OP_RETURN class CoinError(Exception): '''Exception raised for coin-related errors.''' class Coin(object): '''Base class of coin hierarchy.''' REORG_LIMIT = 200 # Not sure if these are coin-specific RPC_URL_REGEX = re.compile('.+@(\\[[0-9a-fA-F:]+\\]|[^:]+)(:[0-9]+)?') VALUE_PER_COIN = 100000000 CHUNK_SIZE = 2016 BASIC_HEADER_SIZE = 80 STATIC_BLOCK_HEADERS = True SESSIONCLS = ElectrumX DESERIALIZER = lib_tx.Deserializer DAEMON = daemon.Daemon BLOCK_PROCESSOR = block_proc.BlockProcessor HEADER_VALUES = [ 'version', 'prev_block_hash', 'merkle_root', 'timestamp', 'bits', 'nonce' ] HEADER_UNPACK = struct.Struct('< I 32s 32s I I I').unpack_from MEMPOOL_HISTOGRAM_REFRESH_SECS = 500 XPUB_VERBYTES = bytes('????', 'utf-8') XPRV_VERBYTES = bytes('????', 'utf-8') ENCODE_CHECK = Base58.encode_check DECODE_CHECK = Base58.decode_check # Peer discovery PEER_DEFAULT_PORTS = {'t': '50001', 's': '50002'} PEERS: List[str] = [] @classmethod def lookup_coin_class(cls, name, net): '''Return a coin class given name and network. Raise an exception if unrecognised.''' req_attrs = ['TX_COUNT', 'TX_COUNT_HEIGHT', 'TX_PER_BLOCK'] for coin in util.subclasses(Coin): if (coin.NAME.lower() == name.lower() and coin.NET.lower() == net.lower()): coin_req_attrs = req_attrs.copy() missing = [attr for attr in coin_req_attrs if not hasattr(coin, attr)] if missing: raise CoinError('coin {} missing {} attributes' .format(name, missing)) return coin raise CoinError('unknown coin {} and network {} combination' .format(name, net)) @classmethod def sanitize_url(cls, url): # Remove surrounding ws and trailing /s url = url.strip().rstrip('/') match = cls.RPC_URL_REGEX.match(url) if not match: raise CoinError('invalid daemon URL: "{}"'.format(url)) if match.groups()[1] is None: url += ':{:d}'.format(cls.RPC_PORT) if not url.startswith('http://') and not url.startswith('https://'): url = 'http://' + url return url + '/' @classmethod def genesis_block(cls, block): '''Check the Genesis block is the right one for this coin. Return the block less its unspendable coinbase. ''' header = cls.block_header(block, 0) header_hex_hash = hash_to_hex_str(cls.header_hash(header)) if header_hex_hash != cls.GENESIS_HASH: raise CoinError('genesis block has hash {} expected {}' .format(header_hex_hash, cls.GENESIS_HASH)) return header + bytes(1) @classmethod def hashX_from_script(cls, script): '''Returns a hashX from a script, or None if the script is provably unspendable so the output can be dropped. ''' if script and script[0] == OP_RETURN: return None return sha256(script).digest()[:HASHX_LEN] @staticmethod def lookup_xverbytes(verbytes): '''Return a (is_xpub, coin_class) pair given xpub/xprv verbytes.''' # Order means BTC testnet will override NMC testnet for coin in util.subclasses(Coin): if verbytes == coin.XPUB_VERBYTES: return True, coin if verbytes == coin.XPRV_VERBYTES: return False, coin raise CoinError('version bytes unrecognised') @classmethod def address_to_hashX(cls, address): '''Return a hashX given a coin address.''' return cls.hashX_from_script(cls.pay_to_address_script(address)) @classmethod def P2PKH_address_from_hash160(cls, hash160): '''Return a P2PKH address given a public key.''' assert len(hash160) == 20 return cls.ENCODE_CHECK(cls.P2PKH_VERBYTE + hash160) @classmethod def P2PKH_address_from_pubkey(cls, pubkey): '''Return a coin address given a public key.''' return cls.P2PKH_address_from_hash160(hash160(pubkey)) @classmethod def P2SH_address_from_hash160(cls, hash160): '''Return a coin address given a hash160.''' assert len(hash160) == 20 return cls.ENCODE_CHECK(cls.P2SH_VERBYTES[0] + hash160) @classmethod def hash160_to_P2PKH_script(cls, hash160): return ScriptPubKey.P2PKH_script(hash160) @classmethod def hash160_to_P2PKH_hashX(cls, hash160): return cls.hashX_from_script(cls.hash160_to_P2PKH_script(hash160)) @classmethod def pay_to_address_script(cls, address): '''Return a pubkey script that pays to a pubkey hash. Pass the address (either P2PKH or P2SH) in base58 form. ''' raw = cls.DECODE_CHECK(address) # Require version byte(s) plus hash160. verbyte = -1 verlen = len(raw) - 20 if verlen > 0: verbyte, hash160 = raw[:verlen], raw[verlen:] if verbyte == cls.P2PKH_VERBYTE: return cls.hash160_to_P2PKH_script(hash160) if verbyte in cls.P2SH_VERBYTES: return ScriptPubKey.P2SH_script(hash160) raise CoinError('invalid address: {}'.format(address)) @classmethod def privkey_WIF(cls, privkey_bytes, compressed): '''Return the private key encoded in Wallet Import Format.''' payload = bytearray(cls.WIF_BYTE) + privkey_bytes if compressed: payload.append(0x01) return cls.ENCODE_CHECK(payload) @classmethod def header_hash(cls, header): '''Given a header return hash''' return double_sha256(header) @classmethod def header_prevhash(cls, header): '''Given a header return previous hash''' return header[4:36] @classmethod def static_header_offset(cls, height): '''Given a header height return its offset in the headers file. If header sizes change at some point, this is the only code that needs updating.''' assert cls.STATIC_BLOCK_HEADERS return height * cls.BASIC_HEADER_SIZE @classmethod def static_header_len(cls, height): '''Given a header height return its length.''' return (cls.static_header_offset(height + 1) - cls.static_header_offset(height)) @classmethod def block_header(cls, block, height): '''Returns the block header given a block and its height.''' return block[:cls.static_header_len(height)] @classmethod def block(cls, raw_block, height): '''Return a Block namedtuple given a raw block and its height.''' header = cls.block_header(raw_block, height) txs = cls.DESERIALIZER(raw_block, start=len(header)).read_tx_block() return Block(raw_block, header, txs) @classmethod def decimal_value(cls, value): '''Return the number of standard coin units as a Decimal given a quantity of smallest units. For example 1 BTC is returned for 100 million satoshis. ''' return Decimal(value) / cls.VALUE_PER_COIN @classmethod def electrum_header(cls, header, height): h = dict(zip(cls.HEADER_VALUES, cls.HEADER_UNPACK(header))) # Add the height that is not present in the header itself h['block_height'] = height # Convert bytes to str h['prev_block_hash'] = hash_to_hex_str(h['prev_block_hash']) h['merkle_root'] = hash_to_hex_str(h['merkle_root']) return h class AuxPowMixin(object): STATIC_BLOCK_HEADERS = False DESERIALIZER = lib_tx.DeserializerAuxPow @classmethod def header_hash(cls, header): '''Given a header return hash''' return double_sha256(header[:cls.BASIC_HEADER_SIZE]) @classmethod def block_header(cls, block, height): '''Return the AuxPow block header bytes''' deserializer = cls.DESERIALIZER(block) return deserializer.read_header(height, cls.BASIC_HEADER_SIZE) class EquihashMixin(object): STATIC_BLOCK_HEADERS = False BASIC_HEADER_SIZE = 140 # Excluding Equihash solution DESERIALIZER = lib_tx.DeserializerEquihash HEADER_VALUES = ['version', 'prev_block_hash', 'merkle_root', 'reserved', 'timestamp', 'bits', 'nonce'] HEADER_UNPACK = struct.Struct('< I 32s 32s 32s I I 32s').unpack_from @classmethod def electrum_header(cls, header, height): h = dict(zip(cls.HEADER_VALUES, cls.HEADER_UNPACK(header))) # Add the height that is not present in the header itself h['block_height'] = height # Convert bytes to str h['prev_block_hash'] = hash_to_hex_str(h['prev_block_hash']) h['merkle_root'] = hash_to_hex_str(h['merkle_root']) h['reserved'] = hash_to_hex_str(h['reserved']) h['nonce'] = hash_to_hex_str(h['nonce']) return h @classmethod def block_header(cls, block, height): '''Return the block header bytes''' deserializer = cls.DESERIALIZER(block) return deserializer.read_header(height, cls.BASIC_HEADER_SIZE) class ScryptMixin(object): DESERIALIZER = lib_tx.DeserializerTxTime HEADER_HASH = None @classmethod def header_hash(cls, header): '''Given a header return the hash.''' if cls.HEADER_HASH is None: import scrypt cls.HEADER_HASH = lambda x: scrypt.hash(x, x, 1024, 1, 1, 32) version, = util.unpack_le_uint32_from(header) if version > 6: return super().header_hash(header) else: return cls.HEADER_HASH(header) class KomodoMixin(object): P2PKH_VERBYTE = bytes.fromhex("3C") P2SH_VERBYTES = [bytes.fromhex("55")] WIF_BYTE = bytes.fromhex("BC") GENESIS_HASH = ('027e3758c3a65b12aa1046462b486d0a' '63bfa1beae327897f56c5cfb7daaae71') DESERIALIZER = lib_tx.DeserializerZcash class BitcoinMixin(object): SHORTNAME = "BTC" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") P2PKH_VERBYTE = bytes.fromhex("00") P2SH_VERBYTES = [bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('000000000019d6689c085ae165831e93' '4ff763ae46a2a6c172b3f1b60a8ce26f') RPC_PORT = 8332 class HOdlcoin(Coin): NAME = "HOdlcoin" SHORTNAME = "HODLC" NET = "mainnet" BASIC_HEADER_SIZE = 88 P2PKH_VERBYTE = bytes.fromhex("28") P2SH_VERBYTES = [bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("a8") GENESIS_HASH = ('008872e5582924544e5c707ee4b839bb' '82c28a9e94e917c94b40538d5658c04b') DESERIALIZER = lib_tx.DeserializerSegWit TX_COUNT = 258858 TX_COUNT_HEIGHT = 382138 TX_PER_BLOCK = 5 class BitcoinCash(BitcoinMixin, Coin): NAME = "BitcoinCash" SHORTNAME = "BCH" TX_COUNT = 246362688 TX_COUNT_HEIGHT = 511484 TX_PER_BLOCK = 400 PEERS = [ 'electroncash.cascharia.com s50002', 'bch.electrumx.cash s t', 'bccarihace4jdcnt.onion t52001 s52002', 'abc1.hsmiths.com t60001 s60002', 'electroncash.checksum0.com s t', 'electrumx-cash.1209k.com s t', 'electrum.leblancnet.us t50011 s50012', 'electroncash.dk s t', 'electrum.imaginary.cash s t', ] class BitcoinSegwit(BitcoinMixin, Coin): NAME = "BitcoinSegwit" DESERIALIZER = lib_tx.DeserializerSegWit MEMPOOL_HISTOGRAM_REFRESH_SECS = 120 TX_COUNT = 318337769 TX_COUNT_HEIGHT = 524213 TX_PER_BLOCK = 1400 PEERS = [ 'btc.smsys.me s995', 'E-X.not.fyi s t', 'elec.luggs.co s443', 'electrum.vom-stausee.de s t', 'electrum3.hachre.de s t', 'electrum.hsmiths.com s t', 'helicarrier.bauerj.eu s t', 'hsmiths4fyqlw5xw.onion s t', 'luggscoqbymhvnkp.onion t80', 'ozahtqwp25chjdjd.onion s t', 'node.arihanc.com s t', 'arihancckjge66iv.onion s t', ] class BitcoinGold(EquihashMixin, BitcoinMixin, Coin): CHUNK_SIZE = 252 NAME = "BitcoinGold" SHORTNAME = "BTG" FORK_HEIGHT = 491407 P2PKH_VERBYTE = bytes.fromhex("26") P2SH_VERBYTES = [bytes.fromhex("17")] DESERIALIZER = lib_tx.DeserializerEquihashSegWit TX_COUNT = 265026255 TX_COUNT_HEIGHT = 499923 TX_PER_BLOCK = 50 REORG_LIMIT = 1000 RPC_PORT = 8338 PEERS = [ 'electrumx-eu.bitcoingold.org s50002 t50001', 'electrumx-us.bitcoingold.org s50002 t50001', 'electrumx-eu.btcgpu.org s50002 t50001', 'electrumx-us.btcgpu.org s50002 t50001' ] @classmethod def header_hash(cls, header): '''Given a header return hash''' height, = util.unpack_le_uint32_from(header, 68) if height >= cls.FORK_HEIGHT: return double_sha256(header) else: return double_sha256(header[:68] + header[100:112]) @classmethod def electrum_header(cls, header, height): h = super().electrum_header(header, height) h['reserved'] = hash_to_hex_str(header[72:100]) h['solution'] = hash_to_hex_str(header[140:]) return h class BitcoinGoldTestnet(BitcoinGold): FORK_HEIGHT = 1 SHORTNAME = "TBTG" XPUB_VERBYTES = bytes.fromhex("043587CF") XPRV_VERBYTES = bytes.fromhex("04358394") P2PKH_VERBYTE = bytes.fromhex("6F") P2SH_VERBYTES = [bytes.fromhex("C4")] WIF_BYTE = bytes.fromhex("EF") TX_COUNT = 0 TX_COUNT_HEIGHT = 1 NET = 'testnet' RPC_PORT = 18338 GENESIS_HASH = ('00000000e0781ebe24b91eedc293adfe' 'a2f557b53ec379e78959de3853e6f9f6') PEERS = [ 'test-node1.bitcoingold.org s50002', 'test-node2.bitcoingold.org s50002', 'test-node3.bitcoingold.org s50002', 'test-node1.btcgpu.org s50002', 'test-node2.btcgpu.org s50002', 'test-node3.btcgpu.org s50002' ] class BitcoinGoldRegtest(BitcoinGold): FORK_HEIGHT = 2000 SHORTNAME = "TBTG" XPUB_VERBYTES = bytes.fromhex("043587CF") XPRV_VERBYTES = bytes.fromhex("04358394") P2PKH_VERBYTE = bytes.fromhex("6F") P2SH_VERBYTES = [bytes.fromhex("C4")] WIF_BYTE = bytes.fromhex("EF") TX_COUNT = 0 TX_COUNT_HEIGHT = 1 NET = 'regtest' RPC_PORT = 18444 GENESIS_HASH = ('0f9188f13cb7b2c71f2a335e3a4fc328' 'bf5beb436012afca590b1a11466e2206') PEERS: List[str] = [] class Emercoin(Coin): NAME = "Emercoin" SHORTNAME = "EMC" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") P2PKH_VERBYTE = bytes.fromhex("21") P2SH_VERBYTES = [bytes.fromhex("5c")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('00000000bcccd459d036a588d1008fce' '8da3754b205736f32ddfd35350e84c2d') TX_COUNT = 217380620 TX_COUNT_HEIGHT = 464000 TX_PER_BLOCK = 1700 VALUE_PER_COIN = 1000000 RPC_PORT = 6662 DESERIALIZER = lib_tx.DeserializerTxTimeAuxPow PEERS: List[str] = [] @classmethod def block_header(cls, block, height): '''Returns the block header given a block and its height.''' deserializer = cls.DESERIALIZER(block) if deserializer.is_merged_block(): return deserializer.read_header(height, cls.BASIC_HEADER_SIZE) return block[:cls.static_header_len(height)] @classmethod def header_hash(cls, header): '''Given a header return hash''' return double_sha256(header[:cls.BASIC_HEADER_SIZE]) class BitcoinTestnetMixin(object): SHORTNAME = "XTN" NET = "testnet" XPUB_VERBYTES = bytes.fromhex("043587cf") XPRV_VERBYTES = bytes.fromhex("04358394") P2PKH_VERBYTE = bytes.fromhex("6f") P2SH_VERBYTES = [bytes.fromhex("c4")] WIF_BYTE = bytes.fromhex("ef") GENESIS_HASH = ('000000000933ea01ad0ee984209779ba' 'aec3ced90fa3f408719526f8d77f4943') REORG_LIMIT = 8000 TX_COUNT = 12242438 TX_COUNT_HEIGHT = 1035428 TX_PER_BLOCK = 21 RPC_PORT = 18332 PEER_DEFAULT_PORTS = {'t': '51001', 's': '51002'} class BitcoinCashTestnet(BitcoinTestnetMixin, Coin): '''Bitcoin Testnet for Bitcoin Cash daemons.''' NAME = "BitcoinCash" PEERS = [ 'electrum-testnet-abc.criptolayer.net s50112', 'bchtestnet.arihanc.com t53001 s53002', 'ciiattqkgzebpp6jofjbrkhvhwmgnsfoayljdcrve2p3qmkbv3duaoyd.onion ' 't53001 s53002', ] class BitcoinCashRegtest(BitcoinCashTestnet): NET = "regtest" GENESIS_HASH = ('0f9188f13cb7b2c71f2a335e3a4fc328' 'bf5beb436012afca590b1a11466e2206') PEERS: List[str] = [] TX_COUNT = 1 TX_COUNT_HEIGHT = 1 class BitcoinSegwitTestnet(BitcoinTestnetMixin, Coin): '''Bitcoin Testnet for Core bitcoind >= 0.13.1.''' NAME = "BitcoinSegwit" DESERIALIZER = lib_tx.DeserializerSegWit PEERS = [ 'electrum.akinbo.org s t', 'he36kyperp3kbuxu.onion s t', 'testnet.hsmiths.com t53011 s53012', 'hsmithsxurybd7uh.onion t53011 s53012', 'testnetnode.arihanc.com s t', 'w3e2orjpiiv2qwem3dw66d7c4krink4nhttngkylglpqe5r22n6n5wid.onion s t', 'testnet.qtornado.com s t', ] class BitcoinSegwitRegtest(BitcoinSegwitTestnet): NAME = "BitcoinSegwit" NET = "regtest" GENESIS_HASH = ('0f9188f13cb7b2c71f2a335e3a4fc328' 'bf5beb436012afca590b1a11466e2206') PEERS: List[str] = [] TX_COUNT = 1 TX_COUNT_HEIGHT = 1 class BitcoinNolnet(BitcoinCash): '''Bitcoin Unlimited nolimit testnet.''' NET = "nolnet" GENESIS_HASH = ('0000000057e31bd2066c939a63b7b862' '3bd0f10d8c001304bdfc1a7902ae6d35') PEERS: List[str] = [] REORG_LIMIT = 8000 TX_COUNT = 583589 TX_COUNT_HEIGHT = 8617 TX_PER_BLOCK = 50 RPC_PORT = 28332 PEER_DEFAULT_PORTS = {'t': '52001', 's': '52002'} class Litecoin(Coin): NAME = "Litecoin" SHORTNAME = "LTC" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") P2PKH_VERBYTE = bytes.fromhex("30") P2SH_VERBYTES = [bytes.fromhex("32"), bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("b0") GENESIS_HASH = ('12a765e31ffd4059bada1e25190f6e98' 'c99d9714d334efa41a195a7e7e04bfe2') DESERIALIZER = lib_tx.DeserializerSegWit TX_COUNT = 8908766 TX_COUNT_HEIGHT = 1105256 TX_PER_BLOCK = 10 RPC_PORT = 9332 REORG_LIMIT = 800 PEERS = [ 'elec.luggs.co s444', 'electrum-ltc.bysh.me s t', 'electrum-ltc.ddns.net s t', 'electrum-ltc.wilv.in s t', 'electrum.cryptomachine.com p1000 s t', 'electrum.ltc.xurious.com s t', 'eywr5eubdbbe2laq.onion s50008 t50007', ] class LitecoinTestnet(Litecoin): SHORTNAME = "XLT" NET = "testnet" XPUB_VERBYTES = bytes.fromhex("043587cf") XPRV_VERBYTES = bytes.fromhex("04358394") P2PKH_VERBYTE = bytes.fromhex("6f") P2SH_VERBYTES = [bytes.fromhex("3a"), bytes.fromhex("c4")] WIF_BYTE = bytes.fromhex("ef") GENESIS_HASH = ('4966625a4b2851d9fdee139e56211a0d' '88575f59ed816ff5e6a63deb4e3e29a0') TX_COUNT = 21772 TX_COUNT_HEIGHT = 20800 TX_PER_BLOCK = 2 RPC_PORT = 19332 REORG_LIMIT = 4000 PEER_DEFAULT_PORTS = {'t': '51001', 's': '51002'} PEERS = [ 'electrum-ltc.bysh.me s t', 'electrum.ltc.xurious.com s t', ] class Viacoin(AuxPowMixin, Coin): NAME = "Viacoin" SHORTNAME = "VIA" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("47") P2SH_VERBYTES = [bytes.fromhex("21")] WIF_BYTE = bytes.fromhex("c7") GENESIS_HASH = ('4e9b54001f9976049830128ec0331515' 'eaabe35a70970d79971da1539a400ba1') TX_COUNT = 113638 TX_COUNT_HEIGHT = 3473674 TX_PER_BLOCK = 30 RPC_PORT = 5222 REORG_LIMIT = 5000 DESERIALIZER: Type = lib_tx.DeserializerAuxPowSegWit PEERS = [ 'vialectrum.bitops.me s t', 'server.vialectrum.org s t', 'vialectrum.viacoin.net s t', 'viax1.bitops.me s t', ] class ViacoinTestnet(Viacoin): SHORTNAME = "TVI" NET = "testnet" P2PKH_VERBYTE = bytes.fromhex("7f") P2SH_VERBYTES = [bytes.fromhex("c4")] WIF_BYTE = bytes.fromhex("ff") GENESIS_HASH = ('00000007199508e34a9ff81e6ec0c477' 'a4cccff2a4767a8eee39c11db367b008') RPC_PORT = 25222 REORG_LIMIT = 2500 PEER_DEFAULT_PORTS = {'t': '51001', 's': '51002'} PEERS = [ 'vialectrum.bysh.me s t', ] class ViacoinTestnetSegWit(ViacoinTestnet): NET = "testnet-segwit" DESERIALIZER = lib_tx.DeserializerSegWit # Source: namecoin.org class Namecoin(AuxPowMixin, Coin): NAME = "Namecoin" SHORTNAME = "NMC" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("d7dd6370") XPRV_VERBYTES = bytes.fromhex("d7dc6e31") P2PKH_VERBYTE = bytes.fromhex("34") P2SH_VERBYTES = [bytes.fromhex("0d")] WIF_BYTE = bytes.fromhex("e4") GENESIS_HASH = ('000000000062b72c5e2ceb45fbc8587e' '807c155b0da735e6483dfba2f0a9c770') TX_COUNT = 4415768 TX_COUNT_HEIGHT = 329065 TX_PER_BLOCK = 10 PEERS = [ 'elec.luggs.co s446', ] BLOCK_PROCESSOR = block_proc.NamecoinBlockProcessor @classmethod def split_name_script(cls, script): from torba.server.script import _match_ops, Script, ScriptError try: ops = Script.get_ops(script) except ScriptError: return None, script match = _match_ops # Name opcodes OP_NAME_NEW = OpCodes.OP_1 OP_NAME_FIRSTUPDATE = OpCodes.OP_2 OP_NAME_UPDATE = OpCodes.OP_3 # Opcode sequences for name operations NAME_NEW_OPS = [OP_NAME_NEW, -1, OpCodes.OP_2DROP] NAME_FIRSTUPDATE_OPS = [OP_NAME_FIRSTUPDATE, -1, -1, -1, OpCodes.OP_2DROP, OpCodes.OP_2DROP] NAME_UPDATE_OPS = [OP_NAME_UPDATE, -1, -1, OpCodes.OP_2DROP, OpCodes.OP_DROP] name_script_op_count = None name_pushdata = None # Detect name operations; determine count of opcodes. # Also extract the name field -- we might use that for something in a # future version. if match(ops[:len(NAME_NEW_OPS)], NAME_NEW_OPS): name_script_op_count = len(NAME_NEW_OPS) elif match(ops[:len(NAME_FIRSTUPDATE_OPS)], NAME_FIRSTUPDATE_OPS): name_script_op_count = len(NAME_FIRSTUPDATE_OPS) name_pushdata = ops[1] elif match(ops[:len(NAME_UPDATE_OPS)], NAME_UPDATE_OPS): name_script_op_count = len(NAME_UPDATE_OPS) name_pushdata = ops[1] if name_script_op_count is None: return None, script # Find the end position of the name data n = 0 for i in range(name_script_op_count): # Content of this loop is copied from Script.get_ops's loop op = script[n] n += 1 if op <= OpCodes.OP_PUSHDATA4: # Raw bytes follow if op < OpCodes.OP_PUSHDATA1: dlen = op elif op == OpCodes.OP_PUSHDATA1: dlen = script[n] n += 1 elif op == OpCodes.OP_PUSHDATA2: dlen, = struct.unpack(' len(script): raise IndexError op = (op, script[n:n + dlen]) n += dlen # Strip the name data to yield the address script address_script = script[n:] if name_pushdata is None: return None, address_script normalized_name_op_script = bytearray() normalized_name_op_script.append(OP_NAME_UPDATE) normalized_name_op_script.extend(Script.push_data(name_pushdata[1])) normalized_name_op_script.extend(Script.push_data(bytes([]))) normalized_name_op_script.append(OpCodes.OP_2DROP) normalized_name_op_script.append(OpCodes.OP_DROP) normalized_name_op_script.append(OpCodes.OP_RETURN) return bytes(normalized_name_op_script), address_script @classmethod def hashX_from_script(cls, script): name_op_script, address_script = cls.split_name_script(script) return super().hashX_from_script(address_script) @classmethod def address_from_script(cls, script): name_op_script, address_script = cls.split_name_script(script) return super().address_from_script(address_script) @classmethod def name_hashX_from_script(cls, script): name_op_script, address_script = cls.split_name_script(script) if name_op_script is None: return None return super().hashX_from_script(name_op_script) class NamecoinTestnet(Namecoin): NAME = "Namecoin" SHORTNAME = "XNM" NET = "testnet" P2PKH_VERBYTE = bytes.fromhex("6f") P2SH_VERBYTES = [bytes.fromhex("c4")] WIF_BYTE = bytes.fromhex("ef") GENESIS_HASH = ('00000007199508e34a9ff81e6ec0c477' 'a4cccff2a4767a8eee39c11db367b008') class Dogecoin(AuxPowMixin, Coin): NAME = "Dogecoin" SHORTNAME = "DOGE" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("02facafd") XPRV_VERBYTES = bytes.fromhex("02fac398") P2PKH_VERBYTE = bytes.fromhex("1e") P2SH_VERBYTES = [bytes.fromhex("16")] WIF_BYTE = bytes.fromhex("9e") GENESIS_HASH = ('1a91e3dace36e2be3bf030a65679fe82' '1aa1d6ef92e7c9902eb318182c355691') TX_COUNT = 27583427 TX_COUNT_HEIGHT = 1604979 TX_PER_BLOCK = 20 REORG_LIMIT = 2000 class DogecoinTestnet(Dogecoin): NAME = "Dogecoin" SHORTNAME = "XDT" NET = "testnet" P2PKH_VERBYTE = bytes.fromhex("71") P2SH_VERBYTES = [bytes.fromhex("c4")] WIF_BYTE = bytes.fromhex("f1") GENESIS_HASH = ('bb0a78264637406b6360aad926284d54' '4d7049f45189db5664f3c4d07350559e') # Source: https://github.com/motioncrypto/motion class Motion(Coin): NAME = "Motion" SHORTNAME = "XMN" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488B21E") XPRV_VERBYTES = bytes.fromhex("0488ADE4") GENESIS_HASH = ('000001e9dc60dd2618e91f7b90141349' '22c374496b61c1a272519b1c39979d78') P2PKH_VERBYTE = bytes.fromhex("32") P2SH_VERBYTES = [bytes.fromhex("12")] WIF_BYTE = bytes.fromhex("80") TX_COUNT_HEIGHT = 54353 TX_COUNT = 92701 TX_PER_BLOCK = 4 RPC_PORT = 3385 SESSIONCLS = DashElectrumX DAEMON = daemon.DashDaemon @classmethod def header_hash(cls, header): '''Given a header return the hash.''' import x16r_hash return x16r_hash.getPoWHash(header) # Source: https://github.com/dashpay/dash class Dash(Coin): NAME = "Dash" SHORTNAME = "DASH" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("02fe52cc") XPRV_VERBYTES = bytes.fromhex("02fe52f8") GENESIS_HASH = ('00000ffd590b1485b3caadc19b22e637' '9c733355108f107a430458cdf3407ab6') P2PKH_VERBYTE = bytes.fromhex("4c") P2SH_VERBYTES = [bytes.fromhex("10")] WIF_BYTE = bytes.fromhex("cc") TX_COUNT_HEIGHT = 569399 TX_COUNT = 2157510 TX_PER_BLOCK = 4 RPC_PORT = 9998 PEERS = [ 'electrum.dash.org s t', 'electrum.masternode.io s t', 'electrum-drk.club s t', 'dashcrypto.space s t', 'electrum.dash.siampm.com s t', 'wl4sfwq2hwxnodof.onion s t', ] SESSIONCLS = DashElectrumX DAEMON = daemon.DashDaemon @classmethod def header_hash(cls, header): '''Given a header return the hash.''' import x11_hash return x11_hash.getPoWHash(header) class DashTestnet(Dash): SHORTNAME = "tDASH" NET = "testnet" XPUB_VERBYTES = bytes.fromhex("3a805837") XPRV_VERBYTES = bytes.fromhex("3a8061a0") GENESIS_HASH = ('00000bafbc94add76cb75e2ec9289483' '7288a481e5c005f6563d91623bf8bc2c') P2PKH_VERBYTE = bytes.fromhex("8c") P2SH_VERBYTES = [bytes.fromhex("13")] WIF_BYTE = bytes.fromhex("ef") TX_COUNT_HEIGHT = 101619 TX_COUNT = 132681 TX_PER_BLOCK = 1 RPC_PORT = 19998 PEER_DEFAULT_PORTS = {'t': '51001', 's': '51002'} PEERS = [ 'electrum.dash.siampm.com s t', 'dasht.random.re s54002 t54001', ] class Argentum(AuxPowMixin, Coin): NAME = "Argentum" SHORTNAME = "ARG" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("17") P2SH_VERBYTES = [bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("97") GENESIS_HASH = ('88c667bc63167685e4e4da058fffdfe8' 'e007e5abffd6855de52ad59df7bb0bb2') TX_COUNT = 2263089 TX_COUNT_HEIGHT = 2050260 TX_PER_BLOCK = 2000 RPC_PORT = 13581 class ArgentumTestnet(Argentum): SHORTNAME = "XRG" NET = "testnet" P2PKH_VERBYTE = bytes.fromhex("6f") P2SH_VERBYTES = [bytes.fromhex("c4")] WIF_BYTE = bytes.fromhex("ef") REORG_LIMIT = 2000 class DigiByte(Coin): NAME = "DigiByte" SHORTNAME = "DGB" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("1E") P2SH_VERBYTES = [bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('7497ea1b465eb39f1c8f507bc877078f' 'e016d6fcb6dfad3a64c98dcc6e1e8496') DESERIALIZER = lib_tx.DeserializerSegWit TX_COUNT = 1046018 TX_COUNT_HEIGHT = 1435000 TX_PER_BLOCK = 1000 RPC_PORT = 12022 class DigiByteTestnet(DigiByte): NET = "testnet" P2PKH_VERBYTE = bytes.fromhex("6f") P2SH_VERBYTES = [bytes.fromhex("c4")] WIF_BYTE = bytes.fromhex("ef") GENESIS_HASH = ('b5dca8039e300198e5fe7cd23bdd1728' 'e2a444af34c447dbd0916fa3430a68c2') RPC_PORT = 15022 REORG_LIMIT = 2000 class FairCoin(Coin): NAME = "FairCoin" SHORTNAME = "FAIR" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("5f") P2SH_VERBYTES = [bytes.fromhex("24")] WIF_BYTE = bytes.fromhex("df") GENESIS_HASH = ('beed44fa5e96150d95d56ebd5d262578' '1825a9407a5215dd7eda723373a0a1d7') BASIC_HEADER_SIZE = 108 HEADER_VALUES = ['version', 'prev_block_hash', 'merkle_root', 'payload_hash', 'timestamp', 'creatorId'] HEADER_UNPACK = struct.Struct('< I 32s 32s 32s I I').unpack_from TX_COUNT = 505 TX_COUNT_HEIGHT = 470 TX_PER_BLOCK = 1 RPC_PORT = 40405 PEER_DEFAULT_PORTS = {'t': '51811', 's': '51812'} PEERS = [ 'electrum.faircoin.world s', 'electrumfair.punto0.org s', ] @classmethod def block(cls, raw_block, height): '''Return a Block namedtuple given a raw block and its height.''' if height > 0: return super().block(raw_block, height) else: return Block(raw_block, cls.block_header(raw_block, height), []) @classmethod def electrum_header(cls, header, height): h = super().electrum_header(header, height) h['payload_hash'] = hash_to_hex_str(h['payload_hash']) return h class Zcash(EquihashMixin, Coin): NAME = "Zcash" SHORTNAME = "ZEC" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("1CB8") P2SH_VERBYTES = [bytes.fromhex("1CBD")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('00040fe8ec8471911baa1db1266ea15d' 'd06b4a8a5c453883c000b031973dce08') DESERIALIZER = lib_tx.DeserializerZcash TX_COUNT = 329196 TX_COUNT_HEIGHT = 68379 TX_PER_BLOCK = 5 RPC_PORT = 8232 REORG_LIMIT = 800 class ZcashTestnet(Zcash): SHORTNAME = "TAZ" NET = "testnet" P2PKH_VERBYTE = bytes.fromhex("1D25") P2SH_VERBYTES = [bytes.fromhex("1CBA")] WIF_BYTE = bytes.fromhex("EF") GENESIS_HASH = ('05a60a92d99d85997cce3b87616c089f' '6124d7342af37106edc76126334a2c38') TX_COUNT = 242312 TX_COUNT_HEIGHT = 321685 TX_PER_BLOCK = 2 RPC_PORT = 18232 class SnowGem(EquihashMixin, Coin): NAME = "SnowGem" SHORTNAME = "SNG" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("1C28") P2SH_VERBYTES = [bytes.fromhex("1C2D")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('00068b35729d9d2b0c294ff1fe9af009' '4740524311a131de40e7f705e4c29a5b') DESERIALIZER = lib_tx.DeserializerZcash TX_COUNT = 140698 TX_COUNT_HEIGHT = 102802 TX_PER_BLOCK = 2 RPC_PORT = 16112 REORG_LIMIT = 800 CHUNK_SIZE = 200 @classmethod def electrum_header(cls, header, height): h = super().electrum_header(header, height) h['n_solution'] = base64.b64encode(lib_tx.Deserializer( header, start=140)._read_varbytes()).decode('utf8') return h class BitcoinZ(EquihashMixin, Coin): NAME = "BitcoinZ" SHORTNAME = "BTCZ" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("1CB8") P2SH_VERBYTES = [bytes.fromhex("1CBD")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('f499ee3d498b4298ac6a64205b8addb7' 'c43197e2a660229be65db8a4534d75c1') DESERIALIZER = lib_tx.DeserializerZcash TX_COUNT = 171976 TX_COUNT_HEIGHT = 81323 TX_PER_BLOCK = 3 RPC_PORT = 1979 REORG_LIMIT = 800 class Hush(EquihashMixin, Coin): NAME = "Hush" SHORTNAME = "HUSH" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("1CB8") P2SH_VERBYTES = [bytes.fromhex("1CBD")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('0003a67bc26fe564b75daf11186d3606' '52eb435a35ba3d9d3e7e5d5f8e62dc17') DESERIALIZER = lib_tx.DeserializerZcash TX_COUNT = 329196 TX_COUNT_HEIGHT = 68379 TX_PER_BLOCK = 5 RPC_PORT = 8822 REORG_LIMIT = 800 class Zclassic(EquihashMixin, Coin): NAME = "Zclassic" SHORTNAME = "ZCL" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("1CB8") P2SH_VERBYTES = [bytes.fromhex("1CBD")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('0007104ccda289427919efc39dc9e4d4' '99804b7bebc22df55f8b834301260602') DESERIALIZER = lib_tx.DeserializerZcash TX_COUNT = 329196 TX_COUNT_HEIGHT = 68379 TX_PER_BLOCK = 5 RPC_PORT = 8023 REORG_LIMIT = 800 class Koto(Coin): NAME = "Koto" SHORTNAME = "KOTO" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("1836") P2SH_VERBYTES = [bytes.fromhex("183B")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('6d424c350729ae633275d51dc3496e16' 'cd1b1d195c164da00f39c499a2e9959e') DESERIALIZER = lib_tx.DeserializerZcash TX_COUNT = 158914 TX_COUNT_HEIGHT = 67574 TX_PER_BLOCK = 3 RPC_PORT = 8432 REORG_LIMIT = 800 PEERS = [ 'fr.kotocoin.info s t', 'electrum.kotocoin.info s t', ] class KotoTestnet(Koto): SHORTNAME = "TOKO" NET = "testnet" P2PKH_VERBYTE = bytes.fromhex("18A4") P2SH_VERBYTES = [bytes.fromhex("1839")] WIF_BYTE = bytes.fromhex("EF") GENESIS_HASH = ('bf84afbde20c2d213b68b231ddb585ab' '616ef7567226820f00d9b397d774d2f0') TX_COUNT = 91144 TX_COUNT_HEIGHT = 89662 TX_PER_BLOCK = 1 RPC_PORT = 18432 PEER_DEFAULT_PORTS = {'t': '51001', 's': '51002'} PEERS = [ 'testnet.kotocoin.info s t', ] class Komodo(KomodoMixin, EquihashMixin, Coin): NAME = "Komodo" SHORTNAME = "KMD" NET = "mainnet" TX_COUNT = 693629 TX_COUNT_HEIGHT = 491777 TX_PER_BLOCK = 2 RPC_PORT = 7771 REORG_LIMIT = 800 PEERS: List[str] = [] class Monaize(KomodoMixin, EquihashMixin, Coin): NAME = "Monaize" SHORTNAME = "MNZ" NET = "mainnet" TX_COUNT = 256 TX_COUNT_HEIGHT = 128 TX_PER_BLOCK = 2 RPC_PORT = 14337 REORG_LIMIT = 800 PEERS: List[str] = [] class Einsteinium(Coin): NAME = "Einsteinium" SHORTNAME = "EMC2" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("21") P2SH_VERBYTES = [bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("b0") GENESIS_HASH = ('4e56204bb7b8ac06f860ff1c845f03f9' '84303b5b97eb7b42868f714611aed94b') DESERIALIZER = lib_tx.DeserializerSegWit TX_COUNT = 2087559 TX_COUNT_HEIGHT = 1358517 TX_PER_BLOCK = 2 RPC_PORT = 41879 REORG_LIMIT = 2000 class Blackcoin(ScryptMixin, Coin): NAME = "Blackcoin" SHORTNAME = "BLK" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("19") P2SH_VERBYTES = [bytes.fromhex("55")] WIF_BYTE = bytes.fromhex("99") GENESIS_HASH = ('000001faef25dec4fbcf906e6242621d' 'f2c183bf232f263d0ba5b101911e4563') DAEMON = daemon.LegacyRPCDaemon TX_COUNT = 4594999 TX_COUNT_HEIGHT = 1667070 TX_PER_BLOCK = 3 RPC_PORT = 15715 REORG_LIMIT = 5000 class Bitbay(ScryptMixin, Coin): NAME = "Bitbay" SHORTNAME = "BAY" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("19") P2SH_VERBYTES = [bytes.fromhex("55")] WIF_BYTE = bytes.fromhex("99") GENESIS_HASH = ('0000075685d3be1f253ce777174b1594' '354e79954d2a32a6f77fe9cba00e6467') TX_COUNT = 4594999 TX_COUNT_HEIGHT = 1667070 TX_PER_BLOCK = 3 RPC_PORT = 19914 REORG_LIMIT = 5000 class Peercoin(Coin): NAME = "Peercoin" SHORTNAME = "PPC" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("37") P2SH_VERBYTES = [bytes.fromhex("75")] WIF_BYTE = bytes.fromhex("b7") GENESIS_HASH = ('0000000032fe677166d54963b62a4677' 'd8957e87c508eaa4fd7eb1c880cd27e3') DESERIALIZER = lib_tx.DeserializerTxTime DAEMON = daemon.LegacyRPCDaemon TX_COUNT = 1207356 TX_COUNT_HEIGHT = 306425 TX_PER_BLOCK = 4 RPC_PORT = 9902 REORG_LIMIT = 5000 class Reddcoin(Coin): NAME = "Reddcoin" SHORTNAME = "RDD" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("3d") P2SH_VERBYTES = [bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("bd") GENESIS_HASH = ('b868e0d95a3c3c0e0dadc67ee587aaf9' 'dc8acbf99e3b4b3110fad4eb74c1decc') DESERIALIZER = lib_tx.DeserializerReddcoin TX_COUNT = 5413508 TX_COUNT_HEIGHT = 1717382 TX_PER_BLOCK = 3 RPC_PORT = 45443 class TokenPay(ScryptMixin, Coin): NAME = "TokenPay" SHORTNAME = "TPAY" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("41") P2SH_VERBYTES = [bytes.fromhex("7e")] WIF_BYTE = bytes.fromhex("b3") GENESIS_HASH = ('000008b71ab32e585a23f0de642dc113' '740144e94c0ece047751e9781f953ae9') DESERIALIZER = lib_tx.DeserializerTokenPay DAEMON = daemon.LegacyRPCDaemon TX_COUNT = 147934 TX_COUNT_HEIGHT = 73967 TX_PER_BLOCK = 100 RPC_PORT = 8800 REORG_LIMIT = 500 XPUB_VERBYTES = bytes.fromhex("0488B21E") XPRV_VERBYTES = bytes.fromhex("0488ADE4") PEERS = [ "electrum-us.tpay.ai s", "electrum-eu.tpay.ai s", ] class Vertcoin(Coin): NAME = "Vertcoin" SHORTNAME = "VTC" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488B21E") XPRV_VERBYTES = bytes.fromhex("0488ADE4") P2PKH_VERBYTE = bytes.fromhex("47") P2SH_VERBYTES = [bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('4d96a915f49d40b1e5c2844d1ee2dccb' '90013a990ccea12c492d22110489f0c4') DESERIALIZER = lib_tx.DeserializerSegWit TX_COUNT = 2383423 TX_COUNT_HEIGHT = 759076 TX_PER_BLOCK = 3 RPC_PORT = 5888 REORG_LIMIT = 1000 class Monacoin(Coin): NAME = "Monacoin" SHORTNAME = "MONA" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488B21E") XPRV_VERBYTES = bytes.fromhex("0488ADE4") P2PKH_VERBYTE = bytes.fromhex("32") P2SH_VERBYTES = [bytes.fromhex("37"), bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("B0") GENESIS_HASH = ('ff9f1c0116d19de7c9963845e129f9ed' '1bfc0b376eb54fd7afa42e0d418c8bb6') DESERIALIZER = lib_tx.DeserializerSegWit TX_COUNT = 2568580 TX_COUNT_HEIGHT = 1029766 TX_PER_BLOCK = 2 RPC_PORT = 9402 REORG_LIMIT = 1000 PEERS = [ 'electrumx.tamami-foundation.org s t', 'electrumx2.tamami-foundation.org s t', 'electrumx3.tamami-foundation.org s t', 'electrumx1.monacoin.nl s t', 'electrumx2.monacoin.nl s t', 'electrumx1.monacoin.ninja s t', 'electrumx2.monacoin.ninja s t', 'electrumx2.movsign.info s t', 'electrum-mona.bitbank.cc s t', 'ri7rzlmdaf4eqbza.onion s t', ] class MonacoinTestnet(Monacoin): SHORTNAME = "XMN" NET = "testnet" XPUB_VERBYTES = bytes.fromhex("043587CF") XPRV_VERBYTES = bytes.fromhex("04358394") P2PKH_VERBYTE = bytes.fromhex("6F") P2SH_VERBYTES = [bytes.fromhex("75"), bytes.fromhex("C4")] WIF_BYTE = bytes.fromhex("EF") GENESIS_HASH = ('a2b106ceba3be0c6d097b2a6a6aacf9d' '638ba8258ae478158f449c321061e0b2') TX_COUNT = 83602 TX_COUNT_HEIGHT = 83252 TX_PER_BLOCK = 1 RPC_PORT = 19402 REORG_LIMIT = 1000 PEER_DEFAULT_PORTS = {'t': '51001', 's': '51002'} PEERS = [ 'electrumx1.testnet.monacoin.ninja s t', 'electrumx1.testnet.monacoin.nl s t', ] class Crown(AuxPowMixin, Coin): NAME = "Crown" SHORTNAME = "CRW" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") P2PKH_VERBYTE = bytes.fromhex("00") P2SH_VERBYTES = [bytes.fromhex("1c")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('0000000085370d5e122f64f4ab19c686' '14ff3df78c8d13cb814fd7e69a1dc6da') TX_COUNT = 13336629 TX_COUNT_HEIGHT = 1268206 TX_PER_BLOCK = 10 RPC_PORT = 9341 REORG_LIMIT = 1000 PEERS = [ 'sgp-crwseed.crowndns.info s t', 'blr-crwseed.crowndns.info s t', 'sfo-crwseed.crowndns.info s t', 'nyc-crwseed.crowndns.info s t', 'ams-crwseed.crowndns.info s t', 'tor-crwseed.crowndns.info s t', 'lon-crwseed.crowndns.info s t', 'fra-crwseed.crowndns.info s t', ] class Fujicoin(Coin): NAME = "Fujicoin" SHORTNAME = "FJC" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") P2PKH_VERBYTE = bytes.fromhex("24") P2SH_VERBYTES = [bytes.fromhex("10")] WIF_BYTE = bytes.fromhex("a4") GENESIS_HASH = ('adb6d9cfd74075e7f91608add4bd2a2e' 'a636f70856183086842667a1597714a0') DESERIALIZER = lib_tx.DeserializerSegWit TX_COUNT = 170478 TX_COUNT_HEIGHT = 1521676 TX_PER_BLOCK = 1 RPC_PORT = 3776 REORG_LIMIT = 1000 class Neblio(ScryptMixin, Coin): NAME = "Neblio" SHORTNAME = "NEBL" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") P2PKH_VERBYTE = bytes.fromhex("35") P2SH_VERBYTES = [bytes.fromhex("70")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('7286972be4dbc1463d256049b7471c25' '2e6557e222cab9be73181d359cd28bcc') TX_COUNT = 23675 TX_COUNT_HEIGHT = 22785 TX_PER_BLOCK = 1 RPC_PORT = 6326 REORG_LIMIT = 1000 class Bitzeny(Coin): NAME = "Bitzeny" SHORTNAME = "ZNY" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") P2PKH_VERBYTE = bytes.fromhex("51") P2SH_VERBYTES = [bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('000009f7e55e9e3b4781e22bd87a7cfa' '4acada9e4340d43ca738bf4e9fb8f5ce') ESTIMATE_FEE = 0.001 RELAY_FEE = 0.001 DAEMON = daemon.FakeEstimateFeeDaemon TX_COUNT = 1408733 TX_COUNT_HEIGHT = 1015115 TX_PER_BLOCK = 1 RPC_PORT = 9252 REORG_LIMIT = 1000 @classmethod def header_hash(cls, header): '''Given a header return the hash.''' import zny_yescrypt return zny_yescrypt.getPoWHash(header) class CanadaeCoin(AuxPowMixin, Coin): NAME = "CanadaeCoin" SHORTNAME = "CDN" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") P2PKH_VERBYTE = bytes.fromhex("1C") P2SH_VERBYTES = [bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("9c") GENESIS_HASH = ('863626dadaef221e2e2f30ff3dacae44' 'cabdae9e0028058072181b3fb675d94a') ESTIMATE_FEE = 0.0001 RELAY_FEE = 0.0001 DAEMON = daemon.FakeEstimateFeeDaemon TX_COUNT = 3455905 TX_COUNT_HEIGHT = 3645419 TX_PER_BLOCK = 1 RPC_PORT = 34330 REORG_LIMIT = 1000 class Denarius(Coin): NAME = "Denarius" SHORTNAME = "DNR" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") P2PKH_VERBYTE = bytes.fromhex("1E") # Address starts with a D P2SH_VERBYTES = [bytes.fromhex("5A")] WIF_BYTE = bytes.fromhex("9E") # WIF starts with a 6 GENESIS_HASH = ('00000d5dbbda01621cfc16bbc1f9bf32' '64d641a5dbf0de89fd0182c2c4828fcd') DESERIALIZER = lib_tx.DeserializerTxTime TX_COUNT = 4230 RPC_PORT = 32339 ESTIMATE_FEE = 0.00001 RELAY_FEE = 0.00001 DAEMON = daemon.FakeEstimateFeeDaemon TX_COUNT_HEIGHT = 306187 TX_PER_BLOCK = 4000 @classmethod def header_hash(cls, header): '''Given a header return the hash.''' import tribus_hash return tribus_hash.getPoWHash(header) class DenariusTestnet(Denarius): NET = "testnet" XPUB_VERBYTES = bytes.fromhex("043587cf") XPRV_VERBYTES = bytes.fromhex("04358394") P2PKH_VERBYTE = bytes.fromhex("12") P2SH_VERBYTES = [bytes.fromhex("74")] WIF_BYTE = bytes.fromhex("ef") GENESIS_HASH = ('000086bfe8264d241f7f8e5393f74778' '4b8ca2aa98bdd066278d590462a4fdb4') RPC_PORT = 32338 REORG_LIMIT = 2000 class Sibcoin(Dash): NAME = "Sibcoin" SHORTNAME = "SIB" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") P2PKH_VERBYTE = bytes.fromhex("3F") P2SH_VERBYTES = [bytes.fromhex("28")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('00000c492bf73490420868bc577680bf' 'c4c60116e7e85343bc624787c21efa4c') DAEMON = daemon.DashDaemon TX_COUNT = 1000 TX_COUNT_HEIGHT = 10000 TX_PER_BLOCK = 1 RPC_PORT = 1944 REORG_LIMIT = 1000 PEERS: List[str] = [] @classmethod def header_hash(cls, header): ''' Given a header return the hash for sibcoin. Need to download `x11_gost_hash` module Source code: https://github.com/ivansib/x11_gost_hash ''' import x11_gost_hash return x11_gost_hash.getPoWHash(header) class Chips(Coin): NAME = "Chips" SHORTNAME = "CHIPS" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("3c") P2SH_VERBYTES = [bytes.fromhex("55")] WIF_BYTE = bytes.fromhex("bc") GENESIS_HASH = ('0000006e75f6aa0efdbf7db03132aa4e' '4d0c84951537a6f5a7c39a0a9d30e1e7') DESERIALIZER = lib_tx.DeserializerSegWit TX_COUNT = 145290 TX_COUNT_HEIGHT = 318637 TX_PER_BLOCK = 2 RPC_PORT = 57776 REORG_LIMIT = 800 class Feathercoin(Coin): NAME = "Feathercoin" SHORTNAME = "FTC" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488BC26") XPRV_VERBYTES = bytes.fromhex("0488DAEE") P2PKH_VERBYTE = bytes.fromhex("0E") P2SH_VERBYTES = [bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("8E") GENESIS_HASH = ('12a765e31ffd4059bada1e25190f6e98' 'c99d9714d334efa41a195a7e7e04bfe2') DESERIALIZER = lib_tx.DeserializerSegWit TX_COUNT = 3170843 TX_COUNT_HEIGHT = 1981777 TX_PER_BLOCK = 2 RPC_PORT = 9337 REORG_LIMIT = 2000 PEERS = [ 'electrumx-ch-1.feathercoin.ch s t', ] class UFO(Coin): NAME = "UniformFiscalObject" SHORTNAME = "UFO" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488B21E") XPRV_VERBYTES = bytes.fromhex("0488ADE4") P2PKH_VERBYTE = bytes.fromhex("1B") P2SH_VERBYTES = [bytes.fromhex("44")] WIF_BYTE = bytes.fromhex("9B") GENESIS_HASH = ('ba1d39b4928ab03d813d952daf65fb77' '97fcf538a9c1b8274f4edc8557722d13') DESERIALIZER = lib_tx.DeserializerSegWit TX_COUNT = 1608926 TX_COUNT_HEIGHT = 1300154 TX_PER_BLOCK = 2 RPC_PORT = 9888 REORG_LIMIT = 2000 PEERS = [ 'electrumx1.ufobject.com s t', ] class Newyorkcoin(AuxPowMixin, Coin): NAME = "Newyorkcoin" SHORTNAME = "NYC" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("3c") P2SH_VERBYTES = [bytes.fromhex("16")] WIF_BYTE = bytes.fromhex("bc") GENESIS_HASH = ('5597f25c062a3038c7fd815fe46c67de' 'dfcb3c839fbc8e01ed4044540d08fe48') TX_COUNT = 5161944 TX_COUNT_HEIGHT = 3948743 TX_PER_BLOCK = 2 REORG_LIMIT = 2000 class NewyorkcoinTestnet(Newyorkcoin): SHORTNAME = "tNYC" NET = "testnet" P2PKH_VERBYTE = bytes.fromhex("71") P2SH_VERBYTES = [bytes.fromhex("c4")] WIF_BYTE = bytes.fromhex("f1") GENESIS_HASH = ('24463e4d3c625b0a9059f309044c2cf0' 'd7e196cf2a6ecce901f24f681be33c8f') TX_COUNT = 5161944 TX_COUNT_HEIGHT = 3948743 TX_PER_BLOCK = 2 REORG_LIMIT = 2000 class Bitcore(BitcoinMixin, Coin): NAME = "Bitcore" SHORTNAME = "BTX" P2PKH_VERBYTE = bytes.fromhex("03") P2SH_VERBYTES = [bytes.fromhex("7D")] WIF_BYTE = bytes.fromhex("80") DESERIALIZER = lib_tx.DeserializerSegWit GENESIS_HASH = ('604148281e5c4b7f2487e5d03cd60d8e' '6f69411d613f6448034508cea52e9574') TX_COUNT = 126979 TX_COUNT_HEIGHT = 126946 TX_PER_BLOCK = 2 RPC_PORT = 8556 class GameCredits(Coin): NAME = "GameCredits" SHORTNAME = "GAME" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("26") P2SH_VERBYTES = [bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("a6") GENESIS_HASH = ('91ec5f25ee9a0ffa1af7d4da4db9a552' '228dd2dc77cdb15b738be4e1f55f30ee') DESERIALIZER = lib_tx.DeserializerSegWit TX_COUNT = 316796 TX_COUNT_HEIGHT = 2040250 TX_PER_BLOCK = 2 RPC_PORT = 40001 REORG_LIMIT = 1000 class Machinecoin(Coin): NAME = "Machinecoin" SHORTNAME = "MAC" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") P2PKH_VERBYTE = bytes.fromhex("32") P2SH_VERBYTES = [bytes.fromhex("26"), bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("b2") GENESIS_HASH = ('6a1f879bcea5471cbfdee1fd0cb2ddcc' '4fed569a500e352d41de967703e83172') DESERIALIZER = lib_tx.DeserializerSegWit TX_COUNT = 137641 TX_COUNT_HEIGHT = 513020 TX_PER_BLOCK = 2 RPC_PORT = 40332 REORG_LIMIT = 800 class BitcoinAtom(Coin): NAME = "BitcoinAtom" SHORTNAME = "BCA" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("17") P2SH_VERBYTES = [bytes.fromhex("0a")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('000000000019d6689c085ae165831e93' '4ff763ae46a2a6c172b3f1b60a8ce26f') STATIC_BLOCK_HEADERS = False DESERIALIZER = lib_tx.DeserializerBitcoinAtom HEADER_SIZE_POST_FORK = 84 BLOCK_PROOF_OF_STAKE = 0x01 BLOCK_PROOF_OF_STAKE_FLAGS = b'\x01\x00\x00\x00' TX_COUNT = 295158744 TX_COUNT_HEIGHT = 589197 TX_PER_BLOCK = 10 RPC_PORT = 9136 REORG_LIMIT = 5000 @classmethod def header_hash(cls, header): '''Given a header return hash''' header_to_be_hashed = header[:cls.BASIC_HEADER_SIZE] # New block header format has some extra flags in the end if len(header) == cls.HEADER_SIZE_POST_FORK: flags, = util.unpack_le_uint32_from(header, len(header) - 4) # Proof of work blocks have special serialization if flags & cls.BLOCK_PROOF_OF_STAKE != 0: header_to_be_hashed += cls.BLOCK_PROOF_OF_STAKE_FLAGS return double_sha256(header_to_be_hashed) @classmethod def block_header(cls, block, height): '''Return the block header bytes''' deserializer = cls.DESERIALIZER(block) return deserializer.read_header(height, cls.BASIC_HEADER_SIZE) class Decred(Coin): NAME = "Decred" SHORTNAME = "DCR" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("02fda926") XPRV_VERBYTES = bytes.fromhex("02fda4e8") P2PKH_VERBYTE = bytes.fromhex("073f") P2SH_VERBYTES = [bytes.fromhex("071a")] WIF_BYTE = bytes.fromhex("22de") GENESIS_HASH = ('298e5cc3d985bfe7f81dc135f360abe0' '89edd4396b86d2de66b0cef42b21d980') BASIC_HEADER_SIZE = 180 HEADER_HASH = lib_tx.DeserializerDecred.blake256 DESERIALIZER = lib_tx.DeserializerDecred DAEMON = daemon.DecredDaemon BLOCK_PROCESSOR = block_proc.DecredBlockProcessor ENCODE_CHECK = partial(Base58.encode_check, hash_fn=lib_tx.DeserializerDecred.blake256d) DECODE_CHECK = partial(Base58.decode_check, hash_fn=lib_tx.DeserializerDecred.blake256d) HEADER_VALUES = ['version', 'prev_block_hash', 'merkle_root', 'stake_root', 'vote_bits', 'final_state', 'voters', 'fresh_stake', 'revocations', 'pool_size', 'bits', 'sbits', 'block_height', 'size', 'timestamp', 'nonce', 'extra_data', 'stake_version'] HEADER_UNPACK = struct.Struct( '< i 32s 32s 32s H 6s H B B I I Q I I I I 32s I').unpack_from TX_COUNT = 4629388 TX_COUNT_HEIGHT = 260628 TX_PER_BLOCK = 17 REORG_LIMIT = 1000 RPC_PORT = 9109 @classmethod def header_hash(cls, header): '''Given a header return the hash.''' return cls.HEADER_HASH(header) @classmethod def block(cls, raw_block, height): '''Return a Block namedtuple given a raw block and its height.''' if height > 0: return super().block(raw_block, height) else: return Block(raw_block, cls.block_header(raw_block, height), []) @classmethod def electrum_header(cls, header, height): h = super().electrum_header(header, height) h['stake_root'] = hash_to_hex_str(h['stake_root']) h['final_state'] = hash_to_hex_str(h['final_state']) h['extra_data'] = hash_to_hex_str(h['extra_data']) return h class DecredTestnet(Decred): SHORTNAME = "tDCR" NET = "testnet" XPUB_VERBYTES = bytes.fromhex("043587d1") XPRV_VERBYTES = bytes.fromhex("04358397") P2PKH_VERBYTE = bytes.fromhex("0f21") P2SH_VERBYTES = [bytes.fromhex("0efc")] WIF_BYTE = bytes.fromhex("230e") GENESIS_HASH = ( 'a649dce53918caf422e9c711c858837e08d626ecfcd198969b24f7b634a49bac') BASIC_HEADER_SIZE = 180 ALLOW_ADVANCING_ERRORS = True TX_COUNT = 217380620 TX_COUNT_HEIGHT = 464000 TX_PER_BLOCK = 1800 REORG_LIMIT = 1000 RPC_PORT = 19109 class Axe(Dash): NAME = "Axe" SHORTNAME = "AXE" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("02fe52cc") XPRV_VERBYTES = bytes.fromhex("02fe52f8") P2PKH_VERBYTE = bytes.fromhex("37") P2SH_VERBYTES = [bytes.fromhex("10")] WIF_BYTE = bytes.fromhex("cc") GENESIS_HASH = ('00000c33631ca6f2f61368991ce2dc03' '306b5bb50bf7cede5cfbba6db38e52e6') DAEMON = daemon.DashDaemon TX_COUNT = 18405 TX_COUNT_HEIGHT = 30237 TX_PER_BLOCK = 1 RPC_PORT = 9337 REORG_LIMIT = 1000 PEERS: List[str] = [] @classmethod def header_hash(cls, header): ''' Given a header return the hash for AXE. Need to download `axe_hash` module Source code: https://github.com/AXErunners/axe_hash ''' import x11_hash return x11_hash.getPoWHash(header) class Xuez(Coin): NAME = "Xuez" SHORTNAME = "XUEZ" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("022d2533") XPRV_VERBYTES = bytes.fromhex("0221312b") P2PKH_VERBYTE = bytes.fromhex("48") P2SH_VERBYTES = [bytes.fromhex("12")] WIF_BYTE = bytes.fromhex("d4") GENESIS_HASH = ('000000e1febc39965b055e8e0117179a' '4d18e24e7aaa0c69864c4054b4f29445') TX_COUNT = 30000 TX_COUNT_HEIGHT = 15000 TX_PER_BLOCK = 1 RPC_PORT = 41799 REORG_LIMIT = 1000 BASIC_HEADER_SIZE = 112 PEERS: List[str] = [] @classmethod def header_hash(cls, header): ''' Given a header return the hash for Xuez. Need to download `xevan_hash` module Source code: https://github.com/xuez/xuez ''' version, = util.unpack_le_uint32_from(header) import xevan_hash if version == 1: return xevan_hash.getPoWHash(header[:80]) else: return xevan_hash.getPoWHash(header) @classmethod def electrum_header(cls, header, height): h = super().electrum_header(header, height) if h['version'] > 1: h['nAccumulatorCheckpoint'] = hash_to_hex_str(header[80:]) return h class Pac(Coin): NAME = "PAC" SHORTNAME = "PAC" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488B21E") XPRV_VERBYTES = bytes.fromhex("0488ADE4") GENESIS_HASH = ('00000354655ff039a51273fe61d3b493' 'bd2897fe6c16f732dbc4ae19f04b789e') P2PKH_VERBYTE = bytes.fromhex("37") P2SH_VERBYTES = [bytes.fromhex("0A")] WIF_BYTE = bytes.fromhex("CC") TX_COUNT_HEIGHT = 14939 TX_COUNT = 23708 TX_PER_BLOCK = 2 RPC_PORT = 7111 PEERS = [ 'electrum.paccoin.io s t', 'electro-pac.paccoin.io s t' ] SESSIONCLS = DashElectrumX DAEMON = daemon.DashDaemon ESTIMATE_FEE = 0.00001 RELAY_FEE = 0.00001 @classmethod def header_hash(cls, header): '''Given a header return the hash.''' import x11_hash return x11_hash.getPoWHash(header) class PacTestnet(Pac): SHORTNAME = "tPAC" NET = "testnet" XPUB_VERBYTES = bytes.fromhex("043587CF") XPRV_VERBYTES = bytes.fromhex("04358394") GENESIS_HASH = ('00000da63bd9478b655ef6bf1bf76cd9' 'af05202ab68643f9091e049b2b5280ed') P2PKH_VERBYTE = bytes.fromhex("78") P2SH_VERBYTES = [bytes.fromhex("0E")] WIF_BYTE = bytes.fromhex("EF") TX_COUNT_HEIGHT = 16275 TX_COUNT = 16275 TX_PER_BLOCK = 1 RPC_PORT = 17111 class Polis(Coin): NAME = "Polis" SHORTNAME = "POLIS" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("03E25D7E") XPRV_VERBYTES = bytes.fromhex("03E25945") GENESIS_HASH = ('000009701eb781a8113b1af1d814e2f0' '60f6408a2c990db291bc5108a1345c1e') P2PKH_VERBYTE = bytes.fromhex("37") P2SH_VERBYTES = [bytes.fromhex("38")] WIF_BYTE = bytes.fromhex("3c") TX_COUNT_HEIGHT = 111111 TX_COUNT = 256128 TX_PER_BLOCK = 4 RPC_PORT = 24127 PEERS = [ 'electrum1-polis.polispay.org', 'electrum2-polis.polispay.org' ] SESSIONCLS = DashElectrumX DAEMON = daemon.DashDaemon @classmethod def header_hash(cls, header): '''Given a header return the hash.''' import x11_hash return x11_hash.getPoWHash(header) class ColossusXT(Coin): NAME = "ColossusXT" SHORTNAME = "COLX" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("022D2533") XPRV_VERBYTES = bytes.fromhex("0221312B") GENESIS_HASH = ('a0ce8206c908357008c1b9a8ba2813af' 'f0989ca7f72d62b14e652c55f02b4f5c') P2PKH_VERBYTE = bytes.fromhex("1E") P2SH_VERBYTES = [bytes.fromhex("0D")] WIF_BYTE = bytes.fromhex("D4") TX_COUNT_HEIGHT = 356500 TX_COUNT = 761041 TX_PER_BLOCK = 4 RPC_PORT = 51473 PEERS = [ 'electrum1-colx.polispay.org', 'electrum2-colx.polispay.org' ] SESSIONCLS = DashElectrumX DAEMON = daemon.DashDaemon @classmethod def header_hash(cls, header): '''Given a header return the hash.''' import quark_hash return quark_hash.getPoWHash(header) class GoByte(Coin): NAME = "GoByte" SHORTNAME = "GBX" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488B21E") XPRV_VERBYTES = bytes.fromhex("0488ADE4") GENESIS_HASH = ('0000033b01055cf8df90b01a14734cae' '92f7039b9b0e48887b4e33a469d7bc07') P2PKH_VERBYTE = bytes.fromhex("26") P2SH_VERBYTES = [bytes.fromhex("0A")] WIF_BYTE = bytes.fromhex("C6") TX_COUNT_HEIGHT = 115890 TX_COUNT = 245030 TX_PER_BLOCK = 4 RPC_PORT = 12454 PEERS = [ 'electrum1-gbx.polispay.org', 'electrum2-gbx.polispay.org' ] SESSIONCLS = DashElectrumX DAEMON = daemon.DashDaemon @classmethod def header_hash(cls, header): '''Given a header return the hash.''' import neoscrypt return neoscrypt.getPoWHash(header) class Monoeci(Coin): NAME = "Monoeci" SHORTNAME = "XMCC" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488B21E") XPRV_VERBYTES = bytes.fromhex("0488ADE4") GENESIS_HASH = ('0000005be1eb05b05fb45ae38ee9c144' '1514a65343cd146100a574de4278f1a3') P2PKH_VERBYTE = bytes.fromhex("32") P2SH_VERBYTES = [bytes.fromhex("49")] WIF_BYTE = bytes.fromhex("4D") TX_COUNT_HEIGHT = 140000 TX_COUNT = 140000 TX_PER_BLOCK = 4 RPC_PORT = 24156 PEERS = [ 'electrum1-gbx.polispay.org', 'electrum2-gbx.polispay.org' ] SESSIONCLS = DashElectrumX DAEMON = daemon.DashDaemon @classmethod def header_hash(cls, header): '''Given a header return the hash.''' import x11_hash return x11_hash.getPoWHash(header) class Minexcoin(EquihashMixin, Coin): NAME = "Minexcoin" SHORTNAME = "MNX" NET = "mainnet" P2PKH_VERBYTE = bytes.fromhex("4b") P2SH_VERBYTES = [bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('490a36d9451a55ed197e34aca7414b35' 'd775baa4a8e896f1c577f65ce2d214cb') STATIC_BLOCK_HEADERS = True BASIC_HEADER_SIZE = 209 HEADER_SIZE_NO_SOLUTION = 140 TX_COUNT = 327963 TX_COUNT_HEIGHT = 74495 TX_PER_BLOCK = 5 RPC_PORT = 8022 CHUNK_SIZE = 960 PEERS = [ 'elex01-ams.turinex.eu s t', 'eu.minexpool.nl s t' ] @classmethod def electrum_header(cls, header, height): h = super().electrum_header(header, height) h['solution'] = hash_to_hex_str(header[cls.HEADER_SIZE_NO_SOLUTION:]) return h @classmethod def block_header(cls, block, height): '''Return the block header bytes''' deserializer = cls.DESERIALIZER(block) return deserializer.read_header(height, cls.HEADER_SIZE_NO_SOLUTION) class Groestlcoin(Coin): NAME = "Groestlcoin" SHORTNAME = "GRS" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") P2PKH_VERBYTE = bytes.fromhex("24") P2SH_VERBYTES = [bytes.fromhex("05")] WIF_BYTE = bytes.fromhex("80") GENESIS_HASH = ('00000ac5927c594d49cc0bdb81759d0d' 'a8297eb614683d3acb62f0703b639023') DESERIALIZER = lib_tx.DeserializerGroestlcoin TX_COUNT = 115900 TX_COUNT_HEIGHT = 1601528 TX_PER_BLOCK = 5 RPC_PORT = 1441 PEERS = [ 'electrum1.groestlcoin.org s t', 'electrum2.groestlcoin.org s t', '6brsrbiinpc32tfc.onion t', 'xkj42efxrcy6vbfw.onion t', ] def grshash(data): import groestlcoin_hash return groestlcoin_hash.getHash(data, len(data)) @classmethod def header_hash(cls, header): '''Given a header return the hash.''' return cls.grshash(header) ENCODE_CHECK = partial(Base58.encode_check, hash_fn=grshash) DECODE_CHECK = partial(Base58.decode_check, hash_fn=grshash) class GroestlcoinTestnet(Groestlcoin): SHORTNAME = "TGRS" NET = "testnet" XPUB_VERBYTES = bytes.fromhex("043587cf") XPRV_VERBYTES = bytes.fromhex("04358394") P2PKH_VERBYTE = bytes.fromhex("6f") P2SH_VERBYTES = [bytes.fromhex("c4")] WIF_BYTE = bytes.fromhex("ef") GENESIS_HASH = ('000000ffbb50fc9898cdd36ec163e6ba' '23230164c0052a28876255b7dcf2cd36') RPC_PORT = 17766 PEERS = [ 'electrum-test1.groestlcoin.org s t', 'electrum-test2.groestlcoin.org s t', '7frvhgofuf522b5i.onion t', 'aocojvqcybdoxekv.onion t', ] class Pivx(Coin): NAME = "Pivx" SHORTNAME = "PIVX" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("022D2533") XPRV_VERBYTES = bytes.fromhex("0221312B") P2PKH_VERBYTE = bytes.fromhex("1e") P2SH_VERBYTES = [bytes.fromhex("0d")] WIF_BYTE = bytes.fromhex("d4") GENESIS_HASH = ('0000041e482b9b9691d98eefb4847340' '5c0b8ec31b76df3797c74a78680ef818') BASIC_HEADER_SIZE = 80 HDR_V4_SIZE = 112 HDR_V4_HEIGHT = 863787 HDR_V4_START_OFFSET = HDR_V4_HEIGHT * BASIC_HEADER_SIZE TX_COUNT = 2930206 TX_COUNT_HEIGHT = 1299212 TX_PER_BLOCK = 2 RPC_PORT = 51473 @classmethod def static_header_offset(cls, height): assert cls.STATIC_BLOCK_HEADERS if height >= cls.HDR_V4_HEIGHT: relative_v4_offset = (height - cls.HDR_V4_HEIGHT) * cls.HDR_V4_SIZE return cls.HDR_V4_START_OFFSET + relative_v4_offset else: return height * cls.BASIC_HEADER_SIZE @classmethod def header_hash(cls, header): version, = util.unpack_le_uint32_from(header) if version >= 4: return super().header_hash(header) else: import quark_hash return quark_hash.getPoWHash(header) class PivxTestnet(Pivx): SHORTNAME = "tPIVX" NET = "testnet" XPUB_VERBYTES = bytes.fromhex("3a8061a0") XPRV_VERBYTES = bytes.fromhex("3a805837") P2PKH_VERBYTE = bytes.fromhex("8B") P2SH_VERBYTES = [bytes.fromhex("13")] WIF_BYTE = bytes.fromhex("EF") GENESIS_HASH = ( '0000041e482b9b9691d98eefb48473405c0b8ec31b76df3797c74a78680ef818') BASIC_HEADER_SIZE = 80 HDR_V4_SIZE = 112 HDR_V4_HEIGHT = 863787 HDR_V4_START_OFFSET = HDR_V4_HEIGHT * BASIC_HEADER_SIZE TX_COUNT = 2157510 TX_COUNT_HEIGHT = 569399 TX_PER_BLOCK = 2 RPC_PORT = 51472 class Bitg(Coin): NAME = "BitcoinGreen" SHORTNAME = "BITG" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") P2PKH_VERBYTE = bytes.fromhex("26") P2SH_VERBYTES = [bytes.fromhex("06")] WIF_BYTE = bytes.fromhex("2e") GENESIS_HASH = ( '000008467c3a9c587533dea06ad9380cded3ed32f9742a6c0c1aebc21bf2bc9b') DAEMON = daemon.DashDaemon TX_COUNT = 1000 TX_COUNT_HEIGHT = 10000 TX_PER_BLOCK = 1 RPC_PORT = 9332 REORG_LIMIT = 1000 SESSIONCLS = DashElectrumX DAEMON = daemon.DashDaemon @classmethod def header_hash(cls, header): '''Given a header return the hash.''' import quark_hash return quark_hash.getPoWHash(header) class tBitg(Bitg): SHORTNAME = "tBITG" NET = "testnet" XPUB_VERBYTES = bytes.fromhex("043587cf") XPRV_VERBYTES = bytes.fromhex("04358394") P2PKH_VERBYTE = bytes.fromhex("62") P2SH_VERBYTES = [bytes.fromhex("0c")] WIF_BYTE = bytes.fromhex("6c") GENESIS_HASH = ( '000008467c3a9c587533dea06ad9380cded3ed32f9742a6c0c1aebc21bf2bc9b') RPC_PORT = 19332 class CivX(Coin): NAME = "CivX" SHORTNAME = "CIVX" NET = "mainnet" XPUB_VERBYTES = bytes.fromhex("0488b21e") XPRV_VERBYTES = bytes.fromhex("0488ade4") GENESIS_HASH = ('00000036090a68c523471da7a4f0f958' 'c1b4403fef74a003be7f71877699cab7') P2PKH_VERBYTE = bytes.fromhex("1C") P2SH_VERBYTE = [bytes.fromhex("57")] WIF_BYTE = bytes.fromhex("9C") RPC_PORT = 4561 TX_COUNT = 1000 TX_COUNT_HEIGHT = 10000 TX_PER_BLOCK = 4 DAEMON = daemon.PreLegacyRPCDaemon DESERIALIZER = lib_tx.DeserializerTxTime @classmethod def header_hash(cls, header): version, = util.unpack_le_uint32_from(header) if version > 2: return double_sha256(header) else: return hex_str_to_hash(CivX.GENESIS_HASH) class CivXTestnet(CivX): SHORTNAME = "tCIVX" NET = "testnet" XPUB_VERBYTES = bytes.fromhex("043587cf") XPRV_VERBYTES = bytes.fromhex("04358394") GENESIS_HASH = ('0000059bb2c2048493efcb0f1a034972' 'b3ce4089d54c93b69aaab212fb369887') P2PKH_VERBYTE = bytes.fromhex("4B") P2SH_VERBYTE = [bytes.fromhex("CE")] WIF_BYTE = bytes.fromhex("CB") RPC_PORT = 14561 @classmethod def header_hash(cls, header): version, = util.unpack_le_uint32_from(header) if version > 2: return double_sha256(header) else: return hex_str_to_hash(CivXTestnet.GENESIS_HASH)