Пример #1
0
    def test_correct_root_calculation_at_one(self):
        reference_tree = TransactionMerkleTree(self.transactions_1[:1])

        merkle_hash_cache, merkle_height_cache = '', ''
        root_hash = ''

        for tx in self.transactions_2[:1]:
            optimized_tree = OptimizedTransactionMerkleTree(
                merkle_hash_cache, merkle_height_cache, tx)
            root_hash = optimized_tree.root_hash()
            merkle_hash_cache, merkle_height_cache = optimized_tree.merkle_cache_stacks(
            )

        self.assertEqual(root_hash, reference_tree.root_hash())
Пример #2
0
    def test_correct_root_calculation_at_zero(self):
        reference_tree = TransactionMerkleTree([])

        merkle_hash_cache, merkle_height_cache = '', ''
        root_hash = ''

        optimized_tree = OptimizedTransactionMerkleTree(
            merkle_hash_cache, merkle_height_cache)

        root_hash = optimized_tree.root_hash()
        merkle_hash_cache, merkle_height_cache = optimized_tree.merkle_cache_stacks(
        )

        self.assertEqual(root_hash, reference_tree.root_hash())
Пример #3
0
    def test_correct_root_calculation_batch_create(self):
        reference_tree = TransactionMerkleTree(self.transactions_1)

        merkle_hash_cache, merkle_height_cache = '', ''
        root_hash = ''

        optimized_tree = OptimizedTransactionMerkleTree(
            merkle_hash_cache,
            merkle_height_cache,
            transactions=self.transactions_2)

        root_hash = optimized_tree.root_hash()
        merkle_hash_cache, merkle_height_cache = optimized_tree.merkle_cache_stacks(
        )

        self.assertEqual(root_hash, reference_tree.root_hash())
Пример #4
0
    def test_last_transfer_index_at_one(self):
        reference_tree = TransactionMerkleTree(self.transactions_1[:1])

        merkle_hash_cache, merkle_height_cache = '', ''
        optimized_tree = None

        for tx in self.transactions_2[:1]:
            optimized_tree = OptimizedTransactionMerkleTree(
                merkle_hash_cache, merkle_height_cache, tx)
            merkle_hash_cache, merkle_height_cache = optimized_tree.merkle_cache_stacks(
            )

        self.assertEqual(optimized_tree.root_hash(),
                         reference_tree.root_hash())
        self.assertEqual(
            optimized_tree.last_tx_index(),
            reference_tree.merkle_tree_nonce_map.get(
                self.transactions_2[0].get('nonce')))
Пример #5
0
    def test_last_transfer_path(self):
        reference_tree = TransactionMerkleTree(self.transactions_1)

        merkle_hash_cache, merkle_height_cache = '', ''
        optimized_tree = None

        self
        for tx in self.transactions_2:
            optimized_tree = OptimizedTransactionMerkleTree(
                merkle_hash_cache, merkle_height_cache, tx)
            merkle_hash_cache, merkle_height_cache = optimized_tree.merkle_cache_stacks(
            )

        last_tx_index = optimized_tree.last_tx_index()

        self.assertEqual(optimized_tree.root_hash(),
                         reference_tree.root_hash())
        self.assertEqual(
            last_tx_index,
            reference_tree.merkle_tree_nonce_map.get(
                self.transactions_2[-1].get('nonce')))
        self.assertEqual(
            optimized_tree.merkle_tree_nonce_map.get(
                self.transactions_2[-1].get('nonce')),
            reference_tree.merkle_tree_nonce_map.get(
                self.transactions_2[-1].get('nonce')))
        self.assertEqual(optimized_tree.last_tx_proof(),
                         reference_tree.proof(last_tx_index))
Пример #6
0
    def optimized_authorized_transfers_tree(
            self,
            force_append=True,
            only_appended=False,
            starting_balance=None,
            assume_active_state_exists=False
    ) -> OptimizedTransactionMerkleTree:

        # fetch last 2 transfers in active set transfers, with cache values
        last_cached_transfer, before_last_cached_transfer = self.get_last_two_cached_transactions(
            only_appended, force_append)

        is_adding_new_transaction = self.transfer is not None and not self.transfer.appended and (
            self.transfer.wallet_id == self.wallet.id
            or not self.transfer.passive)
        is_fetching_complete_set = not force_append
        is_fetching_appended_set = force_append and only_appended and self.transfer is not None and self.transfer.id is not None

        # if the last cache entry exists
        if last_cached_transfer is not None:

            # fetching complete transaction set
            if is_fetching_complete_set:
                # need second last cache item to construct tree
                if before_last_cached_transfer is not None:
                    return OptimizedTransactionMerkleTree(
                        before_last_cached_transfer.hash_cache,
                        before_last_cached_transfer.height_cache,
                        transaction=last_cached_transfer.shorthand(
                            wallet_transfer_context=self,
                            is_last_transfer=True,
                            starting_balance=starting_balance,
                            assume_active_state_exists=
                            assume_active_state_exists))
                # if it does not exist, fallback to recalculating entire tree

            # fetch only appended transaction set
            elif is_fetching_appended_set:

                # if last cached transaction is context transaction
                if last_cached_transfer.id == self.transfer.id:
                    # need second last cache item to construct tree
                    if before_last_cached_transfer is not None:
                        return OptimizedTransactionMerkleTree(
                            before_last_cached_transfer.hash_cache,
                            before_last_cached_transfer.height_cache,
                            transaction=self.transfer.shorthand(
                                wallet_transfer_context=self,
                                is_last_transfer=True,
                                starting_balance=starting_balance,
                                assume_active_state_exists=
                                assume_active_state_exists))
                    # if it does not exist, fallback to recalculating entire tree

                # if last cached transaction is not context transaction
                # use last cached item and context transaction to calculate tree
                else:
                    return OptimizedTransactionMerkleTree(
                        last_cached_transfer.hash_cache,
                        last_cached_transfer.height_cache,
                        transaction=self.transfer.shorthand(
                            wallet_transfer_context=self,
                            is_last_transfer=True,
                            starting_balance=starting_balance,
                            assume_active_state_exists=
                            assume_active_state_exists))

            # adding new transaction to set
            elif is_adding_new_transaction:
                # get last cached items
                merkle_hash_cache = last_cached_transfer.hash_cache
                merkle_height_cache = last_cached_transfer.height_cache

                # is this context transaction a fullfilled or cancelled swap
                # need to reconstruct for the sender as well
                # a partially matched swap in a previous eon will result in a different starting balance (from that of sender state tx set)
                # if multi eon swap is cancelled, since starting balance changed this tx_set_tree should be reconstructed
                is_fulfilled_or_cancelled_swap = last_cached_transfer.is_swap(
                ) and (last_cached_transfer.complete
                       or last_cached_transfer.cancelled)

                # is this context transaction passive
                is_passive = last_cached_transfer.passive

                # reconstruct tree using existing tx set, excluding context transaction
                # to make sure swap or passive transfer is finalized
                should_reconstruct_old_tree = is_fulfilled_or_cancelled_swap or is_passive

                if should_reconstruct_old_tree:
                    # for backward compatibility
                    # if tree before last tree is not cached, re-calculate entire tree
                    if before_last_cached_transfer is None:
                        old_set = self.authorized_transfers_list(
                            only_appended=False,
                            force_append=False,
                        )
                        reconstructed_old_tree = OptimizedTransactionMerkleTree(
                            merkle_hash_cache=None,
                            merkle_height_cache=None,
                            transactions=[
                                tx.shorthand(wallet_transfer_context=self,
                                             starting_balance=starting_balance,
                                             assume_active_state_exists=
                                             assume_active_state_exists)
                                for tx in old_set
                                if tx.index <= last_cached_transfer.index
                            ])

                    # if tree before last tree is cached, use cache to re-construct last tree
                    else:
                        reconstructed_old_tree = OptimizedTransactionMerkleTree(
                            before_last_cached_transfer.hash_cache,
                            before_last_cached_transfer.height_cache,
                            transaction=last_cached_transfer.shorthand(
                                wallet_transfer_context=self,
                                is_last_transfer=False,
                                starting_balance=starting_balance,
                                assume_active_state_exists=
                                assume_active_state_exists))

                    # update last cache item after finalizing included transactions
                    merkle_hash_cache, merkle_height_cache = reconstructed_old_tree.merkle_cache_stacks(
                    )
                    # if context wallet is sender
                    if self.wallet == last_cached_transfer.wallet:
                        last_cached_transfer.sender_merkle_hash_cache = merkle_hash_cache
                        last_cached_transfer.sender_merkle_height_cache = merkle_height_cache
                    # if context wallet is recipient and is_fulfilled_or_cancelled_swap
                    elif self.wallet == last_cached_transfer.recipient and is_fulfilled_or_cancelled_swap:
                        last_cached_transfer.recipient_merkle_hash_cache = merkle_hash_cache
                        last_cached_transfer.recipient_merkle_height_cache = merkle_height_cache
                    last_cached_transfer.save()

                # use last cached item to construct new tree
                return OptimizedTransactionMerkleTree(
                    merkle_hash_cache,
                    merkle_height_cache,
                    transaction=self.transfer.shorthand(
                        wallet_transfer_context=self,
                        starting_balance=starting_balance,
                        assume_active_state_exists=assume_active_state_exists))

        # for backward compatibility
        # fallback to re-calculating the whole tree
        return OptimizedTransactionMerkleTree(
            merkle_hash_cache=None,
            merkle_height_cache=None,
            transactions=self.authorized_transfers_list_shorthand(
                only_appended=only_appended,
                force_append=force_append,
                last_transfer_is_finalized=not (is_fetching_appended_set
                                                or is_adding_new_transaction),
                starting_balance=starting_balance,
                assume_active_state_exists=assume_active_state_exists))
Пример #7
0
 def optimized_authorized_transfers_tree_from_list(
         cls, transfers_list) -> OptimizedTransactionMerkleTree:
     return OptimizedTransactionMerkleTree(merkle_hash_cache=None,
                                           merkle_height_cache=None,
                                           transactions=transfers_list)