I’m running a high throughput application in which many auction-like processes happen every second and budgets are spent based on auction-winning bids.
However, there’s a slight latency between the moment a bid is placed and the time when the auction is decided, so what started happening is this:
- two similar auctions are won by the same highest bidder in the same second, but the total bids for the 2 auctions exceed the budget of the user, so by the time the second auction tries to get the bid, the first one already got it and the user now ends up with a negative balance.
I do understand this is a complicated problem, but I would like to know your opinions.
Some details about my application might offer insights into what the right tradeoffs might be:
-
the bids are, generally, much smaller than the user budget, so not allowing the users to spend the last few cents of their $5 budget might not be a big issue, but there’s no limit to the bids, so this might not, in fact, help decreasing risk (might work for the low-bid transactions, but as soon as the user places, say, a $3 bid, the budget can still go from $5 to -$7 in a second, by winning just 4 auctions with this higher than normal bid).
-
not allowing bids higher than a certain budget ratio can also be an acceptable solution, but this might affect the user experience quite a lot and the bid/budget ratio will be rather arbitrary. The lower the ratio, the safer the budget and the worse user experience, but there’s still no guarantee the budget won’t be exceeded.
-
booking the bid for a certain time can also be an option, but with 100k users bidding multiple times per second, the solution for booking all the bids and releasing the funds can become quite complex
-
simply not paying for the second transaction can also be a (rather crappy and unfair) solution, but it might limit the incentive to abuse this bug.
I realize these details are all direct attempts to solve the problem, but none of them is good enough and I’m curious what your opinion is and if there are any better solution to the Double Spending problem. Unlike the solution found for the Bitcoin protocol, in my case the exchange of "goods" is done in real time and I cannot revert it once there are no more funds available (the goods, in my case, are website visits, so they’re instantaneous, can’t be stored until the transaction is settled and can’t be delayed).
2
Answers
This might work: change the rule for winning an auction.
Now, I guess, a user wins an auction if she’s the highest bidder at the conclusion of the auction. You can change the rule so the user must BOTH be the high bidder AND have sufficient budget to cover the bid. If both criteria aren’t met, the next highest bidder with enough budget wins.
This is easy to explain to users. "to win, you need enough in your budget. If you’re losing auctions you can increase your budget."
Implementation wise, you can use a database transaction to handle the "win" operation. Inside a single database transaction, debit the winning buyer’s budget and credit the seller’s account.
You can use SQL sequences like this:
You can use distributed locks to solve the double-spending /double booking issue. You need to acquire at least three locks that would update
You can also create a bid ledger to verify the user’s spending, seller account balance, and user’s wallet balance. You can run a cron job hourly or every 10 minutes to verify any error and notify support/dev to check for potential errors.
Your logic could be like this
Each executor can use their identity id as a lock value to avoid releasing someone else lock.