Connect the client to the blockchain
In this section, we'll establish the connection between our Unity application and the Chromia blockchain using the Postchain client. Our goal is to initialize the client and define methods to interact with the Tic Tac Toe game on the blockchain.
Installation and setup
Before diving into the integration process, we must set up our Unity project with the necessary dependencies. Specifically, we require the Postchain client and FT4 client to work with the Chromia blockchain.
- For steps to install the Postchain client, see C# client.
- For steps to install the FT4 client, see FT4 client.
Initializing the client
We'll start by initializing the client to connect to the Chromia blockchain. This involves specifying the blockchain RID or IID and setting up the client to interact with the network.
using System.Collections.Generic;
using System.Threading.Tasks;
using Postchain.Client;
public class BlockchainManager : MonoBehaviour
{
private ChromiaClient client;
private Buffer blockchainRID = Buffer.From("7d565d92fd15bd1cdac2dc276cbcbc5581349d05a9e94ba919e1155ef4daf8f9"); // Replace with your blockchain RID
async void Start()
{
await InitializeClient();
}
private async Task InitializeClient()
{
// Initialize Client
client = await ChromiaClient.Create("http://localhost:7740", blockchainRID);
Debug.Log("Client initialized");
// Additional initialization logic can be added here
}
}
Example: using BlockchainService
for connection
Let's look at how to set up BlockchainService
to connect your Unity application to the Chromia blockchain.
-
Initialize the blockchain client: Begin by initializing the
BlockchainService
by callingBlockchainService.Initialize()
and awaiting its completion. Ensure the constantsHOST
andCHROMIA_PORT
are correctly set to point to your blockchain node. -
Register an account: The current implementation supports only the open registration strategy. The method
OpenStrategyRegisterAccount()
will handle this process. Upon successful registration, it will automatically set up anFT4Connection
for further interactions. -
Interact with the blockchain: With the
FT4Connection
established, any subsequent blockchain operations are carried out using theCurrentSession
within theFT4Connection
. For example, creating a new game can be done with:var transactionReceipt = await _blockchainService.Ft4Connection.CurrentSession.Call(new Operation[] { new("create_game") });
BlockchainService
code
public class BlockchainService
{
public Ft4Connection Ft4Connection => _ft4Connection;
public string UserAccountId => _ft4Connection != null ? _ft4Connection.CurrentSession.Account.Id : string.Empty;
// The HOST and PORT values should be adjusted based on the blockchain's configuration
private const string HOST = "localhost";
private const int CHROMIA_PORT = 7740;
private ChromiaClient _client;
private Ft4Connection _ft4Connection;
public async Task Initialize()
{
var nodeUrl = $"http://{HOST}:{CHROMIA_PORT}/";
var brid = await ChromiaClient.GetBlockchainRID(nodeUrl, 0);
_client = await ChromiaClient.Create(nodeUrl, brid);
}
public async UniTask<StoredAccountData> OpenStrategyRegisterAccount()
{
if (_client == null)
{
Debug.LogError("ChromiaClient has not been initialized.");
return null;
}
// Generate a random private key
var privateKeyBytes = new byte[32];
RandomNumberGenerator.Create().GetBytes(privateKeyBytes);
var privateKey = Buffer.From(privateKeyBytes);
var userSignature = SignatureProvider.Create(privateKey);
// Create the authorization descriptor with account and transfer flags
var userAuthDescriptor = new AuthDescriptor<SingleSignatureArgs>(
new SingleSignatureArgs
{
Flags = new AuthFlag[] { AuthFlag.Account, AuthFlag.Transfer },
Signer = userSignature.PubKey
}
);
// Register the account using the open registration strategy
var transaction = await Account.Register(_client, userSignature, userAuthDescriptor, RegistrationStrategies.Open);
if (transaction.Status == TransactionReceipt.ResponseStatus.Confirmed)
{
await InitializeFt4Connection(userSignature);
return new StoredAccountData
{
AccountId = _ft4Connection.CurrentSession.Account.Id,
PrivateKey = privateKey
};
}
Debug.LogError(transaction.RejectReason);
return null;
}
/// <summary>
/// Authenticates and initializes an <see cref="Ft4Connection"/> with an existing account.
/// </summary>
/// <param name="privateKey">The private key used to authenticate.</param>
/// <returns>True if the login was successful; otherwise, false.</returns>
public async UniTask<bool> LoginWithExistingAccount(Buffer privateKey)
{
if (_client == null)
{
Debug.LogError("ChromiaClient has not been initialized.");
return false;
}
var userSignature = SignatureProvider.Create(privateKey);
await InitializeFt4Connection(userSignature);
return _ft4Connection.CurrentSession.Account != null;
}
/// <summary>
/// Initializes the <see cref="Ft4Connection"/> with the provided signature provider.
/// </summary>
private async UniTask InitializeFt4Connection(SignatureProvider userSignature)
{
_ft4Connection = await Ft4Connection.Create(_client, userSignature);
}
}
Initialize()
: Establishes a connection with the Chromia node using the providedHOST
andCHROMIA_PORT
.OpenStrategyRegisterAccount()
: Registers a new account with an open strategy and initializes theFT4Connection
with the resulting account.LoginWithExistingAccount()
: Logs in using an existing private key and establishes anFT4Connection
.InitializeFt4Connection()
: Sets up theFt4Connection
using the providedSignatureProvider
.
Connecting to the blockchain
You can connect to the network using the Directory System Chain to automatically determine node URLs:
private async Task InitializeClientFromDirectory()
{
var client = await ChromiaClient.CreateFromDirectory("http://localhost:7750", blockchainRID);
Debug.Log("Client connected through directory");
}
Queries
To query data from the blockchain, define query parameters and call the query method. For the Tic Tac Toe game, you'll query the game state and player moves.
public async UniTask<GameData> GetGameById(int gameId)
{
return await client.Query<GameData>("get_game_by_id", ("id", gameId));
}
Transactions
To send transactions, create operations and use a signature provider to sign them. Transactions are invoked through the Ft4Connection
's CurrentSession
, which ensures they are authorized using the correct credentials under the hood.
public async UniTask<bool> MakeMove(int gameRowId, int slot)
{
var transactionReceipt =
await _blockchainService.Ft4Connection.CurrentSession.Call(new Operation[]
{ new("make_move", gameRowId, slot) });
if (transactionReceipt.Status is TransactionReceipt.ResponseStatus.Confirmed)
{
return true;
}
Debug.LogError(
$"Could not make move for slot {slot} in game {gameRowId}. Reason: {transactionReceipt.RejectReason}");
return false;
}
Error handling
Handle errors using try-catch blocks. The client throws exceptions like ChromiaException
or TransportException
if issues arise. Be prepared to manage errors related to transaction signing or client communication.
private async Task HandleTransactionAsync()
{
try
{
await MakeMove("gameId", 1, 1, 'X');
}
catch (ChromiaException ex)
{
Debug.LogError($"ChromiaException: {ex.Message}");
}
catch (TransportException ex)
{
Debug.LogError($"TransportException: {ex.Message}");
}
catch (Exception ex)
{
Debug.LogError($"Exception: {ex.Message}");
}
}