Protected DataChain & BlockChain (Pro)
A data chain 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: they can maintain the order of these elements while preserving their integrity. This can be useful for 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 data chain is a chain of linked elements. You can add new elements to the end of the chain or remove the last elements. AntiCheat introduces a data chain class to store data in an orderly manner that preserves its integrity and immediately notifies users of unauthorized changes.
Each addition or removal of an item in the data chain 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 data chain. 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 data chain 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 data chain.
DataChain<Int32> datachain = new DataChain<Int32>();
// Append data and get directly informed about any failed integrity.
if(datachain.Append(1))
{
// Still has its integrity.
// ... TODO: Put your code here.
}
else
{
// Has lost its integrity, probably caused by memory manipulation.
// ... TODO: Put your code here.
}
// Or verify the integrity manually.
if(!datachain.CheckIntegrity())
{
// Has lost its integrity, probably caused by memory manipulation.
// ... TODO: Put your code here.
}
Note: The data chain only allows 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 otherwise lead to an accidental integrity problem, even if it were intended. However, you can of course also allow data by reference if you wish.
BlockChain
A blockchain can be compared to a data chain 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 data chain: the data chain is used as a local in-memory data store, while 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 to easily extend or customize them 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 so as follows.
await blockChain.SynchronizeAsync();
// Validate the integrity of the last block in the blockchain manually.
if(!blockChain.CheckIntegrityOfLastBlock())
{
// Has lost its integrity, probably caused by memory manipulation.
// ... TODO: Put your code here.
}
// Validate the integrity of the whole blockchain manually.
if(!blockChain.CheckIntegrity())
{
// Has lost its integrity, probably caused by memory manipulation.
// ... TODO: Put your code here.
}
Note: The blockchain only allows 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 otherwise lead to an accidental integrity problem, even if it were intended. However, you can of course also allow data by reference if you wish.