Exemple #1
0
 def _from_json_data_object(self, data):
     # decode public key
     if 'pubkey' in data:
         self._public_key = PublicKey.from_json(data['pubkey'])
     else:
         self._public_key = None
     # decode signature
     if 'signature' in data:
         self._signature = ED25519Signature.from_json(data['signature'])
     else:
         self._signature = None
     # decode registration fee
     if 'regfee' in data:
         self.registration_fee = Currency.from_json(data['regfee'])
     else:
         self.registration_fee = None
     # decode transaction fee
     if 'txfee' in data:
         self._transaction_fee = Currency.from_json(data['txfee'])
     else:
         self._transaction_fee = None
     # decode coin inputs
     self._coin_inputs = [
         CoinInput.from_json(ci) for ci in data.get('coininputs', []) or []
     ]
     # decode refund coin output (if it exists)
     if 'refundcoinoutput' in data:
         self._refund_coin_output = CoinOutput.from_json(
             data['refundcoinoutput'])
     else:
         self._refund_coin_output = None
Exemple #2
0
 def _from_json_data_object(self, data):
     # decode address
     if 'address' in data:
         self._address = UnlockHash.from_json(data['address'])
     else:
         self._address = None
     # decode value
     if 'value' in data:
         self._value = Currency.from_json(data['value'])
     else:
         self._value = None
     # decode transaction fee
     if 'txfee' in data:
         self._transaction_fee = Currency.from_json(data['txfee'])
     else:
         self._transaction_fee = None
     # decode blockid
     if 'blockid' in data:
         self._blockid = ERC20Hash.from_json(data['blockid'])
     else:
         self._blockid = None
     # decode transactionid
     if 'txid' in data:
         self._transactionid = ERC20Hash.from_json(data['txid'])
     else:
         self._transactionid = None
Exemple #3
0
 def _from_json_data_object(self, data):
     # decode address
     if 'address' in data:
         self._address = ERC20Address.from_json(data['address'])
     else:
         self._address = None
     # decode value
     if 'value' in data:
         self._value = Currency.from_json(data['value'])
     else:
         self._value = None
     # decode transaction fee
     if 'txfee' in data:
         self._transaction_fee = Currency.from_json(data['txfee'])
     else:
         self._transaction_fee = None
     # decode coin inputs
     self._coin_inputs = [
         CoinInput.from_json(ci) for ci in data.get('coininputs', []) or []
     ]
     # decode refund coin output (if it exists)
     if 'refundcoinoutput' in data:
         self._refund_coin_output = CoinOutput.from_json(
             data['refundcoinoutput'])
     else:
         self._refund_coin_output = None
Exemple #4
0
class BotTransactionBaseClass(TransactionBaseClass, SignatureCallbackBase):
    BOT_FEE_NETWORK_ADDRESS_UPDATE = Currency(value='20 TFT')
    BOT_FEE_ADDITIONAL_NAME = Currency(value='50 TFT')
    BOT_FEE_REGISTRATION = Currency(value='90 TFT')
    BOT_FEE_MONTHLY = Currency(value='10 TFT')

    MAX_NAMES_PER_BOT = 5
    MAX_ADDRESSES_PER_BOT = 10

    SPECIFIER_SENDER = BinaryData(value=b'sender', fixed_size=0)
    SPECIFIER_RECEIVER = BinaryData(value=b'receiver', fixed_size=0)

    @staticmethod
    def compute_monthly_bot_fees(months):
        """
        computes the total monthly fees required for the given months,
        using the given oneCoin value as the currency's unit value.
        """
        fees = BotTransactionBaseClass.BOT_FEE_MONTHLY * months
        if months < 12:
            return fees
        if months < 24:
            return fees * 0.7
        return fees * 0.5

    @property
    @abstractmethod
    def required_bot_fees(self):
        """
        The bot fees required to pay for this Bot Transaction.
        """
        pass
Exemple #5
0
 def registration_fee(self, txfee):
     if txfee is not None:
         fee = Currency(value=txfee)
         if fee != self._registration_fee:
             raise ValueError(
                 "registration fee is hardcoded at {}, cannot be set to {}".
                 format(fee.str(with_unit=True),
                        self._registration_fee.str(with_unit=True)))
Exemple #6
0
    def __init__(self):
        self._public_key = None
        self._signature = None
        self._registration_fee = Currency(
            value=TransactionV210.HARDCODED_REGISTRATION_FEE)
        self._transaction_fee = None
        self._coin_inputs = None
        self._refund_coin_output = None

        super().__init__()
 def unconfirmed_locked(self):
     """
     Total unconfirmed coins that are locked, and thus not available for spending.
     """
     if self.chain_time > 0 and self.chain_height > 0:
         return Currency.sum(*[
             co.value for co in jsobj.dict_values(self._outputs_unconfirmed)
             if co.condition.lock.locked_check(time=self.chain_time,
                                               height=self.chain_height)
         ]) or Currency()
     else:
         return Currency(
         )  # impossible to know for sure without a complete context
 def unconfirmed(self):
     """
     Total unconfirmed coins, available for spending.
     """
     if self.chain_time > 0 and self.chain_height > 0:
         return Currency.sum(*[
             co.value for co in jsobj.dict_values(self._outputs_unconfirmed)
             if not co.condition.lock.locked_check(time=self.chain_time,
                                                   height=self.chain_height)
         ]) or Currency()
     else:
         return Currency.sum(*[
             co.value for co in jsobj.dict_values(self._outputs_unconfirmed)
         ])
    def _fund_individual(self, amount, addresses):
        outputs_available = [
            co for co in self.outputs_available
            if co.condition.unlockhash.__str__() in addresses
        ]

        def sort_output_by_value(a, b):
            if a.value.less_than(b.value):
                return -1
            if a.value.greater_than(b.value):
                return 1
            return 0

        outputs_available = jsarr.sort(outputs_available, sort_output_by_value)

        collected = Currency()
        outputs = []
        # try to fund only with confirmed outputs, if possible
        for co in outputs_available:
            if co.value.greater_than_or_equal_to(amount):
                return [co], co.value
            collected = collected.plus(co.value)
            outputs.append(co)
            if len(outputs) > _MAX_RIVINE_TRANSACTION_INPUTS:
                # to not reach the input limit
                collected = collected.minus(jsarr.pop(outputs, 0).value)
            if collected.greater_than_or_equal_to(amount):
                return outputs, collected

        if collected.greater_than_or_equal_to(amount):
            # if we already have sufficient, we stop now
            return outputs, collected

        # use unconfirmed balance, not ideal, but acceptable
        outputs_available = [
            co for co in self.outputs_unconfirmed_available
            if co.condition.unlockhash.__str__() in addresses
        ]
        outputs_available = jsarr.sort(outputs_available,
                                       sort_output_by_value,
                                       reverse=True)
        for co in outputs_available:
            if co.value.greater_than_or_equal_to(amount):
                return [co], co.value
            collected = collected.plus(co.value)
            outputs.append(co)
            if len(outputs) > _MAX_RIVINE_TRANSACTION_INPUTS:
                # to not reach the input limit
                collected = collected.minus(outputs.pop(0).value)
            if collected.greater_than_or_equal_to(amount):
                return outputs, collected

        # we return whatever we have collected, no matter if it is sufficient
        return outputs, collected
    def fund(self, amount, source=None):
        """
        Fund the specified amount with the available outputs of this wallet's balance.
        """
        # collect addresses and multisig addresses
        addresses = set()
        refund = None
        if source == None:
            for co in self.outputs_available:
                addresses.add(co.condition.unlockhash.__str__())
            for co in self.outputs_unconfirmed_available:
                addresses.add(co.condition.unlockhash.__str__())
        else:
            # if only one address is given, transform it into an acceptable list
            if not isinstance(source, list) and not jsobj.is_js_arr(source):
                if isinstance(source, str):
                    source = UnlockHash.from_json(source)
                elif not isinstance(source, UnlockHash):
                    raise TypeError(
                        "cannot add source address from type {}".format(
                            type(source)))
                source = [source]
            # add one or multiple personal/multisig addresses
            for value in source:
                if isinstance(value, str):
                    value = UnlockHash.from_json(value)
                elif not isinstance(value, UnlockHash):
                    raise TypeError(
                        "cannot add source address from type {}".format(
                            type(value)))
                elif value.uhtype.__eq__(UnlockHashType.PUBLIC_KEY):
                    addresses.add(value)
                else:
                    raise TypeError(
                        "cannot add source address with unsupported UnlockHashType {}"
                        .format(value.uhtype))
            if len(source) == 1:
                if source[0].uhtype.__eq__(UnlockHashType.PUBLIC_KEY):
                    refund = ConditionTypes.unlockhash_new(
                        unlockhash=source[0])

        # ensure at least one address is defined
        if len(addresses) == 0:
            raise tferrors.InsufficientFunds(
                "insufficient funds in this wallet")

        # if personal addresses are given, try to use these first
        # as these are the easiest kind to deal with
        if len(addresses) == 0:
            outputs, collected = ([], Currency())  # start with nothing
        else:
            outputs, collected = self._fund_individual(amount, addresses)

        if collected.greater_than_or_equal_to(amount):
            # if we already have sufficient, we stop now
            return ([CoinInput.from_coin_output(co)
                     for co in outputs], collected.minus(amount), refund)
        raise tferrors.InsufficientFunds(
            "not enough funds available in the wallet to fund the requested amount"
        )
Exemple #11
0
 def _from_json_data_object(self, data):
     self._addresses = [
         NetworkAddress.from_json(address)
         for address in data.get('addresses', []) or []
     ]
     self._names = [
         BotName.from_json(name) for name in data.get('names', []) or []
     ]
     self._number_of_months = int(data.get('nrofmonths', 0) or 0)
     if 'txfee' in data:
         self._transaction_fee = Currency.from_json(data['txfee'])
     else:
         self._transaction_fee = None
     self._coin_inputs = [
         CoinInput.from_json(ci) for ci in data.get('coininputs', []) or []
     ]
     if 'refundcoinoutput' in data:
         self._refund_coin_output = CoinOutput.from_json(
             data['refundcoinoutput'])
     else:
         self._refund_coin_output = None
     if 'identification' not in data or data['identification'] in (None,
                                                                   {}):
         self._public_key = None
         self._signature = None
     else:
         identification = data['identification']
         self._public_key = PublicKey.from_json(identification['publickey'])
         self._signature = ED25519Signature.from_json(
             identification['signature'], as_array=True)
Exemple #12
0
 def _from_json_data_object(self, data):
     self._botid = int(data.get('id', 0) or 0)
     addresses = data.get('addresses', {}) or {}
     self._addresses_to_add = [
         NetworkAddress.from_json(address)
         for address in addresses.get('add', []) or []
     ]
     self._addresses_to_remove = [
         NetworkAddress.from_json(address)
         for address in addresses.get('remove', []) or []
     ]
     names = data.get('names', {}) or {}
     self._names_to_add = [
         BotName.from_json(name) for name in names.get('add', []) or []
     ]
     self._names_to_remove = [
         BotName.from_json(name) for name in names.get('remove', []) or []
     ]
     self._number_of_months = int(data.get('nrofmonths', 0) or 0)
     if 'txfee' in data:
         self._transaction_fee = Currency.from_json(data['txfee'])
     else:
         self._transaction_fee = None
     self._coin_inputs = [
         CoinInput.from_json(ci) for ci in data.get('coininputs', []) or []
     ]
     if 'refundcoinoutput' in data:
         self._refund_coin_output = CoinOutput.from_json(
             data['refundcoinoutput'])
     else:
         self._refund_coin_output = None
     self._signature = ED25519Signature.from_json(
         data.get('signature', None) or None)
Exemple #13
0
 def _from_json_data_object(self, data):
     # decode sender info
     if 'sender' in data:
         bot_data = data['sender']
         self._sender_botid = int(bot_data.get('id', 0) or 0)
         self._sender_signature = ED25519Signature.from_json(bot_data.get('signature', None) or None)
     else:
         self._sender_botid = None
         self._sender_signature = None
     # decode receiver info
     if 'receiver' in data:
         bot_data = data['receiver']
         self._receiver_botid = int(bot_data.get('id', 0) or 0)
         self._receiver_signature = ED25519Signature.from_json(bot_data.get('signature', None) or None)
     else:
         self._receiver_botid = None
         self._receiver_signature = None
     # decode names
     self._names = [BotName.from_json(name) for name in data.get('names', []) or []]
     # decode transaction fee
     if 'txfee' in data:
         self._transaction_fee = Currency.from_json(data['txfee'])
     else:
         self._transaction_fee = None
     # decode coin inputs
     self._coin_inputs = [CoinInput.from_json(ci) for ci in data.get('coininputs', []) or []]
     # decode refund coin output
     if 'refundcoinoutput' in data:
         self._refund_coin_output = CoinOutput.from_json(data['refundcoinoutput'])
     else:
         self._refund_coin_output = None
Exemple #14
0
 def _from_json_data_object(self, data):
     self._nonce = BinaryData.from_json(data.get('nonce', ''),
                                        strencoding='base64')
     self._mint_condition = conditions.from_json(
         data.get('mintcondition', {}))
     self._mint_fulfillment = fulfillments.from_json(
         data.get('mintfulfillment', {}))
     self._miner_fees = [
         Currency.from_json(fee) for fee in data.get('minerfees', []) or []
     ]
     self._data = BinaryData.from_json(data.get('arbitrarydata', None)
                                       or '',
                                       strencoding='base64')
Exemple #15
0
 def _from_json_data_object(self, data):
     self._coin_inputs = [CoinInput.from_json(
         ci) for ci in data.get('coininputs', []) or []]
     self._coin_outputs = [CoinOutput.from_json(
         co) for co in data.get('coinoutputs', []) or []]
     self._blockstake_inputs = [BlockstakeInput.from_json(
         bsi) for bsi in data.get('blockstakeinputs', []) or []]
     self._blockstake_outputs = [BlockstakeOutput.from_json(
         bso) for bso in data.get('blockstakeoutputs', []) or []]
     self._miner_fees = [Currency.from_json(
         fee) for fee in data.get('minerfees', []) or []]
     self._data = BinaryData.from_json(
         data.get('arbitrarydata', None) or '', strencoding='base64')
Exemple #16
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
Exemple #17
0
 def coin_outputs(self):
     """
     Coin outputs of this Transaction,
     funded by the Transaction's coin inputs.
     """
     outputs = []
     if self.fee_payout_address != None and len(self.miner_fees) > 0:
         amount = Currency.sum(*self.miner_fees)
         condition = ConditionTypes.from_recipient(self.fee_payout_address)
         outputs.append(
             CoinOutput(value=amount,
                        condition=condition,
                        id=self._fee_payout_id,
                        is_fee=True))
     return jsarr.concat(outputs, self._custom_coin_outputs_getter())
Exemple #18
0
 def _from_json_data_object(self, data):
     self._nonce = BinaryData.from_json(data.get('nonce', ''),
                                        strencoding='base64')
     self._mint_fulfillment = FulfillmentTypes.from_json(
         data.get('mintfulfillment', {}))
     self._coin_outputs = [
         CoinOutput.from_json(co)
         for co in data.get('coinoutputs', []) or []
     ]
     self._miner_fees = [
         Currency.from_json(fee) for fee in data.get('minerfees', []) or []
     ]
     self._data = BinaryData.from_json(data.get('arbitrarydata', None)
                                       or '',
                                       strencoding='base64')
Exemple #19
0
 def required_bot_fees(self):
     """
     The fees required to pay for this 3Bot Record Update Transaction.
     """
     fees = Currency(value=0)
     # all months have to be paid
     if self._number_of_months > 0:
         fees += BotTransactionBaseClass.compute_monthly_bot_fees(self._number_of_months)
     # if addresses have been modified, this has to be paid
     if len(self._addresses_to_add) > 0 or len(self._addresses_to_remove) > 0:
         fees += BotTransactionBaseClass.BOT_FEE_NETWORK_ADDRESS_UPDATE
     # each additional that is added, has to be paid as well
     lnames = len(self._names_to_add)
     if lnames > 0:
         fees += BotTransactionBaseClass.BOT_FEE_ADDITIONAL_NAME * lnames
     # return the total fees
     return fees
Exemple #20
0
 def value(self, value):
     if isinstance(value, Currency):
         self._value = value
         return
     self._value = Currency(value=value)
Exemple #21
0
 def from_json(cls, obj):
     return cls(
         value=Currency.from_json(obj['value']),
         condition=ConditionTypes.from_json(obj['condition']))
Exemple #22
0
class CoinOutput(BaseDataTypeClass):
    """
    CoinOutput class
    """

    def __init__(self, value=None, condition=None, id=None, is_fee=False):
        self._value = None
        self.value = value
        self._condition = None
        self.condition = condition
        # property that can be set if known, but which is not part of the actual CoinOutput
        self._id = None
        self.id = id
        self._is_fee = False
        self.is_fee = is_fee

    @classmethod
    def from_json(cls, obj):
        return cls(
            value=Currency.from_json(obj['value']),
            condition=ConditionTypes.from_json(obj['condition']))

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, value):
        if isinstance(value, Currency):
            self._value = value
            return
        self._value = Currency(value=value)

    @property
    def condition(self):
        return self._condition

    @condition.setter
    def condition(self, value):
        if value == None:
            self._condition = ConditionNil()
            return
        if not isinstance(value, ConditionBaseClass):
            raise TypeError(
                "cannot assign value of type {} as a CoinOutput's condition (expected: ConditionBaseClass subtype)".format(type(value)))
        self._condition = value

    @property
    def id(self):
        return self._id

    @id.setter
    def id(self, value):
        if isinstance(value, Hash):
            self._id = Hash(value=value.value)
            return
        self._id = Hash(value=value)

    @property
    def is_fee(self):
        return self._is_fee

    @is_fee.setter
    def is_fee(self, value):
        if not isinstance(value, bool):
            raise TypeError("is fee is supposed to be a bool, cannot be {} ({})".format(value, type(value)))
        self._is_fee = value

    def json(self):
        return {
            'value': self._value.json(),
            'condition': self._condition.json()
        }

    def sia_binary_encode(self, encoder):
        """
        Encode this CoinOutput according to the Sia Binary Encoding format.
        """
        encoder.add_all(self._value, self._condition)

    def rivine_binary_encode(self, encoder):
        """
        Encode this CoinOutput according to the Rivine Binary Encoding format.
        """
        encoder.add_all(self._value, self._condition)
Exemple #23
0
 def transaction_fee(self, txfee):
     if txfee is None:
         self._transaction_fee = None
     else:
         self._transaction_fee = Currency(value=txfee)
Exemple #24
0
 def transaction_fee(self):
     if self._transaction_fee is None:
         return Currency()
     return self._transaction_fee
Exemple #25
0
 def minimum_miner_fee(self):
     if self == NetworkType.DEVNET:
         return Currency('1.0')
     return Currency('0.1')
Exemple #26
0
class TransactionV210(TransactionBaseClass, SignatureCallbackBase):
    _SPECIFIER = b'erc20 addrreg tx'

    HARDCODED_REGISTRATION_FEE = '10 TFT'
    SPECIFIER_REGISTRATION_SIGNATURE = BinaryData(value=b'registration',
                                                  fixed_size=0)

    def __init__(self):
        self._public_key = None
        self._signature = None
        self._registration_fee = Currency(
            value=TransactionV210.HARDCODED_REGISTRATION_FEE)
        self._transaction_fee = None
        self._coin_inputs = None
        self._refund_coin_output = None

        super().__init__()

    @property
    def version(self):
        return TransactionVersion.ERC20_ADDRESS_REGISTRATION

    @property
    def public_key(self):
        if self._public_key is None:
            return PublicKey()
        return self._public_key

    @public_key.setter
    def public_key(self, value):
        if value is None:
            self._public_key = None
            return
        if not isinstance(value, PublicKey):
            raise TypeError(
                "cannot assign value of type {} as BotRegistration's public key (expected type: PublicKey)"
                .format(type(value)))
        self._public_key = PublicKey(specifier=value.specifier,
                                     hash=value.hash)

    @property
    def signature(self):
        if self._signature is None:
            return ED25519Signature(as_array=True)
        return self._signature

    @signature.setter
    def signature(self, value):
        if value is None:
            self._signature = None
            return
        self._signature = ED25519Signature(value=value, as_array=True)

    @property
    def coin_inputs(self):
        """
        Coin inputs of this Transaction,
        used as funding for coin outputs, fees and any other kind of coin output.
        """
        return self._coin_inputs

    @coin_inputs.setter
    def coin_inputs(self, value):
        self._coin_inputs = []
        if not value:
            return
        for ci in value:
            self.coin_input_add(ci.parentid,
                                ci.fulfillment,
                                parent_output=ci.parent_output)

    @property
    def refund_coin_output(self):
        if self._refund_coin_output is None:
            return CoinOutput()
        return self._refund_coin_output

    @property
    def coin_outputs(self):
        """
        Empty list, or a singleton with the refund coin output if that one exists.
        """
        if self._refund_coin_output is None:
            return []
        return [self._refund_coin_output]

    @coin_outputs.setter
    def coin_outputs(self, value):
        if isinstance(value, list):
            lvalue = len(value)
            if lvalue == 0:
                value = None
            elif lvalue == 1:
                value = value[0]
            else:
                raise ValueError(
                    "ThreeBot only can have one coin output, a refund coin output"
                )
        if value is None:
            self._refund_coin_output = None
        elif isinstance(value, CoinOutput):
            self._refund_coin_output = CoinOutput(value=value.value,
                                                  condition=value.condition)
            self._refund_coin_output.id = value.id
        else:
            raise TypeError(
                "cannot assign a value of type {} to coin outputs".format(
                    type(value)))

    def coin_input_add(self, parentid, fulfillment, parent_output=None):
        ci = CoinInput(parentid=parentid, fulfillment=fulfillment)
        ci.parent_output = parent_output
        self._coin_inputs.append(ci)

    def refund_coin_output_set(self, value, condition, id=None):
        co = CoinOutput(value=value, condition=condition)
        co.id = id
        self._refund_coin_output = co

    @property
    def registration_fee(self):
        return self._registration_fee

    @registration_fee.setter
    def registration_fee(self, txfee):
        if txfee is not None:
            fee = Currency(value=txfee)
            if fee != self._registration_fee:
                raise ValueError(
                    "registration fee is hardcoded at {}, cannot be set to {}".
                    format(fee.str(with_unit=True),
                           self._registration_fee.str(with_unit=True)))

    @property
    def transaction_fee(self):
        if self._transaction_fee is None:
            return Currency()
        return self._transaction_fee

    @transaction_fee.setter
    def transaction_fee(self, txfee):
        if txfee is None:
            self._transaction_fee = None
        else:
            self._transaction_fee = Currency(value=txfee)

    @property
    def miner_fees(self):
        if self._transaction_fee is None:
            return []
        return [self._transaction_fee]

    def signature_add(self, public_key, signature):
        """
        Implements SignatureCallbackBase.
        """
        if self._public_key.unlockhash != public_key.unlockhash:
            raise ValueError(
                "given public key ({}) does not equal public key ({})".format(
                    str(self._public_key.unlockhash),
                    str(public_key.unlockhash)))
        self.signature = signature

    def _signature_hash_input_get(self, *extra_objects):
        e = encoder_rivine_get()

        # encode the transaction version
        e.add_int8(self.version)

        # encode the specifier
        e.add_array(TransactionV210._SPECIFIER)

        # encode the public key
        e.add_all(self.public_key)

        # extra objects if any
        if extra_objects:
            e.add_all(*extra_objects)

        # encode coin inputs
        e.add(len(self.coin_inputs))
        for ci in self.coin_inputs:
            e.add(ci.parentid)

        # encode registration and transaction fee
        e.add_all(self.registration_fee, self.transaction_fee)

        # encode refund coin output
        if self._refund_coin_output is None:
            e.add_int8(0)
        else:
            e.add_int8(1)
            e.add(self._refund_coin_output)

        # return data
        return e.data

    def _id_input_compute(self):
        return bytearray(
            TransactionV210._SPECIFIER) + self._binary_encode_data()

    def _binary_encode_data(self):
        e = encoder_rivine_get()
        # encode all easy properties
        e.add_all(self.public_key, self.signature, self.registration_fee,
                  self.transaction_fee, self.coin_inputs)
        # encode the only "pointer" property
        if self._refund_coin_output is None:
            e.add_int8(0)
        else:
            e.add_int8(1)
            e.add(self._refund_coin_output)

        # return encoded data
        return e.data

    def _from_json_data_object(self, data):
        # decode public key
        if 'pubkey' in data:
            self._public_key = PublicKey.from_json(data['pubkey'])
        else:
            self._public_key = None
        # decode signature
        if 'signature' in data:
            self._signature = ED25519Signature.from_json(data['signature'])
        else:
            self._signature = None
        # decode registration fee
        if 'regfee' in data:
            self.registration_fee = Currency.from_json(data['regfee'])
        else:
            self.registration_fee = None
        # decode transaction fee
        if 'txfee' in data:
            self._transaction_fee = Currency.from_json(data['txfee'])
        else:
            self._transaction_fee = None
        # decode coin inputs
        self._coin_inputs = [
            CoinInput.from_json(ci) for ci in data.get('coininputs', []) or []
        ]
        # decode refund coin output (if it exists)
        if 'refundcoinoutput' in data:
            self._refund_coin_output = CoinOutput.from_json(
                data['refundcoinoutput'])
        else:
            self._refund_coin_output = None

    def _json_data_object(self):
        tftaddress = self.public_key.unlockhash
        erc20address = ERC20Address.from_unlockhash(tftaddress)
        output = {
            'pubkey': self.public_key.json(),
            'tftaddress': tftaddress.json(),
            'erc20address': erc20address.json(),
            'signature': self.signature.json(),
            'regfee': self.registration_fee.json(),
            'txfee': self.transaction_fee.json(),
            'coininputs': [ci.json() for ci in self.coin_inputs],
        }
        if self._refund_coin_output is not None:
            output['refundcoinoutput'] = self._refund_coin_output.json()
        return output

    def _extra_signature_requests_new(self):
        if self._public_key is None:
            # if no parent public key is defined, cannot do anything
            return []
        if self._signature is not None:
            return []  # nothing to do
        # generate the input hash func
        input_hash_func = InputSignatureHashFactory(
            self, TransactionV210.SPECIFIER_REGISTRATION_SIGNATURE
        ).signature_hash_new
        # define the input_hash_new generator function,
        # used to create the input hash for creating the signature
        unlockhash = self._public_key.unlockhash

        def input_hash_gen(public_key):
            return input_hash_func()

        # create the only signature request
        return [
            SignatureRequest(unlockhash=unlockhash,
                             input_hash_gen=input_hash_gen,
                             callback=self)
        ]

    def _extra_is_fulfilled(self):
        return self._signature is not None
Exemple #27
0
 def value(self):
     if self._value is None:
         return Currency()
     return self._value
Exemple #28
0
 def value(self, value):
     if value is None:
         self._value = None
     else:
         self._value = Currency(value=value)
Exemple #29
0
 def miner_fee_add(self, value):
     self._miner_fees.append(Currency(value=value))
 def available(self):
     """
     Total available coins.
     """
     return Currency.sum(*[co.value for co in self.outputs_available])