Пример #1
0
 def _transaction_from_explorer_transaction(
         self,
         etxn,
         endpoint="/?",
         resp=None):  # keyword parameters for error handling purposes only
     if resp == None:
         resp = jsobj.new_dict()
     # parse the transactions
     transaction = transactions.from_json(obj=etxn['rawtransaction'],
                                          id=etxn['id'])
     # add the parent (coin) outputs
     coininputoutputs = etxn.get_or('coininputoutputs', None) or []
     if len(transaction.coin_inputs) != len(coininputoutputs):
         raise tferrors.ExplorerInvalidResponse(
             "amount of coin inputs and parent outputs are not matching: {} != {}"
             .format(len(transaction.coin_inputs),
                     len(coininputoutputs)), endpoint, resp)
     for (idx, co) in enumerate(coininputoutputs):
         co = CoinOutput.from_json(obj=co)
         co.id = transaction.coin_inputs[idx].parentid
         transaction.coin_inputs[idx].parent_output = co
     # add the coin output ids
     coinoutputids = etxn.get_or('coinoutputids', None) or []
     if len(transaction.coin_outputs) != len(coinoutputids):
         raise tferrors.ExplorerInvalidResponse(
             "amount of coin outputs and output identifiers are not matching: {} != {}"
             .format(len(transaction.coin_outputs),
                     len(coinoutputids)), endpoint, resp)
     for (idx, id) in enumerate(coinoutputids):
         transaction.coin_outputs[idx].id = Hash.from_json(obj=id)
     # add the parent (blockstake) outputs
     blockstakeinputoutputs = etxn.get_or('blockstakeinputoutputs',
                                          None) or []
     if len(transaction.blockstake_inputs) != len(blockstakeinputoutputs):
         raise tferrors.ExplorerInvalidResponse(
             "amount of blockstake inputs and parent outputs are not matching: {} != {}"
             .format(len(transaction.blockstake_inputs),
                     len(blockstakeinputoutputs)), endpoint, resp)
     for (idx, bso) in enumerate(blockstakeinputoutputs):
         bso = BlockstakeOutput.from_json(obj=bso)
         bso.id = transaction.blockstake_inputs[idx].parentid
         transaction.blockstake_inputs[idx].parent_output = bso
     # add the blockstake output ids
     blockstakeoutputids = etxn.get_or('blockstakeoutputids', None) or []
     if len(transaction.blockstake_outputs) != len(blockstakeoutputids):
         raise tferrors.ExplorerInvalidResponse(
             "amount of blokstake outputs and output identifiers are not matching: {} != {}"
             .format(len(transaction.blockstake_inputs),
                     len(blockstakeoutputids)), endpoint, resp)
     for (idx, id) in enumerate(blockstakeoutputids):
         transaction.blockstake_outputs[idx].id = Hash.from_json(obj=id)
     # set the unconfirmed state
     transaction.unconfirmed = etxn.get_or('unconfirmed', False)
     # set the blockid and height of the transaction only if confirmed
     if not transaction.unconfirmed:
         transaction.height = int(etxn.get_or('height', -1))
         transaction.blockid = etxn.get_or('parent', None)
     # return the transaction
     return transaction
Пример #2
0
 def _block_get_parse_cb(self, result):
     endpoint, block = result
     try:
         # parse the transactions
         transactions = []
         for etxn in block['transactions']:
             # parse the explorer transaction
             transaction = self._transaction_from_explorer_transaction(
                 etxn, endpoint=endpoint, resp=block)
             # append the transaction to the list of transactions
             transactions.append(transaction)
         rawblock = block['rawblock']
         # parse the parent id
         parentid = Hash.from_json(obj=rawblock['parentid'])
         # parse the miner payouts
         miner_payouts = []
         minerpayoutids = block.get_or('minerpayoutids', None) or []
         eminerpayouts = rawblock.get_or('minerpayouts', None) or []
         if len(eminerpayouts) != len(minerpayoutids):
             raise tferrors.ExplorerInvalidResponse(
                 "amount of miner payouts and payout ids are not matching: {} != {}"
                 .format(len(eminerpayouts),
                         len(minerpayoutids)), endpoint, block)
         for idx, mp in enumerate(eminerpayouts):
             id = Hash.from_json(minerpayoutids[idx])
             value = Currency.from_json(mp['value'])
             unlockhash = UnlockHash.from_json(mp['unlockhash'])
             miner_payouts.append(
                 ExplorerMinerPayout(id=id,
                                     value=value,
                                     unlockhash=unlockhash))
         # get the timestamp and height
         height = int(block['height'])
         timestamp = int(rawblock['timestamp'])
         # get the block's identifier
         blockid = Hash.from_json(block['blockid'])
         # for all transactions assign these properties
         for transaction in transactions:
             _assign_block_properties_to_transacton(transaction, block)
             transaction.height = height
             transaction.blockid = blockid
         # return the block, as reported by the explorer
         return ExplorerBlock(id=blockid,
                              parentid=parentid,
                              height=height,
                              timestamp=timestamp,
                              transactions=transactions,
                              miner_payouts=miner_payouts)
     except KeyError as exc:
         raise tferrors.ExplorerInvalidResponse(str(exc), endpoint,
                                                block) from exc
Пример #3
0
 def hash(self, value):
     if value == None:
         self._hash = None
     elif isinstance(value, Hash):
         self._hash = value
     else:
         self._hash = Hash(value=value)
Пример #4
0
 def _outputid_new(self, specifier, index):
     encoder = encoder_sia_get()
     encoder.add_array(specifier)
     encoder.add_array(self._id_input_compute())
     encoder.add_int(index)
     hash = bytearray.fromhex(blake2_string(encoder.data))
     return Hash(value=hash)
Пример #5
0
 def __init__(self,
              id=None,
              parentid=None,
              height=None,
              timestamp=None,
              transactions=None,
              miner_payouts=None):
     """
     A Block, registered on a TF blockchain, as reported by an explorer.
     """
     self._id = id or Hash()
     self._parentid = parentid or Hash()
     self._height = height or 0
     self._timestamp = timestamp or 0
     self._transactions = transactions or []
     self._miner_payouts = miner_payouts or []
    def from_str(cls, obj):
        if not isinstance(obj, str):
            raise TypeError(
                "UnlockHash is expected to be a str, not {}".format(type(obj)))
        obj = jsstr.strip(obj)
        if len(obj) != UnlockHash._TOTAL_SIZE_HEX:
            raise ValueError(
                "UnlockHash is expexcted to be of length {} when stringified, not of length {}, invalid: {} ({})"
                .format(UnlockHash._TOTAL_SIZE_HEX, len(obj), obj, type(obj)))

        t = UnlockHashType(
            int(jsarr.slice_array(obj, 0, UnlockHash._TYPE_SIZE_HEX)))
        h = Hash(
            value=obj[UnlockHash._TYPE_SIZE_HEX:UnlockHash._TYPE_SIZE_HEX +
                      UnlockHash._HASH_SIZE_HEX])
        uh = cls(uhtype=t, uhhash=h)

        if t.__eq__(UnlockHashType.NIL):
            expectedNH = jshex.bytes_to_hex(
                bytes(jsarr.new_array(UnlockHash._HASH_SIZE)))
            nh = jshex.bytes_to_hex(h.value)
            if nh != expectedNH:
                raise ValueError("unexpected nil hash {}".format(nh))
        else:
            expected_checksum = jshex.bytes_to_hex(
                jsarr.slice_array(uh._checksum(), 0,
                                  UnlockHash._CHECKSUM_SIZE))
            checksum = jsarr.slice_array(
                obj,
                UnlockHash._TOTAL_SIZE_HEX - UnlockHash._CHECKSUM_SIZE_HEX)
            if expected_checksum != checksum:
                raise ValueError("unexpected checksum {}, expected {}".format(
                    checksum, expected_checksum))

        return uh
Пример #7
0
    def from_json(cls, obj):
        if not isinstance(obj, str):
            raise TypeError(
                "UnlockHash is expected to be JSON-encoded as an str, not {}".
                format(type(obj)))
        if len(obj) != UnlockHash._TOTAL_SIZE_HEX:
            raise ValueError(
                "UnlockHash is expexcted to be of length {} when JSON-encoded, not of length {}"
                .format(UnlockHash._TOTAL_SIZE_HEX, len(obj)))

        t = UnlockHashType(int(obj[:UnlockHash._TYPE_SIZE_HEX]))
        h = Hash(
            value=obj[UnlockHash._TYPE_SIZE_HEX:UnlockHash._TYPE_SIZE_HEX +
                      UnlockHash._HASH_SIZE_HEX])
        uh = cls(type=t, hash=h)

        if t == UnlockHashType.NIL:
            expectedNH = b'\x00' * UnlockHash._HASH_SIZE
            if h.value != expectedNH:
                raise ValueError("unexpected nil hash {}".format(
                    h.value.hex()))
        else:
            expected_checksum = uh._checksum()[:UnlockHash._CHECKSUM_SIZE].hex(
            )
            checksum = obj[-UnlockHash._CHECKSUM_SIZE_HEX:]
            if expected_checksum != checksum:
                raise ValueError("unexpected checksum {}, expected {}".format(
                    checksum, expected_checksum))

        return uh
Пример #8
0
 def cb(result):
     _, transaction = result
     try:
         return Hash(value=transaction['transactionid']).__str__()
     except (KeyError, ValueError, TypeError) as exc:
         # return a KeyError as an invalid Explorer Response
         raise tferrors.ExplorerInvalidResponse(str(exc), endpoint,
                                                transaction) from exc
Пример #9
0
 def blockchain_info_get(self):
     """
     Get the current blockchain info, using the last known block, as reported by an explorer.
     """
     resp = self.explorer_get(endpoint="/explorer")
     resp = json_loads(resp)
     blockid = Hash.from_json(obj=resp['blockid'])
     last_block = self.block_get(blockid)
     return ExplorerBlockchainInfo(last_block=last_block)
Пример #10
0
 def _id_new(self, specifier=None, index=None):
     encoder = SiaBinaryEncoder()
     if specifier != None:
         encoder.add_array(specifier)
     encoder.add_array(self._id_input_compute())
     if index != None:
         encoder.add_int(index)
     hash = blake2b(encoder.data)
     return Hash(value=hash)
Пример #11
0
 def explorer_post(self, endpoint, data):
     """
     Put explorer data onto the stub client for the specified endpoint.
     """
     hash_template = re.compile(r'^.*/transactionpool/transactions$')
     match = hash_template.match(endpoint)
     if match:
         transactionid = Hash(value=jscrypto.random(Hash.SIZE)).__str__()
         transaction = tftransactions.from_json(data)
         # ensure all coin outputs and block stake outputs have identifiers set
         for idx, co in enumerate(transaction.coin_outputs):
             co.id = transaction.coin_outputid_new(idx)
         for idx, bso in enumerate(transaction.blockstake_outputs):
             bso.id = transaction.blockstake_outputid_new(idx)
         self._posted_transactions[transactionid] = transaction
         return jsstr.sprintf('{"transactionid":"%s"}',
                              transactionid.__str__())
     raise Exception("invalid endpoint {}".format(endpoint))
Пример #12
0
        def get_block(result):
            used_addr, raw_block = result
            address = used_addr

            def get_block_with_tag(result):
                return ('b', (address, result))

            blockid = Hash.from_json(obj=raw_block['blockid'])
            return jsasync.chain(self.block_get(blockid), get_block_with_tag)
Пример #13
0
def test_types():
    # currency values can be created from both
    # int and str values, but are never allowed to be negative
    jsass.equals(Currency().str(), '0')
    jsass.equals(Currency(value=123).str(), '123')
    jsass.equals(Currency(value='1').str(), '1')
    jsass.equals(Currency(value='0.1').json(), '100000000')
    # in the string versions you can also add the TFT currency notation,
    # or use decimal notation to express the currency in the TFT Currency Unit,
    # rather than the primitive unit
    jsass.equals(Currency(value='1 TFT').str(), '1')
    jsass.equals(Currency(value='0.123456789').str(), '0.123456789')
    jsass.equals(Currency(value='0.123456789').json(), '123456789')
    jsass.equals(Currency(value='9.123456789').str(), '9.123456789')
    jsass.equals(Currency(value='1234.34').str(), '1234.34')
    jsass.equals(Currency(value='1.00000').str(), '1')
    jsass.equals(Currency(value='1.0 tft').str(), '1')
    jsass.equals(Currency(value=1).str(), '1')
    jsass.equals(Currency(value=12344).str(), '12344')

    # hash values can be created directly from binary data,
    # or from a hex-encoded string, by default the nil hash will be created
    jsass.equals(Hash().str(), '0' * 64)
    jsass.equals(
        Hash(b'12345678901234567890123456789001').value,
        b'12345678901234567890123456789001')

    # binary data is very similar to a hash,
    # except that it doesn't have a fixed length and it is binary serialized
    # as a slice, not an array
    jsass.equals(BinaryData().str(), '')
    jsass.equals(BinaryData(b'1').str(), '31')
    jsass.equals(BinaryData(b'1', fixed_size=0).str(), '31')
    jsass.equals(BinaryData(b'1', fixed_size=1).str(), '31')

    # raw data is pretty much binary data, except that it is
    # base64 encoded/decoded for str/json purposes
    jsass.equals(BinaryData(b'data', strencoding='base64').str(), 'ZGF0YQ==')

    # block stake values can be created from both
    # int and str values, but are never allowed to be negative
    jsass.equals(Blockstake().str(), '0')
    jsass.equals(Blockstake(value=123).str(), '123')
    jsass.equals(Blockstake(value='1').str(), '1')
Пример #14
0
 def input_hash_new(self, public_key):
     """
     Create an input hash for the public key of the fulfiller.
     """
     input_hash = self._input_hash_gen(public_key)
     if isinstance(input_hash, (str, bytearray, bytes)):
         input_hash = Hash(value=input_hash)
     elif not isinstance(input_hash, Hash):
         raise TypeError(
             "signature request requires an input hash of Type Hash, not: {}"
             .format(type(input_hash)))
     return input_hash
Пример #15
0
 def chain_blockid(self, value):
     """
     Set the blockchain block ID, such that applications that which to cache this
     balance object could ensure that the last block is still the same as the
     last known block known by this balance instance.
     """
     if not value:
         self._chain_blockid = Hash()
         return
     if isinstance(value, Hash):
         self._chain_blockid.value = value.value
     else:
         self._chain_blockid.value = value
Пример #16
0
 def from_json(cls, obj):
     if not obj:
         return cls()
     if not isinstance(obj, str):
         raise TypeError(
             "expected JSON-encoded PublicKey to be a string, not {}".
             format(type(obj)))
     parts = jsstr.split(obj, ':', 2)
     if len(parts) != 2:
         raise ValueError("invalid JSON-encoded PublicKey: {}".format(obj))
     pk = cls()
     pk._specifier = PublicKeySpecifier.from_json(parts[0])
     pk._hash = Hash.from_json(parts[1])
     return pk
Пример #17
0
 def __init__(self):
     # personal wallet outputs
     self._outputs = {}
     self._outputs_spent = {}
     self._outputs_unconfirmed = {}
     self._outputs_unconfirmed_spent = {}
     # transactions used by outputs
     self._transactions = {}
     # balance chain context
     self._chain_time = 0
     self._chain_height = 0
     self._chain_blockid = Hash()
     # all wallet addresses tracked in this wallet
     self._addresses = set()
Пример #18
0
 def explorer_post(self, endpoint, data):
     """
     Put explorer data onto the stub client for the specified endpoint.
     """
     hash_template = re.compile(r'^.*/transactionpool/transactions$')
     match = hash_template.match(endpoint)
     if match:
         transactionid = str(Hash(value=generateXByteID(Hash.SIZE)))
         transaction = j.clients.tfchain.types.transactions.from_json(data)
         # ensure all coin outputs and block stake outputs have identifiers set
         for idx, co in enumerate(transaction.coin_outputs):
             co.id = transaction.coin_outputid_new(idx)
         for idx, bso in enumerate(transaction.blockstake_outputs):
             bso.id = transaction.blockstake_outputid_new(idx)
         self._posted_transactions[transactionid] = transaction
         return '{"transactionid":"%s"}' % (str(transactionid))
     raise Exception("invalid endpoint {}".format(endpoint))
Пример #19
0
    def transaction_put(self, transaction):
        """
        Submit a transaction to an available explorer Node.

        @param transaction: the transaction to push to the client transaction pool
        """
        if isinstance(transaction, TransactionBaseClass):
            transaction = transaction.json()
        endpoint = "/transactionpool/transactions"
        resp = self.explorer_post(endpoint=endpoint, data=transaction)
        resp = json_loads(resp)
        try:
            return str(Hash(value=resp['transactionid']))
        except KeyError as exc:
            # return a KeyError as an invalid Explorer Response
            raise tfchain.errors.ExplorerInvalidResponse(
                str(exc), endpoint, resp) from exc
Пример #20
0
 def from_json(cls, obj):
     return cls(
         parentid=Hash.from_json(obj['parentid']),
         fulfillment=FulfillmentTypes.from_json(obj['fulfillment']))
Пример #21
0
 def _normalize_id(self, id):
     return Hash(value=id).str()
class UnlockHash(BaseDataTypeClass):
    """
    An UnlockHash is a specially constructed hash of the UnlockConditions type,
    with a fixed binary length of 33 and a fixed string length of 78 (string version includes a checksum).
    """
    def __init__(self, uhtype=None, uhhash=None):
        self._type = UnlockHashType.NIL
        self.uhtype = uhtype
        self._hash = Hash()
        self.hash = uhhash

    @classmethod
    def from_str(cls, obj):
        if not isinstance(obj, str):
            raise TypeError(
                "UnlockHash is expected to be a str, not {}".format(type(obj)))
        obj = jsstr.strip(obj)
        if len(obj) != UnlockHash._TOTAL_SIZE_HEX:
            raise ValueError(
                "UnlockHash is expexcted to be of length {} when stringified, not of length {}, invalid: {} ({})"
                .format(UnlockHash._TOTAL_SIZE_HEX, len(obj), obj, type(obj)))

        t = UnlockHashType(
            int(jsarr.slice_array(obj, 0, UnlockHash._TYPE_SIZE_HEX)))
        h = Hash(
            value=obj[UnlockHash._TYPE_SIZE_HEX:UnlockHash._TYPE_SIZE_HEX +
                      UnlockHash._HASH_SIZE_HEX])
        uh = cls(uhtype=t, uhhash=h)

        if t.__eq__(UnlockHashType.NIL):
            expectedNH = jshex.bytes_to_hex(
                bytes(jsarr.new_array(UnlockHash._HASH_SIZE)))
            nh = jshex.bytes_to_hex(h.value)
            if nh != expectedNH:
                raise ValueError("unexpected nil hash {}".format(nh))
        else:
            expected_checksum = jshex.bytes_to_hex(
                jsarr.slice_array(uh._checksum(), 0,
                                  UnlockHash._CHECKSUM_SIZE))
            checksum = jsarr.slice_array(
                obj,
                UnlockHash._TOTAL_SIZE_HEX - UnlockHash._CHECKSUM_SIZE_HEX)
            if expected_checksum != checksum:
                raise ValueError("unexpected checksum {}, expected {}".format(
                    checksum, expected_checksum))

        return uh

    @classmethod
    def from_json(cls, obj):
        return UnlockHash.from_str(obj)

    @property
    def uhtype(self):
        return self._type

    @uhtype.setter
    def uhtype(self, value):
        if value == None:
            value = UnlockHashType.NIL
        elif not isinstance(value, UnlockHashType):
            raise TypeError(
                "UnlockHash's type has to be of type UnlockHashType, not {}".
                format(type(value)))
        self._type = value

    @property
    def hash(self):
        return self._hash

    @hash.setter
    def hash(self, value):
        self._hash.value = value

    def __str__(self):
        checksum = jshex.bytes_to_hex(
            jsarr.slice_array(self._checksum(), 0, UnlockHash._CHECKSUM_SIZE))
        return "{}{}{}".format(
            jshex.bytes_to_hex(bytes([self._type.__int__()])),
            self._hash.__str__(), checksum)

    def _checksum(self):
        if self._type.__eq__(UnlockHashType.NIL):
            return bytes(jsarr.new_array(UnlockHash._CHECKSUM_SIZE))
        e = RivineBinaryEncoder()
        e.add_int8(self._type.value)
        e.add(self._hash)
        return jscrypto.blake2b(e.data)

    def __repr__(self):
        return self.__str__()

    def json(self):
        return self.__str__()

    def __eq__(self, other):
        other = UnlockHash._op_other_as_unlockhash(other)
        return self.uhtype.__eq__(other.uhtype) and self.hash.__eq__(
            other.hash)

    def __ne__(self, other):
        other = UnlockHash._op_other_as_unlockhash(other)
        return self.uhtype.__ne__(other.uhtype) or self.hash.__ne__(other.hash)

    def __hash__(self):
        return hash(self.__str__())

    @staticmethod
    def _op_other_as_unlockhash(other):
        if isinstance(other, str):
            other = UnlockHash.from_json(other)
        elif not isinstance(other, UnlockHash):
            raise TypeError("UnlockHash of type {} is not supported".format(
                type(other)))
        return other

    def sia_binary_encode(self, encoder):
        """
        Encode this unlock hash according to the Sia Binary Encoding format.
        """
        encoder.add_byte(self._type.__int__())
        encoder.add(self._hash)

    def rivine_binary_encode(self, encoder):
        """
        Encode this unlock hash according to the Rivine Binary Encoding format.
        """
        encoder.add_int8(self._type.__int__())
        encoder.add(self._hash)
Пример #23
0
 def id(self, id):
     if isinstance(id, Hash):
         self._id = Hash(value=id.value)
     self._id = Hash(value=id)
Пример #24
0
class CoinInput(BaseDataTypeClass):
    """
    CoinIput class
    """

    def __init__(self, parentid=None, fulfillment=None, parent_output=None):
        self._parent_id = None
        self.parentid = parentid
        self._fulfillment = None
        self.fulfillment = fulfillment
        # property that can be set if known, but which is not part of the actual CoinInput
        self._parent_output = None
        self.parent_output = parent_output

    @classmethod
    def from_json(cls, obj):
        return cls(
            parentid=Hash.from_json(obj['parentid']),
            fulfillment=FulfillmentTypes.from_json(obj['fulfillment']))

    @classmethod
    def from_coin_output(cls, co):
        if not isinstance(co, CoinOutput):
            raise TypeError(
                "invalid co parameter, expected value of type CoinOutput, not {}".format(type(co)))
        ci = cls(
            parentid=co.id,
            fulfillment=FulfillmentTypes.from_condition(co.condition))
        ci.parent_output = co
        return ci

    @property
    def parentid(self):
        return self._parent_id

    @parentid.setter
    def parentid(self, value):
        if isinstance(value, Hash):
            self._parent_id = Hash(value=value.value)
            return
        self._parent_id = Hash(value=value)

    @property
    def fulfillment(self):
        return self._fulfillment

    @fulfillment.setter
    def fulfillment(self, value):
        if value == None:
            self._fulfillment = FulfillmentSingleSignature()
            return
        if not isinstance(value, FulfillmentBaseClass):
            raise TypeError(
                "cannot assign value of type {} as a  CoinInput's fulfillment (expected: FulfillmentBaseClass)".format(type(value)))
        self._fulfillment = value

    @property
    def has_parent_output(self):
        return self._parent_output != None

    @property
    def parent_output(self):
        return self._parent_output or CoinOutput()

    @parent_output.setter
    def parent_output(self, value):
        if value == None:
            self._parent_output = None
            return
        if not isinstance(value, CoinOutput):
            raise TypeError(
                "cannot assign value of type {} as a CoinInput's parent output (expected: CoinOutput)".format(type(value)))
        self._parent_output = value

    def json(self):
        return {
            'parentid': self._parent_id.json(),
            'fulfillment': self._fulfillment.json()
        }

    def sia_binary_encode(self, encoder):
        """
        Encode this CoinInput according to the Sia Binary Encoding format.
        """
        encoder.add_all(self._parent_id, self._fulfillment)

    def rivine_binary_encode(self, encoder):
        """
        Encode this CoinInput according to the Rivine Binary Encoding format.
        """
        encoder.add_all(self._parent_id, self._fulfillment)

    def signature_requests_new(self, input_hash_func):
        """
        Returns all signature requests that can be generated for this Coin Inputs,
        only possible if the parent (coin) output is defined and when there
        are still signatures required.
        """
        if self._parent_output == None:
            # no requestsd get created if the parent output is not set,
            # this allows for partial Tx signings
            return []
        return self._fulfillment.signature_requests_new(
            input_hash_func=input_hash_func,
            parent_condition=self._parent_output.condition,
        )

    def is_fulfilled(self):
        """
        Returns true if this CoinInput is fulfilled.
        """
        if self._parent_output == None:
            return False
        return self._fulfillment.is_fulfilled(self._parent_output.condition)
Пример #25
0
 def parentid(self, value):
     if isinstance(value, Hash):
         self._parent_id = Hash(value=value.value)
         return
     self._parent_id = Hash(value=value)
Пример #26
0
 def blockid(self, value):
     self._blockid = Hash(value=value)
Пример #27
0
 def block_get(self, value):
     """
     Get a block from an available explorer Node.
     
     @param value: the identifier or height that points to the desired block
     """
     endpoint = "/explorer/?"
     resp = {}
     try:
         # get the explorer block
         if isinstance(value, int):
             endpoint = "/explorer/blocks/{}".format(int(value))
             resp = self.explorer_get(endpoint=endpoint)
             resp = json_loads(resp)
             resp = resp['block']
         else:
             blockid = self._normalize_id(value)
             endpoint = "/explorer/hashes/" + blockid
             resp = self.explorer_get(endpoint=endpoint)
             resp = json_loads(resp)
             if resp['hashtype'] != 'blockid':
                 raise tfchain.errors.ExplorerInvalidResponse(
                     "expected hash type 'blockid' not '{}'".format(
                         resp['hashtype']), endpoint, resp)
             resp = resp['block']
             if resp['blockid'] != blockid:
                 raise tfchain.errors.ExplorerInvalidResponse(
                     "expected block ID '{}' not '{}'".format(
                         blockid, resp['blockid']), endpoint, resp)
         # parse the transactions
         transactions = []
         for etxn in resp['transactions']:
             # parse the explorer transaction
             transaction = self._transaction_from_explorer_transaction(
                 etxn, endpoint=endpoint, resp=resp)
             # append the transaction to the list of transactions
             transactions.append(transaction)
         rawblock = resp['rawblock']
         # parse the parent id
         parentid = Hash.from_json(obj=rawblock['parentid'])
         # parse the miner payouts
         miner_payouts = []
         minerpayoutids = resp.get('minerpayoutids', None) or []
         eminerpayouts = rawblock.get('minerpayouts', None) or []
         if len(eminerpayouts) != len(minerpayoutids):
             raise tfchain.errors.ExplorerInvalidResponse(
                 "amount of miner payouts and payout ids are not matching: {} != {}"
                 .format(len(eminerpayouts),
                         len(minerpayoutids)), endpoint, resp)
         for idx, mp in enumerate(eminerpayouts):
             id = Hash.from_json(minerpayoutids[idx])
             value = Currency.from_json(mp['value'])
             unlockhash = UnlockHash.from_json(mp['unlockhash'])
             miner_payouts.append(
                 ExplorerMinerPayout(id=id,
                                     value=value,
                                     unlockhash=unlockhash))
         # get the timestamp and height
         height = int(resp['height'])
         timestamp = int(rawblock['timestamp'])
         # get the block's identifier
         blockid = Hash.from_json(resp['blockid'])
         # return the block, as reported by the explorer
         return ExplorerBlock(id=blockid,
                              parentid=parentid,
                              height=height,
                              timestamp=timestamp,
                              transactions=transactions,
                              miner_payouts=miner_payouts)
     except KeyError as exc:
         # return a KeyError as an invalid Explorer Response
         raise tfchain.errors.ExplorerInvalidResponse(
             str(exc), endpoint, resp) from exc
Пример #28
0
 def hash(self):
     if self._hash == None:
         return Hash()
     return self._hash
 def __init__(self, uhtype=None, uhhash=None):
     self._type = UnlockHashType.NIL
     self.uhtype = uhtype
     self._hash = Hash()
     self.hash = uhhash
Пример #30
0
 def _normalize_id(self, id):
     return str(Hash(value=id))