Beispiel #1
0
    def to_representation(self, transfer: Transfer):
        if transfer.final_receipt_hashes is None:
            return {}

        # include proof if
        # 1) context wallet_id is provided and parent is sender wallet
        # 2) context wallet_id is None
        include_proof = self.context.get(
            'wallet_id') is None or self.context.get(
                'wallet_id') == transfer.wallet.id

        if include_proof:
            recipient_balance = WalletTransferContext(
                wallet=transfer.recipient,
                transfer=transfer).balance_as_of_eon(transfer.eon_number + 1)

        return {
            'merkle_proof':
            ProofSerializer(recipient_balance, read_only=True).data
            if include_proof else None,
            'transfer_membership_chain':
            long_string_to_list(transfer.final_receipt_hashes, 64),
            'transfer_membership_trail':
            int(transfer.final_receipt_index),
            'transfer_membership_values':
            csf_to_list(transfer.final_receipt_values)
            if transfer.passive else None
        }
Beispiel #2
0
 def to_representation(self, instance: ExclusiveBalanceAllotment):
     wallet_context = WalletTransferContext(
         wallet=instance.wallet, transfer=None)
     passive_checksum, passive_amount, passive_marker = wallet_context.get_passive_values(
         eon_number=instance.eon_number - 1)
     return {
         'eon_number': int(instance.eon_number),
         'left': str_int(instance.left),
         'right': str_int(instance.right),
         'allotment_chain': long_string_to_list(instance.merkle_proof_hashes, 64),
         'membership_chain': long_string_to_list(instance.merkle_membership_chain(), 64),
         'values': csf_to_list(instance.merkle_proof_values, str_int),
         'trail': int(instance.merkle_proof_trail),
         'active_state_checksum':
             encode_hex(instance.active_state.checksum()) if instance.active_state else
             encode_hex(b'\0'*32),
         'active_state':
             ConciseActiveStateSerializer(
                 instance.active_state, read_only=True).data if instance.active_state else None,
         'passive_checksum': encode_hex(passive_checksum),
         'passive_amount': str_int(passive_amount),
         'passive_marker': str_int(passive_marker)
     }
Beispiel #3
0
def place_parallel_withdrawals(test_case: RPCTestCase,
                               token,
                               wallet_address,
                               current_eon,
                               dishonest=False):
    token_commitment = TokenCommitment.objects.get(
        token=token, root_commitment__eon_number=current_eon - 1)

    wallet = Wallet.objects.get(token=token,
                                address=remove_0x_prefix(wallet_address))
    wallet_transfer_context = WalletTransferContext(wallet=wallet,
                                                    transfer=None)
    allotment = wallet_transfer_context.balance_as_of_eon(
        eon_number=current_eon - 1)

    passive_checksum, passive_amount, passive_marker = wallet_transfer_context.get_passive_values(
        eon_number=current_eon - 1)

    available_balance = wallet_transfer_context.loosely_available_funds_at_eon(
        eon_number=current_eon,
        current_eon_number=current_eon,
        is_checkpoint_created=True,
        only_appended=True)

    overdraw = dishonest and available_balance < allotment.amount()

    if overdraw:
        total_draw = max(available_balance, allotment.amount()) // 4
    else:
        total_draw = min(available_balance, allotment.amount()) // 4

    total_amount = 0

    if (total_draw == 0):
        return (total_amount, [], False)

    withdrawal_amounts = [total_draw // 4, total_draw // 2, total_draw // 4]

    for withdrawal_amount in withdrawal_amounts:

        cyan([
            wallet.address, wallet.token.address, withdrawal_amount,
            available_balance
        ])

        test_case.contract_interface.withdraw(
            token_address=wallet.token.address,
            wallet=wallet.address,
            active_state_checksum=crypto.zfill(
                allotment.active_state_checksum()),
            trail=int(allotment.merkle_proof_trail),
            allotment_chain=[
                crypto.zfill(crypto.decode_hex(checksum))
                for checksum in long_string_to_list(
                    allotment.merkle_proof_hashes, 64)
            ],
            membership_chain=[
                crypto.zfill(crypto.decode_hex(checksum))
                for checksum in long_string_to_list(
                    token_commitment.membership_hashes, 64)
            ],
            values=csf_to_list(allotment.merkle_proof_values, int),
            exclusive_allotment_interval=[
                int(allotment.left), int(allotment.right)
            ],
            withdrawal_amount=int(withdrawal_amount),
            passive_checksum=passive_checksum,
            passive_amount=passive_amount,
            passive_marker=passive_marker)

        total_amount += int(withdrawal_amount)

    return (total_amount, withdrawal_amounts, overdraw)
Beispiel #4
0
def respond_to_challenges():
    contract_interface = NOCUSTContractInterface()

    contract_interface.get_current_eon_number()

    latest_root_commitment = RootCommitment.objects\
        .all()\
        .order_by('eon_number')\
        .last()

    if latest_root_commitment is None:
        return

    with Challenge.global_lock():
        challenges = Challenge.objects\
            .filter(rebuted=False, eon_number__lte=latest_root_commitment.eon_number)\
            .order_by('block')
        for challenge in challenges:
            token = challenge.wallet.token
            challenge_entry_token = token.address

            if challenge.wallet.token != challenge.recipient.token:
                try:
                    tp = TokenPair.objects.get(
                        token_from=challenge.wallet.token,
                        token_to=challenge.recipient.token)
                except TokenPair.DoesNotExist:
                    logger.warning(
                        "Skipping challenge for {}. token pair not found!".
                        format(challenge.wallet.address))
                    continue

                token = challenge.recipient.token
                challenge_entry_token = to_checksum_address(tp.conduit)

            challenge_entry = contract_interface.get_challenge_record(
                token_address=challenge_entry_token,
                recipient=challenge.recipient.address,
                sender=challenge.wallet.address)

            if not challenge_entry.challengeStage:
                logger.warning(
                    "Skipping answered challenge for {}. Where is the answer tx_id?"
                    .format(challenge.wallet.address))
                continue

            try:
                recipient_balance = ExclusiveBalanceAllotment.objects.get(
                    wallet=challenge.recipient,
                    eon_number=challenge.eon_number)
            except ExclusiveBalanceAllotment.DoesNotExist:
                logger.error("Could not find balance for {} at eon {}.".format(
                    challenge.wallet.address, challenge.eon_number))
                send_admin_email(subject='DISPUTE! NO BALANCE!',
                                 content='{}'.format(challenge.wallet.address))
                return

            token_commitment = TokenCommitment.objects.get(
                token=token, root_commitment__eon_number=challenge.eon_number)

            # state update challenge
            if challenge.wallet.token == challenge.recipient.token and challenge.wallet.address == challenge.recipient.address:

                v_0, r_0, s_0 = recipient_balance.wallet_v_r_s()
                v_1, r_1, s_1 = recipient_balance.operator_v_r_s()

                recipient_transfer_context = WalletTransferContext(
                    wallet=challenge.recipient, transfer=None)

                passive_checksum, passive_amount, passive_marker = recipient_transfer_context.get_passive_values(
                    eon_number=challenge_entry.initialStateEon)

                logger.info(
                    "Answering challenge for {} with balance {}.".format(
                        challenge.wallet.address, recipient_balance.amount()))
                logger.info("{}{}{}, {}{}{}".format(v_0, r_0, s_0, v_1, r_1,
                                                    s_1))
                send_admin_email(subject='DISPUTE! Sate Update.',
                                 content='{}'.format(challenge.wallet.address))

                # TODO signal critical failure if this does not succeed!
                transaction = contract_interface.queue_answer_state_update_challenge(
                    challenge=challenge,
                    allotment_chain=[
                        crypto.zfill(crypto.decode_hex(checksum))
                        for checksum in long_string_to_list(
                            recipient_balance.merkle_proof_hashes, 64)
                    ],
                    membership_chain=[
                        crypto.zfill(crypto.decode_hex(checksum))
                        for checksum in long_string_to_list(
                            token_commitment.membership_hashes, 64)
                    ],
                    values=csf_to_list(recipient_balance.merkle_proof_values,
                                       int),
                    l_r=[
                        int(recipient_balance.left),
                        int(recipient_balance.right)
                    ],
                    tx_set_root=crypto.zfill(
                        crypto.decode_hex(
                            recipient_balance.transaction_set_root())),
                    deltas=[d for d in recipient_balance.deltas()],
                    r=[crypto.uint256(r_0),
                       crypto.uint256(r_1)],
                    s=[crypto.uint256(s_0),
                       crypto.uint256(s_1)],
                    v=[v_0, v_1],
                    passive_checksum=passive_checksum,
                    passive_amount=passive_amount,
                    passive_marker=passive_marker)

            # transfer challenge
            elif challenge.wallet.token == challenge.recipient.token and challenge.wallet.address != challenge.recipient.address:
                try:
                    transfer = Transfer.objects.get(
                        recipient=challenge.recipient,
                        eon_number=challenge_entry.initialStateEon,
                        nonce=challenge_entry.deliveredTxNonce)
                except Transfer.DoesNotExist:
                    logger.error(
                        "Could not find transfer for {} at eon {} with nonce {}."
                        .format(challenge.recipient.address,
                                challenge.eon_number,
                                challenge_entry.deliveredTxNonce))
                    send_admin_email(
                        subject='DISPUTE! NO TRANSFER!',
                        content=
                        "Could not find transfer for {} at eon {} with nonce {}."
                        .format(challenge.recipient.address,
                                challenge.eon_number,
                                challenge_entry.deliveredTxNonce))
                    return

                recipient_transfer_context = WalletTransferContext(
                    wallet=challenge.recipient, transfer=None)

                transfers_list_nonce_index_map = {}
                transfers_list = recipient_transfer_context.authorized_transfers_list_shorthand(
                    only_appended=True,
                    force_append=False,
                    eon_number=challenge_entry.initialStateEon,
                    last_transfer_is_finalized=False,
                    index_map=transfers_list_nonce_index_map)

                transfer_tree = TransactionMerkleTree(transfers_list)
                transfer_index = transfers_list_nonce_index_map.get(
                    transfer.nonce)
                transfer_node = transfer_tree.merkle_tree_leaf_map.get(
                    transfer_index)
                transfer_proof = [
                    node.get('hash') for node in calculate_merkle_proof(
                        transfer_index, transfer_node)
                ]

                passive_checksum, passive_amount, passive_marker = recipient_transfer_context.get_passive_values(
                    eon_number=challenge_entry.initialStateEon)

                send_admin_email(subject='DISPUTE! Transfer Delivery.',
                                 content='{} {} {}'.format(
                                     challenge.wallet.address,
                                     challenge.recipient.address,
                                     transfer_index))

                # TODO signal critical failure if this does not succeed!
                transaction = contract_interface.queue_answer_delivery_challenge(
                    challenge=challenge,
                    tx_trail=transfer_index,
                    allotment_chain=[
                        crypto.zfill(crypto.decode_hex(v))
                        for v in long_string_to_list(
                            recipient_balance.merkle_proof_hashes, 64)
                    ],
                    membership_chain=[
                        crypto.zfill(crypto.decode_hex(checksum))
                        for checksum in long_string_to_list(
                            token_commitment.membership_hashes, 64)
                    ],
                    values=csf_to_list(recipient_balance.merkle_proof_values,
                                       int),
                    l_r=[
                        int(recipient_balance.left),
                        int(recipient_balance.right)
                    ],
                    deltas=[d for d in recipient_balance.deltas()],
                    tx_set_root=crypto.decode_hex(
                        recipient_balance.transaction_set_root()),
                    tx_chain=[crypto.zfill(x) for x in transfer_proof],
                    passive_checksum=passive_checksum,
                    passive_amount=passive_amount,
                    passive_marker=passive_marker)

            # swap challenge
            elif challenge.wallet.token != challenge.recipient.token and challenge.wallet.address == challenge.recipient.address:
                try:
                    transfer = Transfer.objects.get(
                        recipient=challenge.recipient,
                        eon_number=challenge_entry.initialStateEon,
                        nonce=challenge_entry.deliveredTxNonce)
                except Transfer.DoesNotExist:
                    logger.error(
                        "Could not find transfer for {} at eon {} with nonce {}."
                        .format(challenge.recipient.address,
                                challenge.eon_number,
                                challenge_entry.deliveredTxNonce))
                    send_admin_email(
                        subject='DISPUTE! NO SWAP!',
                        content=
                        "Could not find transfer for {} at eon {} with nonce {}."
                        .format(challenge.recipient.address,
                                challenge.eon_number,
                                challenge_entry.deliveredTxNonce))
                    return

                recipient_transfer_context = WalletTransferContext(
                    wallet=challenge.recipient, transfer=None)

                # if not initial transfer in a multi eon swap
                # override starting balance to cached starting balance
                if Transfer.objects.filter(eon_number=transfer.eon_number - 1,
                                           tx_id=transfer.tx_id).exists():
                    starting_balance = int(transfer.recipient_starting_balance)
                else:
                    starting_balance = int(
                        recipient_transfer_context.starting_balance_in_eon(
                            challenge_entry.initialStateEon))

                transfers_list_nonce_index_map = {}
                transfers_list = recipient_transfer_context.authorized_transfers_list_shorthand(
                    only_appended=True,
                    force_append=False,
                    eon_number=challenge_entry.initialStateEon,
                    last_transfer_is_finalized=True,
                    index_map=transfers_list_nonce_index_map,
                    starting_balance=starting_balance)

                transfer_tree = TransactionMerkleTree(transfers_list)
                transfer_index = transfers_list_nonce_index_map.get(
                    transfer.nonce)
                transfer_node = transfer_tree.merkle_tree_leaf_map.get(
                    transfer_index)
                transfer_proof = [
                    node.get('hash') for node in calculate_merkle_proof(
                        transfer_index, transfer_node)
                ]

                passive_checksum, passive_amount, passive_marker = recipient_transfer_context.get_passive_values(
                    eon_number=challenge_entry.initialStateEon)

                send_admin_email(subject='DISPUTE! Swap Delivery.',
                                 content='{} {} {}'.format(
                                     challenge.wallet.address,
                                     challenge.recipient.address,
                                     transfer_index))

                is_cancelled = transfer.cancelled and transfer.recipient_cancellation_active_state is not None
                if transfer.complete or is_cancelled:
                    starting_balance = 2**256 - 1

                # TODO signal critical failure if this does not succeed!
                transaction = contract_interface.queue_answer_swap_challenge(
                    challenge=challenge,
                    token_pair=[
                        challenge.wallet.token.address,
                        challenge.recipient.token.address
                    ],
                    balance_at_start_of_eon=starting_balance,
                    tx_trail=int(transfer_index),
                    allotment_chain=[
                        crypto.zfill(crypto.decode_hex(v))
                        for v in long_string_to_list(
                            recipient_balance.merkle_proof_hashes, 64)
                    ],
                    membership_chain=[
                        crypto.zfill(crypto.decode_hex(checksum))
                        for checksum in long_string_to_list(
                            token_commitment.membership_hashes, 64)
                    ],
                    values=csf_to_list(recipient_balance.merkle_proof_values,
                                       int),
                    l_r=[
                        int(recipient_balance.left),
                        int(recipient_balance.right)
                    ],
                    deltas=[d for d in recipient_balance.deltas()],
                    tx_set_root=crypto.zfill(
                        crypto.decode_hex(
                            recipient_balance.transaction_set_root())),
                    tx_chain=[crypto.zfill(x) for x in transfer_proof],
                    passive_checksum=passive_checksum,
                    passive_amount=passive_amount,
                    passive_marker=passive_marker)

            challenge.rebuted = True
            challenge.save()
            logger.warning(transaction)
Beispiel #5
0
def init_swap_challenge(test_case: RPCTestCase, swap: Transfer, eon_number):
    sender_transfer_context = WalletTransferContext(wallet=swap.wallet,
                                                    transfer=None)

    if Transfer.objects.filter(eon_number=swap.eon_number - 1,
                               tx_id=swap.tx_id).exists():
        starting_balance = int(swap.sender_starting_balance)
    else:
        starting_balance = int(
            sender_transfer_context.starting_balance_in_eon(eon_number))

    transfers_list_nonce_index_map = {}
    transfers_list = sender_transfer_context.authorized_transfers_list_shorthand(
        only_appended=True,
        force_append=False,
        eon_number=eon_number,
        last_transfer_is_finalized=True,
        index_map=transfers_list_nonce_index_map,
        starting_balance=starting_balance)

    sender_active_state = sender_transfer_context.last_appended_active_state(
        eon_number=eon_number)

    transfer_tree = TransactionMerkleTree(transfers_list)
    transfer_index = transfers_list_nonce_index_map.get(int(swap.nonce))
    transfer_node = transfer_tree.merkle_tree_leaf_map.get(transfer_index)
    transfer_proof = [
        node.get('hash')
        for node in calculate_merkle_proof(transfer_index, transfer_node)
    ]

    test_case.assertEqual(sender_active_state.tx_set_hash,
                          crypto.hex_value(transfer_tree.root_hash()))

    tx_set_root = crypto.zfill(
        crypto.decode_hex(sender_active_state.tx_set_hash))
    deltas = [
        int(sender_active_state.updated_spendings),
        int(sender_active_state.updated_gains)
    ]

    test_case.assertTrue(
        test_case.contract_interface.check_merkle_membership_proof(
            trail=int(transfer_index),
            chain=[crypto.zfill(x) for x in transfer_proof],
            node=transfer_node.get('hash'),
            merkle_root=tx_set_root))

    token_commitment = TokenCommitment.objects.get(
        token=swap.wallet.token, root_commitment__eon_number=eon_number + 1)

    v, r, s = sender_active_state.operator_signature.vrs()

    # swap_sender_balance = sender_transfer_context.balance_as_of_eon(
    #     eon_number)
    sender_balance = sender_transfer_context.balance_as_of_eon(eon_number + 1)

    passive_checksum, passive_amount, passive_marker = sender_transfer_context.get_passive_values(
        eon_number=eon_number + 1)

    swap_order = [
        int(swap.amount),  # sell
        int(swap.amount_swapped),  # buy
        # int(swap_sender_balance.right - swap_sender_balance.left),
        starting_balance,  # balance
        int(swap.nonce)
    ]  # nonce

    chain_transition_checksum = test_case.contract_interface.check_proof_of_transition_agreement(
        token_address=swap.wallet.token.address,
        holder=swap.wallet.address,
        trail_identifier=swap.wallet.trail_identifier,
        eon_number=eon_number,
        tx_set_root=tx_set_root,
        deltas=deltas,
        attester=settings.HUB_OWNER_ACCOUNT_ADDRESS,
        r=crypto.uint256(r),
        s=crypto.uint256(s),
        v=v)
    test_case.assertEqual(crypto.hex_value(sender_active_state.checksum()),
                          crypto.hex_value(chain_transition_checksum))

    node_hash = merkle_tree.leaf_hash(
        merkle_tree.wallet_leaf_inner_hash, {
            'contract': settings.HUB_LQD_CONTRACT_ADDRESS,
            'token': swap.wallet.token.address,
            'wallet': swap.wallet.address,
            'left': sender_balance.left,
            'right': sender_balance.right,
            'active_state_checksum': sender_active_state.checksum(),
            'passive_checksum': passive_checksum,
            'passive_amount': passive_amount,
            'passive_marker': passive_marker,
        })
    checkpoint = RootCommitment.objects.get(eon_number=eon_number + 1)
    test_case.contract_interface.check_exclusive_allotment_proof(
        allotment_trail=int(sender_balance.merkle_proof_trail),
        membership_trail=swap.wallet.token.trail,
        node=node_hash,
        merkle_root=crypto.decode_hex(checkpoint.merkle_root),
        allotment_chain=[
            crypto.zfill(crypto.decode_hex(v)) for v in long_string_to_list(
                sender_balance.merkle_proof_hashes, 64)
        ],
        membership_chain=[
            crypto.zfill(crypto.decode_hex(checksum))
            for checksum in long_string_to_list(
                token_commitment.membership_hashes, 64)
        ],
        value=csf_to_list(sender_balance.merkle_proof_values, int),
        left=int(sender_balance.left),
        right=int(sender_balance.right))

    test_case.contract_interface.issue_swap_challenge(
        token_pair=[swap.wallet.token.address, swap.recipient.token.address],
        wallet=swap.wallet.address,
        swap_order=swap_order,
        sender_tx_recipient_trails=[
            swap.wallet.trail_identifier,
            int(transfer_index), swap.recipient.trail_identifier
        ],
        allotment_chain=[
            crypto.zfill(crypto.decode_hex(v)) for v in long_string_to_list(
                sender_balance.merkle_proof_hashes, 64)
        ],
        membership_chain=[
            crypto.zfill(crypto.decode_hex(checksum))
            for checksum in long_string_to_list(
                token_commitment.membership_hashes, 64)
        ],
        tx_chain=[crypto.zfill(x) for x in transfer_proof],
        values=csf_to_list(sender_balance.merkle_proof_values, int),
        l_r=[int(sender_balance.left),
             int(sender_balance.right)],
        tx_set_root=tx_set_root,
        deltas=deltas,
        passive_checksum=passive_checksum,
        passive_amount=passive_amount,
        passive_marker=passive_marker)