2022-10-09 02:24:31 +03:00
|
|
|
from django.db.models.signals import pre_save
|
|
|
|
from django.dispatch import receiver
|
|
|
|
from rest_framework.exceptions import ValidationError
|
|
|
|
|
|
|
|
from blockchain.models import Transaction
|
|
|
|
from utils.blockchain import get_balance, transfer_rubbles
|
|
|
|
|
|
|
|
|
|
|
|
@receiver(pre_save, sender=Transaction)
|
|
|
|
def validate_create_transaction(sender, instance: Transaction, **kwargs):
|
|
|
|
# validate transaction
|
|
|
|
if instance.user_from == instance.user_to:
|
|
|
|
raise ValidationError("Cannot transfer to yourself")
|
|
|
|
|
|
|
|
if instance.amount == 0:
|
|
|
|
raise ValidationError("Cannot transfer 0 money")
|
|
|
|
|
|
|
|
# Potential Race condition, use transaction with atomics in prod
|
|
|
|
user_from_money = int(get_balance(instance.user_from.wallet_public_key).coins)
|
|
|
|
if instance.user_from.money != user_from_money:
|
|
|
|
instance.user_from.money = user_from_money
|
|
|
|
instance.user_from.save(update_fields=["money"])
|
|
|
|
|
2022-10-09 04:33:12 +03:00
|
|
|
if user_from_money - instance.amount < 0:
|
2022-10-09 02:24:31 +03:00
|
|
|
raise ValidationError(
|
|
|
|
f"{instance.user_from.username} doesn't have enough money"
|
|
|
|
)
|
2022-10-09 04:33:12 +03:00
|
|
|
try:
|
|
|
|
transaction = transfer_rubbles(
|
|
|
|
instance.user_from.wallet_private_key,
|
|
|
|
instance.user_to.wallet_public_key,
|
|
|
|
amount=instance.amount,
|
|
|
|
)
|
|
|
|
except AttributeError:
|
|
|
|
raise ValidationError("Transaction unsuccessful")
|
2022-10-09 02:24:31 +03:00
|
|
|
instance.user_from.money -= instance.amount
|
|
|
|
instance.user_from.save(update_fields=["money"])
|
|
|
|
|
|
|
|
instance.user_to.money += instance.amount
|
|
|
|
instance.user_to.save(update_fields=["money"])
|
|
|
|
|
|
|
|
instance.hash = transaction.transaction_hash
|