Exemplo n.º 1
0
class TransactionV129(TransactionBaseClass):
    _SPECIFIER = b'coin mint tx\0\0\0\0'

    def __init__(self):
        self._mint_fulfillment = None
        self._coin_outputs = []
        self._miner_fees = []
        self._data = None
        self._nonce = BinaryData(generateXByteID(8), strencoding='base64')

        # current mint condition
        self._parent_mint_condition = None

        super().__init__()

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

    @property
    def miner_fees(self):
        """
        Miner fees, paid to the block creator of this Transaction,
        funded by this Transaction's coin inputs.
        """
        return self._miner_fees

    @property
    def data(self):
        """
        Optional binary data attached to this Transaction,
        with a max length of 83 bytes.
        """
        if self._data is None:
            return BinaryData(strencoding='base64')
        return self._data

    @data.setter
    def data(self, value):
        if value is None:
            self._data = None
            return
        if isinstance(value, BinaryData):
            value = value.value
        elif isinstance(value, str):
            value = value.encode('utf-8')
        if len(value) > 83:
            raise ValueError(
                "arbitrary data can have a maximum bytes length of 83, {} exceeds this limit"
                .format(len(value)))
        self._data = BinaryData(value=value, strencoding='base64')

    @property
    def coin_outputs(self):
        """
        Coin outputs of this Transaction,
        funded by the Transaction's coin inputs.
        """
        return self._coin_outputs

    @coin_outputs.setter
    def coin_outputs(self, value):
        self._coin_outputs = []
        if not value:
            return
        for co in value:
            self.coin_output_add(co.value, co.condition, id=co.id)

    def coin_output_add(self, value, condition, id=None):
        co = CoinOutput(value=value, condition=condition)
        co.id = id
        self._coin_outputs.append(co)

    def miner_fee_add(self, value):
        self._miner_fees.append(Currency(value=value))

    def mint_fulfillment_defined(self):
        return self._mint_fulfillment is not None

    @property
    def mint_fulfillment(self):
        """
        Retrieve the current mint fulfillment
        """
        if self._mint_fulfillment is None:
            return FulfillmentSingleSignature()
        return self._mint_fulfillment

    @mint_fulfillment.setter
    def mint_fulfillment(self, value):
        if value is None:
            self._mint_fulfillment = None
            return
        if not isinstance(value, FulfillmentBaseClass):
            raise TypeError(
                "CoinCreation (v129) Transaction's mint fulfillment has to be a subtype of FulfillmentBaseClass, not {}"
                .format(type(value)))
        self._mint_fulfillment = value

    @property
    def parent_mint_condition(self):
        """
        Retrieve the parent mint condition which will be set
        """
        if self._parent_mint_condition is None:
            return ConditionNil()
        return self._parent_mint_condition

    @parent_mint_condition.setter
    def parent_mint_condition(self, value):
        if value is None:
            self._parent_mint_condition = None
            return
        if not isinstance(value, ConditionBaseClass):
            raise TypeError(
                "CoinCreation (v129) Transaction's parent mint condition has to be a subtype of ConditionBaseClass, not {}"
                .format(type(value)))
        self._parent_mint_condition = value

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

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

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

        # encode nonce
        e.add_array(self._nonce.value)

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

        # encode coin outputs
        e.add_slice(self.coin_outputs)

        # encode miner fees
        e.add_slice(self.miner_fees)

        # encode custom data
        e.add(self.data)

        # return the encoded data
        return e.data

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

    def _binary_encode_data(self):
        encoder = encoder_sia_get()
        encoder.add_array(self._nonce.value)
        encoder.add_all(
            self.mint_fulfillment,
            self.coin_outputs,
            self.miner_fees,
            self.data,
        )
        return encoder.data

    def _from_json_data_object(self, data):
        self._nonce = BinaryData.from_json(data.get('nonce', ''),
                                           strencoding='base64')
        self._mint_fulfillment = fulfillments.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')

    def _json_data_object(self):
        return {
            'nonce': self._nonce.json(),
            'mintfulfillment': self.mint_fulfillment.json(),
            'coinoutputs': [co.json() for co in self.coin_outputs],
            'minerfees': [fee.json() for fee in self.miner_fees],
            'arbitrarydata': self.data.json(),
        }

    def _extra_signature_requests_new(self):
        if self._parent_mint_condition is None:
            return []  # nothing to be signed
        return self._mint_fulfillment.signature_requests_new(
            # no extra objects are to be included within txn scope
            input_hash_func=self.signature_hash_get,
            parent_condition=self._parent_mint_condition,
        )

    def _extra_is_fulfilled(self):
        if self._parent_mint_condition is None:
            return False
        return self.mint_fulfillment.is_fulfilled(
            parent_condition=self._parent_mint_condition)
Exemplo n.º 2
0
class TransactionV128(TransactionBaseClass):
    _SPECIFIER = b'minter defin tx\0'

    def __init__(self):
        self._mint_fulfillment = None
        self._mint_condition = None
        self._miner_fees = []
        self._data = None
        self._nonce = BinaryData(crandom(8), strencoding='base64')

        # current mint condition
        self._parent_mint_condition = None

        super().__init__()

    def _custom_version_getter(self):
        return TransactionVersion.MINTER_DEFINITION

    def _custom_miner_fees_getter(self):
        """
        Miner fees, paid to the block creator of this Transaction,
        funded by this Transaction's coin inputs.
        """
        return self._miner_fees

    def _custom_data_getter(self):
        """
        Optional binary data attached to this Transaction,
        with a max length of 83 bytes.
        """
        if self._data == None:
            return BinaryData(strencoding='base64')
        return self._data

    def _custom_data_setter(self, value):
        if value == None:
            self._data = None
            return
        if isinstance(value, BinaryData):
            value = value.value
        elif isinstance(value, str):
            value = jsstr.to_utf8(value)
        if len(value) > 83:
            raise ValueError(
                "arbitrary data can have a maximum bytes length of 83, {} exceeds this limit"
                .format(len(value)))
        self._data = BinaryData(value=value, strencoding='base64')

    @property
    def mint_condition(self):
        """
        Retrieve the new mint condition which will be set
        """
        if self._mint_condition == None:
            return ConditionNil()
        return self._mint_condition

    @mint_condition.setter
    def mint_condition(self, value):
        if value == None:
            self._mint_condition = None
            return
        if not isinstance(value, ConditionBaseClass):
            raise TypeError(
                "MintDefinition (v128) Transaction's mint condition has to be a subtype of ConditionBaseClass, not {}"
                .format(type(value)))
        self._mint_condition = value

    @property
    def parent_mint_condition(self):
        """
        Retrieve the parent mint condition which will be set
        """
        if self._parent_mint_condition == None:
            return ConditionNil()
        return self._parent_mint_condition

    @parent_mint_condition.setter
    def parent_mint_condition(self, value):
        if value == None:
            self._parent_mint_condition = None
            return
        if not isinstance(value, ConditionBaseClass):
            raise TypeError(
                "MintDefinition (v128) Transaction's parent mint condition has to be a subtype of ConditionBaseClass, not {}"
                .format(type(value)))
        self._parent_mint_condition = value

    def mint_fulfillment_defined(self):
        return self._mint_fulfillment != None

    @property
    def mint_fulfillment(self):
        """
        Retrieve the current mint fulfillment
        """
        if self._mint_fulfillment == None:
            return FulfillmentSingleSignature()
        return self._mint_fulfillment

    @mint_fulfillment.setter
    def mint_fulfillment(self, value):
        if value == None:
            self._mint_fulfillment = None
            return
        if not isinstance(value, FulfillmentBaseClass):
            raise TypeError(
                "MintDefinition (v128) Transaction's mint fulfillment has to be a subtype of FulfillmentBaseClass, not {}"
                .format(type(value)))
        self._mint_fulfillment = value

    def miner_fee_add(self, value):
        self._miner_fees.append(Currency(value=value))

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

        # encode the transaction version
        e.add_byte(self.version.value)

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

        # encode nonce
        e.add_array(self._nonce.value)

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

        # encode new mint condition
        e.add(self.mint_condition)

        # encode miner fees
        e.add_slice(self.miner_fees)

        # encode custom data
        e.add(self.data)

        # return the encoded data
        return e.data

    def _id_input_compute(self):
        return jsarr.concat(TransactionV128._SPECIFIER,
                            self._binary_encode_data())

    def _binary_encode_data(self):
        encoder = SiaBinaryEncoder()
        encoder.add_array(self._nonce.value)
        encoder.add_all(
            self.mint_fulfillment,
            self.mint_condition,
            self.miner_fees,
            self.data,
        )

        return encoder.data

    def _from_json_data_object(self, data):
        self._nonce = BinaryData.from_json(data.get_or('nonce', ''),
                                           strencoding='base64')
        self._mint_condition = ConditionTypes.from_json(
            data.get_or('mintcondition', jsobj.new_dict()))
        self._mint_fulfillment = FulfillmentTypes.from_json(
            data.get_or('mintfulfillment', jsobj.new_dict()))
        self._miner_fees = [
            Currency.from_json(fee)
            for fee in data.get_or('minerfees', []) or []
        ]
        self._data = BinaryData.from_json(data.get_or('arbitrarydata', None)
                                          or '',
                                          strencoding='base64')

    def _json_data_object(self):
        return {
            'nonce': self._nonce.json(),
            'mintfulfillment': self.mint_fulfillment.json(),
            'mintcondition': self.mint_condition.json(),
            'minerfees': [fee.json() for fee in self._miner_fees],
            'arbitrarydata': self.data.json(),
        }

    def _extra_signature_requests_new(self):
        if self._parent_mint_condition == None:
            return []  # nothing to be signed
        return self._mint_fulfillment.signature_requests_new(
            # no extra objects are to be included within txn scope
            input_hash_func=self.signature_hash_get,
            parent_condition=self._parent_mint_condition,
        )

    def _extra_is_fulfilled(self):
        if self._parent_mint_condition == None:
            return False
        return self.mint_fulfillment.is_fulfilled(
            parent_condition=self._parent_mint_condition)