text: # 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
  
  import lib.util as util
  from lib.hash import Base58, hash160, double_sha256, hash_to_str
  from lib.script import ScriptPubKey, OpCodes
  import lib.tx as lib_tx
  from server.block_processor import BlockProcessor
  import server.daemon as daemon
  from 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
      HASHX_LEN = 11
      BASIC_HEADER_SIZE = 80
      STATIC_BLOCK_HEADERS = True
      SESSIONCLS = ElectrumX
      DESERIALIZER = lib_tx.Deserializer
      DAEMON = daemon.Daemon
      BLOCK_PROCESSOR = BlockProcessor
      XPUB_VERBYTES = bytes('????', 'utf-8')
      XPRV_VERBYTES = bytes('????', 'utf-8')
      # Peer discovery
      PEER_DEFAULT_PORTS = {'t': '50001', 's': '50002'}
      PEERS = []
  
      @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 daemon_urls(cls, urls):
          return [cls.sanitize_url(url) for url in urls.split(',')]
  
      @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_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()[:cls.HASHX_LEN]
  
      @util.cachedproperty
      def address_handlers(cls):
          return ScriptPubKey.PayToHandlers(
              address=cls.P2PKH_address_from_hash160,
              script_hash=cls.P2SH_address_from_hash160,
              pubkey=cls.P2PKH_address_from_pubkey,
              unspendable=lambda: None,
              strange=lambda script: None,
          )
  
      @classmethod
      def address_from_script(cls, script):
          '''Given a pk_script, return the adddress it pays to, or None.'''
          return ScriptPubKey.pay_to(cls.address_handlers, script)
  
      @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 Base58.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 Base58.encode_check(cls.P2SH_VERBYTES[0] + hash160)
  
      @classmethod
      def multisig_address(cls, m, pubkeys):
          '''Return the P2SH address for an M of N multisig transaction.
  
          Pass the N pubkeys of which M are needed to sign it.  If
          generating an address for a wallet, it is the caller's
          responsibility to sort them to ensure order does not matter
          for, e.g., wallet recovery.
          '''
          script = cls.pay_to_multisig_script(m, pubkeys)
          return cls.P2SH_address_from_hash160(hash160(script))
  
      @classmethod
      def pay_to_multisig_script(cls, m, pubkeys):
          '''Return a P2SH script for an M of N multisig transaction.'''
          return ScriptPubKey.multisig_script(m, pubkeys)
  
      @classmethod
      def pay_to_pubkey_script(cls, pubkey):
          '''Return a pubkey script that pays to a pubkey.
  
          Pass the raw pubkey bytes (length 33 or 65).
          '''
          return ScriptPubKey.P2PK_script(pubkey)
  
      @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 = Base58.decode_check(address)
  
          # Require version byte(s) plus hash160.
          verbyte = -1
          verlen = len(raw) - 20
          if verlen > 0:
              verbyte, hash_bytes = raw[:verlen], raw[verlen:]
  
          if verbyte == cls.P2PKH_VERBYTE:
              return ScriptPubKey.P2PKH_script(hash_bytes)
          if verbyte in cls.P2SH_VERBYTES:
              return ScriptPubKey.P2SH_script(hash_bytes)
  
          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 Base58.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):
          version, = struct.unpack('<I', header[:4])
          timestamp, bits, nonce = struct.unpack('<III', header[68:80])
  
          return {
              'block_height': height,
              'version': version,
              'prev_block_hash': hash_to_str(header[4:36]),
              'merkle_root': hash_to_str(header[36:68]),
              'timestamp': timestamp,
              'bits': bits,
              'nonce': nonce,
          }
  
  
  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
  
      @classmethod
      def electrum_header(cls, header, height):
          version, = struct.unpack('<I', header[:4])
          timestamp, bits = struct.unpack('<II', header[100:108])
  
          return {
              'block_height': height,
              'version': version,
              'prev_block_hash': hash_to_str(header[4:36]),
              'merkle_root': hash_to_str(header[36:68]),
              'timestamp': timestamp,
              'bits': bits,
              'nonce': hash_to_str(header[108:140]),
          }
  
      @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, = struct.unpack('<I', header[:4])
          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 BitcoinCash(BitcoinMixin, Coin):
      NAME = "BitcoinCash"
      SHORTNAME = "BCC"
      TX_COUNT = 243631085
      TX_COUNT_HEIGHT = 479636
      TX_PER_BLOCK = 50
      PEERS = [
          'electroncash.bitcoinplug.com s t',
          'electrum-abc.criptolayer.net s50012',
          'electroncash.cascharia.com s50002',
          'bch.arihanc.com t52001 s52002',
          'mash.1209k.com s t',
          'h.1209k.com s t',
          'abc.vom-stausee.de t52001 s52002',
          'abc1.hsmiths.com t60001 s60002',
      ]
  
  
  class BitcoinSegwit(BitcoinMixin, Coin):
      NAME = "BitcoinSegwit"
      DESERIALIZER = lib_tx.DeserializerSegWit
      TX_COUNT = 217380620
      TX_COUNT_HEIGHT = 464000
      TX_PER_BLOCK = 1800
      PEERS = [
          'btc.smsys.me s995',
          'E-X.not.fyi s t',
          'elec.luggs.co s443',
          'electrum.vom-stausee.de s t',
          'electrum3.hachre.de p10000 s t',
          'electrum.hsmiths.com s t',
          'erbium1.sytes.net s t',
          'helicarrier.bauerj.eu s t',
          'hsmiths4fyqlw5xw.onion s t',
          'luggscoqbymhvnkp.onion t80',
          'ozahtqwp25chjdjd.onion s t',
          'us11.einfachmalnettsein.de s t',
          'ELEX01.blackpole.online s t',
      ]
  
  
  class BitcoinGold(EquihashMixin, BitcoinMixin, Coin):
      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
  
      @classmethod
      def header_hash(cls, header):
          '''Given a header return hash'''
          height, = struct.unpack('<I', header[68:72])
  
          if height >= cls.FORK_HEIGHT:
              return double_sha256(header)
          else:
              return double_sha256(header[:68] + header[100:112])
  
  
  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 = []
  
      @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',
      ]
  
  
  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',
      ]
  
  
  class BitcoinGoldTestnet(BitcoinTestnetMixin, BitcoinGold):
      NAME = "BitcoinGold"
      FORK_HEIGHT = 1210320
  
  
  class BitcoinSegwitRegtest(BitcoinSegwitTestnet):
      NAME = "BitcoinSegwit"
      NET = "regtest"
      GENESIS_HASH = ('0f9188f13cb7b2c71f2a335e3a4fc328'
                      'bf5beb436012afca590b1a11466e2206')
      PEERS= []
      TX_COUNT = 1
      TX_COUNT_HEIGHT = 1
  
  
  class BitcoinNolnet(BitcoinCash):
      '''Bitcoin Unlimited nolimit testnet.'''
      NET = "nolnet"
      GENESIS_HASH = ('0000000057e31bd2066c939a63b7b862'
                      '3bd0f10d8c001304bdfc1a7902ae6d35')
      PEERS = []
      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("019d9cfe")
      XPRV_VERBYTES = bytes.fromhex("019da462")
      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("0436ef7d")
      XPRV_VERBYTES = bytes.fromhex("0436f6e1")
      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 = 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',
      ]
  
  
  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/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',
      ]
  
  
  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
      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):
          version, = struct.unpack('<I', header[:4])
          timestamp, creatorId = struct.unpack('<II', header[100:108])
          return {
              'block_height': height,
              'version': version,
              'prev_block_hash': hash_to_str(header[4:36]),
              'merkle_root': hash_to_str(header[36:68]),
              'payload_hash': hash_to_str(header[68:100]),
              'timestamp': timestamp,
              'creatorId': creatorId,
          }
  
  
  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 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 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 = []
  
  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 = []
  
  
  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')
      DAEMON = daemon.LegacyRPCDaemon
      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 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',
          'electrumx1.movsign.info t',
          'electrumx2.movsign.info t',
          'electrum-mona.bitbank.cc 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')
      ESTIMATE_FEE = 0.001
      RELAY_FEE = 0.001
      DAEMON = daemon.FakeEstimateFeeDaemon
      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 = 1000
      TX_COUNT_HEIGHT = 10000
      TX_PER_BLOCK = 1
      RPC_PORT = 9252
      REORG_LIMIT = 1000
  
  
  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 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 = []
  
      @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("32"), bytes.fromhex("05")]
      WIF_BYTE = bytes.fromhex("8E")
      GENESIS_HASH = ('12a765e31ffd4059bada1e25190f6e98'
                      'c99d9714d334efa41a195a7e7e04bfe2')
      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 Flo(Coin):
      NAME = "Flo"
      SHORTNAME = "FLO"
      NET = "mainnet"
      XPUB_VERBYTES = bytes.fromhex("0134406b")
      XPRV_VERBYTES = bytes.fromhex("01343c31")
      P2PKH_VERBYTE = bytes.fromhex("23")
      P2SH_VERBYTES = [bytes.fromhex("08")]
      WIF_BYTE = bytes.fromhex("b0")
      GENESIS_HASH = ('09c7781c9df90708e278c35d38ea5c9041d7ecfcdd1c56ba67274b7cff3e1cea')
      TX_COUNT = 8908766
      TX_COUNT_HEIGHT = 1105256
      TX_PER_BLOCK = 10
      RPC_PORT = 7313
      REORG_LIMIT = 800
      PEERS = [
      ]
      DESERIALIZER = lib_tx.DeserializerFlo
      
      
      class Blackcoin(ScryptMixin, Coin):
      NAME = "BitcoinWSpectrum"
      SHORTNAME = "BWS"
      NET = "mainnet"
      P2PKH_VERBYTE = bytes.fromhex("25")
      P2SH_VERBYTES = [bytes.fromhex("85")]
      WIF_BYTE = bytes.fromhex("99")
      GENESIS_HASH = ('00000198707c071cdb39cc8332eccfe8'
                      '89013ad88b65a63673672b0bda8177e7')
      DAEMON = daemon.LegacyRPCDaemon
      TX_COUNT = 7910
      TX_COUNT_HEIGHT = 4000
      TX_PER_BLOCK = 2
      RPC_PORT = 22320
      REORG_LIMIT = 1000
  