示例#1
0
    def finalize(self):
        # type: () -> None
        """
    Finalizes the bundle, preparing it to be attached to the Tangle.
    """
        if self.hash:
            raise RuntimeError('Bundle is already finalized.')

        if not self:
            raise ValueError('Bundle has no transactions.')

        # Quick validation.
        balance = self.balance

        if balance < 0:
            if self.change_address:
                self.add_transaction(
                    ProposedTransaction(
                        address=self.change_address,
                        value=-balance,
                        tag=self.tag,
                    ))
            else:
                raise ValueError(
                    'Bundle has unspent inputs (balance: {balance}); '
                    'use ``send_unspent_inputs_to`` to create '
                    'change transaction.'.format(balance=balance, ), )
        elif balance > 0:
            raise ValueError(
                'Inputs are insufficient to cover bundle spend '
                '(balance: {balance}).'.format(balance=balance, ), )

        # Generate bundle hash.
        sponge = Curl()
        last_index = len(self) - 1

        for (i,
             txn) in enumerate(self):  # type: Tuple[int, ProposedTransaction]
            txn.current_index = i
            txn.last_index = last_index

            sponge.absorb(txn.get_signature_validation_trytes().as_trits())

        bundle_hash_trits = [0] * HASH_LENGTH  # type: MutableSequence[int]
        sponge.squeeze(bundle_hash_trits)

        # Copy bundle hash to individual transactions.
        bundle_hash = BundleHash.from_trits(bundle_hash_trits)
        for txn in self:
            txn.bundle_hash = bundle_hash

            # Initialize signature/message fragment.
            txn.signature_message_fragment = Fragment(txn.message or b'')
示例#2
0
    def calc_hash(self, bundle):
        Trxn_HASH_Trytes = 81
        HASH_LENGTH = Trxn_HASH_Trytes * 3  # Trits conversion

        # Generate bundle hash. (taken from python API client)
        while True:
            sponge = Kerl()
            last_index = len(bundle) - 1

            for i, txn in enumerate(bundle):
                txn.current_index = i
                txn.last_index = last_index

                sponge.absorb(txn.get_bundle_essence_trits())

            bundle_hash_trits = [0] * HASH_LENGTH
            sponge.squeeze(bundle_hash_trits)

            bundle_hash = BundleHash.from_trits(
                bundle_hash_trits)  # Convert trits to ascii Trytes
            bundle.bundle_hash = bundle_hash
            # Check that we generated a secure bundle hash.
            # https://github.com/iotaledger/iota.py/issues/84
            if any(13 in part for part in normalize(bundle_hash)):
                # Increment the legacy tag and try again.
                bundle.tail_transaction.increment_legacy_tag()
            else:
                break

        # Copy bundle hash to individual transactions.
        for txn in bundle:
            txn.bundle_hash = bundle_hash

            # Initialize signature/message fragment.
            if not txn.value_trxn:
                # Put dummy message in fragment.
                # txn.signature_message_fragment = Fragment('9' * 2187) # Fragment Length
                txn.signature_message_fragment = Fragment(
                    TryteString.from_string(
                        'IOTA is cool! This is a meta transaction!')
                )  # Fragment Length
            else:
                # Generate signature for bundle transaction
                txn.signature_message_fragment = self.genSig(
                    bundleHash=bundle_hash)
                bundle.data_payload = self.name + " (" + str(
                    bundle.outputTrxn.value
                ) + ") ->" + bundle.outputTrxn.recName

        return self.conductPOW(bundle)
示例#3
0
    def from_tryte_string(cls, trytes, hash_=None):
        # type: (TrytesCompatible, Optional[TransactionHash]) -> Transaction
        """
        Creates a Transaction object from a sequence of trytes.

        :param trytes:
            Raw trytes.  Should be exactly 2673 trytes long.

        :param hash_:
            The transaction hash, if available.

            If not provided, it will be computed from the transaction
            trytes.
        """
        tryte_string = TransactionTrytes(trytes)

        if not hash_:
            hash_trits = [0] * HASH_LENGTH  # type: MutableSequence[int]

            sponge = Curl()
            sponge.absorb(tryte_string.as_trits())
            sponge.squeeze(hash_trits)

            hash_ = TransactionHash.from_trits(hash_trits)

        return cls(
            hash_=hash_,
            signature_message_fragment=Fragment(tryte_string[0:2187]),
            address=Address(tryte_string[2187:2268]),
            value=int_from_trits(tryte_string[2268:2295].as_trits()),
            legacy_tag=Tag(tryte_string[2295:2322]),
            timestamp=int_from_trits(tryte_string[2322:2331].as_trits()),
            current_index=int_from_trits(tryte_string[2331:2340].as_trits()),
            last_index=int_from_trits(tryte_string[2340:2349].as_trits()),
            bundle_hash=BundleHash(tryte_string[2349:2430]),
            trunk_transaction_hash=TransactionHash(tryte_string[2430:2511]),
            branch_transaction_hash=TransactionHash(tryte_string[2511:2592]),
            tag=Tag(tryte_string[2592:2619]),
            attachment_timestamp=int_from_trits(
                tryte_string[2619:2628].as_trits()),
            attachment_timestamp_lower_bound=int_from_trits(
                tryte_string[2628:2637].as_trits()),
            attachment_timestamp_upper_bound=int_from_trits(
                tryte_string[2637:2646].as_trits()),
            nonce=Nonce(tryte_string[2646:2673]),
        )
示例#4
0
  def test_finalize_insecure_bundle(self):
    """
    When finalizing, the bundle detects an insecure bundle hash.

    References:
      - https://github.com/iotaledger/iota.lib.py/issues/84
    """
    # noinspection SpellCheckingInspection
    bundle =\
      ProposedBundle([
        ProposedTransaction(
          address =\
            Address(
              '9XV9RJGFJJZWITDPKSQXRTHCKJAIZZY9BYLBEQUX'
              'UNCLITRQDR9CCD99AANMXYEKD9GLJGVB9HIAGRIBQ',
            ),

          tag       = Tag('PPDIDNQDJZGUQKOWJ9JZRCKOVGP'),
          timestamp = 1509136296,
          value     = 0,
        ),
      ])

    bundle.finalize()

    # The resulting bundle hash is insecure (contains a [1, 1, 1]), so
    # the legacy tag is manipulated until a secure hash is generated.
    # noinspection SpellCheckingInspection
    self.assertEqual(bundle[0].legacy_tag, Tag('ZTDIDNQDJZGUQKOWJ9JZRCKOVGP'))

    # The proper tag is left alone, however.
    # noinspection SpellCheckingInspection
    self.assertEqual(bundle[0].tag, Tag('PPDIDNQDJZGUQKOWJ9JZRCKOVGP'))

    # The bundle hash takes the modified legacy tag into account.
    # noinspection SpellCheckingInspection
    self.assertEqual(
      bundle.hash,

      BundleHash(
        'NYSJSEGCWESDAFLIFCNJFWGZ9PCYDOT9VCSALKBD'
        '9UUNKBJAJCB9KVMTHZDPRDDXC9UFJQBJBQFUPJKFC',
      )
    )
示例#5
0
    def finalize(self):
        # type: () -> None
        """
    Finalizes the bundle, preparing it to be attached to the Tangle.
    """
        if self.hash:
            raise RuntimeError('Bundle is already finalized.')

        if not self:
            raise ValueError('Bundle has no transactions.')

        # Quick validation.
        balance = self.balance

        if balance < 0:
            if self.change_address:
                self.add_transaction(
                    ProposedTransaction(
                        address=self.change_address,
                        value=-balance,
                        tag=self.tag,
                    ))
            else:
                raise ValueError(
                    'Bundle has unspent inputs (balance: {balance}); '
                    'use ``send_unspent_inputs_to`` to create '
                    'change transaction.'.format(balance=balance, ), )
        elif balance > 0:
            raise ValueError(
                'Inputs are insufficient to cover bundle spend '
                '(balance: {balance}).'.format(balance=balance, ), )

        # Generate bundle hash.
        while True:
            sponge = Kerl()
            last_index = len(self) - 1

            for (i, txn
                 ) in enumerate(self):  # type: Tuple[int, ProposedTransaction]
                txn.current_index = i
                txn.last_index = last_index

                sponge.absorb(txn.get_signature_validation_trytes().as_trits())

            bundle_hash_trits = [0] * HASH_LENGTH  # type: MutableSequence[int]
            sponge.squeeze(bundle_hash_trits)

            bundle_hash = BundleHash.from_trits(bundle_hash_trits)

            # Check that we generated a secure bundle hash.
            # https://github.com/iotaledger/iota.lib.py/issues/84
            if any(13 in part for part in normalize(bundle_hash)):
                # Increment the legacy tag and try again.
                tail_transaction = self.tail_transaction  # type: ProposedTransaction
                tail_transaction.increment_legacy_tag()
            else:
                break

        # Copy bundle hash to individual transactions.
        for txn in self:
            txn.bundle_hash = bundle_hash

            # Initialize signature/message fragment.
            txn.signature_message_fragment = Fragment(txn.message or b'')
示例#6
0
    def from_tryte_string(cls: Type[T],
                          trytes: TrytesCompatible,
                          hash_: Optional[TransactionHash] = None) -> T:
        """
        Creates a Transaction object from a sequence of trytes.

        :param TrytesCompatible trytes:
            Raw trytes.  Should be exactly 2673 trytes long.

        :param Optional[TransactionHash] hash_:
            The transaction hash, if available.

            If not provided, it will be computed from the transaction
            trytes.

        :return:
            :py:class:`Transaction` object.

        Example usage::

            from iota import Transaction

            txn =\\
              Transaction.from_tryte_string(
                b'GYPRVHBEZOOFXSHQBLCYW9ICTCISLHDBNMMVYD9JJHQMPQCTIQAQTJNNNJ9IDXLRCC'
                b'OYOXYPCLR9PBEY9ORZIEPPDNTI9CQWYZUOTAVBXPSBOFEQAPFLWXSWUIUSJMSJIIIZ'
                b'WIKIRH9GCOEVZFKNXEVCUCIIWZQCQEUVRZOCMEL9AMGXJNMLJCIA9UWGRPPHCEOPTS'
                b'VPKPPPCMQXYBHMSODTWUOABPKWFFFQJHCBVYXLHEWPD9YUDFTGNCYAKQKVEZYRBQRB'
                b'XIAUX9SVEDUKGMTWQIYXRGSWYRK9SRONVGTW9YGHSZRIXWGPCCUCDRMAXBPDFVHSRY'
                b'WHGB9DQSQFQKSNICGPIPTRZINYRXQAFSWSEWIFRMSBMGTNYPRWFSOIIWWT9IDSELM9'
                b'JUOOWFNCCSHUSMGNROBFJX9JQ9XT9PKEGQYQAWAFPRVRRVQPUQBHLSNTEFCDKBWRCD'
                b'X9EYOBB9KPMTLNNQLADBDLZPRVBCKVCYQEOLARJYAGTBFR9QLPKZBOYWZQOVKCVYRG'
                b'YI9ZEFIQRKYXLJBZJDBJDJVQZCGYQMROVHNDBLGNLQODPUXFNTADDVYNZJUVPGB9LV'
                b'PJIYLAPBOEHPMRWUIAJXVQOEM9ROEYUOTNLXVVQEYRQWDTQGDLEYFIYNDPRAIXOZEB'
                b'CS9P99AZTQQLKEILEVXMSHBIDHLXKUOMMNFKPYHONKEYDCHMUNTTNRYVMMEYHPGASP'
                b'ZXASKRUPWQSHDMU9VPS99ZZ9SJJYFUJFFMFORBYDILBXCAVJDPDFHTTTIYOVGLRDYR'
                b'TKHXJORJVYRPTDH9ZCPZ9ZADXZFRSFPIQKWLBRNTWJHXTOAUOL9FVGTUMMPYGYICJD'
                b'XMOESEVDJWLMCVTJLPIEKBE9JTHDQWV9MRMEWFLPWGJFLUXI9BXPSVWCMUWLZSEWHB'
                b'DZKXOLYNOZAPOYLQVZAQMOHGTTQEUAOVKVRRGAHNGPUEKHFVPVCOYSJAWHZU9DRROH'
                b'BETBAFTATVAUGOEGCAYUXACLSSHHVYDHMDGJP9AUCLWLNTFEVGQGHQXSKEMVOVSKQE'
                b'EWHWZUDTYOBGCURRZSJZLFVQQAAYQO9TRLFFN9HTDQXBSPPJYXMNGLLBHOMNVXNOWE'
                b'IDMJVCLLDFHBDONQJCJVLBLCSMDOUQCKKCQJMGTSTHBXPXAMLMSXRIPUBMBAWBFNLH'
                b'LUJTRJLDERLZFUBUSMF999XNHLEEXEENQJNOFFPNPQ9PQICHSATPLZVMVIWLRTKYPI'
                b'XNFGYWOJSQDAXGFHKZPFLPXQEHCYEAGTIWIJEZTAVLNUMAFWGGLXMBNUQTOFCNLJTC'
                b'DMWVVZGVBSEBCPFSM99FLOIDTCLUGPSEDLOKZUAEVBLWNMODGZBWOVQT9DPFOTSKRA'
                b'BQAVOQ9RXWBMAKFYNDCZOJGTCIDMQSQQSODKDXTPFLNOKSIZEOY9HFUTLQRXQMEPGO'
                b'XQGLLPNSXAUCYPGZMNWMQWSWCKAQYKXJTWINSGPPZG9HLDLEAWUWEVCTVRCBDFOXKU'
                b'ROXH9HXXAXVPEJFRSLOGRVGYZASTEBAQNXJJROCYRTDPYFUIQJVDHAKEG9YACV9HCP'
                b'JUEUKOYFNWDXCCJBIFQKYOXGRDHVTHEQUMHO999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999RKWEEVD99A99999999A99999999NFDPEEZCWVYLKZGSLCQNOFUSENI'
                b'XRHWWTZFBXMPSQHEDFWZULBZFEOMNLRNIDQKDNNIELAOXOVMYEI9PGTKORV9IKTJZQ'
                b'UBQAWTKBKZ9NEZHBFIMCLV9TTNJNQZUIJDFPTTCTKBJRHAITVSKUCUEMD9M9SQJ999'
                b'999TKORV9IKTJZQUBQAWTKBKZ9NEZHBFIMCLV9TTNJNQZUIJDFPTTCTKBJRHAITVSK'
                b'UCUEMD9M9SQJ999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999'
              )

        """
        tryte_string = TransactionTrytes(trytes)

        if not hash_:
            hash_trits: MutableSequence[int] = [0] * HASH_LENGTH

            sponge = Curl()
            sponge.absorb(tryte_string.as_trits())
            sponge.squeeze(hash_trits)

            hash_ = TransactionHash.from_trits(hash_trits)

        return cls(
            hash_=hash_,
            signature_message_fragment=Fragment(tryte_string[0:2187]),
            address=Address(tryte_string[2187:2268]),
            value=int_from_trits(tryte_string[2268:2295].as_trits()),
            legacy_tag=Tag(tryte_string[2295:2322]),
            timestamp=int_from_trits(tryte_string[2322:2331].as_trits()),
            current_index=int_from_trits(tryte_string[2331:2340].as_trits()),
            last_index=int_from_trits(tryte_string[2340:2349].as_trits()),
            bundle_hash=BundleHash(tryte_string[2349:2430]),
            trunk_transaction_hash=TransactionHash(tryte_string[2430:2511]),
            branch_transaction_hash=TransactionHash(tryte_string[2511:2592]),
            tag=Tag(tryte_string[2592:2619]),
            attachment_timestamp=int_from_trits(
                tryte_string[2619:2628].as_trits()),
            attachment_timestamp_lower_bound=int_from_trits(
                tryte_string[2628:2637].as_trits()),
            attachment_timestamp_upper_bound=int_from_trits(
                tryte_string[2637:2646].as_trits()),
            nonce=Nonce(tryte_string[2646:2673]),
        )
示例#7
0
文件: creation.py 项目: lzpap/pyota
    def finalize(self):
        # type: () -> None
        """
        Finalizes the bundle, preparing it to be attached to the Tangle.

        This operation includes checking if the bundle has zero balance,
        generating the bundle hash and updating the transactions with it,
        furthermore to initialize signature/message fragment fields.

        Once this method is invoked, no new transactions may be added to the
        bundle.

        :raises RuntimeError: if bundle is already finalized.
        :raises ValueError:
            - if bundle has no transactions.
            - if bundle has unspent inputs (there is no ``change_address``
              attribute specified.)
            - if inputs are insufficient to cover bundle spend.
        """
        if self.hash:
            raise RuntimeError('Bundle is already finalized.')

        if not self:
            raise ValueError('Bundle has no transactions.')

        # Quick validation.
        balance = self.balance

        if balance < 0:
            if self.change_address:
                self.add_transaction(
                    ProposedTransaction(
                        address=self.change_address,
                        value=-balance,
                        tag=self.tag,
                    ))
            else:
                raise ValueError(
                    'Bundle has unspent inputs (balance: {balance}); '
                    'use ``send_unspent_inputs_to`` to create '
                    'change transaction.'.format(balance=balance, ), )
        elif balance > 0:
            raise ValueError(
                'Inputs are insufficient to cover bundle spend '
                '(balance: {balance}).'.format(balance=balance, ), )

        # Generate bundle hash.
        while True:
            sponge = Kerl()
            last_index = len(self) - 1

            for i, txn in enumerate(self):
                txn.current_index = i
                txn.last_index = last_index

                sponge.absorb(txn.get_signature_validation_trytes().as_trits())

            bundle_hash_trits = [0] * HASH_LENGTH
            sponge.squeeze(bundle_hash_trits)

            bundle_hash = BundleHash.from_trits(bundle_hash_trits)

            # Check that we generated a secure bundle hash.
            # https://github.com/iotaledger/iota.py/issues/84
            if any(13 in part for part in normalize(bundle_hash)):
                # Increment the legacy tag and try again.
                tail_transaction = (self.tail_transaction
                                    )  # type: ProposedTransaction
                tail_transaction.increment_legacy_tag()
            else:
                break

        # Copy bundle hash to individual transactions.
        for txn in self:
            txn.bundle_hash = bundle_hash

            # Initialize signature/message fragment.
            txn.signature_message_fragment = Fragment(txn.message or b'')
示例#8
0
  def finalize(self):
    # type: () -> None
    """
    Finalizes the bundle, preparing it to be attached to the Tangle.
    """
    if self.hash:
      raise RuntimeError('Bundle is already finalized.')

    if not self:
      raise ValueError('Bundle has no transactions.')

    # Quick validation.
    balance = self.balance

    if balance < 0:
      if self.change_address:
        self.add_transaction(ProposedTransaction(
          address = self.change_address,
          value   = -balance,
          tag     = self.tag,
        ))
      else:
        raise ValueError(
          'Bundle has unspent inputs (balance: {balance}); '
          'use ``send_unspent_inputs_to`` to create '
          'change transaction.'.format(
            balance = balance,
          ),
        )
    elif balance > 0:
      raise ValueError(
        'Inputs are insufficient to cover bundle spend '
        '(balance: {balance}).'.format(
          balance = balance,
        ),
      )

    # Generate bundle hash.
    while True:
      sponge      = Kerl()
      last_index  = len(self) - 1

      for (i, txn) in enumerate(self): # type: Tuple[int, ProposedTransaction]
        txn.current_index = i
        txn.last_index    = last_index

        sponge.absorb(txn.get_signature_validation_trytes().as_trits())

      bundle_hash_trits = [0] * HASH_LENGTH # type: MutableSequence[int]
      sponge.squeeze(bundle_hash_trits)

      bundle_hash = BundleHash.from_trits(bundle_hash_trits)

      # Check that we generated a secure bundle hash.
      # https://github.com/iotaledger/iota.lib.py/issues/84
      if any(13 in part for part in normalize(bundle_hash)):
        # Increment the legacy tag and try again.
        tail_transaction = self.tail_transaction # type: ProposedTransaction
        tail_transaction.increment_legacy_tag()
      else:
        break

    # Copy bundle hash to individual transactions.
    for txn in self:
      txn.bundle_hash = bundle_hash

      # Initialize signature/message fragment.
      txn.signature_message_fragment = Fragment(txn.message or b'')