Source code for cryptoassets.core.coin.registry

"""All running cryptoassets are maintained in a coin registry.

Each cryptoasset provides its own Wallet SQLAlchemy model and backend instance which is used to communicate with the network of the cryptoasset.
"""
from zope.dottedname.resolve import resolve


[docs]class CoinModelDescription: """Describe one cryptocurrency data structures: what SQLAlchemy models and database tables it uses. The instance of this class is used by :py:class:`cryptoassets.core.models.CoinDescriptionModel` to build the model relatinoships and foreign keys between the tables of one cryptoasset. """ def __init__(self, coin_name, wallet_model_name, address_model_name, account_model_name, transaction_model_name, network_transaction_model_name, address_validator): """Create the description with fully dotted paths to Python classes. :param coin_name: Name of this coin, lowercase acronym """ assert coin_name == coin_name.lower() self.coin_name = coin_name self.wallet_model_name = wallet_model_name self.address_model_name = address_model_name self.account_model_name = account_model_name self.transaction_model_name = transaction_model_name self.network_transaction_model_name = network_transaction_model_name self.address_validator = address_validator # Direct model class reference. Available after Python modules are loaded and Cryptoassets App session initialized self._Wallet = None self._Address = None self._Account = None self._NetworkTransaction = None self._Transaction = None @property def Wallet(self): """Get wallet model class.""" return self._lazy_initialize_class_ref("_Wallet", self.wallet_model_name) @property def Address(self): """Get address model class.""" return self._lazy_initialize_class_ref("_Address", self.address_model_name) @property def Account(self): """Get account model class.""" return self._lazy_initialize_class_ref("_Account", self.account_model_name) @property def NetworkTransaction(self): """Get network transaction model class.""" return self._lazy_initialize_class_ref("_NetworkTransaction", self.network_transaction_model_name) @property def Transaction(self): """Get transaction model class.""" return self._lazy_initialize_class_ref("_Transaction", self.transaction_model_name) @property def wallet_table_name(self): return "{}_wallet".format(self.coin_name) @property def account_table_name(self): return "{}_account".format(self.coin_name) @property def address_table_name(self): return "{}_address".format(self.coin_name) @property def transaction_table_name(self): return "{}_transaction".format(self.coin_name) @property def network_transaction_table_name(self): return "{}_network_transaction".format(self.coin_name) def _lazy_initialize_class_ref(self, name, dotted_name): val = getattr(self, name, None) if val: return val else: val = resolve(dotted_name) setattr(self, name, val) return val
[docs]class Coin: """Describe one cryptocurrency setup. Binds cryptocurrency to its backend and database models. We also carry a flag if we are running in testnet or not. This affects address validation. """ def __init__(self, coin_description, backend=None, max_confirmation_count=15, testnet=False): """Create a binding between asset models and backend. :param coin_description: :py:class:`cryptoassets.core.coin.registry.CoinModelDescription` :param testnet: Are we running a testnet node or real node. :param backend: :py:class:`cryptoassets.core.backend.base.CoinBackend` """ assert isinstance(coin_description, CoinModelDescription) self.coin_description = coin_description #: Subclass of :py:class:`cryptoassets.core.backend.base.CoinBackend`. self.backend = None #: Lowercase acronym name of this asset self.name = None #: This is how many confirmations ``tools.confirmationupdate`` tracks for each network transactions, both incoming and outgoing, until we consider it "closed" and stop polling backend for updates. self.max_confirmation_count = max_confirmation_count self.testnet = testnet @property def address_model(self): """Property to get SQLAlchemy model for address of this cryptoasset. Subclass of :py:class:`cryptoassets.core.models.GenericAddress`. """ return self.coin_description.Address @property def transaction_model(self): """Property to get SQLAlchemy model for transaction of this cryptoasset. Subclass of :py:class:`cryptoassets.core.models.GenericTransaction`. """ return self.coin_description.Transaction @property def account_model(self): """Property to get SQLAlchemy model for account of this cryptoasset. Subclass of :py:class:`cryptoassets.core.models.GenericAccount`. """ return self.coin_description.Account @property def wallet_model(self): """Property to get SQLAlchemy model for account of this cryptoasset. Subclass of :py:class:`cryptoassets.core.models.GenericWallet`. """ return self.coin_description.Wallet @property def network_transaction_model(self): """Property to get SQLAlchemy model for account of this cryptoasset. Subclass of :py:class:`cryptoassets.core.models.GenericWallet`. """ return self.coin_description.NetworkTransaction
[docs] def validate_address(self, address): """Check the address validy against current network. :return: True if given address is valid. """ return self.coin_description.address_validator.validate_address(address, self.testnet)
[docs]class CoinRegistry: """Holds data of set up cryptocurrencies. Usually you access this through :py:attr:`cryptoasssets.core.app.CryptoassetsApp.coins` instance. Example:: cryptoassets_app = CryptoassetsApp() # ... setup ... bitcoin = cryptoassets_app.coins.get("btc) print("We are running bitcoin with backend {}".format(bitcoin.backend)) """ def __init__(self): self.coins = {} def register(self, name, coin): self.coins[name] = coin # Setup backref coin.name = name
[docs] def all(self): """Get all registered coin models. :return: List of tuples(coin name, Coin) """ return self.coins.items()
[docs] def get(self, name): """Return coin setup data by its acronym name. :param name: All lowercase, e.g. ``btc``. """ return self.coins.get(name)