def validate(self, attrs): authorization = attrs.pop('authorization').get('value') address = attrs.get('address') token = attrs.get('token') tos_signature = attrs.pop('tos_signature').get('value') if BlacklistEntry.objects.filter( address__iexact=remove_0x_prefix(address)).exists(): raise serializers.ValidationError( detail='', code=ErrorCode.WALLET_BLACKLISTED) if Wallet.objects.filter(address__iexact=remove_0x_prefix(address), token=token).exists(): raise serializers.ValidationError( detail='', code=ErrorCode.WALLET_ALREADY_ADMITTED) dummy_wallet = Wallet(token=token, address=remove_0x_prefix(address)) attrs['registration_eon_number'] = LocalViewInterface.latest( ).eon_number() admission_hash = hex_value( dummy_wallet.get_admission_hash(attrs['registration_eon_number'])) attrs['signature'] = Signature(wallet=dummy_wallet, checksum=admission_hash, value=authorization) if not attrs['signature'].is_valid(): raise serializers.ValidationError( detail='', code=ErrorCode.INVALID_ADMISSION_SIGNATURE) latest_tos_config = TOSConfig.objects.all().order_by('time').last() attrs['tos_signature'] = Signature(wallet=dummy_wallet, checksum=latest_tos_config.digest(), value=tos_signature) if not attrs['tos_signature'].is_valid(): raise serializers.ValidationError( detail='Invalid TOS (digest: {}) signature'.format( latest_tos_config.digest()), code=ErrorCode.INVALID_TOS_SIGNATURE) attrs['tos_config'] = latest_tos_config return attrs
def update(self, swap, validated_data): with transaction.atomic(): current_eon = LocalViewInterface.latest().eon_number() swap_set = Transfer.objects.select_for_update().filter( tx_id=swap.tx_id, eon_number__gte=current_eon, swap=True).order_by('eon_number') current_swap = swap_set[0] if current_swap.complete: raise serializers.ValidationError( detail='', code=ErrorCode.SWAP_ALREADY_FULFILLED) elif current_swap.cancelled: raise serializers.ValidationError( detail='', code=ErrorCode.SWAP_ALREADY_FROZEN) elif current_swap.voided: raise serializers.ValidationError( detail='', code=ErrorCode.SWAP_ALREADY_VOIDED) elif current_swap.processed: raise serializers.ValidationError( detail='', code=ErrorCode.SWAP_ALREADY_CLOSED) freezing_signature_data = validated_data.pop('freezing_signature') freezing_checksum = crypto.hex_value( current_swap.swap_cancellation_message_checksum()) freezing_signature = Signature( wallet=current_swap.wallet, checksum=freezing_checksum, value=freezing_signature_data.get('value')) if not freezing_signature.is_valid(): raise serializers.ValidationError( detail='', code=ErrorCode.INVALID_FREEZING_SIGNATURE) freezing_signature.save() # only current swap should be locked, future swaps are not matched with current_swap.lock( auto_renewal=False), current_swap.wallet.lock( auto_renewal=False), current_swap.recipient.lock( auto_renewal=False): swap_set.update(cancelled=True, swap_freezing_signature=freezing_signature) return current_swap
def test_wallet_funds(self): hub_mba = MinimumAvailableBalanceMarker(wallet=self.hub_wallet, amount=1, eon_number=3) mba_checksum = hub_mba.checksum() sign = Signature(wallet=self.hub_wallet, checksum=crypto.hex_value(mba_checksum), value=crypto.encode_signature( crypto.sign_message( mba_checksum, self.hub_private.to_string()))) sign.save() hub_mba.signature = sign hub_mba.save() hub_state = ActiveState(wallet=self.hub_wallet, eon_number=3, updated_spendings=4, updated_gains=76, tx_set_hash=uuid.uuid4().hex, tx_set_index=2) state_checksum = hub_state.checksum() sign = Signature( wallet=self.hub_wallet, checksum=crypto.hex_value(state_checksum), value=crypto.encode_signature( crypto.sign_message(state_checksum, self.hub_private.to_string()))) sign.save() hub_state.wallet_signature = sign hub_state.save() transfer = Transfer( wallet=self.hub_wallet, sender_balance_marker=hub_mba, amount=100000, eon_number=NOCUSTContractInterface().get_current_eon_number(), recipient=self.wallet, nonce=random.randint(1, 1000), sender_active_state=hub_state, passive=True) transfer.save() response = self.client.post(self.url, data=self.payload).json() self.assertEqual(response, "Ok")
def validate(self, attrs): address = attrs.get('address') tos_signature = attrs.pop('tos_signature') latest_tos_config = TOSConfig.objects.all().order_by('time').last() if TOSSignature.objects.filter( address__iexact=remove_0x_prefix(address), tos_config=latest_tos_config).exists(): raise serializers.ValidationError( detail='', code=ErrorCode.LATEST_TOS_ALREADY_SIGNED) wallet = Wallet.objects.filter( address__iexact=remove_0x_prefix(address)).last() if wallet is None: raise serializers.ValidationError( detail='', code=ErrorCode.WALLET_NOT_ADMITTED) attrs['tos_signature'] = Signature(wallet=wallet, checksum=hex_value( latest_tos_config.digest()), value=tos_signature) if not attrs['tos_signature'].is_valid(): raise serializers.ValidationError( detail= 'Invalid TOS (digest: {}) privacy polict (digest: {}) signature' .format(latest_tos_config.terms_of_service_digest, latest_tos_config.privacy_policy_digest), code=ErrorCode.INVALID_TOS_SIGNATURE) attrs['address'] = wallet.address attrs['tos_config'] = latest_tos_config return attrs
def validate(self, attrs): admission_requests = attrs.pop('admissions') if len(admission_requests) > settings.BULK_ADMISSION_LIMIT: raise serializers.ValidationError( detail='Expected <= {} but got {} admisson requests.'.format( settings.BULK_ADMISSION_LIMIT, len(admission_requests)), code=ErrorCode.TOO_MANY_ADMISSION_REQUESTS) registration_eon_number = LocalViewInterface.latest().eon_number() latest_tos_config = TOSConfig.objects.all().order_by('time').last() attrs['signatures'] = [] attrs['tos_signatures'] = [] attrs['wallets'] = [] all_tokens = {} for token in Token.objects.all(): all_tokens[token.address.lower()] = token for admission_request in admission_requests: address = remove_0x_prefix(admission_request['address']) token = all_tokens.get( remove_0x_prefix(admission_request['token']).lower()) if token is None: raise serializers.ValidationError( detail='This token {} is not registered.'.format( admission_request['token']), code=ErrorCode.TOKEN_NOT_REGISTERED) if BlacklistEntry.objects.filter(address__iexact=address).exists(): continue if Wallet.objects.filter(address__iexact=address, token=token).exists(): continue wallet = Wallet(token=token, address=address, registration_eon_number=registration_eon_number) admission_hash = hex_value( wallet.get_admission_hash(registration_eon_number)) signature = Signature( wallet=wallet, checksum=admission_hash, value=admission_request.get('authorization').get('value')) if not signature.is_valid(): raise serializers.ValidationError( detail='Invalid authorization for address {} and token {}.' .format(admission_request['address'], admission_request['token']), code=ErrorCode.INVALID_ADMISSION_SIGNATURE) tos_signature = Signature( wallet=wallet, checksum=latest_tos_config.digest(), value=admission_request.get('tos_signature').get('value')) if not tos_signature.is_valid(): raise serializers.ValidationError( detail= 'Invalid TOS (digest: {}) signature for address {} and token {}.' .format(latest_tos_config.digest(), admission_request['address'], admission_request['token']), code=ErrorCode.INVALID_TOS_SIGNATURE) attrs['signatures'].append(signature) attrs['tos_signatures'].append(tos_signature) attrs['wallets'].append(wallet) attrs['tos_config'] = latest_tos_config return attrs
def create(self, validated_data): active_state_signature_data = validated_data.pop('debit_signature') wallet = validated_data.pop('wallet') recipient = validated_data.pop('recipient') # get current eon current_eon = LocalViewInterface.latest().eon_number() # transfer 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) # TODO refactor this such that the recipient is only locked after the sender's details are verified wallets = sorted([wallet, recipient], key=lambda w: w.trail_identifier) 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='', code=ErrorCode.EON_NUMBER_OUT_OF_SYNC) transfer = Transfer(wallet=wallet, amount=validated_data.pop('amount'), eon_number=current_eon, recipient=recipient, nonce=validated_data.pop('nonce'), passive=True) wallet_view_context = WalletTransferContext(wallet=wallet, transfer=transfer) recipient_view_context = WalletTransferContext(wallet=recipient, transfer=transfer) # Minimal SLA if not wallet.is_sla_exempt() and not recipient.is_sla_exempt(): if not wallet.has_valid_sla(): sender_transfers_list = wallet_view_context.authorized_transfers_list( only_appended=False, force_append=True) if len(sender_transfers_list) > settings.SLA_THRESHOLD: raise serializers.ValidationError( detail='', code=ErrorCode.DEBIT_WALLET_EXCEEDED_SLA) elif not recipient.has_valid_sla(): recipient_transfers_list = recipient_view_context.authorized_transfers_list( only_appended=False, force_append=True) if len(recipient_transfers_list) > settings.SLA_THRESHOLD: raise serializers.ValidationError( detail='', code=ErrorCode.CREDIT_WALLET_EXCEEDED_SLA) # 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 transfer consistency can_spend, currently_available_funds = 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) # Validate data concise_balance_marker_signature_data = validated_data.pop( 'debit_balance_signature') concise_balance_marker_amount = validated_data.pop('debit_balance') if concise_balance_marker_amount > currently_available_funds - transfer.amount: raise serializers.ValidationError( detail='', code=ErrorCode.DEBIT_WALLET_BALANCE_MARKER_EXCEED_BALANCE) concise_balance_marker = MinimumAvailableBalanceMarker( wallet=wallet, eon_number=transfer.eon_number, amount=concise_balance_marker_amount) concise_balance_marker_checksum = hex_value( concise_balance_marker.checksum()) concise_balance_marker_signature = Signature( wallet=transfer.wallet, checksum=concise_balance_marker_checksum, value=concise_balance_marker_signature_data.get('value')) if not concise_balance_marker_signature.is_valid(): raise serializers.ValidationError( detail='', code=ErrorCode.INVALID_DEBIT_BALANCE_SIGNATURE) tx_set_tree = wallet_view_context.optimized_authorized_transfers_tree( ) tx_set_hash = hex_value(tx_set_tree.root_hash()) transfer_index = tx_set_tree.merkle_tree_nonce_map.get( transfer.nonce) transfer_proof = tx_set_tree.proof(transfer_index) highest_spendings, highest_gains = wallet_view_context.off_chain_actively_sent_received_amounts( eon_number=transfer.eon_number, only_appended=False) active_state = ActiveState(wallet=wallet, updated_spendings=highest_spendings + transfer.amount, updated_gains=highest_gains, tx_set_hash=tx_set_hash, tx_set_proof_hashes=transfer_proof, tx_set_index=transfer_index, eon_number=transfer.eon_number) checksum = hex_value(active_state.checksum()) active_state_signature = Signature( wallet=transfer.wallet, checksum=checksum, value=active_state_signature_data.get('value')) if not active_state_signature.is_valid(): raise serializers.ValidationError( detail='', code=ErrorCode.INVALID_DEBIT_SIGNATURE) transfer.position = recipient_view_context.off_chain_passively_received_amount( eon_number=transfer.eon_number, only_appended=False) # locking context covers saving the state as well to make sure checkpoint creation is consistent with transaction.atomic(): Signature.objects.bulk_create( [concise_balance_marker_signature, active_state_signature]) concise_balance_marker.signature = concise_balance_marker_signature concise_balance_marker.save() active_state.wallet_signature = active_state_signature active_state.operator_signature = active_state.sign_active_state( settings.HUB_OWNER_ACCOUNT_ADDRESS, settings.HUB_OWNER_ACCOUNT_KEY) active_state.save() transfer.sender_active_state = active_state transfer.sender_balance_marker = concise_balance_marker # cache transfer index in sender active set transfer.sender_merkle_index = transfer_index # transfer.sender_merkle_root_cache = tx_set_hash # cache active set merkle mountains height array and hash array for recipient active set transfer.sender_merkle_hash_cache, transfer.sender_merkle_height_cache = tx_set_tree.merkle_cache_stacks( ) transfer.complete = True transfer.appended = True transfer.processed = True transfer.save() if transfer.appended: operator_celery.send_task('auditor.tasks.on_transfer_confirmation', args=[transfer.id]) return transfer
def check_active_state_signature(swap, wallet, active_state_signature_data, is_future_state, starting_balance, highest_spendings, highest_gains, signature_type=None): wallet_view_context = WalletTransferContext(wallet=wallet, transfer=swap) # fulfillment active state if signature_type == SignatureType.FULFILLMENT: swap.processed, swap.complete = True, True if is_future_state: # done for all future eons # assumes this is the only TX in set tx_set_tree = WalletTransferContext.optimized_authorized_transfers_tree_from_list( [ swap.shorthand(wallet_view_context, is_last_transfer=True, starting_balance=starting_balance) ]) else: # done once for current eon tx_set_tree = wallet_view_context.optimized_authorized_transfers_tree() # fulfillment active state if signature_type == SignatureType.FULFILLMENT: swap.processed, swap.complete = False, False tx_set_hash = crypto.hex_value(tx_set_tree.root_hash()) transfer_index = tx_set_tree.merkle_tree_nonce_map.get(swap.nonce) transfer_proof = tx_set_tree.proof(transfer_index) # debit active state if signature_type == SignatureType.DEBIT: updated_spendings = highest_spendings + swap.amount updated_gains = highest_gains state_name = "Debit" # credit active state elif signature_type == SignatureType.CREDIT: updated_spendings = highest_spendings updated_gains = highest_gains state_name = "Credit" # fulfillment active state elif signature_type == SignatureType.FULFILLMENT: updated_spendings = highest_spendings updated_gains = highest_gains + swap.amount_swapped state_name = "Fulfillment" active_state = ActiveState(wallet=wallet, updated_spendings=updated_spendings, updated_gains=updated_gains, tx_set_hash=tx_set_hash, tx_set_proof_hashes=transfer_proof, tx_set_index=transfer_index, eon_number=swap.eon_number) active_state_checksum = crypto.hex_value(active_state.checksum()) active_state_signature = Signature( wallet=wallet, checksum=active_state_checksum, value=active_state_signature_data.get('value')) if not active_state_signature.is_valid(): error_code = None if signature_type == SignatureType.CREDIT: error_code = ErrorCode.INVALID_FUTURE_CREDIT_SIGNATURE if is_future_state else ErrorCode.INVALID_CREDIT_SIGNATURE elif signature_type == SignatureType.DEBIT: error_code = ErrorCode.INVALID_FUTURE_DEBIT_SIGNATURE if is_future_state else ErrorCode.INVALID_DEBIT_SIGNATURE elif signature_type == SignatureType.FULFILLMENT: error_code = ErrorCode.INVALID_FUTURE_CREDIT_FULFILLMENT_SIGNATURE if is_future_state else ErrorCode.INVALID_CREDIT_FULFILLMENT_SIGNATURE raise serializers.ValidationError( 'Active state signature failed for eon {}'.format(swap.eon_number), code=error_code) return active_state, active_state_signature, transfer_index, tx_set_tree.merkle_cache_stacks( )
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
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]
def update(self, swap, validated_data): current_swap = None is_swap_finalized = False with transaction.atomic(): current_eon = LocalViewInterface.latest().eon_number() swap_set = Transfer.objects.select_for_update().filter( tx_id=swap.tx_id, eon_number__gte=current_eon, swap=True).order_by('eon_number') current_swap = swap_set[0] if not current_swap.complete: raise serializers.ValidationError( detail='', code=ErrorCode.SWAP_NOT_FULFILLED) elif current_swap.cancelled: raise serializers.ValidationError( detail='', code=ErrorCode.SWAP_ALREADY_FROZEN) elif current_swap.voided: raise serializers.ValidationError( detail='', code=ErrorCode.SWAP_ALREADY_VOIDED) elif current_swap.processed: raise serializers.ValidationError( detail='', code=ErrorCode.SWAP_ALREADY_CLOSED) elif current_swap.recipient_finalization_active_state is not None: raise serializers.ValidationError( detail='', code=ErrorCode.SWAP_ALREADY_FINALIZED) finalization_signatures = validated_data.pop( 'finalization_signature') # state to save finalization_active_state_signature_records = [] finalization_active_state_records = [] if swap_set.count() != len(finalization_signatures): raise serializers.ValidationError( detail= 'Wrong number of finalization signatures, expected {} but got {}' .format(swap_set.count(), len(finalization_signatures)), code=ErrorCode.WRONG_NUMBER_OF_CREDIT_SIGNATURES) recipient_view_context = WalletTransferContext( wallet=current_swap.recipient, transfer=current_swap) tx_set_tree = recipient_view_context.optimized_authorized_transfers_tree( ) tx_set_hash = crypto.hex_value(tx_set_tree.root_hash()) transfer_index = tx_set_tree.merkle_tree_nonce_map.get( current_swap.nonce) transfer_proof = tx_set_tree.proof(transfer_index) highest_spendings, highest_gains = recipient_view_context.off_chain_actively_sent_received_amounts( eon_number=current_swap.eon_number, only_appended=False) finalization_active_state = ActiveState( wallet=current_swap.recipient, updated_spendings=highest_spendings + current_swap.amount_swapped, updated_gains=highest_gains + current_swap.amount_swapped, tx_set_hash=tx_set_hash, tx_set_proof_hashes=transfer_proof, tx_set_index=transfer_index, eon_number=current_swap.eon_number) finalization_active_state_signature_data = finalization_signatures[ 0] finalization_active_state_checksum = crypto.hex_value( finalization_active_state.checksum()) finalization_active_state_signature = Signature( wallet=current_swap.recipient, checksum=finalization_active_state_checksum, value=finalization_active_state_signature_data.get('value')) if not finalization_active_state_signature.is_valid(): raise serializers.ValidationError( detail='', code=ErrorCode.INVALID_CREDIT_SIGNATURE) finalization_active_state_signature_records.append( finalization_active_state_signature) finalization_active_state_records.append(finalization_active_state) # calculate future spent, gained, empty tx set future_spent_gained = max(highest_spendings, highest_gains) + swap.amount_swapped + 1 empty_tx_set_hash = crypto.hex_value(NODE_CACHE[0]['hash']) for index in range(1, len(swap_set)): future_swap = swap_set[index] finalization_active_state = ActiveState( wallet=future_swap.recipient, updated_spendings=future_spent_gained, updated_gains=future_spent_gained, tx_set_hash=empty_tx_set_hash, # any dummy value tx_set_proof_hashes='', # any dummy value tx_set_index=0, eon_number=future_swap.eon_number) finalization_active_state_checksum = crypto.hex_value( finalization_active_state.checksum()) finalization_active_state_signature = Signature( wallet=swap.recipient, checksum=finalization_active_state_checksum, value=finalization_signatures[index].get('value')) if not finalization_active_state_signature.is_valid(): raise serializers.ValidationError( detail='', code=ErrorCode.INVALID_FUTURE_CREDIT_SIGNATURE) finalization_active_state_signature_records.append( finalization_active_state_signature) finalization_active_state_records.append( finalization_active_state) Signature.objects.bulk_create( finalization_active_state_signature_records) with current_swap.lock( auto_renewal=False), current_swap.wallet.lock( auto_renewal=False), current_swap.recipient.lock( auto_renewal=False): for index in range(len(finalization_active_state_records)): finalization_active_state_records[ index].wallet_signature = finalization_active_state_signature_records[ index] ActiveState.objects.bulk_create( finalization_active_state_records) for index in range(len(swap_set)): swap_set[ index].recipient_finalization_active_state = finalization_active_state_records[ index] if index > 0: swap_set[index].voided = True swap_set[index].appended = False swap_set[index].processed = True Transfer.objects.bulk_update(swap_set, [ 'recipient_finalization_active_state', 'voided', 'appended', 'processed' ]) swap_set[0].sign_swap_finalization( settings.HUB_OWNER_ACCOUNT_ADDRESS, settings.HUB_OWNER_ACCOUNT_KEY) swap_set[0].close(complete=True, appended=True) current_swap = swap_set[0] is_swap_finalized = True if is_swap_finalized: operator_celery.send_task('auditor.tasks.on_swap_finalization', args=[current_swap.id]) return current_swap
def update(self, swap, validated_data): current_swap = None is_swap_cancelled = False with transaction.atomic(): current_eon = LocalViewInterface.latest().eon_number() swap_set = Transfer.objects.select_for_update().filter( tx_id=swap.tx_id, eon_number__gte=current_eon, swap=True).order_by('eon_number') current_swap = swap_set[0] if not current_swap.cancelled: raise serializers.ValidationError( detail='', code=ErrorCode.SWAP_NOT_FROZEN) elif current_swap.processed: raise serializers.ValidationError( detail='', code=ErrorCode.SWAP_ALREADY_CLOSED) elif current_swap.swap_freezing_signature is None: raise serializers.ValidationError( detail='', code=ErrorCode.MISSING_FREEZING_SIGNATURE) elif None not in [ current_swap.sender_cancellation_active_state, current_swap.recipient_cancellation_active_state ]: raise serializers.ValidationError( detail='', code=ErrorCode.SWAP_ALREADY_CANCELLED) sender_cancellation_signatures = validated_data.get( 'sender_cancellation_signature') recipient_cancellation_signatures = validated_data.get( 'recipient_cancellation_signature') # state to save sender_cancellation_active_state_signature_records = [] sender_cancellation_active_state_records = [] recipient_cancellation_active_state_signature_records = [] recipient_cancellation_active_state_records = [] # make sure appropriate number of signatures was provided if swap_set.count() != len(sender_cancellation_signatures): raise serializers.ValidationError( detail= 'Wrong number of sender cancellation signatures, expected {} but got {}' .format(swap_set.count(), len(sender_cancellation_signatures)), code=ErrorCode.WRONG_NUMBER_OF_DEBIT_SIGNATURES) if swap_set.count() != len(recipient_cancellation_signatures): raise serializers.ValidationError( detail= 'Wrong number of recipient cancellation signatures, expected {} but got {}' .format(swap_set.count(), len(recipient_cancellation_signatures)), code=ErrorCode.WRONG_NUMBER_OF_CREDIT_SIGNATURES) sender_view_context = WalletTransferContext( wallet=current_swap.wallet, transfer=current_swap) debit_tx_set_tree = sender_view_context.optimized_authorized_transfers_tree( force_append=False, assume_active_state_exists=True) tx_set_hash = crypto.hex_value(debit_tx_set_tree.root_hash()) transfer_index = debit_tx_set_tree.merkle_tree_nonce_map.get( current_swap.nonce) transfer_proof = debit_tx_set_tree.proof(transfer_index) sender_highest_spendings, sender_highest_gains = sender_view_context.off_chain_actively_sent_received_amounts( eon_number=current_swap.eon_number, only_appended=False) matched_out, _ = current_swap.matched_amounts() sender_highest_gains += current_swap.amount - matched_out sender_cancellation_active_state = ActiveState( wallet=current_swap.wallet, updated_spendings=sender_highest_spendings, updated_gains=sender_highest_gains, tx_set_hash=tx_set_hash, tx_set_proof_hashes=transfer_proof, tx_set_index=transfer_index, eon_number=current_swap.eon_number) sender_cancellation_active_state_checksum = crypto.hex_value( sender_cancellation_active_state.checksum()) sender_cancellation_active_state_signature = Signature( wallet=current_swap.wallet, checksum=sender_cancellation_active_state_checksum, value=sender_cancellation_signatures[0].get('value')) if not sender_cancellation_active_state_signature.is_valid(): raise serializers.ValidationError( detail='', code=ErrorCode.INVALID_DEBIT_SIGNATURE) sender_cancellation_active_state_records.append( sender_cancellation_active_state) sender_cancellation_active_state_signature_records.append( sender_cancellation_active_state_signature) recipient_view_context = WalletTransferContext( wallet=current_swap.recipient, transfer=current_swap) credit_tx_set_tree = recipient_view_context.optimized_authorized_transfers_tree( force_append=False, assume_active_state_exists=True) tx_set_hash = crypto.hex_value(credit_tx_set_tree.root_hash()) transfer_index = credit_tx_set_tree.merkle_tree_nonce_map.get( current_swap.nonce) transfer_proof = credit_tx_set_tree.proof(transfer_index) recipient_highest_spendings, recipient_highest_gains = recipient_view_context.off_chain_actively_sent_received_amounts( eon_number=current_swap.eon_number, only_appended=False) recipient_cancellation_active_state = ActiveState( wallet=current_swap.recipient, updated_spendings=recipient_highest_spendings + current_swap.amount_swapped, updated_gains=recipient_highest_gains + current_swap.amount_swapped, tx_set_hash=tx_set_hash, tx_set_proof_hashes=transfer_proof, tx_set_index=transfer_index, eon_number=current_swap.eon_number) recipient_cancellation_active_state_checksum = crypto.hex_value( recipient_cancellation_active_state.checksum()) recipient_cancellation_active_state_signature = Signature( wallet=current_swap.recipient, checksum=recipient_cancellation_active_state_checksum, value=recipient_cancellation_signatures[0].get('value')) if not recipient_cancellation_active_state_signature.is_valid(): raise serializers.ValidationError( detail='', code=ErrorCode.INVALID_CREDIT_SIGNATURE) recipient_cancellation_active_state_records.append( recipient_cancellation_active_state) recipient_cancellation_active_state_signature_records.append( recipient_cancellation_active_state_signature) # calculate future spent, gained, empty tx set empty_tx_set_hash = crypto.hex_value(NODE_CACHE[0]['hash']) sender_future_spent_gained = max(sender_highest_spendings, sender_highest_gains) + 1 recipient_future_spent_gained = max( recipient_highest_spendings, recipient_highest_gains) + current_swap.amount_swapped + 1 for index in range(1, len(swap_set)): future_swap = swap_set[index] sender_cancellation_active_state = ActiveState( wallet=future_swap.wallet, updated_spendings=sender_future_spent_gained, updated_gains=sender_future_spent_gained, tx_set_hash=empty_tx_set_hash, # any dummy value tx_set_proof_hashes='', # any dummy value tx_set_index=0, eon_number=future_swap.eon_number) sender_cancellation_active_state_checksum = crypto.hex_value( sender_cancellation_active_state.checksum()) sender_cancellation_active_state_signature = Signature( wallet=future_swap.recipient, checksum=sender_cancellation_active_state_checksum, value=sender_cancellation_signatures[index].get('value')) if not sender_cancellation_active_state_signature.is_valid(): raise serializers.ValidationError( detail='', code=ErrorCode.INVALID_FUTURE_DEBIT_SIGNATURE) sender_cancellation_active_state_signature_records.append( sender_cancellation_active_state_signature) sender_cancellation_active_state_records.append( sender_cancellation_active_state) recipient_cancellation_active_state = ActiveState( wallet=future_swap.recipient, updated_spendings=recipient_future_spent_gained, updated_gains=recipient_future_spent_gained, tx_set_hash=empty_tx_set_hash, # any dummy value tx_set_proof_hashes='', # any dummy value tx_set_index=0, eon_number=future_swap.eon_number) recipient_cancellation_active_state_checksum = crypto.hex_value( recipient_cancellation_active_state.checksum()) recipient_cancellation_active_state_signature = Signature( wallet=future_swap.recipient, checksum=recipient_cancellation_active_state_checksum, value=recipient_cancellation_signatures[index].get( 'value')) if not recipient_cancellation_active_state_signature.is_valid( ): raise serializers.ValidationError( detail='', code=ErrorCode.INVALID_FUTURE_CREDIT_SIGNATURE) recipient_cancellation_active_state_signature_records.append( recipient_cancellation_active_state_signature) recipient_cancellation_active_state_records.append( recipient_cancellation_active_state) assert (len(swap_set) == len( sender_cancellation_active_state_signature_records)) assert (len(swap_set) == len( recipient_cancellation_active_state_signature_records)) Signature.objects.bulk_create( sender_cancellation_active_state_signature_records + recipient_cancellation_active_state_signature_records) with current_swap.lock( auto_renewal=False), current_swap.wallet.lock( auto_renewal=False), current_swap.recipient.lock( auto_renewal=False): for index in range(len(swap_set)): sender_cancellation_active_state_records[ index].wallet_signature = sender_cancellation_active_state_signature_records[ index] recipient_cancellation_active_state_records[ index].wallet_signature = recipient_cancellation_active_state_signature_records[ index] ActiveState.objects.bulk_create( sender_cancellation_active_state_records + recipient_cancellation_active_state_records) for index in range(len(swap_set)): swap_set[ index].sender_cancellation_active_state = sender_cancellation_active_state_records[ index] swap_set[ index].recipient_cancellation_active_state = recipient_cancellation_active_state_records[ index] if index > 0: swap_set[index].voided = True swap_set[index].appended = False swap_set[index].processed = True Transfer.objects.bulk_update(swap_set, [ 'sender_cancellation_active_state', 'recipient_cancellation_active_state', 'voided', 'appended', 'processed' ]) swap_set[0].sign_swap_cancellation( settings.HUB_OWNER_ACCOUNT_ADDRESS, settings.HUB_OWNER_ACCOUNT_KEY) swap_set[0].close(cancelled=True, appended=True) current_swap = swap_set[0] is_swap_cancelled = True if is_swap_cancelled: operator_celery.send_task('auditor.tasks.on_swap_cancellation', args=[current_swap.id]) return current_swap
def send_transaction(test_case, eon_number, sender, recipient, amount, nonce, token, expected_status=status.HTTP_201_CREATED): # Sender account sender_wallet = Wallet.objects.get(address=remove_0x_prefix( sender.get('address')), token=token) # Recipient account recipient_wallet = Wallet.objects.get(address=remove_0x_prefix( recipient.get('address')), token=token) transfer = Transfer(wallet=sender_wallet, amount=amount, eon_number=eon_number, recipient=recipient_wallet, nonce=nonce, passive=True) sender_view_context = WalletTransferContext(wallet=sender_wallet, transfer=transfer) sender_highest_spent, sender_highest_gained = sender_view_context.off_chain_actively_sent_received_amounts( eon_number=eon_number, only_appended=False) updated_spendings = sender_highest_spent + amount # Authorize transaction transfer_set_root = hex_value( sender_view_context.authorized_transfers_tree_root(only_appended=False, force_append=True)) active_state = ActiveState(wallet=sender_wallet, updated_spendings=updated_spendings, updated_gains=sender_highest_gained, eon_number=eon_number, tx_set_hash=transfer_set_root) sender_active_state_authorization = sign_message(active_state.checksum(), sender.get('pk')) sender_active_state_signature = Signature( wallet=sender_wallet, checksum=hex_value(active_state.checksum()), value=encode_signature(sender_active_state_authorization)) test_case.assertTrue(sender_active_state_signature.is_valid()) _, available_balance = sender_view_context.can_send_transfer( current_eon_number=eon_number, using_only_appended_funds=False) new_balance = available_balance - transfer.amount concise_balance_marker = MinimumAvailableBalanceMarker( wallet=sender_wallet, eon_number=eon_number, amount=new_balance) sender_concise_balance_marker_authorization = sign_message( concise_balance_marker.checksum(), sender.get('pk')) concise_balance_marker_signature = Signature( wallet=sender_wallet, checksum=hex_value(concise_balance_marker.checksum()), value=encode_signature(sender_concise_balance_marker_authorization)) test_case.assertTrue(concise_balance_marker_signature.is_valid()) print("Sender view:") print("available_balance:", available_balance) print("transfer_set_root:", transfer_set_root) print("active_state.updated_spendings:", active_state.updated_spendings) print("active_state.updated_gains:", active_state.updated_gains) # Make API Request url = reverse('transfer-endpoint') data = { 'debit_signature': { 'value': encode_signature(sender_active_state_authorization), }, 'debit_balance_signature': { 'value': encode_signature(sender_concise_balance_marker_authorization), }, 'debit_balance': new_balance, 'eon_number': eon_number, 'amount': amount, 'nonce': nonce, 'wallet': { 'address': sender_wallet.address, 'token': sender_wallet.token.address, }, 'recipient': { 'address': recipient_wallet.address, 'token': recipient_wallet.token.address, }, } # Send tx to server x = datetime.datetime.now() response = test_case.client.post(url, data, format='json') y = datetime.datetime.now() delta = y - x # Ensure the transaction was recorded test_case.assertEqual(response.status_code, expected_status, '\n'.join([url, str(data), str(response.content)])) print('TX Time: {}s for {}'.format(delta, amount)) # fo rpassive transfer assert that transaction is confirmed tx = json.loads(response.content) transfer = Transfer.objects.get(id=tx['id']) test_case.assertTrue(transfer.complete) test_case.assertTrue(transfer.appended) test_case.assertNotEqual(transfer.sender_active_state.operator_signature, None) # Log time delta return delta