xeroc/python-graphenelib

View on GitHub
graphenecommon/witness.py

Summary

Maintainability
A
25 mins
Test Coverage
# -*- coding: utf-8 -*-
from .exceptions import WitnessDoesNotExistsException
from .blockchainobject import BlockchainObject, BlockchainObjects
from .instance import AbstractBlockchainInstanceProvider


class Witness(BlockchainObject, AbstractBlockchainInstanceProvider):
    """Read data about a witness in the chain

    :param str account_name: Name of the witness
    :param instance blockchain_instance: instance to use when accesing a RPC

    """

    def __init__(self, *args, **kwargs):
        self.define_classes()
        assert self.type_id or self.type_ids
        assert self.account_class
        BlockchainObject.__init__(self, *args, **kwargs)

    def refresh(self):
        if self.test_valid_objectid(self.identifier):
            _, i, _ = self.identifier.split(".")
            if int(i) == 6:
                witness = self.blockchain.rpc.get_object(self.identifier)
            else:
                witness = self.blockchain.rpc.get_witness_by_account(self.identifier)
        else:
            account = self.account_class(
                self.identifier, blockchain_instance=self.blockchain
            )
            witness = self.blockchain.rpc.get_witness_by_account(account["id"])
        if not witness:
            raise WitnessDoesNotExistsException(self.identifier)
        super(Witness, self).__init__(witness, blockchain_instance=self.blockchain)

    @property
    def account(self):
        return self.account_class(
            self["witness_account"], blockchain_instance=self.blockchain
        )

    @property
    def weight(self):
        if not self.is_active:
            return 0
        else:
            account = self.account_class(
                "witness-account", blockchain_instance=self.blockchain
            )
            threshold = account["active"]["weight_threshold"]
            weight = next(
                filter(
                    lambda x: x[0] == self.account["id"],
                    account["active"]["account_auths"],
                )
            )
            return float(weight[1]) / float(threshold)

    @property
    def is_active(self):
        account = self.account_class(
            "witness-account", blockchain_instance=self.blockchain
        )
        return self.account["id"] in [x[0] for x in account["active"]["account_auths"]]


class Witnesses(BlockchainObjects, AbstractBlockchainInstanceProvider):
    """Obtain a list of **active** witnesses and the current schedule

    :param bool only_active: (False) Only return witnesses that are
        actively producing blocks
    :param instance blockchain_instance: instance to use when accesing a RPC
    """

    def __init__(self, *args, only_active=False, lazy=False, **kwargs):
        self.define_classes()
        assert self.account_class
        assert self.witness_class

        self.lazy = lazy
        self.only_active = only_active
        super().__init__(*args, **kwargs)

    def refresh(self, *args, **kwargs):
        self.schedule = self.blockchain.rpc.get_object("2.12.0").get(
            "current_shuffled_witnesses", []
        )

        witnesses = [
            self.witness_class(x, lazy=self.lazy, blockchain_instance=self.blockchain)
            for x in self.schedule
        ]

        if self.only_active:
            account = self.account_class(
                "witness-account", blockchain_instance=self.blockchain
            )
            filter_by = [x[0] for x in account["active"]["account_auths"]]
            witnesses = list(
                filter(lambda x: x["witness_account"] in filter_by, witnesses)
            )

        self.store(witnesses)

    def __contains__(self, item):
        if self.witness_class.objectid_valid(item):
            id = item
        elif isinstance(item, self.account_class):
            id = item["id"]
        else:
            account = self.account_class(item, blockchain_instance=self.blockchain)
            id = account["id"]

        return any([id == x["id"] for x in self]) or any(
            [id == x["witness_account"] for x in self]
        )