This describes, what is global market trading system, and how it was implemented. It also contains discussion of security and race conditions
This is sub-layout for documentation pages
We require following things:
The solution uses direct sql database access method,
which means, that (almost) every request executes an sql query,
and then returns some result (asynchronously).
This is extremely dangerous since it must be implemented correctly, and even a smallest flaw can lead to serious game exploits.
On the other hand, the persistence (data saving) happens immediatelly
We will have 2 database tables:
dol_globalMarketOffers will contain all available sales,
and dol_globalMarketDepositBoxes will contain
all deposit boxes data for all users.
The data will never be deleted from these tables, which will allow players to see a transaction history. Only the old records will have some bit indicating, that they are no longer valid now.
By this, we reffer to code functions, which will
be called as a result of a user input (=when packet is received)
This defines, what actions can player take upon the global market:
This is harmless function, which only executes a select upon a database. There is no mutex needed, and no race condition may occur. The worst thing that can happen, is that the player will see not up to date results, (due to insert statement completing right after select statement). But really, player has no way to tell that such a thing happen, and even if so, we do not care, as he can search again...
When used, the player would buy X items out of Y offered, where \(X < Y\).
If finishes correctly, will give the buyer bought item into a deposit box,
and to seller, the money to his deposit box.
This function executes following sql statements: select, insert, update.
It is vital, that this function uses a mutex, since calling this function multiple times in fast succession will generate undefined behavior.
If mutex is used, and all input is validated (and all situations are validated), then this is safe, and can not be exploited. Here is a rough list of situations, taken to consideration:
When used, the items ready for collection in the target deposit box
are given to the owner player, and removed from the deposit box.
If the deposit box shall not contain any more items, and the underlying offer
is completed, the deposit box is freed.
This function may execute following sql statements: select, delete, update.
As this is user-only related feature, there is not much that can go wrong. Of course, validate all input, but there are no serous race cunditions that may occur
When used, a new sell offer will be created, and added to the system
for everyone to see. The sold goods will be removed from the seller.
This function may execute following sql statements: select, insert.
This function needs a mutex aswell, but again, there are no situations, when you might create some serious race conditions.
Let's now have a look on how we might try to exploit the game,
crash the server, or gain nefarious advantage, and discuss, whether it would be possible,
Exploits that contain bad values, numbers, or non existent items, are quite silly, and they are impossible in my implemetation. Let's have a look at more advanced stuff here:
There are 2 situations, which can lead to udefined behavior. The basic idea is,
that when player (seller of offer \(A\)) logs in, and in the same time,
offer for that seller is bought, then the select and update
can lead to undefined behavior.
Players, A, B. Player A is offline, player B is online.
Player A has created a sell offer. Player B buys that sell offer.
In that exact moment, player A logs in, loading all his saves / data.
player B's loaded data would contain all except the just completed offer, as it would be saved to the database after loading player, but therefore, would not be loaded into a memory.
Here are diagrams:
This is quite vicious problem. Normally, we would not let action \(1\) proceed,
while action \(2\) is taking place, but in this case, we must load the data for user.
The solution is to create a third class, which contains priority queue for loading user data, and then a mutex.