I'm developing an cryptocurrency project. When a customer tries to withdraw his money, I use the code shown here to ensure that this customer has enough balance to make the withdrawal, then I pay the desired amount into customer wallet.
public async Task EnsureCustomerHasEnoughBalance(decimal withdrawAmount, Guid customerId)
{
var currentBalance = await _transactionService.GetCustomerBalance(customerId);
if (currentBalance < withdrawAmount)
throw new Exception("Insufficient balance");
}
The problem is if someone calls my async API many times and quickly, some of the requests will be processed the same time in different threads. So, any customer can hack my code and withdraw more money than his balance allows.
I've tried using lock, semaphore and etc but none of them work in async. Do you have any solution?
Thanks for any help
CodePudding user response:
I have some experiences for this case. To be honest when running a payment application, and with the critical action relate to balance, we need to be really carefully. In this case i don't use interal lock since we would deploy the app in many nodes, that can not guarantee the atomic. In my project, we have two options:
- Centralize locking by using redis (redlock).
- Using transaction, we write procedure and wrap it in transaction.
CREATE PROCEDURE withraw(in amount int)
BEGIN
START TRANSACTION;
select balance from accounts where id = account_id into @avaiable_balance for update;
if(@avaiable_balance > amount )
then
update accounts set balance = balance -amount,balance=balance-amount where id = account_id;
select 1;
else
select -1;
COMMIT;
END
CodePudding user response:
Do you use Nethereum nuget package? If you use Nethereum package, it's ok. I used Nethereum package for withdraw money. There is no problem. Please check this site. https://nethereum.com/ https://docs.nethereum.com/en/latest/nethereum-block-processing-detail/