Пример #1
0
    def test_checkpoint_creation(self):
        self.eth_token = Token.objects.first()

        lqd_token_address = deploy_new_test_token(test_case=self)

        distribute_token_balance_to_addresses(
            test_case=self,
            token_address=lqd_token_address,
            recipients=testrpc_accounts.accounts)

        self.lqd_token = register_token(token_address=lqd_token_address,
                                        name='Liquidity',
                                        short_name='LQD',
                                        register_on_chain=True)

        send_queued_transactions()

        self.tokens = [self.eth_token, self.lqd_token]

        TokenPair.objects.create(token_from=self.eth_token,
                                 token_to=self.lqd_token)
        TokenPair.objects.create(token_from=self.lqd_token,
                                 token_to=self.eth_token)

        self.registered_accounts = {
            self.eth_token: register_testrpc_accounts(self,
                                                      token=self.eth_token),
            self.lqd_token: register_testrpc_accounts(self,
                                                      token=self.lqd_token)
        }

        for token in self.tokens:
            self.assertEqual(
                self.contract_interface.get_unmanaged_funds(token.address, 1),
                0)
            self.assertEqual(
                self.contract_interface.get_managed_funds(token.address, 1), 0)

        for token in self.tokens:
            create_deposits(self, testrpc_accounts.accounts, token)

        for token in self.tokens:
            self.assertEqual(
                self.contract_interface.get_unmanaged_funds(token.address, 1),
                self.contract_interface.get_total_balance(token.address))
            self.assertEqual(
                self.contract_interface.get_managed_funds(token.address, 1), 0)

        for account in testrpc_accounts.accounts[1:5]:
            eth_wallet = Wallet.objects.get(address=remove_0x_prefix(
                account.get('address')),
                                            token=self.eth_token)
            lqd_wallet = Wallet.objects.get(address=remove_0x_prefix(
                account.get('address')),
                                            token=self.lqd_token)

            eth_wallet_context = WalletTransferContext(wallet=eth_wallet,
                                                       transfer=None)
            lqd_wallet_context = WalletTransferContext(wallet=lqd_wallet,
                                                       transfer=None)

            account[
                'reduced_eth_balance'] = eth_wallet_context.available_funds_at_eon(
                    eon_number=1, only_appended=False) - 1
            account[
                'reduced_lqd_balance'] = lqd_wallet_context.available_funds_at_eon(
                    eon_number=1, only_appended=False)

            send_swap(  # Buy LQD at 0.5 ETH
                test_case=self,
                eon_number=1,
                account=account,
                token=self.eth_token,
                token_swapped=self.lqd_token,
                amount=1,
                amount_swapped=2,
                nonce=random.randint(1, 999999))

        for account in testrpc_accounts.accounts[5:9]:
            eth_wallet = Wallet.objects.get(address=remove_0x_prefix(
                account.get('address')),
                                            token=self.eth_token)
            lqd_wallet = Wallet.objects.get(address=remove_0x_prefix(
                account.get('address')),
                                            token=self.lqd_token)

            eth_wallet_context = WalletTransferContext(wallet=eth_wallet,
                                                       transfer=None)
            lqd_wallet_context = WalletTransferContext(wallet=lqd_wallet,
                                                       transfer=None)

            account[
                'reduced_eth_balance'] = eth_wallet_context.available_funds_at_eon(
                    eon_number=1, only_appended=False)
            account[
                'reduced_lqd_balance'] = lqd_wallet_context.available_funds_at_eon(
                    eon_number=1, only_appended=False) - 2

            send_swap(  # Sell LQD at 0.5 ETH
                test_case=self,
                eon_number=1,
                account=account,
                token=self.lqd_token,
                token_swapped=self.eth_token,
                amount=2,
                amount_swapped=1,
                nonce=random.randint(1, 999999))

        confirm_swaps_for_eon(operator_eon_number=1)
        cancel_finalize_swaps_for_eon(operator_eon_number=1)
        process_swaps_for_eon(operator_eon_number=1)
        for account in testrpc_accounts.accounts[1:5]:
            finalize_last_swap(test_case=self,
                               token=self.eth_token,
                               token_swapped=self.lqd_token,
                               account=account)
        for account in testrpc_accounts.accounts[5:9]:
            finalize_last_swap(test_case=self,
                               token=self.lqd_token,
                               token_swapped=self.eth_token,
                               account=account)
        confirm_swaps_for_eon(operator_eon_number=1)
        cancel_finalize_swaps_for_eon(operator_eon_number=1)
        process_swaps_for_eon(operator_eon_number=1)

        buyers_sellers = [
            testrpc_accounts.accounts[1:5], testrpc_accounts.accounts[5:9]
        ]
        for i in range(0, 2):
            for account in buyers_sellers[i]:
                eth_wallet = Wallet.objects.get(address=remove_0x_prefix(
                    account.get('address')),
                                                token=self.eth_token)
                lqd_wallet = Wallet.objects.get(address=remove_0x_prefix(
                    account.get('address')),
                                                token=self.lqd_token)

                eth_wallet_context = WalletTransferContext(wallet=eth_wallet,
                                                           transfer=None)
                lqd_wallet_context = WalletTransferContext(wallet=lqd_wallet,
                                                           transfer=None)

                eth_out, eth_in = eth_wallet_context.off_chain_actively_sent_received_amounts(
                    eon_number=1, only_appended=False)
                lqd_out, lqd_in = lqd_wallet_context.off_chain_actively_sent_received_amounts(
                    eon_number=1, only_appended=False)

                eth_out -= account['reduced_eth_balance']
                lqd_out -= account['reduced_lqd_balance']

                if i == 0:  # LQD buyers
                    assert eth_out == 1 and eth_in == 0, '{}/{}'.format(
                        eth_out, eth_in)
                    assert lqd_out - 2 == 0 and lqd_in - 2 == 2, '{}/{}'.format(
                        lqd_out, lqd_in)
                else:  # LQD sellers
                    assert lqd_out == 2 and lqd_in == 0, '{}/{}'.format(
                        lqd_out, lqd_in)
                    assert eth_out - 1 == 0 and eth_in - 1 == 1, '{}/{}'.format(
                        eth_out, eth_in)

        # Verify transfers were complete
        swaps = Transfer.objects.filter(swap=True)
        for transfer in swaps:
            self.assertTrue(transfer.is_fulfilled_swap())

        commit_eon(test_case=self, eon_number=1)

        advance_to_next_eon(test_case=self, eon_number=1)

        commit_eon(test_case=self, eon_number=2)
Пример #2
0
def create_token_commitment_for_eon(token: Token, eon_number):
    logger.info('Creating Token Commitment for {} at {}'.format(
        token.address, eon_number))
    last_eon_number = eon_number - 1

    with transaction.atomic():
        wallets = Wallet.objects\
            .filter(
                token=token,
                registration_operator_authorization__isnull=False,
                trail_identifier__isnull=False)\
            .order_by('trail_identifier')

        new_balances = []
        left, right = 0, 0

        for wallet in wallets:
            with wallet.lock(auto_renewal=True):
                wallet_transfer_context = WalletTransferContext(
                    wallet=wallet, transfer=None)

                last_transfer, last_transfer_is_outgoing = wallet_transfer_context.last_appended_active_transfer(
                    eon_number=last_eon_number)

                last_transfer_active_state = None
                if last_transfer is not None and last_transfer.is_open_swap():
                    last_transfer.retire_swap()

                if last_transfer is not None:
                    last_transfer_active_state = WalletTransferContext.appropriate_transfer_active_state(
                        transfer=last_transfer,
                        is_outgoing=last_transfer_is_outgoing)

                available_funds = wallet_transfer_context.available_funds_at_eon(
                    eon_number=last_eon_number,
                    only_appended=True)

                right = left + available_funds
                assert right >= left, 'Wallet {} Token {} Balance {}'.format(
                    wallet.address, token.address, available_funds)

                passive_checksum, passive_amount, passive_marker = wallet_transfer_context.get_passive_values(
                    eon_number=last_eon_number)

                new_balances.append({
                    'contract': settings.HUB_LQD_CONTRACT_ADDRESS,
                    'token': token.address,
                    'wallet': wallet.address,
                    'left': left,
                    'right': right,
                    'active_state_checksum': last_transfer_active_state.checksum() if last_transfer_active_state is not None else b'\0'*32,
                    'active_state': last_transfer_active_state,
                    'passive_checksum': passive_checksum,
                    'passive_amount': passive_amount,
                    'passive_marker': passive_marker,
                })
                left = right

                last_incoming_passive_transfer = wallet_transfer_context.last_appended_incoming_passive_transfer(
                    eon_number=last_eon_number)
                if last_incoming_passive_transfer:
                    wallet_transfer_context = WalletTransferContext(
                        wallet=wallet, transfer=last_incoming_passive_transfer)

                    passive_eon_transfers_list = wallet_transfer_context.incoming_passive_transfers_list(
                        only_appended=True,
                        force_append=False)
                    passive_transfers_merkle_tree = wallet_transfer_context.incoming_passive_transfers_tree(
                        only_appended=True,
                        force_append=False)

                    for index, incoming_passive_transfer in enumerate(passive_eon_transfers_list):

                        final_transfer_index = index
                        final_transfer_membership_proof = passive_transfers_merkle_tree.proof(
                            final_transfer_index)
                        final_transfer_membership_proof_chain = final_transfer_membership_proof.get(
                            "chain")
                        final_transfer_membership_proof_values = final_transfer_membership_proof.get(
                            "values")

                        assert incoming_passive_transfer.final_receipt_hashes is None
                        assert incoming_passive_transfer.final_receipt_index is None
                        assert incoming_passive_transfer.final_receipt_values is None

                        incoming_passive_transfer.final_receipt_hashes = final_transfer_membership_proof_chain
                        incoming_passive_transfer.final_receipt_index = final_transfer_index
                        incoming_passive_transfer.final_receipt_values = final_transfer_membership_proof_values

                        incoming_passive_transfer.save()

                if last_transfer_active_state is None:
                    continue

                wallet_transfer_context = WalletTransferContext(
                    wallet=wallet, transfer=last_transfer)
                starting_balance = int(
                    wallet_transfer_context.starting_balance_in_eon(last_eon_number))

                # if last active transfer is a multi eon swap
                # starting balance included in every tx checksum should be set to the cached starting balance
                # this way checkpoint state will match signed active state
                if last_transfer.is_swap() and not last_transfer.cancelled:
                    if Transfer.objects.filter(eon_number=last_transfer.eon_number-1, tx_id=last_transfer.tx_id).exists():
                        matched_out, matched_in = last_transfer.matched_amounts(
                            all_eons=True)
                        current_matched_out, current_matched_in = last_transfer.matched_amounts(
                            all_eons=False)
                        if last_transfer_is_outgoing:
                            sender_starting_balance = last_transfer.sender_starting_balance

                            # current eon's starting balance should be equal to
                            # cached starting balance - committed matched out amount in past rounds
                            assert(starting_balance == sender_starting_balance -
                                   matched_out + current_matched_out)
                            starting_balance = sender_starting_balance
                        else:
                            recipient_starting_balance = last_transfer.recipient_starting_balance

                            # current eon's starting balance should be equal to
                            # cached starting balance + committed matched in amount in past rounds
                            assert(
                                starting_balance == recipient_starting_balance + matched_in - current_matched_in)
                            starting_balance = recipient_starting_balance

                confirmed_eon_transfers_list = wallet_transfer_context.authorized_transfers_list(
                    only_appended=True,
                    force_append=False)
                confirmed_eon_transfers_list_shorthand = wallet_transfer_context.authorized_transfers_list_shorthand(
                    only_appended=True,
                    force_append=False,
                    last_transfer_is_finalized=False,
                    starting_balance=starting_balance)
                transaction_merkle_tree = TransactionMerkleTree(
                    confirmed_eon_transfers_list_shorthand)
                transaction_merkle_tree_root = hex_value(
                    transaction_merkle_tree.root_hash())

                assert transaction_merkle_tree_root == last_transfer_active_state.tx_set_hash,\
                    '{}/{}'.format(transaction_merkle_tree_root,
                                   last_transfer_active_state.tx_set_hash)

                for confirmed_incoming_transfer in confirmed_eon_transfers_list:
                    if confirmed_incoming_transfer.recipient != wallet:
                        continue

                    final_transfer_index = transaction_merkle_tree.merkle_tree_nonce_map.get(
                        confirmed_incoming_transfer.nonce)
                    final_transfer_membership_proof_chain = transaction_merkle_tree.proof(
                        final_transfer_index)

                    assert confirmed_incoming_transfer.final_receipt_hashes is None
                    assert confirmed_incoming_transfer.final_receipt_index is None

                    confirmed_incoming_transfer.final_receipt_hashes = final_transfer_membership_proof_chain
                    confirmed_incoming_transfer.final_receipt_index = final_transfer_index

                    confirmed_incoming_transfer.save()

        managed_funds = 0
        if eon_number > 1:
            last_eon = LocalViewInterface.confirmed(eon_number=last_eon_number)
            pending_withdrawals_until_last_eon = \
                WithdrawalRequest.objects\
                .filter(wallet__token=token, eon_number__lte=last_eon_number, slashed=False)\
                .filter(Q(withdrawal__isnull=True) | Q(withdrawal__block__gt=last_eon.block))

            if not pending_withdrawals_until_last_eon.exists():
                last_eon_pending_withdrawals = 0
            else:
                last_eon_pending_withdrawals = pending_withdrawals_until_last_eon\
                    .aggregate(Sum('amount')) \
                    .get('amount__sum')

            total_token_balance = last_eon.contractledgerstate_set.get(
                token=token).total_balance
            managed_funds = total_token_balance - last_eon_pending_withdrawals

        if right < managed_funds:
            logger.warning('UNCLAIMED FUNDS: {} in {}'.format(
                managed_funds - right, token.address))
            send_admin_email(
                subject='Soft TokenCommitment Warning: Extra funds',
                content='There are some additional funds in the balance pool that belong to no one: {} of {}'
                .format(managed_funds - right, token.address))
            altered_balances = new_balances + [{
                'contract': settings.HUB_LQD_CONTRACT_ADDRESS,
                'token': token.address,
                'wallet': settings.HUB_OWNER_ACCOUNT_ADDRESS,
                'left': left,
                'right': managed_funds,
                'active_state_checksum': b'\0'*32,
                'active_state': None,
                'passive_checksum': b'\0'*32,
                'passive_amount': 0,
                'passive_marker': 0,
            }]
            new_merkle_tree = MerkleTree(altered_balances, managed_funds)
            right = managed_funds
        else:
            if right > managed_funds:
                logger.error('OVERCLAIMING FUNDS!! {} > {} in {}'.format(
                    right, managed_funds, token.address))
                send_admin_email(
                    subject='HARD Checkpoint Error: OVERCLAIMING!',
                    content='OVERCLAIMING FUNDS!! {} > {} in {}'.format(right, managed_funds, token.address))
            new_merkle_tree = MerkleTree(new_balances, right)

        bulk_manager = BulkCreateManager(chunk_size=500)
        for index, balance in enumerate(new_balances):
            if not balance.get('wallet') or balance.get('wallet') == '0x0000000000000000000000000000000000000000':
                continue

            merkle_proof = new_merkle_tree.proof(index)

            wallet = Wallet.objects.get(
                token=token,
                address=remove_0x_prefix(balance.get('wallet')))

            # TODO verify validity through RPC prior to insertion

            assert(wallet.trail_identifier == index)

            # create records in batches
            bulk_manager.add(
                ExclusiveBalanceAllotment(
                    wallet=wallet,
                    eon_number=eon_number,
                    left=balance.get('left'),
                    right=balance.get('right'),
                    merkle_proof_hashes=merkle_proof.get('chain'),
                    merkle_proof_values=merkle_proof.get('values'),
                    merkle_proof_trail=index,
                    active_state=balance.get('active_state')
                )
            )
        # make sure remaining batch is added
        bulk_manager.done()

        token_commitment = TokenCommitment.objects.create(
            token=token,
            merkle_root=hex_value(new_merkle_tree.root_hash()),
            upper_bound=right)

        return token_commitment
Пример #3
0
    def test_partial_match_multi_eon_swap(self):
        commit_eon(test_case=self, eon_number=1)

        advance_to_next_eon(test_case=self, eon_number=1)
        commit_eon(test_case=self, eon_number=2)

        buy_lqd_nonce = random.randint(1, 999999)
        sell_lqd_nonce = random.randint(1, 999999)

        total_remaining_eons = 8
        # make persistent swap
        send_swap(  # Buy LQD at 0.5 ETH
            test_case=self,
            eon_number=2,
            account=self.testrpc_accounts[1],
            token=self.eth_token,
            token_swapped=self.lqd_token,
            amount=4,
            amount_swapped=8,
            nonce=buy_lqd_nonce,
            eon_count=total_remaining_eons)

        swap = Transfer.objects.filter(
            swap=True, wallet__token=self.eth_token).order_by('id')[0]
        swap_tx_id = swap.tx_id
        wallet_transfer_context = WalletTransferContext(wallet=swap.wallet,
                                                        transfer=None)
        recipient_transfer_context = WalletTransferContext(
            wallet=swap.recipient, transfer=None)

        wallet_funds_before = 4
        recipient_funds_before = 0

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=2)
        cancel_finalize_swaps_for_eon(operator_eon_number=2)
        process_swaps_for_eon(operator_eon_number=2)

        # make opposite swap
        send_swap(  # Sell LQD at 0.5 ETH
            test_case=self,
            eon_number=2,
            account=self.testrpc_accounts[2],
            token=self.lqd_token,
            token_swapped=self.eth_token,
            amount=2,
            amount_swapped=1,
            nonce=sell_lqd_nonce,
            eon_count=1)

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=2)
        cancel_finalize_swaps_for_eon(operator_eon_number=2)
        process_swaps_for_eon(operator_eon_number=2)

        self.assertEqual(
            wallet_transfer_context.available_funds_at_eon(2, False),
            wallet_funds_before - 1)
        self.assertEqual(
            recipient_transfer_context.available_funds_at_eon(2, False),
            recipient_funds_before + 2)
        wallet_funds_before = wallet_funds_before - 1
        recipient_funds_before = recipient_funds_before + 2

        # skip some eons
        for i in range(3, 5):
            # proceed to next eon
            advance_to_next_eon(test_case=self, eon_number=i - 1)
            commit_eon(test_case=self, eon_number=i)
            total_remaining_eons -= 1
            swap = Transfer.objects.get(swap=True,
                                        tx_id=swap_tx_id,
                                        eon_number=i)
            self.assertEqual(swap.eon_number, i)

            # process swaps
            confirm_swaps_for_eon(operator_eon_number=i)
            cancel_finalize_swaps_for_eon(operator_eon_number=i)
            process_swaps_for_eon(operator_eon_number=i)

            self.assertEqual(
                wallet_transfer_context.available_funds_at_eon(i, False),
                wallet_funds_before)
            self.assertEqual(
                recipient_transfer_context.available_funds_at_eon(i, False),
                recipient_funds_before)

        new_wallet_funds = wallet_funds_before
        new_recipient_funds = recipient_funds_before
        # partial match across eons
        for i in range(5, 8):
            # proceed to next eon
            advance_to_next_eon(test_case=self, eon_number=i - 1)
            commit_eon(test_case=self, eon_number=i)
            total_remaining_eons -= 1
            swap = Transfer.objects.get(swap=True,
                                        tx_id=swap_tx_id,
                                        eon_number=i)
            self.assertEqual(swap.eon_number, i)

            # process swaps
            confirm_swaps_for_eon(operator_eon_number=i)
            cancel_finalize_swaps_for_eon(operator_eon_number=i)
            process_swaps_for_eon(operator_eon_number=i)

            self.assertEqual(
                wallet_transfer_context.available_funds_at_eon(i, False),
                new_wallet_funds)
            self.assertEqual(
                recipient_transfer_context.available_funds_at_eon(i, False),
                new_recipient_funds)

            # make opposite swap
            send_swap(  # Sell LQD at 0.5 ETH
                test_case=self,
                eon_number=i,
                account=self.testrpc_accounts[i - 2],
                token=self.lqd_token,
                token_swapped=self.eth_token,
                amount=2,
                amount_swapped=1,
                nonce=sell_lqd_nonce,
                eon_count=1)

            # process swaps
            confirm_swaps_for_eon(operator_eon_number=i)
            cancel_finalize_swaps_for_eon(operator_eon_number=i)
            process_swaps_for_eon(operator_eon_number=i)

            finalize_last_swap(test_case=self,
                               token=self.lqd_token,
                               token_swapped=self.eth_token,
                               account=self.testrpc_accounts[i - 2],
                               eon_count=1)

            # process swaps
            confirm_swaps_for_eon(operator_eon_number=i)
            cancel_finalize_swaps_for_eon(operator_eon_number=i)
            process_swaps_for_eon(operator_eon_number=i)

            self.assertEqual(
                wallet_transfer_context.available_funds_at_eon(i, False),
                new_wallet_funds - 1)
            self.assertEqual(
                recipient_transfer_context.available_funds_at_eon(i, False),
                new_recipient_funds + 2)
            new_wallet_funds = new_wallet_funds - 1
            new_recipient_funds = new_recipient_funds + 2

        swap = Transfer.objects.get(swap=True, tx_id=swap_tx_id, eon_number=7)
        matched_out, matched_in = swap.matched_amounts(all_eons=True)
        # self.assertTrue(swap.processed)
        self.assertTrue(swap.appended)
        self.assertFalse(swap.voided)
        self.assertFalse(swap.cancelled)
        self.assertEqual(matched_out, 4)
        self.assertEqual(matched_in, 8)
        self.assertTrue(swap.complete)

        self.assertEqual(
            Transfer.objects.filter(tx_id=swap_tx_id,
                                    eon_number__gt=7,
                                    swap=True,
                                    voided=False).count(), 0)
        finalize_swap(test_case=self,
                      swap=swap,
                      account=self.testrpc_accounts[1],
                      eon_count=total_remaining_eons)

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=7)
        cancel_finalize_swaps_for_eon(operator_eon_number=7)
        process_swaps_for_eon(operator_eon_number=7)

        self.assertEqual(
            wallet_transfer_context.available_funds_at_eon(7, False),
            wallet_funds_before - 3)
        self.assertEqual(
            recipient_transfer_context.available_funds_at_eon(7, False),
            recipient_funds_before + 6)

        advance_to_next_eon(test_case=self, eon_number=7)
        commit_eon(test_case=self, eon_number=8)

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=8)
        cancel_finalize_swaps_for_eon(operator_eon_number=8)
        process_swaps_for_eon(operator_eon_number=8)

        self.assertEqual(
            wallet_transfer_context.available_funds_at_eon(8, False),
            wallet_funds_before - 3)
        self.assertEqual(
            recipient_transfer_context.available_funds_at_eon(8, False),
            recipient_funds_before + 6)
Пример #4
0
    def test_match_multi_eon_swap(self):
        commit_eon(test_case=self, eon_number=1)

        advance_to_next_eon(test_case=self, eon_number=1)
        commit_eon(test_case=self, eon_number=2)

        buy_lqd_nonce = random.randint(1, 999999)
        sell_lqd_nonce = random.randint(1, 999999)

        total_remaining_eons = 5
        # make persistent swap
        send_swap(  # Buy LQD at 0.5 ETH
            test_case=self,
            eon_number=2,
            account=self.testrpc_accounts[1],
            token=self.eth_token,
            token_swapped=self.lqd_token,
            amount=1,
            amount_swapped=2,
            nonce=buy_lqd_nonce,
            eon_count=total_remaining_eons)

        self.assertEqual(
            Transfer.objects.filter(swap=True).count(), total_remaining_eons)

        swap = Transfer.objects.filter(swap=True)[0]
        swap_tx_id = swap.tx_id
        wallet_transfer_context = WalletTransferContext(wallet=swap.wallet,
                                                        transfer=None)
        recipient_transfer_context = WalletTransferContext(
            wallet=swap.recipient, transfer=None)

        wallet_funds_before = 1
        recipient_funds_before = 0

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=2)
        cancel_finalize_swaps_for_eon(operator_eon_number=2)
        process_swaps_for_eon(operator_eon_number=2)

        # skip some eons
        for i in range(3, 6):
            # proceed to next eon
            advance_to_next_eon(test_case=self, eon_number=i - 1)
            commit_eon(test_case=self, eon_number=i)
            total_remaining_eons -= 1

            # process swaps
            confirm_swaps_for_eon(operator_eon_number=i)
            cancel_finalize_swaps_for_eon(operator_eon_number=i)
            process_swaps_for_eon(operator_eon_number=i)

            self.assertEqual(
                wallet_transfer_context.available_funds_at_eon(i, False),
                wallet_funds_before)
            self.assertEqual(
                recipient_transfer_context.available_funds_at_eon(i, False),
                recipient_funds_before)

        # make opposite swap
        send_swap(  # Sell LQD at 0.5 ETH
            test_case=self,
            eon_number=5,
            account=self.testrpc_accounts[2],
            token=self.lqd_token,
            token_swapped=self.eth_token,
            amount=2,
            amount_swapped=1,
            nonce=sell_lqd_nonce,
            eon_count=1)

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=5)
        cancel_finalize_swaps_for_eon(operator_eon_number=5)
        process_swaps_for_eon(operator_eon_number=5)

        swap1 = Transfer.objects.filter(eon_number=5).order_by('time')[0]
        swap2 = Transfer.objects.filter(eon_number=5).order_by('time')[1]

        self.assertNotEqual(swap1.tx_id, swap2.tx_id)

        # finalize swaps
        swap = Transfer.objects.get(swap=True, tx_id=swap_tx_id, eon_number=5)
        self.assertEqual(
            Transfer.objects.filter(tx_id=swap_tx_id,
                                    eon_number__gt=5,
                                    swap=True,
                                    voided=False).count(), 0)
        finalize_swap(test_case=self,
                      swap=swap,
                      account=self.testrpc_accounts[1],
                      eon_count=total_remaining_eons)
        finalize_last_swap(test_case=self,
                           token=self.lqd_token,
                           token_swapped=self.eth_token,
                           account=self.testrpc_accounts[2],
                           eon_count=1)

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=5)
        cancel_finalize_swaps_for_eon(operator_eon_number=5)
        process_swaps_for_eon(operator_eon_number=5)

        self.assertEqual(
            wallet_transfer_context.available_funds_at_eon(5, False),
            wallet_funds_before - 1)
        self.assertEqual(
            recipient_transfer_context.available_funds_at_eon(5, False),
            recipient_funds_before + 2)
Пример #5
0
    def test_cancel_after_partial_match_swap(self):
        commit_eon(test_case=self, eon_number=1)

        advance_to_next_eon(test_case=self, eon_number=1)
        commit_eon(test_case=self, eon_number=2)

        buy_lqd_nonce = random.randint(1, 999999)
        sell_lqd_nonce = random.randint(1, 999999)

        total_remaining_eons = 5
        # make persistent swap
        send_swap(  # Buy LQD at 0.5 ETH
            test_case=self,
            eon_number=2,
            account=self.testrpc_accounts[1],
            token=self.eth_token,
            token_swapped=self.lqd_token,
            amount=2,
            amount_swapped=4,
            nonce=buy_lqd_nonce,
            eon_count=total_remaining_eons)

        swap = Transfer.objects.filter(
            swap=True, wallet__token=self.eth_token).order_by('id')[0]
        swap_tx_id = swap.tx_id
        wallet_transfer_context = WalletTransferContext(wallet=swap.wallet,
                                                        transfer=None)
        recipient_transfer_context = WalletTransferContext(
            wallet=swap.recipient, transfer=None)

        wallet_funds_before = 2
        recipient_funds_before = 0

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=2)
        cancel_finalize_swaps_for_eon(operator_eon_number=2)
        process_swaps_for_eon(operator_eon_number=2)

        # make opposite swap
        send_swap(  # Sell LQD at 0.5 ETH
            test_case=self,
            eon_number=2,
            account=self.testrpc_accounts[2],
            token=self.lqd_token,
            token_swapped=self.eth_token,
            amount=2,
            amount_swapped=1,
            nonce=sell_lqd_nonce,
            eon_count=1)

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=2)
        cancel_finalize_swaps_for_eon(operator_eon_number=2)
        process_swaps_for_eon(operator_eon_number=2)

        finalize_last_swap(test_case=self,
                           token=self.lqd_token,
                           token_swapped=self.eth_token,
                           account=self.testrpc_accounts[2],
                           eon_count=1)

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=2)
        cancel_finalize_swaps_for_eon(operator_eon_number=2)
        process_swaps_for_eon(operator_eon_number=2)

        swap = Transfer.objects.get(swap=True, tx_id=swap_tx_id, eon_number=2)
        freeze_swap(test_case=self,
                    swap=swap,
                    account=self.testrpc_accounts[1])
        swap = Transfer.objects.get(swap=True, tx_id=swap_tx_id, eon_number=2)
        cancel_swap(test_case=self,
                    swap=swap,
                    account=self.testrpc_accounts[1],
                    eon_count=total_remaining_eons)
        self.assertEqual(
            Transfer.objects.filter(tx_id=swap_tx_id,
                                    eon_number__gt=2,
                                    swap=True,
                                    voided=False).count(), 0)
        # process swaps
        confirm_swaps_for_eon(operator_eon_number=2)
        cancel_finalize_swaps_for_eon(operator_eon_number=2)
        process_swaps_for_eon(operator_eon_number=2)

        self.assertEqual(
            wallet_transfer_context.available_funds_at_eon(2, False),
            wallet_funds_before - 1)
        self.assertEqual(
            recipient_transfer_context.available_funds_at_eon(2, False),
            recipient_funds_before + 2)

        advance_to_next_eon(test_case=self, eon_number=2)
        commit_eon(test_case=self, eon_number=3)

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=3)
        cancel_finalize_swaps_for_eon(operator_eon_number=3)
        process_swaps_for_eon(operator_eon_number=3)

        self.assertEqual(
            wallet_transfer_context.available_funds_at_eon(3, False),
            wallet_funds_before - 1)
        self.assertEqual(
            recipient_transfer_context.available_funds_at_eon(3, False),
            recipient_funds_before + 2)
Пример #6
0
    def test_cancel_after_partial_match_multi_eon_swap(self):
        commit_eon(test_case=self, eon_number=1)

        advance_to_next_eon(test_case=self, eon_number=1)
        commit_eon(test_case=self, eon_number=2)

        buy_lqd_nonce = random.randint(1, 999999)
        sell_lqd_nonce = random.randint(1, 999999)

        total_remaining_eons = 5
        # make persistent swap
        send_swap(  # Buy LQD at 0.5 ETH
            test_case=self,
            eon_number=2,
            account=self.testrpc_accounts[1],
            token=self.eth_token,
            token_swapped=self.lqd_token,
            amount=2,
            amount_swapped=4,
            nonce=buy_lqd_nonce,
            eon_count=total_remaining_eons)

        swap = Transfer.objects.filter(
            swap=True, wallet__token=self.eth_token).order_by('id')[0]
        swap_tx_id = swap.tx_id
        wallet_transfer_context = WalletTransferContext(wallet=swap.wallet,
                                                        transfer=None)
        recipient_transfer_context = WalletTransferContext(
            wallet=swap.recipient, transfer=None)

        wallet_funds_before = 2
        recipient_funds_before = 0

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=2)
        cancel_finalize_swaps_for_eon(operator_eon_number=2)
        process_swaps_for_eon(operator_eon_number=2)

        # skip some eons
        for i in range(3, 5):
            # proceed to next eon
            advance_to_next_eon(test_case=self, eon_number=i - 1)
            commit_eon(test_case=self, eon_number=i)
            total_remaining_eons -= 1

            try:
                swap = Transfer.objects.get(swap=True,
                                            tx_id=swap_tx_id,
                                            eon_number=i)
                self.assertTrue(True)
            except Transfer.DoesNotExist:
                self.assertTrue(False)

            # process swaps
            confirm_swaps_for_eon(operator_eon_number=i)
            cancel_finalize_swaps_for_eon(operator_eon_number=i)
            process_swaps_for_eon(operator_eon_number=i)

            self.assertEqual(
                wallet_transfer_context.available_funds_at_eon(i, False),
                wallet_funds_before)
            self.assertEqual(
                recipient_transfer_context.available_funds_at_eon(i, False),
                recipient_funds_before)

        # make opposite swap
        send_swap(  # Sell LQD at 0.5 ETH
            test_case=self,
            eon_number=4,
            account=self.testrpc_accounts[2],
            token=self.lqd_token,
            token_swapped=self.eth_token,
            amount=2,
            amount_swapped=1,
            nonce=sell_lqd_nonce,
            eon_count=1)

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=4)
        cancel_finalize_swaps_for_eon(operator_eon_number=4)
        process_swaps_for_eon(operator_eon_number=4)

        finalize_last_swap(test_case=self,
                           token=self.lqd_token,
                           token_swapped=self.eth_token,
                           account=self.testrpc_accounts[2],
                           eon_count=1)

        self.assertEqual(
            wallet_transfer_context.available_funds_at_eon(4, False),
            wallet_funds_before - 1)
        self.assertEqual(
            recipient_transfer_context.available_funds_at_eon(4, False),
            recipient_funds_before + 2)

        # proceed to next eon
        advance_to_next_eon(test_case=self, eon_number=4)
        commit_eon(test_case=self, eon_number=5)
        total_remaining_eons -= 1

        swap = Transfer.objects.get(swap=True, tx_id=swap_tx_id, eon_number=5)
        self.assertFalse(swap.processed)
        self.assertTrue(swap.appended)
        self.assertFalse(swap.voided)
        self.assertFalse(swap.cancelled)
        self.assertFalse(swap.complete)
        self.assertEqual(
            wallet_transfer_context.available_funds_at_eon(5, False),
            wallet_funds_before - 1)
        self.assertEqual(
            recipient_transfer_context.available_funds_at_eon(5, False),
            recipient_funds_before + 2)

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=5)
        cancel_finalize_swaps_for_eon(operator_eon_number=5)
        process_swaps_for_eon(operator_eon_number=5)

        swap = Transfer.objects.get(swap=True, tx_id=swap_tx_id, eon_number=5)
        freeze_swap(test_case=self,
                    swap=swap,
                    account=self.testrpc_accounts[1])
        swap = Transfer.objects.get(swap=True, tx_id=swap_tx_id, eon_number=5)
        cancel_swap(test_case=self,
                    swap=swap,
                    account=self.testrpc_accounts[1],
                    eon_count=total_remaining_eons)
        self.assertEqual(
            Transfer.objects.filter(tx_id=swap_tx_id,
                                    eon_number__gt=5,
                                    swap=True,
                                    voided=False).count(), 0)
        # process swaps
        confirm_swaps_for_eon(operator_eon_number=5)
        cancel_finalize_swaps_for_eon(operator_eon_number=5)
        process_swaps_for_eon(operator_eon_number=5)

        swap = Transfer.objects.get(swap=True, tx_id=swap_tx_id, eon_number=5)
        self.assertTrue(swap.processed)
        self.assertTrue(swap.appended)
        self.assertFalse(swap.voided)
        self.assertTrue(swap.cancelled)
        self.assertFalse(swap.complete)
        self.assertEqual(
            wallet_transfer_context.available_funds_at_eon(5, False),
            wallet_funds_before - 1)
        self.assertEqual(
            recipient_transfer_context.available_funds_at_eon(5, False),
            recipient_funds_before + 2)

        # proceed to next eon
        advance_to_next_eon(test_case=self, eon_number=5)
        commit_eon(test_case=self, eon_number=6)
        total_remaining_eons -= 1

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=6)
        cancel_finalize_swaps_for_eon(operator_eon_number=6)
        process_swaps_for_eon(operator_eon_number=6)

        swap = Transfer.objects.get(swap=True, tx_id=swap_tx_id, eon_number=6)
        self.assertTrue(swap.processed)
        self.assertFalse(swap.appended)
        self.assertTrue(swap.voided)
        self.assertTrue(swap.cancelled)
        self.assertFalse(swap.complete)
        self.assertEqual(
            wallet_transfer_context.available_funds_at_eon(6, False),
            wallet_funds_before - 1)
        self.assertEqual(
            recipient_transfer_context.available_funds_at_eon(6, False),
            recipient_funds_before + 2)

        # make opposite swap
        send_swap(  # Sell LQD at 0.5 ETH
            test_case=self,
            eon_number=6,
            account=self.testrpc_accounts[3],
            token=self.lqd_token,
            token_swapped=self.eth_token,
            amount=2,
            amount_swapped=1,
            nonce=sell_lqd_nonce,
            eon_count=1)

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=6)
        cancel_finalize_swaps_for_eon(operator_eon_number=6)
        process_swaps_for_eon(operator_eon_number=6)

        self.assertEqual(
            wallet_transfer_context.available_funds_at_eon(6, False),
            wallet_funds_before - 1)
        self.assertEqual(
            recipient_transfer_context.available_funds_at_eon(6, False),
            recipient_funds_before + 2)

        commit_eon(test_case=self, eon_number=6)
Пример #7
0
    def test_cancel_multi_eon_swap(self):
        commit_eon(test_case=self, eon_number=1)

        advance_to_next_eon(test_case=self, eon_number=1)
        commit_eon(test_case=self, eon_number=2)

        buy_lqd_nonce = random.randint(1, 999999)
        sell_lqd_nonce = random.randint(1, 999999)

        total_remaining_eons = 5
        # make persistent swap
        buy_lqd = send_swap(  # Buy LQD at 0.5 ETH
            test_case=self,
            eon_number=2,
            account=self.testrpc_accounts[1],
            token=self.eth_token,
            token_swapped=self.lqd_token,
            amount=1,
            amount_swapped=2,
            nonce=buy_lqd_nonce,
            eon_count=total_remaining_eons)

        swap = Transfer.objects.filter(
            swap=True, wallet__token=self.eth_token).order_by('id')[0]
        swap_tx_id = swap.tx_id
        wallet_transfer_context = WalletTransferContext(wallet=swap.wallet,
                                                        transfer=None)
        recipient_transfer_context = WalletTransferContext(
            wallet=swap.recipient, transfer=None)

        wallet_funds_before = 1
        recipient_funds_before = 0

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=2)
        cancel_finalize_swaps_for_eon(operator_eon_number=2)
        process_swaps_for_eon(operator_eon_number=2)

        # skip some eons
        for i in range(3, 5):
            # proceed to next eon
            advance_to_next_eon(test_case=self, eon_number=i - 1)
            commit_eon(test_case=self, eon_number=i)
            total_remaining_eons -= 1

            # process swaps
            confirm_swaps_for_eon(operator_eon_number=i)
            cancel_finalize_swaps_for_eon(operator_eon_number=i)
            process_swaps_for_eon(operator_eon_number=i)

            self.assertEqual(
                wallet_transfer_context.available_funds_at_eon(i, False),
                wallet_funds_before)
            self.assertEqual(
                recipient_transfer_context.available_funds_at_eon(i, False),
                recipient_funds_before)
            self.assertEqual(
                wallet_transfer_context.balance_as_of_eon(i).amount(),
                wallet_funds_before)

        swap = Transfer.objects.get(swap=True, tx_id=swap_tx_id, eon_number=4)
        freeze_swap(test_case=self,
                    swap=swap,
                    account=self.testrpc_accounts[1])
        swap = Transfer.objects.get(swap=True, tx_id=swap_tx_id, eon_number=4)
        cancel_swap(test_case=self,
                    swap=swap,
                    account=self.testrpc_accounts[1],
                    eon_count=total_remaining_eons)
        self.assertEqual(
            Transfer.objects.filter(tx_id=swap_tx_id,
                                    eon_number__gt=4,
                                    swap=True,
                                    voided=False).count(), 0)

        swap = Transfer.objects.filter(swap=True)[0]
        self.assertTrue(swap.cancelled)
        self.assertTrue(swap.processed)
        self.assertTrue(swap.appended)
        self.assertTrue(swap.sender_cancellation_active_state.
                        operator_signature is not None)

        # proceed to next eon
        advance_to_next_eon(test_case=self, eon_number=4)
        commit_eon(test_case=self, eon_number=5)
        total_remaining_eons -= 1

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=5)
        cancel_finalize_swaps_for_eon(operator_eon_number=5)
        process_swaps_for_eon(operator_eon_number=5)

        swap = Transfer.objects.filter(swap=True)[0]
        self.assertTrue(swap.cancelled)
        self.assertTrue(swap.processed)
        self.assertTrue(swap.appended)
        self.assertEqual(swap.eon_number, 4)
        self.assertEqual(
            wallet_transfer_context.balance_as_of_eon(5).amount(),
            wallet_funds_before)

        self.assertEqual(
            wallet_transfer_context.available_funds_at_eon(5, False),
            wallet_funds_before)
        self.assertEqual(
            recipient_transfer_context.available_funds_at_eon(5, False),
            recipient_funds_before)

        # make opposite swap
        sell_lqd = send_swap(  # Sell LQD at 0.5 ETH
            test_case=self,
            eon_number=5,
            account=self.testrpc_accounts[2],
            token=self.lqd_token,
            token_swapped=self.eth_token,
            amount=2,
            amount_swapped=1,
            nonce=sell_lqd_nonce,
            eon_count=1)

        # process swaps
        confirm_swaps_for_eon(operator_eon_number=5)
        cancel_finalize_swaps_for_eon(operator_eon_number=5)
        process_swaps_for_eon(operator_eon_number=5)

        self.assertEqual(
            wallet_transfer_context.available_funds_at_eon(5, False),
            wallet_funds_before)
        self.assertEqual(
            recipient_transfer_context.available_funds_at_eon(5, False),
            recipient_funds_before)

        commit_eon(test_case=self, eon_number=5)
Пример #8
0
def send_swap(test_case: RPCTestCase,
              eon_number,
              account,
              token,
              token_swapped,
              amount,
              amount_swapped,
              nonce,
              expected_status=status.HTTP_201_CREATED,
              eon_count=1,
              sell_order=True):
    # Sender account
    sender_wallet = Wallet.objects.get(address=remove_0x_prefix(
        account.get('address')),
                                       token=token)
    # Recipient account
    recipient_wallet = Wallet.objects.get(address=remove_0x_prefix(
        account.get('address')),
                                          token=token_swapped)

    sender_wallet_context = WalletTransferContext(wallet=sender_wallet,
                                                  transfer=None)
    recipient_wallet_context = WalletTransferContext(wallet=recipient_wallet,
                                                     transfer=None)

    initial_sender_balance = sender_wallet_context.available_funds_at_eon(
        eon_number=eon_number, only_appended=False)
    initial_recipient_balance = recipient_wallet_context.available_funds_at_eon(
        eon_number=eon_number, only_appended=False)

    if initial_sender_balance < amount:
        send_transaction(test_case=test_case,
                         eon_number=eon_number,
                         sender=testrpc_accounts.accounts[0],
                         recipient=account,
                         amount=amount - initial_sender_balance,
                         nonce=random.randint(1, 999999),
                         token=token)
    if initial_sender_balance > amount:
        # clear sender account
        send_transaction(test_case=test_case,
                         eon_number=eon_number,
                         sender=account,
                         recipient=testrpc_accounts.accounts[0],
                         amount=initial_sender_balance - amount,
                         nonce=random.randint(1, 999999),
                         token=token)
    if initial_recipient_balance > 0:
        # clear recipient account
        send_transaction(test_case=test_case,
                         eon_number=eon_number,
                         sender=account,
                         recipient=testrpc_accounts.accounts[0],
                         amount=initial_recipient_balance,
                         nonce=random.randint(1, 999999),
                         token=token_swapped)

    sender_balance = sender_wallet_context.available_funds_at_eon(
        eon_number=eon_number, only_appended=False)
    recipient_balance = recipient_wallet_context.available_funds_at_eon(
        eon_number=eon_number, only_appended=False)

    test_case.assertEqual(sender_balance, amount)
    test_case.assertEqual(recipient_balance, 0)

    debit_balance_signatures = []
    debit_signatures = []
    credit_balance_signatures = []
    credit_signatures = []
    fulfillment_signatures = []

    for i in range(eon_count):
        swap = Transfer(wallet=sender_wallet,
                        amount=amount,
                        eon_number=eon_number + i,
                        recipient=recipient_wallet,
                        amount_swapped=amount_swapped,
                        nonce=nonce,
                        processed=False,
                        complete=False,
                        swap=True)

        sender_wallet_context = WalletTransferContext(wallet=sender_wallet,
                                                      transfer=swap)
        recipient_wallet_context = WalletTransferContext(
            wallet=recipient_wallet, transfer=swap)

        sender_highest_spent, sender_highest_gained = sender_wallet_context.off_chain_actively_sent_received_amounts(
            eon_number=eon_number + i, only_appended=False)

        if i == 0:
            tx_set_tree = sender_wallet_context.authorized_transfers_tree(
                only_appended=False, force_append=True)
        else:
            tx_set_tree = WalletTransferContext.authorized_transfers_tree_from_list(
                [
                    swap.shorthand(sender_wallet_context,
                                   is_last_transfer=True,
                                   starting_balance=sender_balance)
                ])

        tx_set_hash = hex_value(tx_set_tree.root_hash())

        debiting_active_state = ActiveState(
            wallet=sender_wallet,
            updated_spendings=sender_highest_spent + amount,
            updated_gains=sender_highest_gained,
            eon_number=eon_number + i,
            tx_set_hash=tx_set_hash)
        debiting_active_state_authorization = sign_message(
            debiting_active_state.checksum(), account.get('pk'))

        debiting_active_state_signature = Signature(
            wallet=sender_wallet,
            checksum=hex_value(debiting_active_state.checksum()),
            value=encode_signature(debiting_active_state_authorization))

        test_case.assertTrue(debiting_active_state_signature.is_valid())

        debit_concise_balance_marker = MinimumAvailableBalanceMarker(
            wallet=sender_wallet, eon_number=eon_number + i, amount=0)
        debit_concise_balance_marker_authorization = sign_message(
            debit_concise_balance_marker.checksum(), account.get('pk'))

        debit_concise_balance_marker_signature = Signature(
            wallet=sender_wallet,
            checksum=hex_value(debit_concise_balance_marker.checksum()),
            value=encode_signature(debit_concise_balance_marker_authorization))

        test_case.assertTrue(debit_concise_balance_marker_signature.is_valid())

        recipient_highest_spent, recipient_highest_gained = recipient_wallet_context.off_chain_actively_sent_received_amounts(
            eon_number=eon_number + i, only_appended=False)

        if i == 0:
            tx_set_tree = recipient_wallet_context.authorized_transfers_tree(
                only_appended=False, force_append=True)
        else:
            tx_set_tree = WalletTransferContext.authorized_transfers_tree_from_list(
                [
                    swap.shorthand(recipient_wallet_context,
                                   is_last_transfer=True,
                                   starting_balance=recipient_balance)
                ])

        tx_set_hash = hex_value(tx_set_tree.root_hash())

        crediting_active_state = ActiveState(
            wallet=recipient_wallet,
            updated_spendings=recipient_highest_spent,
            updated_gains=recipient_highest_gained,
            eon_number=eon_number + i,
            tx_set_hash=tx_set_hash)
        crediting_active_state_authorization = sign_message(
            crediting_active_state.checksum(), account.get('pk'))

        crediting_active_state_signature = Signature(
            wallet=recipient_wallet,
            checksum=hex_value(crediting_active_state.checksum()),
            value=encode_signature(crediting_active_state_authorization))

        test_case.assertTrue(crediting_active_state_signature.is_valid())

        credit_concise_balance_marker = MinimumAvailableBalanceMarker(
            wallet=recipient_wallet, eon_number=eon_number + i, amount=0)
        credit_concise_balance_marker_authorization = sign_message(
            credit_concise_balance_marker.checksum(), account.get('pk'))

        credit_concise_balance_marker_signature = Signature(
            wallet=recipient_wallet,
            checksum=hex_value(credit_concise_balance_marker.checksum()),
            value=encode_signature(
                credit_concise_balance_marker_authorization))

        test_case.assertTrue(
            credit_concise_balance_marker_signature.is_valid())

        swap.processed, swap.complete = True, True

        if i == 0:
            tx_set_tree = recipient_wallet_context.authorized_transfers_tree(
                only_appended=False, force_append=True)
        else:
            tx_set_tree = WalletTransferContext.authorized_transfers_tree_from_list(
                [
                    swap.shorthand(recipient_wallet_context,
                                   is_last_transfer=True,
                                   starting_balance=0)
                ])

        tx_set_hash = hex_value(tx_set_tree.root_hash())

        recipient_fulfillment_active_state = ActiveState(
            wallet=recipient_wallet,
            updated_spendings=recipient_highest_spent,
            updated_gains=recipient_highest_gained + amount_swapped,
            eon_number=eon_number + i,
            tx_set_hash=tx_set_hash)
        recipient_fulfillment_active_state_authorization = sign_message(
            recipient_fulfillment_active_state.checksum(), account.get('pk'))
        swap.processed, swap.complete = False, False

        recipient_fulfillment_active_state_signature = Signature(
            wallet=recipient_wallet,
            checksum=hex_value(recipient_fulfillment_active_state.checksum()),
            value=encode_signature(
                recipient_fulfillment_active_state_authorization))

        test_case.assertTrue(
            recipient_fulfillment_active_state_signature.is_valid())

        debit_balance_signatures.append({
            'value':
            encode_signature(debit_concise_balance_marker_authorization)
        })
        debit_signatures.append(
            {'value': encode_signature(debiting_active_state_authorization)})
        credit_balance_signatures.append({
            'value':
            encode_signature(credit_concise_balance_marker_authorization)
        })
        credit_signatures.append(
            {'value': encode_signature(crediting_active_state_authorization)})
        fulfillment_signatures.append({
            'value':
            encode_signature(recipient_fulfillment_active_state_authorization)
        })

    # Make API Request
    url = reverse('swap-endpoint')
    data = {
        'debit_signature': debit_signatures,
        'debit_balance_signature': debit_balance_signatures,
        'credit_signature': credit_signatures,
        'credit_balance_signature': credit_balance_signatures,
        'credit_fulfillment_signature': fulfillment_signatures,
        'eon_number': eon_number,
        'amount': amount,
        'amount_swapped': amount_swapped,
        'nonce': nonce,
        'wallet': {
            'address': sender_wallet.address,
            'token': sender_wallet.token.address,
        },
        'recipient': {
            'address': recipient_wallet.address,
            'token': recipient_wallet.token.address,
        },
        'sell_order': sell_order
    }

    # Send tx to server
    x = datetime.now()
    response = test_case.client.post(url, data, format='json')
    y = datetime.now()
    delta = y - x

    # Ensure the transaction was recorded
    test_case.assertEqual(response.status_code, expected_status,
                          response.content)

    print('SWAP Time: {}s for {}/{}'.format(delta, amount, amount_swapped))

    # assert that swap created for current eon is confirmed
    tx = json.loads(response.content)
    swap = Transfer.objects.get(id=tx['id'])
    test_case.assertEqual(swap.eon_number, eon_number)
    test_case.assertTrue(swap.is_signed_by_operator())

    # Log time delta
    return delta
Пример #9
0
    def create(self, validated_data):
        wallet = validated_data.pop('wallet')
        recipient = validated_data.pop('recipient')

        if not TokenPair.objects.filter(token_from=wallet.token,
                                        token_to=recipient.token).exists():
            raise serializers.ValidationError(
                detail='', code=ErrorCode.TOKEN_PAIR_BLOCKED)

        # swap data
        valid_eons = validated_data.pop('valid_eons')
        swap_amount = validated_data.pop('amount')
        swap_nonce = validated_data.pop('nonce')
        sell_order = validated_data.pop('sell_order', True)
        swap_amount_swapped = validated_data.pop('amount_swapped')
        debit_signatures = validated_data.pop('debit_signature')
        debit_balance_signatures = validated_data.pop(
            'debit_balance_signature')
        credit_balance_signatures = validated_data.pop(
            'credit_balance_signature')
        credit_signatures = validated_data.pop('credit_signature')
        recipient_fulfillment_signatures = validated_data.pop(
            'credit_fulfillment_signature')

        # common transaction id
        tx_id = uuid.uuid4()
        tx_time = timezone.now()

        # cached items to be used later
        sender_available_balance = 0
        recipient_available_balance = 0

        swap_set = []

        debit_tx_set_index = []
        credit_tx_set_index = []
        # recipient_fulfillment_tx_set_index = []

        debit_tx_set_cache = []
        credit_tx_set_cache = []
        # recipient_fulfillment_tx_set_cache = []

        debit_balance_signature_records = []
        credit_balance_signature_records = []
        debit_signature_records = []
        credit_signature_records = []
        recipient_fulfillment_signature_records = []

        debit_balance_records = []
        credit_balance_records = []
        debit_active_state_records = []
        credit_active_state_records = []
        recipient_fulfillment_active_state_records = []

        initial_swap_confirmed = False

        # get current eon
        current_eon = LocalViewInterface.latest().eon_number()

        # initial swap eon should be the current eon number
        if validated_data.pop('eon_number') != current_eon:
            raise serializers.ValidationError(
                detail='', code=ErrorCode.EON_NUMBER_OUT_OF_SYNC)

        wallets = sorted([wallet, recipient], key=lambda w: w.token.id)
        with RootCommitment.read_write_lock(
                suffix=current_eon, auto_renewal=False), wallets[0].lock(
                    auto_renewal=False), wallets[1].lock(auto_renewal=False):
            if RootCommitment.objects.filter(eon_number=current_eon +
                                             1).exists():
                raise serializers.ValidationError(
                    detail='Checkpoint was already created for this eon.',
                    code=ErrorCode.EON_NUMBER_OUT_OF_SYNC)

            for eon_number in range(current_eon, current_eon + valid_eons):
                swap = Transfer(tx_id=tx_id,
                                wallet=wallet,
                                amount=swap_amount,
                                eon_number=eon_number,
                                recipient=recipient,
                                nonce=swap_nonce,
                                amount_swapped=swap_amount_swapped,
                                swap=True,
                                sell_order=sell_order,
                                time=tx_time)

                wallet_view_context = WalletTransferContext(wallet=wallet,
                                                            transfer=swap)
                recipient_view_context = WalletTransferContext(
                    wallet=recipient, transfer=swap)

                if eon_number == current_eon:
                    # Ensure sender log consistency
                    can_append_to_sender_log = wallet_view_context.can_schedule_transfer(
                    )
                    if can_append_to_sender_log is not True:
                        raise serializers.ValidationError(
                            detail='Sender: {}'.format(
                                can_append_to_sender_log),
                            code=ErrorCode.DEBIT_WALLET_CANNOT_ADD_TRANSACTION)

                    # Ensure recipient log consistency
                    can_append_to_recipient_log = recipient_view_context.can_schedule_transfer(
                    )
                    if can_append_to_recipient_log is not True:
                        raise serializers.ValidationError(
                            detail='Recipient: {}'.format(
                                can_append_to_recipient_log),
                            code=ErrorCode.CREDIT_WALLET_CANNOT_ADD_TRANSACTION
                        )

                    # Ensure swap consistency
                    can_spend, sender_available_balance = wallet_view_context.can_send_transfer(
                        current_eon_number=current_eon,
                        using_only_appended_funds=False)
                    if can_spend is not True:
                        raise serializers.ValidationError(
                            detail=can_spend,
                            code=ErrorCode.DEBIT_WALLET_OVERSPENDING)

                    # Ensure that sender balance is exactly equal to total outgoing amount
                    if sender_available_balance != swap.amount:
                        raise serializers.ValidationError(
                            detail=
                            'Sender balance should be exactly equal to outgoing swap amount, {} != {}.'
                            .format(sender_available_balance, swap.amount),
                            code=ErrorCode.DEBIT_WALLET_BALANCE_AMOUNT_MISMATCH
                        )

                    # Ensure that recipient balance is zero
                    recipient_available_balance = recipient_view_context.available_funds_at_eon(
                        eon_number=eon_number, only_appended=False)
                    if recipient_available_balance != 0:
                        raise serializers.ValidationError(
                            detail='Recipient balance should be exactly zero.',
                            code=ErrorCode.CREDIT_WALLET_BALANCE_NOT_ZERO)

                    current_eon_swap = swap
                    sender_highest_spendings, sender_highest_gains = wallet_view_context.off_chain_actively_sent_received_amounts(
                        eon_number=swap.eon_number, only_appended=False)
                    recipient_highest_spendings, recipient_highest_gains = recipient_view_context.off_chain_actively_sent_received_amounts(
                        eon_number=swap.eon_number, only_appended=False)
                else:
                    sender_highest_spendings, sender_highest_gains = 0, 0
                    recipient_highest_spendings, recipient_highest_gains = 0, 0

                # Minimum Debit Balance Marker
                debit_balance_marker_signature_data = debit_balance_signatures[
                    eon_number - current_eon]
                debit_balance_marker = MinimumAvailableBalanceMarker(
                    wallet=wallet, eon_number=eon_number, amount=0)

                debit_balance_marker_checksum = crypto.hex_value(
                    debit_balance_marker.checksum())
                debit_balance_marker_signature = Signature(
                    wallet=wallet,
                    checksum=debit_balance_marker_checksum,
                    value=debit_balance_marker_signature_data.get('value'))
                if not debit_balance_marker_signature.is_valid():
                    raise serializers.ValidationError(
                        detail='',
                        code=ErrorCode.INVALID_DEBIT_BALANCE_SIGNATURE)

                # Minimum Credit Balance Marker
                credit_balance_marker_signature_data = credit_balance_signatures[
                    eon_number - current_eon]
                credit_balance_marker = MinimumAvailableBalanceMarker(
                    wallet=recipient, eon_number=eon_number, amount=0)

                credit_balance_marker_checksum = crypto.hex_value(
                    credit_balance_marker.checksum())
                credit_balance_marker_signature = Signature(
                    wallet=recipient,
                    checksum=credit_balance_marker_checksum,
                    value=credit_balance_marker_signature_data.get('value'))
                if not credit_balance_marker_signature.is_valid():
                    raise serializers.ValidationError(
                        detail='',
                        code=ErrorCode.INVALID_CREDIT_BALANCE_SIGNATURE)
                assert (sender_available_balance == swap.amount)
                # Debit Authorization
                debit_active_state_signature_data = debit_signatures[
                    eon_number - current_eon]
                debit_active_state, \
                    debit_active_state_signature, \
                    debit_transfer_index, \
                    debit_transfer_cache = check_active_state_signature(
                        swap,
                        wallet,
                        debit_active_state_signature_data,
                        eon_number > current_eon,
                        sender_available_balance,
                        sender_highest_spendings,
                        sender_highest_gains,
                        signature_type=SignatureType.DEBIT)

                # Credit Authorization
                credit_active_state_signature_data = credit_signatures[
                    eon_number - current_eon]
                credit_active_state, \
                    credit_active_state_signature, \
                    credit_transfer_index, \
                    credit_transfer_cache = check_active_state_signature(
                        swap,
                        recipient,
                        credit_active_state_signature_data,
                        eon_number > current_eon,
                        recipient_available_balance,
                        recipient_highest_spendings,
                        recipient_highest_gains,
                        signature_type=SignatureType.CREDIT)

                # Finality Authorization
                recipient_fulfillment_active_state_signature_data = recipient_fulfillment_signatures[
                    eon_number - current_eon]
                recipient_fulfillment_active_state, \
                    recipient_fulfillment_active_state_signature, \
                    recipient_fulfillment_transfer_index, \
                    recipient_fulfillment_transfer_cache = check_active_state_signature(
                        swap,
                        recipient,
                        recipient_fulfillment_active_state_signature_data,
                        eon_number > current_eon,
                        recipient_available_balance,
                        recipient_highest_spendings,
                        recipient_highest_gains,
                        signature_type=SignatureType.FULFILLMENT)

                # accumulate records to be saved
                debit_balance_signature_records.append(
                    debit_balance_marker_signature)
                credit_balance_signature_records.append(
                    credit_balance_marker_signature)
                debit_signature_records.append(debit_active_state_signature)
                credit_signature_records.append(credit_active_state_signature)
                recipient_fulfillment_signature_records.append(
                    recipient_fulfillment_active_state_signature)

                debit_balance_records.append(debit_balance_marker)
                credit_balance_records.append(credit_balance_marker)
                debit_active_state_records.append(debit_active_state)
                credit_active_state_records.append(credit_active_state)
                recipient_fulfillment_active_state_records.append(
                    recipient_fulfillment_active_state)

                debit_tx_set_index.append(debit_transfer_index)
                credit_tx_set_index.append(credit_transfer_index)
                # recipient_fulfillment_tx_set_index.append(recipient_fulfillment_transfer_index)

                debit_tx_set_cache.append(debit_transfer_cache)
                credit_tx_set_cache.append(credit_transfer_cache)
                # recipient_fulfillment_tx_set_cache.append(recipient_fulfillment_transfer_cache)
                swap_set.append(swap)

            assert (swap_set[0] is not None
                    and swap_set[0].eon_number == current_eon)
            assert (len(swap_set) == valid_eons)

            # locking context covers saving the state as well to make sure checkpoint creation is consistent
            with transaction.atomic():
                Signature.objects.bulk_create(
                    debit_balance_signature_records +
                    credit_balance_signature_records +
                    debit_signature_records + credit_signature_records +
                    recipient_fulfillment_signature_records)

                for index in range(valid_eons):
                    debit_balance_records[
                        index].signature = debit_balance_signature_records[
                            index]
                    credit_balance_records[
                        index].signature = credit_balance_signature_records[
                            index]
                    debit_active_state_records[
                        index].wallet_signature = debit_signature_records[
                            index]
                    credit_active_state_records[
                        index].wallet_signature = credit_signature_records[
                            index]
                    recipient_fulfillment_active_state_records[
                        index].wallet_signature = recipient_fulfillment_signature_records[
                            index]

                ActiveState.objects.bulk_create(
                    debit_active_state_records + credit_active_state_records +
                    recipient_fulfillment_active_state_records)

                MinimumAvailableBalanceMarker.objects.bulk_create(
                    debit_balance_records + credit_balance_records)

                for index in range(valid_eons):
                    swap_set[
                        index].sender_active_state = debit_active_state_records[
                            index]
                    swap_set[
                        index].recipient_active_state = credit_active_state_records[
                            index]
                    swap_set[
                        index].recipient_fulfillment_active_state = recipient_fulfillment_active_state_records[
                            index]
                    swap_set[
                        index].sender_balance_marker = debit_balance_records[
                            index]

                    swap_set[
                        index].sender_starting_balance = sender_available_balance
                    swap_set[
                        index].recipient_starting_balance = recipient_available_balance

                    # cache swap index in sender active set
                    swap_set[index].sender_merkle_index = debit_tx_set_index[
                        index]
                    # cache swap index in recipient active set
                    swap_set[
                        index].recipient_merkle_index = credit_tx_set_index[
                            index]
                    # cache active set merkle mountains height array and hash array for sender active set
                    swap_set[index].sender_merkle_hash_cache, swap_set[
                        index].sender_merkle_height_cache = debit_tx_set_cache[
                            index]
                    # cache active set merkle mountains height array and hash array for recipient active set
                    swap_set[index].recipient_merkle_hash_cache, swap_set[
                        index].recipient_merkle_height_cache = debit_tx_set_cache[
                            index]

                Transfer.objects.bulk_create(swap_set)

                swap_set[0].sign_swap(settings.HUB_OWNER_ACCOUNT_ADDRESS,
                                      settings.HUB_OWNER_ACCOUNT_KEY)
                initial_swap_confirmed = True

        if initial_swap_confirmed:
            operator_celery.send_task('auditor.tasks.on_swap_confirmation',
                                      args=[swap_set[0].id])

        return swap_set[0]