Protected DataChain & BlockChain (Pro)
A datachain or blockchain is similar to a linked list consisting of a sequence of elements arranged in a specific order. However, they have an additional property, namely that they can maintain the order of these elements while preserving their integrity. This can be useful or developers in the following use cases:
- Digital assets: Store in-game assets such as weapons, skins or cosmetics so that players have real ownership rights and secure trading opportunities.
- Achievements: Ensure the immutability and transparency of achievements, increasing trust and credibility within the community.
- Virtual currency: Manage game currencies to ensure transparency and protect against cheating or manipulation.
Datachain
A datachain is a chain of linked elements. You can add new elements to the end of the chain or remove the last elements. AntiCheat introduced a datachain class to store data in an orderly manner to preserve its integrity and to immediately notify users of unauthorized changes.
Each addition or removal of an item in the datachain triggers an integrity check process, but this can incur performance costs, especially for large data sets. It is therefore important to take this aspect into account when using a datachain. But once a failed integrity check is detected, the 'PrimitiveCheatingDetector' will be notified.
/// <summary>
/// Represents a generic data chain that implements the <see cref="IDataChain{T}"/> interface and is observed by the primitive cheating detector.
/// Using this class, you can ensure that a chain of data is not modified without your knowledge. Each time you append or remove an item from the
/// chain, the class verifies its integrity and notifies the primitive cheating detector if a change is detected. This can be performance costly,
/// so do not use it for large amounts of data.
/// Only primitive types are supported.
/// </summary>
/// <typeparam name="T">The type of elements stored in the data chain, must be a nullable value type.</typeparam>
public class DataChain<T> : IDataChain<T>, IWatchedSubject where T: struct
How to use
Using a datachain is quite simple. You can find the 'DataChain' class in the namespace 'GUPS.AntiCheat.Protected.Collection.Chain'. A possible use case could look like this:
// Create a new datachain.
DataChain<Int32> datachain = new DataChain<Int32>();
// Append data and get directly informed about any failed integrity.
if(datachain.Append(1))
{
// Has still its integrity.
// ... TODO: Put your code here.
}
else
{
// Has no longer its integrity, probably caused through memory manipulation.
// ... TODO: Put your code here.
}
// Or verify the integrity manually.
if(!datachain.CheckIntegrity())
{
// Has no longer its integrity, probably caused through memory manipulation.
// ... TODO: Put your code here.
}
Note: The datachain only allow data that is stored as a value (structs) and not as a reference (classes). This ensures that the list elements cannot be indirectly manipulated by you, which would lead to an accidental integrity problem, even if it is meant to be. However, you can of course also allow data by reference if you wish.
BlockChain
A blockchain can be compared to a datachain that connects blocks in a continuous sequence. Each block within this chain records transactions, containing the actual data. And this is where it differs from a datachain. The datachain is used as a local in memory data store. But the blockchain can synchronize its transactions with a remote source to retrieve and upload data while maintaining the integrity of the blockchain.
AntiCheat provides two built-in classes for remote synchronization that are based on a shared interface. This enables you for easy extension or customization for your own use case.
- FileSynchronizer: Represents a synchronizer that is responsible for synchronizing a BlockChain with a file on the local file storage.
- WebSynchronizer: Represents a synchronizer that is responsible for synchronizing a BlockChain with a web server. The web server has to provide a read and write endpoint.
Before synchronization with the remote location, the last block of the blockchain is automatically checked for integrity. If there are unauthorized or unexpected changes, the user and the "PrimitiveCheatingDetector" are notified.
/// <summary>
/// Represents an implementation of the <see cref="IDataChain{Block{T}}"/> interface, storing linked blocks to form a blockchain. The
/// blockchain can be synchronized with a remote source to retrieve and upload data while maintaining its integrity. Valid use cases
/// could be to store game data, such as scores, achievements, or player progress and synchronize it with a remote server. This
/// implementation is not designed to store large amounts of data, but rather to store small amounts of data that require integrity
/// and synchronization.
/// </summary>
/// <typeparam name="T">The value type of the content stored in the block transactions.</typeparam>
public class BlockChain<T> : IDataChain<Block<T>>, IWatchedSubject
How to use
Using a blockchain is quite simple. You can find the 'BlockChain' class in the namespace 'GUPS.AntiCheat.Protected.Collection.Chain'. A possible use case could look like this:
// Create a temporary file location.
String filePath = System.IO.Path.GetTempFileName();
// Create a file synchronizer using the temporary file.
FileSynchronizer<Int32> fileSynchronizer = new FileSynchronizer<Int32>(filePath);
// Create a blockchain with a block size of 10 (amount of possible transactions per block) using the file synchronizer.
BlockChain<Int32> blockChain = new BlockChain<Int32>(10, fileSynchronizer);
// Append example data asynchronously, if data already exists at the file location, it will be synchronized automatically.
await blockChain.AppendAsync(1);
await blockChain.AppendAsync(2);
await blockChain.AppendAsync(3);
await blockChain.AppendAsync(4);
// If you wish to manually synchronize data with the remote source you can do as following.
await blockChain.SynchronizeAsync();
// Validate the integrity of the last block in the blockchain manually.
if(!compareBlockChain.CheckIntegrityOfLastBlock())
{
// Has no longer its integrity, probably caused through memory manipulation.
// ... TODO: Put your code here.
}
// Validate the integrity of the whole blockchain manually.
if(!compareBlockChain.CheckIntegrity())
{
// Has no longer its integrity, probably caused through memory manipulation.
// ... TODO: Put your code here.
}
Note: The blockchain only allow data that is stored as a value (structs) and not as a reference (classes). This ensures that the list elements cannot be indirectly manipulated by you, which would lead to an accidental integrity problem, even if it is meant to be. However, you can of course also allow data by reference if you wish.