lbry-sdk/torba/basecoin.py
2018-05-25 02:03:25 -04:00

80 lines
2.8 KiB
Python

import six
from typing import Dict, Type
from torba.hash import hash160, double_sha256, Base58
class CoinRegistry(type):
coins = {} # type: Dict[str, Type[BaseCoin]]
def __new__(mcs, name, bases, attrs):
cls = super(CoinRegistry, mcs).__new__(mcs, name, bases, attrs) # type: Type[BaseCoin]
if not (name == 'BaseCoin' and not bases):
coin_id = cls.get_id()
assert coin_id not in mcs.coins, 'Coin with id "{}" already registered.'.format(coin_id)
mcs.coins[coin_id] = cls
assert cls.ledger_class.coin_class is None, (
"Ledger ({}) which this coin ({}) references is already referenced by another "
"coin ({}). One to one relationship between a coin and a ledger is strictly and "
"automatically enforced. Make sure that coin_class=None in the ledger and that "
"another Coin isn't already referencing this Ledger."
).format(cls.ledger_class.__name__, name, cls.ledger_class.coin_class.__name__)
# create back reference from ledger to the coin
cls.ledger_class.coin_class = cls
return cls
@classmethod
def get_coin_class(mcs, coin_id): # type: (str) -> Type[BaseCoin]
return mcs.coins[coin_id]
class BaseCoin(six.with_metaclass(CoinRegistry)):
name = None
symbol = None
network = None
ledger_class = None # type: Type[BaseLedger]
transaction_class = None # type: Type[BaseTransaction]
secret_prefix = None
pubkey_address_prefix = None
script_address_prefix = None
extended_public_key_prefix = None
extended_private_key_prefix = None
def __init__(self, ledger, fee_per_byte):
self.ledger = ledger
self.fee_per_byte = fee_per_byte
@classmethod
def get_id(cls):
return '{}_{}'.format(cls.symbol.lower(), cls.network.lower())
def to_dict(self):
return {'fee_per_byte': self.fee_per_byte}
def get_input_output_fee(self, io):
""" Fee based on size of the input / output. """
return self.fee_per_byte * io.size
def get_transaction_base_fee(self, tx):
""" Fee for the transaction header and all outputs; without inputs. """
return self.fee_per_byte * tx.base_size
def hash160_to_address(self, h160):
raw_address = self.pubkey_address_prefix + h160
return Base58.encode(bytearray(raw_address + double_sha256(raw_address)[0:4]))
@staticmethod
def address_to_hash160(address):
bytes = Base58.decode(address)
prefix, pubkey_bytes, addr_checksum = bytes[0], bytes[1:21], bytes[21:]
return pubkey_bytes
def public_key_to_address(self, public_key):
return self.hash160_to_address(hash160(public_key))
@staticmethod
def private_key_to_wif(private_key):
return b'\x1c' + private_key + b'\x01'